microsoft/language-server-protocol

Real model for snippets

mickaelistria opened this issue · 10 comments

Currently, the snippets are defined with string conventions. That causes multiple issues:

  • Every client has to reimplement a parser for those $... strings
  • adopting snippets is somehow difficult and error-prone as it requires to make computations on the insertText. It also needs to be reimplemented by all clients
  • if the language actually wants to deal with $, { or :, it requires to escape those characters.

I believe the protocol would be better at creating a model object for those tabstops. It would make things simpler to specify, adopt and maintain.

Here is a suggestion: allow those tabstops in text edit:

interface TextEdit {
	range: Range;
	newText: string;
	editGroups?: EditGroup[]
}

interface EditGroup {
	ranges: Range[]; /* Relative to the new Text of the edit, not overlapping */
	possibleValues?: string[] /* possible suggested values for this group */
}

So instead of sending a TextEdit with newText=one$1 two${2:foo} three$1, LS would send

TextEdit: {
	range: {offset: o, length: l},
	newText: "one twofoo three",
	editGroups: [
		{
			ranges: [
				{offset: 0, length: 0},
				{offset: 16, length: 0}
			]
		},
		{
			ranges: [
				{offset: 7, length: 3}
			],
			possibleValues: [ "foo", "bar", "whatever" ]
		}
	]
}

Then applying this becomes trivial: first apply the text, and then use the editGroups to put tabstops and so on.
Some additional benefits:

  • it allows the clients that don't support tabstops to use the result anyway, as they can ignore the tabstops but still get interesting completion/edit
  • it introduces the possibleValues which are nice assistance for placeholder (widely use in Eclipse Java Development Tools)
alanz commented

Where are these $... strings specified?

The docs for InsertTextFormat as well as (redundantly) in the docs for completion capabilities. The capability to handle snippets is one of the 'optional' features a client can implement.

Note that with my proposal, a server wouldn't really need to make the difference between snippet support or not: the edit only would already be valuable and usable (whereas snippets don't make it nice if not supported nowadays) and then clients could -optionally- implement the support for snippets/editGroups.
So adopting such a model over some text conventions would make it simpler to write multi-IDE servers (as the snippetSupport capability could become ignored) and clients (who'd have way less string manipulation to do).

Actually when we worked in the snippet support in VS Code we discussed such an approach. The reason why we decided against it is that creating the snippets is harder. If a character is added to the string you might need to adjust offset and length. This seemed to be very cumbersome. So you will either write code to help you with that or the client writes code to parse the snippet. We decided that overall it is better to ask the client to parse a string with a certain syntax (as other tools do as well). We took a subset of the text mate syntax so that client don't need to start from scratch.

I agree that such a support would allow clients to easier provide snippet support since applied edits is easier than parsing strings.

If I change the newText to one twofoo three four and I want the last tab stop to be at the end I need to update ranges. Same is true if I for example change foo. So you need to track the positions when creating the snippet programmatically. If you use a language you can do something like this in TypeScript (back tick strings)

`one$1 two${my variable name} three$1`

If I change the newText to one twofoo three four and I want the last tab stop to be at the end I need to update ranges. Same is true if I for example change foo. So you need to track the positions when creating the snippet programmatically. If you use a language you can do something like this in TypeScript (back tick strings)

When you say "I", you mean as a user of the tool or as the provider of the language server? If it's as a user of the tool, then I'd say it's up to the tool to keep consistent range according to user input. If it's a language server provider, I imagine there could be helpers to easilty turn a string with parameter capturing into a modeled text edit.

To keep the number of issues in our inbox at a manageable level, we’re closing issues that have been on the backlog for a long time but haven’t gained traction: we look at the number of votes the issue has received and the number of duplicate issues filed. Thank you for your time and understanding.

If you disagree and feel that this issue is crucial: we’re happy to listen and to reconsider.