Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign a scope to a sublime text 3 context menu?

I added a right click context menu to sublime text 3 by creating a Context.sublime-menu file in Packages/user folder with the following configuration:

[
    {
        "caption": "wrap with try",
        "mnemonic": "t",
        "id": "try",
        "command": "insert_snippet",
        "args": { "name": "Packages/User/js-try.sublime-snippet" }
    }
]

This works fine. But I want it to appear only when the current file is a javascript file, just like you can assign a scope to a snippet by configuring <scope>source.js</scope>. I did not find any documentation on this on the one hand, on the other hand I see that there are context menu's that are behaving this way, so I know its possible. Does anyone know how to achieve this?

like image 993
aviv Avatar asked Nov 25 '25 19:11

aviv


1 Answers

Menu item visibility is controlled by the command being referenced. See the is_visible method at https://www.sublimetext.com/docs/3/api_reference.html#sublime_plugin.TextCommand.

As the built in insert_snippet command always returns True for this method, to achieve this, you will need to write a (small) custom plugin which will act as a wrapper for your desired command:

  • From the Tools menu -> Developer -> New Plugin...
  • Replace the template with:
import sublime
import sublime_plugin


class ProxyCommand(sublime_plugin.TextCommand):
    def run(self, edit, command_name, scope_selector, **kwargs):
        self.view.run_command(command_name, kwargs)

    def is_visible(self, command_name, scope_selector, **kwargs):
        return self.view.match_selector(self.view.sel()[0].begin(), scope_selector)
  • save it, in the User package, as something like proxy_command.py - the base filename doesn't matter, only the extension matters
  • now, change your context menu entry to: (note that we are now asking the menu entry to point to the proxy command we just created, and passing in arguments to tell it which scope (selector) it should be active for, and which real command to execute and with what arguments.)
[
    {
        "caption": "wrap with try",
        "mnemonic": "t",
        "id": "try",
        "command": "proxy",
        "args": {
            "command_name": "insert_snippet",
            "name": "Packages/User/js-try.sublime-snippet",
            "scope_selector": "source.js",
        },
    }
]

You could take this a step further and build a general purpose snippet wrapper command, which could read the snippet file (using the sublime.load_resource API and then parse the XML) to see if the <scope> specified there matches, rather than requiring it to be entered(/potentially duplicated) in the context menu entry.

like image 125
Keith Hall Avatar answered Nov 28 '25 17:11

Keith Hall