[Visual Studio Extensibility] Adding/Installing snippets programmatically

Malte Klapper 1 Reputation point
2022-09-22T08:25:18.413+00:00

Hi,

I would like to fill a custom completion set/expansion menu with code snippets obtained from a server.

Is there a way to create snippet completion items programmatically without the need to create XML files?
I'm looking for something like VS Code has with CompletionItem and CompletionItemKind.Snippet.

Thank you!

Community Center | Not monitored
{count} votes

1 answer

Sort by: Most helpful
  1. Malte Klapper 1 Reputation point
    2022-10-12T07:32:50.957+00:00

    So I finally found a way to do in-memory snippets.

    The solution can be divided into two parts:

    • The completion session with the known completion dropdown
    • The snippet session, which allows switching between literals and so on

    1 Provide custom completion
    For the first part, I used this example of the AsyncCompletion.

    2 Starting expansion session with in-memory snippet
    For the snippet session I found a method on IVsExpansion called InsertSpecificExpansion (see documentation)
    This allows starting an expansion session with an in-memory XMLDOMNode. To be able to use this with my custom in memory snippet structure I had to do the following:

    • Create a serializable C#-Model for the Visual Studio Snippet Schema
    • Parse my custom snippets to that VS-Model
    • Use XML Serializer to create a IXMLDOMNode

    3 Link the parts together
    In order to link the two parts, I used the following approach: When a CompletionItem is chosen from the list, I cancel the regular completion and instead perform a ExpansionSession.
    First I had to add an additional Property to the CompletionItem so that the ExpansionSession later can access the XMLNode:

    completionItem.Properties.AddProperty("SnippetXML", snippetXMLNode);  
    

    This can later be used by the ExpansionSession to provide the node Parameter of InsertSpecificExpansion

    In CommitManager.TryCommit I first start the ExpansionSession and mark the CompletionSession as handled so no further actions are done:

            // use IVsEditorAdaptersFactoryService to get access to IVsTextview  
    	var vsTextView = VsEditorAdapter.GetViewAdapter(session.TextView);  
    	// start a snippet session using in-memory XML rather than .xml files  
    	ExpansionClient.StartExpansion(vsTextView, item);  
    
    	// we handled the completion by starting an expansion session so no other handlers should participate  
    	return CommitResult.Handled;  
    

    The ExpansionClient is an implementation of IOleCommandTarget and IVsExpansionClient. The Expansion follows the approach described here but the difference is it calls InsertSpecificExpansion instead of InsertNamedExpansion.

    I hope this may help anyone with the same problem. At some point, I will add a complete example on GitHub.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.