Sublime Forum

KSP Sublime Kontakt Script Processor Plugin

#1

Would anyone know of a way to make the $ character work as an autocomplete trigger in Sublime?

The KSP Sublime plugin was developed by Nils Liberg for editing scripting code for the Kontakt instrument sample player app.

The Kontakt script language uses the $, %, ~, @, ! characters as variable name prefixes to indicate the type of variable it is. When these characters are put in KSP Sublime settings as additional Sublime autocomplete triggers, only %, @, ! work correctly.

The $ character does trigger an autocomplete dropdown but when a completion is selected, the entry is erased instead of being completed.

The ~ character does not trigger autocomplete.

Since $ is the prefix for integer variables, it is used more often than any other prefix. Triggering on $ for completion of integer variable names would be most beneficial while editing Kontakt script. As a work around until I find a way to make the $ character work, I will use the Sublime built-in trigger character."<" with “<?” as the integer variable prefix while editing and then replacing all “<?” instances with $ before compiling the script.

0 Likes

#2

It looks like there’s a KSP (Kontakt Script Processor) package currently in Package Control that’s a fork of the original plugin; can you confirm which one you’re using?

If you can also provide a small example script and an example of a completion that doesn’t work for testing purposes, we can dig in a little more and see what we can find.

0 Likes

#3
I am using the KSP Syntax package in Package Control. To experience what I described in my post, do the following:

1. Open a new file in Sublime
2. Select the KSP Syntax package in Package Control
3. Navigate to Preferences / Settings - Syntax Specific
    This opens a window with two tabs
        a. Preferences.sublime settings on the left
        b. KSP.sublime settings on the right

4.Replace the code in the KSP.sublime settings tab with the following code

code
// These settings override both User and Default settings for the KSP syntax
    {
        // Additional situations to trigger auto complete
        "auto_complete_triggers": [ {"selector": "text.html", "characters": "<, $,%, @, !, ~"} ],
    }
end code

This code sets "<, $, %, @, !, ~"  as additional autocomplete trigger characters in sublime.

5. Type the following declare statements in the new file text editing window.

code
declare $integer
declare %intarray
declare @string
declare !stringarray
declare ~realvariable
end code

6. Then type each of the trigger characters in the subsequent lines and observe the autocomplete behaviors.
0 Likes

#4

Your problem is partly settings related and partly to do with problems with the package itself.

The first thing to note is that the selector in the auto_complete_triggers setting is for telling Sublime in what types of files the triggers should be applied. The setting that you outlined above has this set to text.html, which means that the setting only applies to HTML files.

The top level scope for files of this type is source.ksp (while editing a file of this type, choose Tools > Developer > Show Scope Name to see this; the first line in the popup is the one you would use to detect files of a specific type).

So in this case, the setting that you’re adding should look more like:

        // Additional situations to trigger auto complete
        "auto_complete_triggers": [
            {"selector": "source.ksp", "characters": "<$%@!~"}
        ],

Making this change in your settings will cause the ~ character to open the autocomplete popup as expected. This doesn’t fix the $ issue (more on that in a moment), and it doesn’t provide the completions you want (probably) in response.

If the intent of this is to have ~realvariable (as in this example) appear in the popup list, that’s not what happens. Instead, it contains a list of every built in function and variable in this language instead. This is partly because of the plugin in this package that’s providing the completions and partly because of a faulty setting provided by the package itself.

On the plugin front, the plugin is explicitly trying to gather all of the completions from the current file that start with the partial word to the left of the cursor, to which it adds the list of built in variables and functions in the language.

Technically this should work (it does for the other types), except that the package provides a broken setting. Specifically, if you use View Package File from the command palette and enter the filter text ksp ksp settings, you can find and open KSP (Kontakt Script Processor)/KSP.sublime-settings.

This is a syntax specific settings file for files of this type that ships directly with the package itself; it’s the packaged version of the syntax specific settings that you created yourself, only these settings are applied first and then your settings are applied on top.

In this file, you can see this setting:

    "word_separators": "/\\()\"'-:,;<>~#^&*|+=[]{}`~?",

This setting represents a list of all of the characters that should be considered to separate words (or if you will, they thus aren’t considered a part of a word). The ~ character appears in this setting (twice). That makes Sublime consider the ~ character to be a word separator.

The result of this is that when you type ~|, the autocomplete popup opens, but there’s no partial word to the left of the cursor. The plugin responds by not trying to get any completions from the buffer (it wants words that start with the partial word, but there is no partial word), and the result is that you only get the default functions and variables.

