turbo-editors/turbo-pythonpublic Fork 0
v1.0.3
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-python.git
git clone ssh://git@rickub.com/turbo-editors/turbo-python.git

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

architecture.md · 97 lines · 8.3 KBmarkdown Blame HistoryRaw
📦 Turbo Python 6fc62ea k33g 22h ago1# Architecture — explication
2
3## De quoi s'agit-il ?
4
5Turbo Python est une commande, un profil et un analyseur. Tout le reste — le composant d'édition, les fenêtres, les menus, les dialogues, les thèmes, l'émulateur de terminal, l'arborescence de fichiers, le client LSP — est [turbo-core](https://rickub.com/turbo-editors/turbo-core), la bibliothèque sur laquelle repose chaque éditeur Turbo.
6
7Cette page parle de cette coupure : ce qui est ici, ce qui est là-bas, et pourquoi la ligne tombe où elle tombe.
8
9## Ce qu'il y a dans ce dépôt
10
11```
12main.go les drapeaux, le terminal, et le câblage
13internal/pythonlang la totalité de ce qui fait Turbo Python
14 pythonlang.go le profil : nom, menu, serveur, marqueurs de racine, où pylsp se cache
15 scan.go l'aiguillage de l'analyseur, les commentaires, les décorateurs
16 literals.go les seize orthographes d'un littéral chaîne
17 words.go nombres, mots-clés, primitives, les conventions de nommage
18 templates.go trois déclarations //go:embed
19 *.toml.tmpl les trois fichiers de départ qu'un projet reçoit, embarqués
20```
21
22Environ huit cents lignes, dont six cents pour l'analyseur. Il n'y a pas d'`internal/app`, pas d'`internal/ui`, pas d'`internal/buffer` — ceux-là existent une fois, dans la bibliothèque, et les six éditeurs s'en servent sans les modifier.
23
24## Ce que fait `main`
25
26Six choses, dans cet ordre :
27
281. Analyse les drapeaux.
292. Appelle `pythonlang.Register()`, qui apprend à la bibliothèque à colorer les fichiers `.py`.
303. Construit `pythonlang.Profile()` — la valeur qui dit que cet éditeur est Turbo Python.
314. Lit `.turbo-python/settings.toml` dans le répertoire courant, s'il y en a un.
325. Ouvre le terminal et passe l'écran, le nom du thème et le profil à `app.New`.
336. Démarre pylsp à la racine du projet, et lance la boucle d'événements.
34
35C'est toute la commande. Chaque décision qu'elle prend — quel thème l'emporte, quels fichiers ouvrir, faut-il démarrer un serveur de langage — porte sur *cette exécution*, pas sur Python.
36
37## Le profil est la couture
38
39```go
40profile.Profile{
41 Name: "Turbo Python",
42 Slug: "turbo-python",
43 Language: "Python",
44 ToolsMenu: "~P~ython",
45 RootMarkers: []string{"pyproject.toml", "setup.py", "setup.cfg"},
46 Server: profile.Server{Command: "pylsp", },
47 Templates: profile.Templates{Settings: , Snippets: , Tools: },
48}
49```
50
51Tout ce qui serait sinon un `"turbo-python"`, un `"pylsp"` ou un `"pyproject.toml"` en dur quelque part dans onze mille lignes est ici un champ. La bibliothèque les lit ; rien dans la bibliothèque ne sait ce qu'ils veulent dire.
52
53`Slug` porte plus qu'il n'y paraît. Le binaire est `turbo-python`, le répertoire de projet est `.turbo-python`, la configuration de l'utilisateur vit dans `~/.config/turbo-python`, et les variables d'environnement qui la remplacent sont `TURBO_PYTHON_THEME_DIR` et `TURBO_PYTHON_SNIPPET_DIR` — toutes dérivées de ce seul mot.
54
55## Pourquoi l'analyseur est ici et pas dans la bibliothèque
56
57turbo-core colore huit langages lui-même : TOML, YAML, Markdown, JavaScript, HTML, XML, les Dockerfiles et le shell. Ce sont ceux que tout éditeur rencontre quel que soit son objet — la configuration d'un projet est du TOML ou du YAML, sa documentation du Markdown, ses scripts du shell, sa construction d'image un Dockerfile.
58
59Python n'en fait pas partie, et Go et Rust non plus. Le langage qui *définit* un éditeur est enregistré par cet éditeur, ce qui explique qu'un fichier `.rs` s'ouvre ici en texte brut et qu'un fichier `.py` s'ouvre en texte brut dans Turbo Rust.
60
61L'inverse était possible. Mettre les trois analyseurs dans la bibliothèque permettrait à chaque éditeur de colorer n'importe lequel des langages, sans coût en dépendances — un analyseur Python n'est que du Go ordinaire. Cela a été rejeté parce que la bibliothèque gagnerait alors un langage chaque fois que quelqu'un construit un éditeur, et parce que « qu'est-ce que cet éditeur enregistre ? » cesserait d'être la première question qu'on pose sur un nouvel éditeur.
62
63## Pourquoi le menu de la chaîne d'outils est `~P~ython` et non `~U~v`
64
65La touche rapide était la partie facile. Neuf lettres sont prises par les menus fixes — F, E, S, R, C, O, W, N et H — et `P` n'en fait pas partie : elle tombe donc sur la première lettre du mot, ce qui ne coûte à personne un second regard. Turbo Rust n'a pas eu cette chance et a fini sur `Rus~t~`.
66
67Le nom, lui, était la vraie décision, et elle a tourné comme celle de Turbo Rust. Le menu contient ce que le projet a mis dans son fichier d'outils, et ce n'est pas toujours uv : le premier fichier d'outils que quiconque écrit déborde de la chaîne d'outils du langage, parce que les commandes d'un projet incluent des conteneurs, des bases de données et une cible de `Makefile` que quelqu'un a ajoutée en 2019. Un menu appelé uv contenant `docker compose up` est un mensonge sur ce qu'est le menu, exactement de la façon dont la documentation de la bibliothèque met en garde. `Python` est le langage, et le langage est ce pour quoi cet éditeur existe.
68
69## Pourquoi les tests pilotent le vrai éditeur
70
71`internal/pythonlang/editor_test.go` construit un Turbo Python entier sur un terminal simulé — `app.New(screen, "turbo-classic", pythonlang.Profile())` — ouvre un fichier et vérifie la coloration, la barre de menus et les touches rapides. Il n'utilise que l'API publique de la bibliothèque.
72
73C'est délibéré. La suite de la bibliothèque prouve que la bibliothèque marche ; ce que ces tests prouvent, c'est que *cet éditeur est correctement assemblé* — que `Register` a été appelé, que le profil a atteint la barre de menus, qu'un fichier `.py` ressort coloré. Un bug où `main` aurait oublié d'enregistrer Python passerait tous les tests de turbo-core.
74
75Le même fichier pilote un **vrai pylsp** de bout en bout, quatre fois. Il écrit un projet, ouvre un fichier, démarre le serveur, puis :
76
77- **tape un texte qui n'existe que dans le tampon** et demande une complétion — un texte déjà présent sur le disque ne prouverait rien, puisque le serveur répond depuis le disque pour tout ce qu'on ne lui a pas dit être ouvert ;
78- demande les **références** d'un nom utilisé à trois endroits, c'est-à-dire la forme de réponse qui était autrefois tronquée à un seul élément ;
79- demande les **symboles du fichier**, encore une autre forme de réponse ;
80- ouvre un fichier qui **ne s'analyse pas** et attend qu'un diagnostic arrive de lui-même — la seule fonction dont l'échec ressemble exactement à la réussite, puisqu'un éditeur qui n'a aucune erreur à montrer et un éditeur incapable de trouver l'erreur ont la même gouttière vide.
81
82Un cinquième test épingle ce que pylsp *ne peut pas* faire : il n'annonce ni `implementation` ni `workspace/symbol`, la documentation le dit, et le test échoue si un futur pylsp se met à répondre — la page est alors relue plutôt que de vieillir en silence.
83
84## Alternatives rejetées
85
86**Forker Turbo Rust.** La façon évidente d'obtenir un troisième éditeur, et la raison pour laquelle la bibliothèque existe à la place : trois copies de onze mille lignes divergent en un mois, et chaque correctif doit être fait trois fois par quelqu'un qui se souvient qu'il y en a trois.
87
88**Un système de greffons.** Turbo Python est un programme Go qui importe une bibliothèque. Il n'y a ni chargement dynamique ni ABI. En ajouter un voudrait dire figer l'API de tous les paquets de turbo-core plutôt que de la poignée qu'un profil touche.
89
90**Un fichier de configuration au lieu d'un profil.** Le profil aurait pu être du TOML lu au démarrage, ce qui ferait d'un nouvel éditeur un fichier plutôt qu'un programme. Cela rendrait aussi l'analyseur inexprimable, et un éditeur à moitié configurable — tout sauf la coloration — est pire que l'une ou l'autre réponse entière.
91
92## Comment cela se relie au reste
93
94- Ce que fait chaque paquet de la bibliothèque : [la référence des paquets de turbo-core](https://rickub.com/turbo-editors/turbo-core/blob/main/docs/fr/reference/packages.md)
95- Comment marche la coloration ici : [Coloration et complétion](colouring-and-completion.md)
96- Pourquoi le menu d'outils est une donnée : [Outils Python](python-tools.md)
97- Les décisions qui ont survécu au refactoring : [Décisions de conception](design-decisions.md)