Sublime Forum

Question about on_query_completions()

#1

I’m working on a plugin with a ton of completions and would like to include a feature to be able to make them active or inactive.

My current way of going about this is to store the completions in a .json and then import them into a script in a .py file based on if corresponding values are true or false in the settings fil. These are then put in a list that I’m calling ‘allCompletions’, which is returned using on_query_completions() as seen here:

class CompletionsCommand(sublime_plugin.EventListener):
  def on_query_completions(self, view, prefix, locations):
    if JSON['scope'] in view.scope_name(view.sel()[-1].b):
      return allCompletions

As convoluted as this may seem, it’s working great! Thing is, it blocks any other completions that would otherwise appear in the specified scope, as if this is replacing all pre-existing completions. Is that what’s going on? Any idea how to stop it from doing that?

I’m also open to suggestions about other ways to go about making the specific completions active or inactive. I think I would ultimately prefer to be using .sublime-completions files, but is there a way to tell auto-complete to ignore specific ones via settings?

0 Likes

#2

First of all, why enable/disable certain completions? Do you want to apply some kind of context sensitive completion with it?

The later one could be achieved by splitting your completions into several lists with required scope selector being set up. You can create “SQL” like scope queries to select certain places in the text a completion should be offered.

Example of a *.sublime-completions

{
    "scope": "source.s840d_gcode - comment - string - support.variable - meta.control - meta.definition.variable - meta.redefinition - meta.function - meta.function-call",
    "completions": [
        {"trigger": "ACC\taddress", "contents": "ACC[${1:<AXIS>}]=${0:<REAL>}"},
        //...
    ]
}

You can also use &, |, , to create scope selectors to exactly determine when and where to offer completions.

In case of python driven completions I’d suggest the following structure to decide whether to offer something. match_selector and score_selector both allow the same queries as sublime-completions files.

    def on_query_completions(self, prefix, locations):
        """Provide a list of dynamically created completions."""
        # don't offer anything for multiple cursors
        if len(locations) > 1:
            return ([], 0)
        # start determines which completion to offer
        start = locations[0] - len(prefix)
        # check scope of charactor on `start`
        if not self.view.match_selector(start, 'source.mylang & keyword - string - comment'):
            return None
        return (allCompletions, 0)

I didn’t check how ST reacts if an ordinary list of strings is returned, but I use the tuple (list, flags) to explicitly set flags to 0, which enables explicit and word completions. This way ST offers results from all sources (allCompletions, *.sublime-completions and words from view-buffer).

1 Like

#3

Thanks for the reply!

What I’m working on is a package of completions for a rather extensive JS library with ~900 completions. So the first reason for enabling/disabling them would be for the sake of making the completions list less cluttered. The other reason would be that the package also includes a context menu that acts as a reference guide for the library and I could imagine the user wanting to turn off the completions while keeping the context menu available. If I stay the route of using *.sublime-completions files (the current version in production uses them), it seems like you can only disable/enable the entire package rather than turn the completions off while keeping the context menu available, correct? Is there a way to tell ST to ignore specific *.sublime-completions files?

0 Likes

#4

The settings to enable/disable completions are meant for the user to decide whether he is working in a JS file which uses your library or not?

There is no direct way to enable/disable *.sublime-completions files as they are expected to provide completions which are selected by ST based on the scope of a file. You could either rename the files dynamically to enable/disable them, but I wouldn’t recommend something like that as it is some kind of hack only.

Another possible solution might be to create a custom sublime-syntax file which just replaces the top-level source.js scope by a custom one source.js.myone which you can use as selector in the sublime-completions files. This way a user would just need to select the correct syntax to enable completions for your library.

The file could look like:

%YAML 1.2
---
name: JavaScript (My One) # custom name
file_extensions:
  - js
  - htc
first_line_match: ^#!\s*/.*\b(node|js)\b
scope: source.js.myone    # replace / extend top-level scope
contexts:
  main:
    - include: scope:source.js

You won’t loose any feature or break with a future update of a default JavaScript package.

Otherwise you’ll need to implement completions as a python module and need to handle the selectors on your own, to gain some kind of context sensitive completions. You could use https://github.com/sublimehq/Packages/blob/master/CSS/css_completions.py as an example to learn how to something like that. It supports context sensitive completions for CSS but is still quite easy to understand.

2 Likes

#5

The enable/disable would be more for the purpose of being able to turn the completions off but still have other features available - like the context menu.

I’ll take a look through css_completions.py and see how they do it. Thanks for the help!

0 Likes