Sublime Forum

How does sublime merges menu files?

#1

I’ve asked already about it on StackOverflow https://stackoverflow.com/questions/55995518/how-to-merge-menu-subtrees

Even so, does anyone know how the algorithm used to merge json menu files in Sublime could be coded in python? If not, do you know any library to accomplish this?

Thanks in advance :wink:

0 Likes

#2

I did a lot of testing and reverse engineering to end up with the explanation on the unofficial docs. The described mechanisms match all observed behavior:

http://docs.sublimetext.info/en/latest/reference/menus.html

1 Like

#3

@FichteFoll Thanks, I was already aware of that link… but my question is different, I’m trying to figure out what’s the algorithm used behind the curtains that creates the final menu. If we see the sublime-menu files as subtrees with an implicit hidden root it feels to me like the algorithm is some sort of special case of tree insertion operation, for instance, consider this:

subtree1 = {
    "id": "root",
    "children": [
        {
            "id": "file",
            "caption": "File",
            "children": []
        },
        {
            "id": "edit",
            "caption": "Edit",
            "children": []
        },
        {
            "id": "tools",
            "caption": "Tools",
            "children": [
                {
                    "id": "packages",
                    "caption": "Packages",
                    "children": []
                }
            ]
        },
        {
            "id": "help",
            "caption": "Help",
            "children": []
        },
    ]
}

subtree2 = {
    "id": "root",
    "children": [
        {
            "id": "file",
            "caption": "File",
            "children": [
                {"caption": "New"},
                {"caption": "Exit"},
            ]        
        }
    ]
}

subtree3 = {
    "id": "root",
    "children": [
        {
            "id": "edit",
            "children": [
                {"caption": "Copy"},
                {"caption": "Cut"},
                {"caption": "Paste"},
            ]
        },
        {
            "id": "help",
            "children": [
                {"caption": "About"},
            ]
        }
    ]
}

subtree4 = {
    "id": "root",
    "children": [
        {
            "id": "edit",
            "children": [
                {
                    "id": "text",
                    "caption": "Text",
                    "children": [
                        { "caption": "Insert line before" },
                        { "caption": "Insert line after" }
                    ]
                }
            ]
        }
    ]
}

I’d like to know how to code a merge algorithm so doing something like:

tree0 = merge(subtree1, subtree2)
tree0 = merge(tree0, subtree3)
tree0 = merge(tree0, subtree4)

would produce this:

tree0 = {
    "id": "root",
    "children": [
        {
            "id": "file",
            "caption": "File",
            "children": [
                {"caption": "New"},
                {"caption": "Exit"},
            ]   
        },
        {
            "id": "edit",
            "caption": "Edit",
            "children": [
                {"caption": "Copy"},
                {"caption": "Cut"},
                {"caption": "Paste"},
                {
                    "id": "text",
                    "caption": "Text",
                    "children": [
                        { "caption": "Insert line before" },
                        { "caption": "Insert line after" }
                    ]
                }
            ]
        },
        {
            "id": "tools",
            "caption": "Tools",
            "children": [
                {
                    "id": "packages",
                    "caption": "Packages",
                    "children": []
                }
            ]
        },
        {
            "id": "help",
            "caption": "Help",
            "children": [
                {"caption": "About"},
            ]
        },
    ]
}

but doing something like this:

tree1 = merge(subtree1, subtree2)
tree1 = merge(tree1, subtree4)
tree1 = merge(tree1, subtree3)

would produce:

tree1 = {
    "id": "root",
    "children": [
        {
            "id": "file",
            "caption": "File",
            "children": [
                {"caption": "New"},
                {"caption": "Exit"},
            ]   
        },
        {
            "id": "edit",
            "caption": "Edit",
            "children": [
                {
                    "id": "text",
                    "caption": "Text",
                    "children": [
                        { "caption": "Insert line before" },
                        { "caption": "Insert line after" }
                    ]
                },
                {"caption": "Copy"},
                {"caption": "Cut"},
                {"caption": "Paste"},
            ]
        },
        {
            "id": "tools",
            "caption": "Tools",
            "children": [
                {
                    "id": "packages",
                    "caption": "Packages",
                    "children": []
                }
            ]
        },
        {
            "id": "help",
            "caption": "Help",
            "children": [
                {"caption": "About"},
            ]
        },
    ]
}

Said otherwise, loading the sublime-menu in the same order (you’ve already claimed in the docs they’re loaded in lexicographical order) will always produce the same tree but using the same subtrees in different order are not guaranteed to produce the same tree (children list will be extended in different order)

0 Likes

#4

@FichteFoll I’ve edited my original question and posted some random chunk of code… but not sure if that’s even on the right track :confused: , so any advice will be well received

0 Likes

#5

Are you sure this is actually what happens? I don’t have the time around these days to go investigate into these things, but my understanding was that even if the fourth subtree was inserted before the third, you would still get the same output. If this is not the case, then my information on the undocs page is probably worng.

0 Likes

#6

Well, I haven’t tested directly on SublimeText but I thought that would be the expected outcome… I mean, imagine this simple case:

tree1 = {
    "id": "root",
    "children": [
        {
            "id": "file",
            "caption": "File"
        }
    ]

tree2 = {
    "id": "root",
    "children": [
        {
            "id": "edit",
            "caption": "Edit"
        }
    ]
}

You’d like to be able to specify the order of appearence in the menu, right? So to me it’s obvious that merge(tree1,tree2) would be different than merge(tree2,tree1). In case you wanted the item File to be the leftmost or not in the menu…

Anyway, I’ve decided to give some bounties to my SO question, hopefully some smart guy will be able to explain which algorithm could be used :slight_smile: . Probably the logic is simple but I haven’t had any “aha” moment so far… so this beats me :stuck_out_tongue:

0 Likes

#7

Well, so far I’m quite confident in what I wrote down in the page I linked to be an accurate description of the algorithm that st uses internally. I hope that will be enough for you to translate it into code because I don’t have the time to do this very specific task for you. If you find anything during your investigation that doesn’t line up with what I wrote, I’d be glad to hear about it, review it and eventually update the docs.

0 Likes

#8

Sure, hopefully when the bounty period of my question expires a nice algorithm will emerge… so far one SO volunteer has created this algorithm … I’ll be testing it on the next coming days but so far so good

0 Likes