don't have to write code to "support for XYZ language" anymore • Programming language toolchain developers ◦ They don't have to write "XYZ editor plugin" anymore • YOU! • Microsoft
or executables • Modern languages (in certain culture): also provide libraries/tools/features to let developers programmatically compile and query states about the sources and referenced libraries. = works as a language service • existing language servers (or alike): clang, Roslyn, typescript server
`Foo` are available?" - Completion • "Where is this `Bar` defined?" - Go To Definition • "From which source lines is this `Baz` referenced/used?" - Find Usages etc.
• Why "protocol" ? ◦ should not be exclusive to specific programming languages ◦ If it is a C library then web-based editors won't support it (wasm? / text encoding?) • uses JSON-RPC ◦ gnome-code-assistance: depends on DBus = GNOME specific • common subset from many languages
• Client: basically a text editor • Available Clients ◦ vscode, eclipse, emacs, vim, atom, VS • Available Servers ◦ "some" languages, but already too many to list.
completion onto the source code. textDocument/signatureHelp to get help for method arguments etc. completion triggers are fixed to dot '.' may be specified by server at `initialize` (may also be triggered by CTRL+SPACE etc.) signature help triggers are fixed to comma ',' also customizible.
(typically) at cursor. ◦ typically for "Go To Definition" ◦ It can point to multiple source locations • textDocument/typeDefinition - similar to `definition`, but for the "type" of the symbol at cursor. ◦ for `val` (Kotlin), `var` (C#), `let` (TypeScript) etc. • textDocument/hover - can be API definitions etc. but not limited to them.
interesting, but text editors need to send them to language servers. • textDocument/didOpen • textDocument/didChange • textDocument/willSave • textDocument/didSave • textDocument/willClose • textDocument/didClose • workspace/applyEdit
language server protocol fits with... • simple-to-mid-level language ◦ for too simple languages you wouldn't even need any editor support. ◦ If you only need syntax highlighting, just use tmLanguage. • it should be noted that LSP is a common subset of various languages. ◦ "language servers and IDEs" - critical post on LSP (rust rls/KDevelop)
e.g. extension/css (has `css.tmLanguage.json` which works without LS) • Extensions with language service ◦ Direct implementation - uses only vscode API ◦ LSP implementation - uses LS (`vscode-languageserver ` package) ▪ e.g. extension/css-language-features Language Extension Guidelines - very nice documentation about them.
and language server. Server can be out-of-process. VSCode Language Feature Extension "client" entrypoint (JS) activate() { ... } package.json "main": "src/out/entrypoint" "server" implementation listen and notify on stdio/ipc
`src/extension/css-language-features` (as an example) ◦ `client` // extension entrypoint (`activate()`), launches server ◦ `server` // actual LS, typically standalone executable ▪ import "vscode-languageserver" // LSP for node.js [repo] Microsoft/vscode-languageserver-node ▪ import "vscode-css-languageservice" // actual CSS parser/compiler [repo] Microsoft/vscode-css-languageservice Server can be implemented in any language. You can use stdio. Useful example: [repo] Microsoft/vscode-languageserver-node-example
a compiler, or make changes to existing one • Compilation phases ◦ parsing: build token trees ▪ folding parser (#if etc.) ▪ tokenizer/lexer and parser (syntax errors) ◦ semantic analysis: build semantic trees ▪ symbol resolution (check unknown identifiers) ▪ validation (inheritance, type checking) ◦ code generation - most unlikely relevant to language services
always get precise location, and they have to be for both start and end of the tokens. • Don't try too hard, start implementing from whichever you can. ◦ e.g. compile everything whenever language feature is requested. ◦ e.g. compile and update symbol locations only when sources are saved.
compile and get errors, then report them ◦ `documentSymbols`: get source code tree (AST) and return the locations. • HARD: ◦ `definition`: need to get AST, then find where "current token" is, resolve semantic tree, search symbol by identifier from semantic tree. ◦ `completion`: similarly get semantic node from "current token", then return list of available members depending on context (e.g. static or instance).
developers and their users. • LSP provides various features e.g. completion, definition, references... ◦ Yet the feature set is limited to common usages. • You can implement LS in any language, adapt it in a language extension ◦ You can use stdio.