If you were to modify the setting and apply it in your own settings (along with the one you’re already using from above), the ~ character will open the autocomplete panel and offer all variables that start with ~:

    "word_separators": "/\\()\"'-:,;<>#^&*|+=[]{}`?",

The reason that the $ expansions don’t work is that the plugin isn’t generating them correctly, which is due to the fact that the $ is a special character in the body of a sublime-snippet, the completions from a sublime-completions file and the completions returned by a plugin.

Specifically Sublime treats the character specially (as if it starts an internal variable that Sublime should expand when the completion expands), so the completion is technically expanding, but the completion is telling Sublime to replace itself with nothing.

This is a bug in the plugin itself, and has already been reported in the package issue tracker back in 2018. Comments in the issue seem to indicate that you may not need to include the $ in usages of those variables in some cases. On the other hand, the plugin also explcitly tells Sublime to never try to gather its own completions from the file, which means that it’s not possible to autocomplete a variable name at all in that case.

Regardless of that, the fix for this is pretty simple if you want to get this up and running, although it does require modifying a line in the plugin file to get it to fix the completions for you.

In order to do that I would recommend the OverrideAudit package (though I’m biased because I’m the author, it’s more or less made for this kind of thing).

  1. Install OverrideAudit if it’s not already installed (it’s available in Package Control)
  2. Open the command palette and choose OverrideAudit: Create Override
  3. Select KSP (Kontakt Script Processor), then ksp_plugin.py
  4. Jump down to line 298, where this line exists:
            compl = [(item + "\tdefault", item) for item in compl
    
  5. Modify that line to look like this (make sure the indent is not changed; indent is important in Python)
            compl = [(item + "\tdefault", item.replace('$', '\\$', 1)) for item in compl
    
  6. Save the file

Essentially this is changing the text item to item.replace('$', '\\$', 1), so that in the completion item returned to Sublime, the first $ character (if any) is turned into \$ so that Sublime knows that it should leave it alone.

This change will create a folder named KSP (Kontakt Script Processor) in your Packages folder, and inside of that folder a file named ksp_plugin.py. As long as that file exists (you can find the folder by using Preferences > Browse Packages) it will be used instead of the version that is provided by the package author. You can remove the change at any time by removing that file.

4 Likes

#5

I was blown away by your response to my post. After reading numerous discussions about this issue in google search results and on forums, I pretty much concluded no resolution of the issue was out there. In fact, I began using the workaround described in my post. Not only do you provide the solution you also explain what is going wrong under the hood with explicit instructions on how to fix it.

I followed your directions and now autocompletion in my KSP sublime works beautifully. Thank you for taking the time and effort to provide an education on the underlying causes of the issues and how to fix them. Thanks also for the OverrideAudit package that you wrote -the tool needed to fix the $ autocomplete problem.

I am sure other Kontakt script developers would appreciate having your solution to the autocomplete problems. With your permission, I would like to post your reply verbatim on the Native Instruments Kontakt scripting forum. If you consent, how should I credit you as the author?

Thanks again.

2 Likes

#6

Glad I could help! Feel free to post/link as you see fit. Just a mention is enough, I don’t require any particular credit as the author or anything like that.

0 Likes

#7

This fix for making the Kontakt script variable prefixes trigger autocomplete in Sublime works perfectly until I close Sublime and then restart Sublime. After restarting, the triggers still work but the enter key no longer generates a new line. This seems to happen if no ksp source was open for editing when Sublime was closed.

I could find nothing amiss in the OverrideAudit reports.

Here’s what I get in the console when I log inputs and commands
key evt: enter
command: ksp_on_enter

The ksp_on_enter command does nothing. I have not been able to trace the issue any further.

0 Likes

#8

This issue is ultimately the result of something a bit hacky that the plugin is doing at startup. Once the override from above is in place, the code will no longer load from a clean start. It doesn’t matter if there was a KSP file open or not, just quitting and restarting is enough to break it.

For example, if you were to start Sublime fresh with the change in place, and then use View > Show Console, you can see this appearing in the console (though the path you see will be different based on your install, operating system, etc):

reloading plugin KSP (Kontakt Script Processor).ksp_plugin
Traceback (most recent call last):
  File "/home/tmartin/local/sublime_text_3_sandbox/sublime_plugin.py", line 116, in reload_plugin
    m = importlib.import_module(modulename)
  File "./python3.3/importlib/__init__.py", line 90, in import_module
  File "<frozen importlib._bootstrap>", line 1584, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1565, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1532, in _find_and_load_unlocked
  File "/home/tmartin/local/sublime_text_3_sandbox/sublime_plugin.py", line 1183, in load_module
    exec(compile(source, source_path, 'exec'), mod.__dict__)
  File "/home/tmartin/local/sublime_text_3_sandbox/Data/Packages/KSP (Kontakt Script Processor)/ksp_plugin.py", line 15, in <module>
    import ksp_compiler
ImportError: No module named 'ksp_compiler'

With this error occuring, the plugin doesn’t load properly and thus no longer works. The problem here is less that ksp_on_enter does nothing and more that it now no longer exists as a command (it was never loaded). Sublime doesn’t generate errors if you try to execute a command that doesn’t exist, it just does nothing.

Without getting overly technical, this package contains a couple of external libraries that it needs in order to function. There are specific places that Python knows to look for code when it’s asked to load it, but inside of arbitrary packages isn’t one of them.

Generally a package author would handle this sort of situation by either converting the libraries into standard Sublime Text dependency libraries, or include them inside of their own package and modify them so that everything knows how to load them properly from there.

In this case, the package author is including the libraries directly inside of the package and then having the plugin manually modify the location where Python looks for libraries to include the place where these package files live.

As long as this plugin file is stored in the same place as the rest of the package, this works as intended. However in order to fix the problem above, this one plugin file is now stored in a different physical location, and as a result it’s telling Python to look in the wrong place.

The best ways to resolve this issue revolve around getting the package author to make changes so that it doesn’t need to do this sort of thing (or fixing the original bug so that you don’t need this file at all). You could also make those sorts of changes locally, but that’s fairly technical and requires a good working knowledge of Python.

There are other ways to fix this, but for a variety of reasons they’re not really recommended because they’re likely to cause problems down the line:

  1. If the modifications from above were made directly to the sublime-package version of the package, then it would work as expected. However in that case your changes would get discarded without warning if the package ever gets updated by its author.

  2. If you extracted the entirety of the sublime-package file to the Packages folder, then it would again work as expected because all of the files would be in the same place again. In this case the issue is that no matter what the package author does to update things, you’ll never know about it because you’ve explicitly told Sublime to ignore every file. Thus you’d miss bug fixes, new features, etc.

  3. You could delete the file we created above; that would stop the problem with the proviso that tab completions on $ variables won’t work because the bug fix is not in place. The other expansions would work though, since those were just settings based.

To a degree OverrideAudit would mitigate #2 because it will tell you if a file you’ve overriden has been updated at the source, but for the sheer volume of files that the package contains that might get a little daunting to handle should it actually occur.

One other method would be to modify the plugin just enough that it will still load as expected, but without the sort of technical, sweeping changes that would be needed to properly resolve the problem by the package authors. Should the authors fix the bug (or apply other updates), the edited file would still take precedence, though in that case OverrideAudit telling you that the file was updated is easier to handle because it’s just one file and not dozens.

To do that:

  1. Use View Package File from the command palette and enter ksp_plugin to filter the list, and then load the KSP (Kontakt Script Processor)/ksp_plugin.py file. The lines we want to change here are lines 12 and 13, which should look like this:

    sys.path.append(os.path.dirname(__file__))
    sys.path.append(os.path.join(os.path.dirname(__file__), 'ksp_compiler3'))
    
  2. Open up the Sublime console with View > Show Console and enter the following lines in the input, one at a time, pressing enter after each one

    import os
    print("sys.path.append(r'%s')" % os.path.join(sublime.installed_packages_path(), "KSP (Kontakt Script Processor).sublime-package"))
    print("sys.path.append(r'%s')" % os.path.join(sublime.installed_packages_path(), "KSP (Kontakt Script Processor).sublime-package", "ksp_compiler3"))
    
  3. After each of the print lines, Sublime will respond with output (in the trace, the output is text that doesn’t start with >>>). Copy each of those lines and replace the lines above with them. For me, that would make the top of the file look like this, but the paths that you see would be different based on your operating system, where you’ve installed Sublime, etc.

    sys.path.append(r'/home/tmartin/local/sublime_text_3_sandbox/Data/Installed Packages/KSP (Kontakt Script Processor).sublime-package')
    sys.path.append(r'/home/tmartin/local/sublime_text_3_sandbox/Data/Installed Packages/KSP (Kontakt Script Processor).sublime-package/ksp_compiler3')
    
  4. Save the plugin file

Once you save in step #4, if you look in the console you should see something like:

reloading plugin KSP (Kontakt Script Processor).ksp_plugin

If there are no errors following it, then you should be good to go. The plugin is now successfully loading the libraries it needs from the sublime-package version of the file.

0 Likes

#9

Thanks for your follow up again. Your 4 step fix above fixes the enter key problem. I’m back in business with a fully functioning autocomplete in KSP Sublime. I will place a link to this solution on GitHub where I also posted this issue.

0 Likes