sublime_lib icon indicating copy to clipboard operation
sublime_lib copied to clipboard

API to list/inspect commands

Open Thom1729 opened this issue 6 years ago • 3 comments

PackageDev needs to know what commands exist in order to perform autocompletion, and it provides an implementation of the necessary logic (as well as a list of known built-in commands). The same logic could be useful for other packages as well. For instance, I have an unpublished concise keymap package that could provide similar autocomplete functionality.

Integrating this functionality into sublime_lib, in a similar-ish manner to sublime_lib.list_syntaxes() and such, would allow other plugins to easily make use of it. It would also be an opportunity to add a robust test suite.

Thom1729 avatar Jun 05 '19 15:06 Thom1729

I have to wonder how packages would use the quite specific implementation for PackageDev and how many those would be tbh. Currently it has a large focus on auto completion, which is why built-in commands are included separately, at which point I believe that another package looking to implement completions for their own configuration format might as well require PD to be installed and use the module from there.

FichteFoll avatar Jun 05 '19 15:06 FichteFoll

I imagine that the API would be something like this:

  • list_commands() → List[CommandInfo]
  • get_command_by_name(name) → CommandInfo

Where CommandInfo is a namedtuple with the following properties:

  • name: string
  • kind: "application" | "window" | "text"
  • command_class: optional subtype of Command
  • parameters: ordereddict[string, inspect.Parameter]

A builtin command would have a command_class of None.

Currently, one of the PackageDev completions is implemented as follows:

from ..lib import sorted_completions
from .commandinfo import (
    get_command_name,
    get_builtin_commands,
    iter_python_command_classes
)

class SublimeTextCommandCompletionListener(sublime_plugin.EventListener):

    @staticmethod
    def _create_completion(c):
        name = get_command_name(c)
        module = c.__module__
        package = module.split(".")[0]
        show = "{name}\t{package}".format(**locals())
        return show, name

    def on_query_completions(self, view, prefix, locations):
        # scope check omitted

        command_classes = iter_python_command_classes()

        completions = set()
        completions.update((c + "\tbuilt-in", c) for c in get_builtin_commands())
        completions.update(self._create_completion(c) for c in command_classes)
        return sorted_completions(completions), sublime.INHIBIT_WORD_COMPLETIONS

With this API, it could be implemented thus:

from ..lib import sorted_completions
from sublime_lib import list_commands

class SublimeTextCommandCompletionListener(sublime_plugin.EventListener):

    def on_query_completions(self, view, prefix, locations):
        # scope check omitted

        def command_source(klass):
            if klass is None:
                return 'built-in'
            else:
                return klass.__module__.split(".")[0]

        completions = [
            ("{name}\t{source}".format(
                name=command.name,
                source=command_source(command.command_class)
            ), command.name)
            for commmand in list_commands()
        ]

        return sorted_completions(completions), sublime.INHIBIT_WORD_COMPLETIONS

The sublime_lib API would determine the command names and merge the builtin and class-based commands so that the client code would be presented with a uniform list.

Thom1729 avatar Jun 05 '19 17:06 Thom1729

Can you think of a use case other than what PD already provides?

The only other thing I know is EditPreferences which opens a command palette with all commands implemented through plugins and allows you to view their source. But that doesn't need the commands' arguments or built-in commands and would barely make use of this in form of a library.

FichteFoll avatar Jun 05 '19 20:06 FichteFoll