Sublime Forum

A few questions on a completions plugin

#1

Hi All,

FIrstly, this is my first play around the plugin system so I’m very new to this so please excuse any unintended stupid questions. Now, I’m trying to write a plugin to enhance the JavaScript auto completion functionality. But I was wondering a few things which I’m having trouble finding info about:

  • Is it possible for my plugin to get access to the Snippets/Buffer Contents generated completions, i.e. Can I just return completions from my on_query_completions function and ensure that will be the only list of completions displayed?
  • For testing purposes I have hard coded some completions, this works in some cases however, sometimes even though I return this list the status bar still says: ‘No available completions’, why are my completions being ignored?
  • How can I set a scope for my plugin? Even though I’m being performance concious I’d rather not even be notified of say python auto completions when I only care about JS
  • How can I force my plugin to also get called when in comments (support auto-complete for comments). Currently my on_query_completions is not fired when CTRL+ENTER in comments.
  • Finally does sublime keep a cached files map (CTRL + P is so fast that I assume it does). Is this available to the plugin ecosystem?

Thanks all

0 Likes

#2

Here is an extract from my ‘on_query_completions’. It’s for Python, but you can gain a few hints from it.

match_selector allows you to target/scope the completions behaviour. Remove ‘-comments’ if you wish;
‘prefix’ allows you to check what they’ve typed as the trigger, and ‘locations’ gains you access to preceding text;
extract_completions enables reading of the default completions list;
INHIBIT_WORD_COMPLETIONS and INHIBIT_EXPLICIT_COMPLETIONS enables you to prevent the default completions from appearing.

[code]import sublime, sublime_plugin

py_funcs =
(“import()\t__import__ fn”,
import(${1:name}${2:, globals, locals, fromlist, level]})$0”),
(“abs()\tabs fn”, “abs(${1:number})$0”),
(“all()\tall fn”, “all(${1:iterable})$0”),
(“any()\tany fn”, “any(${1:iterable})$0”),
(“bin()\tbin fn”, “bin(${1:integer})$0”),
(“bool()\tbool fn”, “bool(${1:[value]})$0”),
(“super()\tsuper fn”, “super(${1:type}${2:, object/type]})$0”),
(“tuple()\ttuple fn/ctor”, “tuple(${1:[iterable]})$0”),
(“type()\ttype fn”, “type(${1:object})$0”),
(“type()\ttype ctor”, “type(${1:name}, ${2:bases}, ${3:dict})$0”),
(“unichr()\tunichr fn”, “unichr(${1:[integer]})$0”),
(“unicode()\tunicode fn”, “unicode(${1:[object, ]}${2:encoding}${3:, errors]})$0”),
(“vars()\tvars fn”, “vars(${1:[object]})$0”),
(“xrange()\txrange fn”, “xrange(${1:[start, ]}${2:stop}${3:, step]})$0”),
(“zip()\tzip fn”, “zip(${1:iterable})$0”)
]

py_members = # methods and attributes
(“add()\tset”, “add(${1:elem})$0”),
(“append()\tMutable”, “append(${1:x})$0”),
(“split()\tstring”, “split(${1:[sep]}${2:, maxsplit]})$0”),
(“splitlines()\tstring”, “splitlines(${1:[keepends]})$0”),
(“writelines()\tfile”, “writelines(${1:sequence})$0”),
(“zfill()\tstring”, “zfill(${1:width})$0”)
]

subl_methods =
(“active_group()\tST Window”, “active_group()$0”),
(“active_view()\tST Window”, “active_view()$0”),
(“active_view_in_group()\tST Window”, “active_view_in_group(${1:group})$0”),
(“active_window()\tsublime”, “active_window()$0”),
(“add()\tST RegionSet”, “add(${1:region})$0”),
(“add_all()\tST RegionSet”, “add_all(${1:region_set})$0”),
(“add_on_change()\tST Settings”, “add_on_change(${1:key}, ${2:on_change})$0”),
(“window()\tST View”, “window()$0”),
(“windows()\tsublime”, “windows()$0”),
(“word()\tST View”, “word(${1:region/pt})$0”)
]

sublime_methods_all = list(py_members)
sublime_methods_all.extend(subl_methods)

class PythonCompletions(sublime_plugin.EventListener):
def on_query_completions(self, view, prefix, locations):
global py_funcs, py_members, subl_methods, subl_methods_all
if not view.match_selector(locations[0], ‘source.python -string -comment -constant’):
return ]
completions = ]
pt = locations[0] - len(prefix) - 1
ch = view.substr(sublime.Region(pt, pt + 1)) # the character before the trigger
is_dot = (ch == ‘.’)
if is_dot: completions = py_members
if not is_dot: completions = py_funcs
if view.find("(?:from|import)\s+sublime", 0) is not None and is_dot:
completions = sublime_methods_all # include Python methods/attributes
compl_default = [view.extract_completions(prefix)]
compl_default = (item + “\tDefault”, item) for sublist in compl_default
for item in sublist if len(item) > 3] # flatten
compl_default = list(set(compl_default)) # make unique
compl_full = list(completions)
compl_full.extend(compl_default)
compl_full.sort()
return (compl_full, sublime.INHIBIT_WORD_COMPLETIONS |
sublime.INHIBIT_EXPLICIT_COMPLETIONS)[/code]
I’ve attached my JS completions file as well, as it may save you some typing :wink:. Mine exhibit specific behaviour. For example, it prepends ‘window’ or ‘document’ for some members.
AndyJS.zip (10.1 KB)

