turbo-editors/turbo-corepublic Fork 0
v1.0.2
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

talk-to-a-language-server.md · 79 lines · 4.8 KBmarkdown
Blame HistoryOpen raw

Comment dialoguer avec un serveur de langage

Ce guide montre comment brancher un éditeur bâti sur turbo-core sur un serveur de langage, pour que la complétion, le survol et le saut à la définition fonctionnent. Il suppose que vous avez un éditeur et un serveur qui parle LSP sur son entrée et sa sortie standard.

Étapes

1. Décrire le serveur dans votre profil

Server: profile.Server{
	Command:     "rust-analyzer",
	Args:        nil,
	InstallHint: "rustup component add rust-analyzer",
	Dirs:        []string{cargoBinDir()},
},
Champ À quoi il sert
Command le nom de l'exécutable, cherché dans PATH
Args ce avec quoi il démarre — gopls veut serve, rust-analyzer ne veut rien
InstallHint une commande que l'utilisateur peut copier, affichée sur la barre d'état quand le serveur manque
Dirs des répertoires supplémentaires à fouiller quand PATH ne donne rien

Dirs compte plus qu'il n'y paraît. L'installateur de chaque langage pose ses binaires quelque part qui n'est très souvent pas dans PATH — GOPATH/bin, ~/.cargo/bin — et « la complétion ne fait rien » est ce que voit l'utilisateur quand l'éditeur ne trouve pas un serveur qu'il croit avoir installé.

2. Dire où commence le projet

RootMarkers: []string{"Cargo.toml"},

Le serveur est démarré dans le premier répertoire, à partir du fichier et en remontant, qui contient l'un de ces fichiers. Un serveur lancé à la mauvaise racine charge le mauvais code puis ne répond rien du tout, sans erreur — ce qui est la façon la plus déroutante dont la complétion peut échouer.

3. Le démarrer depuis votre commande

editor.StartLanguageServer(ctx, app.ProjectRoot(p, files))
defer editor.Language().Stop(context.Background())

Démarrez-le après avoir ouvert les fichiers, pas avant. L'éditeur annonce les documents déjà ouverts au premier tour de sa boucle d'événements où le serveur est prêt, et c'est ce qui rend cet ordre sûr.

Variantes

Un fichier est créé dans l'éditeur

Rien à faire. Une fenêtre née sans titre n'a pas de chemin, donc le serveur n'en entend pas parler — jusqu'à la première sauvegarde, qui annonce le document au lieu de simplement signaler une écriture. La complétion, le survol et les diagnostics fonctionnent dans cette fenêtre dès qu'elle a un nom, sans redémarrage. La sauvegarde qui crée le fichier dit aussi au serveur qu'un fichier est apparu (workspace/didChangeWatchedFiles) : un serveur qui établit la liste des fichiers d'un paquet depuis le répertoire — moon-lsp — connaîtrait sinon le document sans jamais le diagnostiquer. Un « Enregistrer sous » vers un nom réellement nouveau ferme aussi l'ancien document côté serveur, pour qu'aucun fantôme n'y reste ouvert.

Le serveur a besoin d'une configuration

turbo-core répond à workspace/configuration par un objet vide. Si votre serveur exige des réglages avant de fonctionner, cette réponse est dans lsp.Client.handleRequest et n'est pas encore configurable — dites-le à vos utilisateurs plutôt que de laisser la complétion échouer en silence.

Il n'existe pas de serveur pour votre langage

Laissez Server à sa valeur nulle. app.Language ne fait rien quand rien n'est connecté, donc rien d'autre dans l'éditeur n'a à vérifier : la coloration, l'édition, les thèmes, l'arborescence et les fenêtres de terminal fonctionnent exactement pareil.

La commande existe mais ne s'exécute pas

C'est réel et cela mérite d'être traité. rustup installe un relais nommé rust-analyzer que le composant soit là ou non, et le relais n'échoue qu'une fois lancé. Trouver le fichier n'est pas la même chose que pouvoir s'en servir ; si vous cherchez un serveur dans un script d'installation, exécutez-le plutôt que de faire un stat dessus.

Le vérifier de bout en bout

Le test qui vaut la peine d'être écrit est celui qui tape un texte que le serveur n'a jamais vu sur le disque :

  1. Écrivez un fichier qui s'arrête juste avant ce qu'on veut compléter.
  2. Ouvrez-le, puis démarrez le serveur.
  3. Faites un tour de boucle avec editor.Tick().
  4. Tapez la suite dans le tampon avec editor.Handle(...).
  5. Demandez une complétion.

Un fichier de test qui contient déjà le texte ne prouve rien : le serveur répond depuis le disque pour tout ce qu'on ne lui a pas dit être ouvert, si bien qu'un tel test passe que l'éditeur ait parlé ou non.

Attendez-vous à devoir demander plusieurs fois. rust-analyzer répond une liste vide tant qu'il n'a pas fini de charger l'espace de travail, et il le signale par une notification $/progress que ce client ne lit pas.

Voir aussi

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# Comment dialoguer avec un serveur de langage

