Implementing Custom Code Completion

There is two ways of adding custom code completion to HippoEDIT:

  • Implementing/registering own Completion provider. Recommended for most of use cases.
  • Subscribing on Application.onCompletion event, and showing completion list by yourself. Can be used if you want to use different UI for completion.

There are several APIs and scripting object that helps implementing the code completion logic.

Implementing a custom code completion using Completion Providers is a preferred way. You can register to call back only for specific syntax (and all other syntaxes inherited from it) and been called exactly at the moment when items are necessary, with minimum service code from your side, to give items back. In addition to that, usage of completion providers, allows HippoEDIT to call collection from different providers in parallel, that speedups general processing.

code-completion1.hejs
function onCompletionCollect(view, selection, set) {
	// if we are not inside of comments or documentation (Style.Text == 1 ), add our items to the list
	if ( view.Document.GetStyleFromPos(selection.Start, true).Style.Text != 1 ) {
		// add item as string, ше would be displayed using default style
		set.Add("Variable1");
		// or explicitely as completion item, if you want to better item customizing options
		// for example, assigning of special style, as below
		set.Add(CompletionItem("Variable1", "variable"));	
	}
	return true;
}
 
// create and register completion provider to be used for JavaScript (id="js") and all syntaxes inherited from it
Application.RegisterCompletionProvider("js", Application.CompletionProvider(onCompletionCollect));

If you want to take full control over the completion process, you can subscribe to onCompletion event and decide by yourself, what shall be the result of the event.
It can be a display of pre-filled Completion List or maybe, some special dialog or other UI. Be aware, that onCompletion event called for any syntax, so, if you want to limit your code completion to only some specific programming language, you need to implement filtering in the event code by yourself.

code-completion2.hejs
////////////////////////////////////////////////////////////////////////
// Register Code Completion Handler
Application.onCompletion = function(/*IRange*/ selection ) {
	if ( ActiveDocument.Syntax.IsInheritedFrom("js") ) {
                // simplest, just pass a list of strings
		var aSuggestions = ["Item1", "Item2", "Item3", "Item4", "Item5"];
		this.ShowCompletionList(selection, aSuggestions, false);
		return true; // event is handled
	}
	// event is not handled, editor shall execute default logic
	return false;	 
};

If for some reason, in your plugin you cannot create JS like array, to pass a list of strings, you can pass it as CompletionSet.

code-completion2.hejs
////////////////////////////////////////////////////////////////////////
// Register Code Completion Handler
Application.onCompletion = function(/*IRange*/ selection ) {
	if ( ActiveDocument.Syntax.IsInheritedFrom("js") ) {
		var completion_set = CompletionSet();
                // add as a string
                completion_set.Add("Variable1");
                // add as a completion item. To refer style you can use relative syntax e.g. "variable", 
                // absolute "js:method" or at all pass Syntax object directly
                completion_set.Add(CompletionItem("Variable2", "js:methods"));
		this.ShowCompletionList(selection, completion_set, true);
		return true; // event is handled
	}
	// event is not handled, editor shall execute default logic
	return false;	 
};

When you construct CompletionSet, you can initialize an object by another CompletionSet object (items would be copied) or by JS array with strings or CompletionItems.

var completion_set = CompletionSet([
CompletionItem("Item1", "js:methods"), 
CompletionItem("Item2", "variable"), 
CompletionItem("Item3") 
]);
 
// or
var completion_set2 = CompletionSet(["Item1", "Item2", "Item3"]);
Do not mix strings and CompletionItems in the same set - it is not supported, and editor will use a type of first object

If you need more customization of your item displayed in CompletionList, there are several options you can use when constructing explicit CompletionItem and passing it to the list.

var item5 = CompletionItem("Item5");
// custom insetion pattern, with code template syntax. 
// %CurrentWord% - inserted text
item5.Pattern = "%CurrentWord%(%|%)";
// custom description tooltip, shown when user scrolls over items and stops on one of them
item5.onDescription = function () { return this.Text + "() ..."; };
 
function onExpand(view, selection) {
	ActiveDocument.ReplaceText(selection, this.Text + "(...)");
}
 
var item6 = CompletionItem("Item6");
// adding of custom handler, which is called when item is selected and inserted
// default, inserts item Text property
item6.onExpand = onExpand;
// add small arrow icon on the right of the item, indicating that items expands
item6.SubMenu = true;
 
var aSuggestions = [
// add completion items with text and style, from which color/image/style of item shall be derived 
CompletionItem("Item1", "js:methods"), 
CompletionItem("Item2", "variable"), 
 
// use default style for item display
CompletionItem("Item3"), 
 
// define an item witthout style, but with explicit image, subimage (public/protected/private)
// description and selection call-back
CompletionItem("Item4", null, 11, 1, "Item4 Description", onExpand), 
item5, 
item6];