Horay
Horay

Reputation: 1408

Sublime Text menu item not working

I'm trying to create a sublime text plugin. I successfully created it, and I'm now trying to add an item to the menu, and when it's selected, it will call the plugin. I'm having trouble inserting the menu item in the correct place, and calling the plugin once created.

Say I have the following plugin:

import sublime, sublime_plugin

class ExampleCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.insert(edit, 0, "Hello, World!")

I created a folder at

C:\Users\"userName"\AppData\Roaming\Sublime Text 3\Packages\"My Plugin"

and added the plugin file to that directory. I then added the following code in a file called Main.sublime-menu

[
{
    "id": "file",
    "children":
    [
        {"id": "save"},
        {"caption": "My Plugin"},
        { "command": "myPlugin" }
    ]
}
]

The problem is, I get two My Plugin and myPlugin items in the menu, and it's after the exit menu. I want it to be after save. Also, when I select My Plugin, I get an error in the console:

Unable to parse command:

How can I add a menu item after the save menu item, and have the menu item call a plugin called myPlugin?

Upvotes: 4

Views: 715

Answers (1)

OdatNurd
OdatNurd

Reputation: 22791

Command names in plugins are not taken from the name of the python file that they're stored in; they are derived from the name of the class that implements the command so that multiple commands can be stored in a single file.

Additionally, command names are snake cased and forced to be all lower case. If your class is not named in that style, Sublime will convert it to that style by:

  1. Throwing away the Command text at the end (if it exists)
  2. Convert a leading upper case character to lower case
  3. Replacing every other upper case character with an underscore and that character's lower case equivalent.

This means that for your example above, the command name you would use is example. You can't make it be myPlugin because that has an upper case character in it. Naming the class MyPluginCommand, MyPlugin or my_plugin would create a command named my_plugin, which is as close as you can get.

Your example content for Main.sublime-menu is not following the proper data structure for the items in the children array, which is why the items appear twice. There is some unofficial documentation on the menu format that outlines the fields and structure for menu items.

The reason the items are being appended to the end of the menu is because of how menus from multiple packages are merged together. Basically some items have an id field in them that gives them a unique ID; when multiple items have the same ID, they get concatenated together in the order that the packages that they came from were loaded.

Your menu items use the id of file to indicate the file menu, and then include an id of save; since the default main menu does not contain an item with that id, your items get stuck onto the end of the menu instead.

The error you're seeing in the console is because the menu item with the caption of My Plugin does not contain a command field; instead, the menu item that follows it specifies a command and does not specify a caption. Sublime is telling you that it can't parse the command because it couldn't find one.

In order to do what you want, you want a Main.sublime-menu that looks something like this:

[
    {
        "id": "file",
        "children":
        [
            {
                "caption": "My Plugin",
                "command": "my_plugin"
            }
        ]
    },
]

This assumes that you have renamed the class implementing the command as outlined above.

Upvotes: 2

Related Questions