Ce guide montre comment brancher un éditeur bâti sur turbo-core sur un serveur de langage, pour que la complétion, le survol et le saut à la définition fonctionnent. Il suppose que vous avez un éditeur et un serveur qui parle LSP sur son entrée et sa sortie standard.

## Étapes

### 1. Décrire le serveur dans votre profil

```go
Server: profile.Server{
	Command:     "rust-analyzer",
	Args:        nil,
	InstallHint: "rustup component add rust-analyzer",
	Dirs:        []string{cargoBinDir()},
},
```

| Champ | À quoi il sert |
| --- | --- |
| `Command` | le nom de l'exécutable, cherché dans PATH |
| `Args` | ce avec quoi il démarre — gopls veut `serve`, rust-analyzer ne veut rien |
| `InstallHint` | une commande que l'utilisateur peut copier, affichée sur la barre d'état quand le serveur manque |
| `Dirs` | des répertoires supplémentaires à fouiller quand PATH ne donne rien |

`Dirs` compte plus qu'il n'y paraît. L'installateur de chaque langage pose ses binaires quelque part qui n'est très souvent pas dans PATH — `GOPATH/bin`, `~/.cargo/bin` — et « la complétion ne fait rien » est ce que voit l'utilisateur quand l'éditeur ne trouve pas un serveur qu'il croit avoir installé.

### 2. Dire où commence le projet

```go
RootMarkers: []string{"Cargo.toml"},
```

Le serveur est démarré dans le premier répertoire, à partir du fichier et en remontant, qui contient l'un de ces fichiers. Un serveur lancé à la mauvaise racine charge le mauvais code puis ne répond rien du tout, sans erreur — ce qui est la façon la plus déroutante dont la complétion peut échouer.

### 3. Le démarrer depuis votre commande

```go
editor.StartLanguageServer(ctx, app.ProjectRoot(p, files))
defer editor.Language().Stop(context.Background())
```

Démarrez-le **après** avoir ouvert les fichiers, pas avant. L'éditeur annonce les documents déjà ouverts au premier tour de sa boucle d'événements où le serveur est prêt, et c'est ce qui rend cet ordre sûr.

## Variantes

### Un fichier est créé dans l'éditeur

Rien à faire. Une fenêtre née sans titre n'a pas de chemin, donc le serveur n'en entend pas parler — jusqu'à la première sauvegarde, qui annonce le document au lieu de simplement signaler une écriture. La complétion, le survol et les diagnostics fonctionnent dans cette fenêtre dès qu'elle a un nom, sans redémarrage. La sauvegarde qui crée le fichier dit aussi au serveur qu'un fichier est apparu (`workspace/didChangeWatchedFiles`) : un serveur qui établit la liste des fichiers d'un paquet depuis le répertoire — moon-lsp — connaîtrait sinon le document sans jamais le diagnostiquer. Un « Enregistrer sous » vers un nom réellement nouveau ferme aussi l'ancien document côté serveur, pour qu'aucun fantôme n'y reste ouvert.

### Le serveur a besoin d'une configuration

turbo-core répond à `workspace/configuration` par un objet vide. Si votre serveur exige des réglages avant de fonctionner, cette réponse est dans `lsp.Client.handleRequest` et n'est pas encore configurable — dites-le à vos utilisateurs plutôt que de laisser la complétion échouer en silence.

### Il n'existe pas de serveur pour votre langage

Laissez `Server` à sa valeur nulle. `app.Language` ne fait rien quand rien n'est connecté, donc rien d'autre dans l'éditeur n'a à vérifier : la coloration, l'édition, les thèmes, l'arborescence et les fenêtres de terminal fonctionnent exactement pareil.

### La commande existe mais ne s'exécute pas

C'est réel et cela mérite d'être traité. `rustup` installe un *relais* nommé `rust-analyzer` que le composant soit là ou non, et le relais n'échoue qu'une fois lancé. Trouver le fichier n'est pas la même chose que pouvoir s'en servir ; si vous cherchez un serveur dans un script d'installation, exécutez-le plutôt que de faire un `stat` dessus.

## Le vérifier de bout en bout

Le test qui vaut la peine d'être écrit est celui qui tape un texte que le serveur n'a jamais vu sur le disque :

1. Écrivez un fichier qui s'arrête juste avant ce qu'on veut compléter.
2. Ouvrez-le, **puis** démarrez le serveur.
3. Faites un tour de boucle avec `editor.Tick()`.
4. Tapez la suite dans le tampon avec `editor.Handle(...)`.
5. Demandez une complétion.

Un fichier de test qui contient déjà le texte ne prouve rien : le serveur répond depuis le disque pour tout ce qu'on ne lui a pas dit être ouvert, si bien qu'un tel test passe que l'éditeur ait parlé ou non.

Attendez-vous à devoir demander plusieurs fois. rust-analyzer répond une liste vide tant qu'il n'a pas fini de charger l'espace de travail, et il le signale par une notification `$/progress` que ce client ne lit pas.

## Voir aussi

- Tous les champs : [référence profile](../reference/profile.md)
- Ce que l'éditeur expose pour être piloté : [référence app](../reference/app.md)