Description
openedon Nov 25, 2018
Hi!
A very useful feature of a syntax-aware code editor is semantic selection: editor.action.smartSelect
which is based on the real syntax tree and not on the lexical grammar approximation.
I've implemented it as a custom extension to LSP for a couple of my language servers, and I'd like to suggest adding this feature to the LSP proper, with the following interface:
// `document/extendSelection` is sent from client to server
interface ExtendSelectionParams {
textDocument: TextDocumentIdentifier;
selections: Range[];
}
interface ExtendSelectionResult {
selections: Range[];
}
Q&A:
Q: Why do we send an array of ranges?
A: This is to support multiple cursors. An argument could be made that this should be supported by the protocol-level batching of requests, but that seems much more complicated and potentially slow (server will have to resolve URL to document several times, etc)
Q: How about the opposition action, "shrinkSelection"?
A: Shrink selection is "ambiguous": given syntax node has many children, and selection could be shrunk to any child. The natural handling of "shrinkSelection" should be a client-side selection undo list.
Q: Why a range-based interface? Shouldn't the server just tell the client the syntax tree structure, and let the client implement "extendSelection"?
A: Using ranges is more general. There are cases when you want to do extend selection on a granularity smaller then a syntax node. For example, you might want to select an escape sequence in a string literal, or a word in a comment, or an expression in the code snippet in the comment. By providing a low-level range-based interface, we give servers maximum flexibility.
Q: Is there an example implementation?
A: Yep! Here's the bits then implement this feature in rust-analyzer server 1, 2, 3. Here's the client side implementation.