0 Likes

Completions - find previous word
#3

My JS completions list includes CSS properties, listed at the bottom. They are preceded by an underscore but you could find/replace the underscores.

0 Likes

#4

[quote]* For testing purposes I have hard coded some completions, this works in some cases however, sometimes even though I return this list the status bar still says: ‘No available completions’, why are my completions being ignored?

  • How can I force my plugin to also get called when in comments (support auto-complete for comments). Currently my on_query_completions is not fired when CTRL+ENTER in comments.
  • Finally does sublime keep a cached files map (CTRL + P is so fast that I assume it does). Is this available to the plugin ecosystem?[/quote]
  1. Do you get an error message in the console (Ctrl-’)? Perhaps you can post your (zipped) completions - there may be a syntax error. Is the file named ‘.sublime-completions’?
  2. As mentioned, you could remove ‘-comments’ - this is also mentioned in the default settings. [Personally, I’d rather live without this - it’s too intrusive :frowning: ].
  3. Do you want access to all the files in your project, or just open files? What is your aim?
0 Likes

#5

Thanks for the great answers agibsonsw.

  1. No no error and no the file is a plugin not a sublime-completions file. I’ll add to gihub soon and send link, however I don’t think its my plugin as even with a super simple plugin (i.e. return (‘testing’,)]) this still happens in certain cases. For instance in the method:
    def on_query_completions(self, vi**|**, prefix, locations):
    If I ctrl+enter here then I do not get my ‘testing’ completion, infact the name ‘view’ is automatically being inserted without showing an auto completion list.

  2. Thanks

  3. I’m parsing files for auto completion purposes and I figured if I can check a cache before reading them in it could save time. These files are not necessarily open files but they are in the project.

0 Likes

#6

@gatapia

I would need to see your code, but** Ctrl-Space** is usually the key-sequence that produces the auto-complete list. If the code is correct then it’s likely to be a scoping rule. The scope for auto-completions is in the default settings file, but can be overridden by user settings or syntax-specific settings (or by your code).

The following code indicates how you can extract completions from open tabs/files; it would need to be modified to scope JS files only. You can either use ‘view.match_selector(0,‘source.js’)’ for each view (easier!) or use the os library to read each file extension.

To extract completions from all files in the project - whether open or not - would be more of a challenge. You would probably need to open each file, then use a regex (or extract_completions) to create your list. This should probably be run (if at all :wink: ) as a TextCommand, to build and store these additional completions. [There is an auto_complete list in the file ‘.sublime-workspace’, but it’s really a history of auto-complete usage and not particularly useful.]

It might be worth considering using the open/close file events. This way, you could open a file temporarily, it’s completions could be extracted, and then you could close the file. But I’m guessing, as I don’t know your ultimate aim :laughing: .

[code]import sublime_plugin, sublime

class AutocompleteAll(sublime_plugin.EventListener):

def on_query_completions(self, view, prefix, locations):
    window = sublime.active_window()
    # get results from each tab
    results = [v.extract_completions(prefix) for v in window.views() if v.buffer_id() != view.buffer_id()]
    results = (item,item) for sublist in results for item in sublist] #flatten
    results = list(set(results)) # make unique
    results.sort() # sort
    return results[/code]
0 Likes

#7

Additional: If you consider using the open event to extract completions, you would need to persist (pickle!) this list and then extract it into a global variable-list. Otherwise, you would have to re-open the same file whenever you re-start ST. But I’m just thinking out loud :wink:

0 Likes

#8

‘but can be overridden by user settings or syntax-specific settings’:
This must be the problem, as its not my code. I’ll go through all settings. I guess it could also be docblockr or codeintel doing some fancy things here also.

And yes, currently I’m just using os.path to read all files in the background and pickling to disk so this works well also.

I think most ‘hurdles’ are now out of my way and I just need to code this.

Your first code sample was really great and I got a lot out of it, namely the compl_default, and the sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS flags. So thanks heaps for your effort.

BTW, I’m actually working on a plugin to handle google closure (github.com/gatapia/sublime_sett … Command.py) (as part of my ST2 settings repo I use to share settings between computers), but again this is just a scratch pad at the moment.

Thanks heaps

0 Likes

#9

Hello @gatapia.

I’ve only just glanced at this Google closure thing. Being of a cynical turn-of-mind… now Google can not only trawl our web-sites, but they can even read, and interpret, our JavaScript code :astonished: :laughing:

0 Likes