Teaching your editor a new programming language
NICOLÒ RIBAUDO
@nicolo-ribaudo
@NicoloRibaudo
https://nicr.dev
@NicoloRibaudo
Me
2
This is how I look online
These are things I do you might be using
This is where I work
@NicoloRibaudo
Why?
3
@NicoloRibaudo
Why?
You are creating your own programming language
Somebody else created a programming language, and your editor does not support it
Your editor poorly supports your usage of a given programming language
4
@NicoloRibaudo
Why?
Somebody else is creating a new programming language, you think it's cool, and you want to help more people use it
5
MessageFormat 2.0
@NicoloRibaudo
MessageFormat 2.0
MessageFormat 2.0 is a Unicode standard for localizable dynamic message strings, designed to make it simple to create natural sounding localized messages.
6
@NicoloRibaudo
MessageFormat 2.0
const message = new Intl.MessageFormat("en-US", `
`);
message.format({ name: "Luca" });
7
Hello, {$name}!
@NicoloRibaudo
MessageFormat 2.0
const message = new Intl.MessageFormat("en-US", `
`);
const message = new Intl.MessageFormat("fr-FR", `
`);
message.format({ name: "Luca" });
8
Hello, {$name}!
Salut, {$name}!
@NicoloRibaudo
MessageFormat 2.0
9
Today is {$today :date}.
Aujourd'hui c'est le {$today :date}.
"en-US"
"fr-FR"
"today": "2024-11-15"
Today is Nov 15, 2024.
Aujourd'hui c'est le 15 nov. 2024.
@NicoloRibaudo
MessageFormat 2.0
10
.input {$today :date}
{{Today is {$today}.}}
"en-US"
"fr-FR"
.input {$today :date}
{{Aujourd'hui c'est le {$today}.}}
@NicoloRibaudo
MessageFormat 2.0
11
.match $genderMarker
M {{He is {$name}}}
F {{She is {$name}}}
* {{They are {$name}}}
"en-US"
.match $genderMarker
M {{Il est {$name}}}
F {{Elle est {$name}}}
* {{Iel est {$name}}}
"fr-FR"
@NicoloRibaudo
MessageFormat 2.0
12
.match $genderMarker
M {{He is {$name}}}
F {{She is {$name}}}
* {{They are {$name}}}
"en-US"
"name": "Luca",
"genderMarker": "M"
He is Luca
They are Luca
"name": "Luca",
"genderMarker": "X"
@NicoloRibaudo
MessageFormat 2.0
Check https://messageformat.dev/�to learn more about it!
13
@NicoloRibaudo
Let's get started!
14
@NicoloRibaudo
15
@NicoloRibaudo
Syntax Highlighting
16
@NicoloRibaudo
17
mf2.tmLanguage.json
@NicoloRibaudo
TextMate grammars
18
@NicoloRibaudo
TextMate grammars
19
{
"name": "MessageFormat 2",
"patterns": [{
"name": "variable.other.mf2",
"match": "\\$[a-zA-Z_][a-zA-Z0-9_]*"
}]
}
Anything that matches the regular expression /\$[a-zA-Z_][a-zA-Z0-9_]*/ is in the category "variable".
@NicoloRibaudo
TextMate grammars
20
"patterns": [{
"name": "placeholder",
"begin": "\\{",
"end": "\\}",
"patterns": [{
"name": "variable.other.mf2",
"match": "\\$[a-zA-Z_][a-zA-Z0-9_]*"
}]
}]
… anything that matches the regular expression /\$[a-zA-Z_][a-zA-Z0-9_]*/ is in the category "variable".
Inside a section that starts with /\{/ and ends with /\}/…
Today $notVar is {$var}.
@NicoloRibaudo
TM grammars
We can have a variable both inside a placeholder, and inside a .input declaration.
Grammars can get … verbose.
21
{
"name": "MessageFormat 2",
"patterns": [{
"name": "placeholder",
"begin": "\\{",
"end": "\\}",
"patterns": [{ "include": "#variable" }]
}],
"repository": {
"variable": {
"name": "variable.other.mf2",
"match": "\\$[a-zA-Z_]…
}
}
}
Reference
@NicoloRibaudo
TextMate grammars
Tip! Grammars can get verbose: generate them!
lucacasonato/mf2-tools - tools/vscode/grammar.ts
lucacasonato/mf2-tools - vscode/syntaxes/mf2.tmLanguage.json
22
@NicoloRibaudo
23
@NicoloRibaudo
Marking the editor understand our code
24
@NicoloRibaudo
25
@NicoloRibaudo
What can editors do?
26
All of this is very interactive, we cannot just define it with a declarative JSON file!
@NicoloRibaudo
27
We can create an extension for !
VS Code
Sublime Text
WebStorm
Vim
Eclipse
@NicoloRibaudo
The�Language Server Protocol
28
@NicoloRibaudo
The Language Server Protocol
It's kind of like the web you have a single server, and multiple clients can talk with it using a shared language (HTTP).
29
@NicoloRibaudo
The Language Server Protocol
30
@NicoloRibaudo
The Language Server Protocol
31
The MessageFormat language server
Hey, the user opened this file.
The user is typing a variable, do you have any completions?
Yes: $name and $lastName
Hey, the user typed …
Hey, the user typed …
Hey, I noticed some errors
@NicoloRibaudo
The Language Server Protocol
32
The MessageFormat language server
@NicoloRibaudo
The Language Server Protocol
What features does it support?
33
@NicoloRibaudo
The Language Server Protocol
Like for HTTP, you don't actually have to implement the protocol by yourself. There are libraries that abstract it away and let you focus on the interesting parts.
34
@NicoloRibaudo
The interesting parts
(or "The ingredients")
35
@NicoloRibaudo
Parser
36
Salut, {$name :str}!
Message
Text: "Salut, "
Placeholder
Text: "!"
Variable: $name
Annotation: :str
@NicoloRibaudo
Parser
37
We need to parse incomplete code while the user is typing!
Salut, {$na│
Hello {$na│, welcome!
@NicoloRibaudo
Semantic Analyzer
Whenever the parser generates an AST, it analyses it to find:
38
Auto completions!
Go to definition!
Rename!
Inlay hints!
@NicoloRibaudo
Pretty-printer
Given an AST generated by the parser, it converts it back into a good looking string of code
39
.match $count 0
{{No notifications}}
1{{One notification}}
* {{{$count} notifications}}
.match $count
0 {{No notifications}}
1 {{One notification}}
* {{{ $count } notifications}}
@NicoloRibaudo
… and more
40
@NicoloRibaudo
MessageFormat 2.0 LSP
41
@NicoloRibaudo
Go build your own!
42
@NicoloRibaudo