Aller au contenu

Configuration

Les réglages de Textchum suivent un principe : l'interface graphique est le moyen confortable de les changer, et un simple fichier JSON est la sortie de secours toujours disponible. Il y a exactement un seul dépôt — le fichier — et la fenêtre Réglages le lit et l'écrit ; rien ne vit uniquement à l'intérieur de l'application.

La fenêtre Réglages

Textchum → Settings… (⌘,) édite les réglages reconnus :

  • Apparence — suivre le système (en changeant en direct quand macOS le fait) ou forcer le clair ou le sombre.
  • Thème — la palette de syntaxe ; voir Thèmes plus bas.
  • Icônes de fichier — un pack d'icônes VS Code pour l'arborescence ; voir Icônes de fichier.
  • Ouvrir les fichiers dans — des onglets de la fenêtre courante (le défaut) ou des fenêtres séparées. Avec des fenêtres séparées, le navigateur de chaque fenêtre ne liste que les documents de son propre groupe d'onglets.
  • Police — toute famille à chasse fixe installée sur le système, ou la police à chasse fixe de la plateforme.
  • Taille de police — de 6 à 72 points.
  • Largeur de tabulation — de 1 à 16 colonnes.
  • Afficher les numéros de ligne — la marge, aussi basculables par session avec View → Toggle Line Numbers (⇧⌘L).

Chaque changement s'applique immédiatement aux fenêtres d'édition ouvertes et s'écrit sur disque au même instant. Il n'y a aucun bouton Appliquer ou Enregistrer à oublier.

Le fichier

Les réglages vivent dans :

~/Library/Application Support/Textchum/config.json

Un fichier édité à la main pourrait ressembler à :

{
  "appearance": "dark",
  "editor": {
    "font_family": "JetBrains Mono",
    "font_size": 13,
    "tab_width": 4,
    "hover": false
  }
}

appearance accepte "system", "light" ou "dark" ; en son absence (le défaut), le système est suivi. editor.hover désactive la bulle de documentation au survol (true, le défaut, la laisse active). editor.new_files_in place les documents neufs dans un "tab" du groupe de la fenêtre frontale (le défaut) ou dans une "window" à eux. editor.mark_occurrences (true par défaut) marque les autres endroits où apparaît le mot sélectionné ; editor.occurrences_case_sensitive et editor.occurrences_whole_word décident de ce qui en est un, tous deux true par défaut.

Tout est optionnel — fichier, section ou clé manquants signifient simplement la valeur par défaut. Les écritures sont atomiques (fichier temporaire puis renommage), comme toute écriture de Textchum.

Deux garanties rendent l'édition à la main sûre :

  • Les clés inconnues survivent. La fenêtre de réglages ne réécrit que les clés qui lui appartiennent. Tout le reste du fichier — vos annotations, des clés d'une version plus récente — est préservé tel quel à chaque enregistrement.
  • Les fichiers cassés ne sont jamais écrasés. Si le fichier ne peut pas être analysé, Textchum démarre avec les réglages par défaut, le signale une fois au lancement et laisse le fichier exactement tel que vous l'aviez écrit, pour le réparer dans n'importe quel éditeur — y compris Textchum lui-même. Si vous changez un réglage depuis l'interface pendant que le fichier est cassé, l'original inanalysable est d'abord copié vers config.json.bak, puis remplacé.

Les valeurs hors limites ou mal typées ne comptent pas comme une casse : un font_size de 4000 est ramené dans la plage valide, un font_family de 42 est ignoré, et le reste du fichier fonctionne normalement.

Ailleurs, le temps d'une exécution

--data-dir <chemin> garde tout ce que Textchum possède sous un seul répertoire pour cette exécution — la configuration, les thèmes, les packs d'icônes, la session et le journal du serveur de langage — au lieu des emplacements habituels :

Textchum --data-dir ~/profil-d-essai

C'est un profil entier fabriqué pour l'occasion et jeté ensuite, le vrai n'étant jamais ouvert ; make playground s'en sert, et tout ce qui ne doit pas toucher à vos réglages aussi. Sous Linux, une exécution avec son propre profil est son propre processus : remettre les fichiers à une instance déjà lancée les ouvrirait dans le profil de celle-ci.

--config <chemin> en est la version étroite : il désigne un fichier de configuration, et la session le suit.

Thèmes

Le sélecteur Theme de l'onglet General choisit la palette de syntaxe. Sept sont fournis d'origine : Textchum (par défaut), Textchum High Contrast, Graphite (un thème feutré presque monochrome) et les classiques — Molokai, Solarized, Dracula et Gruvbox. Chaque thème porte une palette claire et une palette sombre dans un même fichier, si bien qu'un thème sert aux deux modes d'apparence (les classiques nés sombres associent leur palette canonique à une claire au contraste ajusté ; Solarized et Gruvbox utilisent leurs vraies palettes claires).

Les thèmes personnels sont des fichiers JSON dans :

~/Library/Application Support/Textchum/themes/

sélectionnés par nom de fichier (sans .json) ; un fichier portant le nom d'un thème intégré le remplace. Textchum → Open Themes Folder ouvre (et crée) ce dossier. Le plus rapide pour en commencer un est de générer un point de départ complet — chaque nom de capture stylée, rempli avec la palette par défaut — et de ne changer que les couleurs :

Textchum --emit-theme ~/Library/Application\ Support/Textchum/themes/Mien.json

Les entrées associent des noms de capture tree-sitter à des styles :

{
  "name": "Mien",
  "styles": {
    "keyword": {"light": "#AD3DA4", "dark": "#FC5FA3", "bold": true},
    "comment": {"light": "#707F8C", "dark": "#7F8C98", "italic": true}
  }
}

Les couleurs s'écrivent #RRGGBB ou #RRGGBBAA. Tout ce qui est omis — une couleur, un drapeau, une capture entière — garde la valeur de la palette par défaut : un thème n'a besoin de dire que ce qu'il change. Les règles de secours sont celles de la configuration : un thème qui ne se laisse pas analyser retombe sur le thème par défaut avec un seul avertissement et n'est jamais écrasé, et les clés inconnues survivent. Les fichiers de thème sont lus au lancement et au changement de sélection.

En importer un depuis un autre éditeur

Textchum → Importer un thème récupère les couleurs de VS Code ou de TextMate. Choisissez un fichier de thème, ou un dossier qui en contient plusieurs — un répertoire d'extension VS Code (son package.json dit ce qu'il apporte) ou un bundle TextMate (ses thèmes sont dans Themes/). Tout ce qui s'y trouve est importé, et le premier est mis.

Les deux éditeurs décrivent la couleur par portée TextMate ; importer revient donc à traduire les portées vers les noms de capture de Textchum : entity.name.function devient function, keyword.control.loop devient repeat. Les portées s'arrêtent là où les captures continuent — aucun thème ne colore if autrement que while — alors une capture que la source n'a jamais nommée prend la couleur de celle dont elle est un cas particulier, dans les deux sens : un thème qui dit keyword colore toutes les sortes de mot-clé, et un qui ne dit que constant.numeric colore toute la famille des constantes.

Deux choses à savoir avant de trouver les couleurs fausses :

  • Un thème remplit une apparence. Les deux éditeurs écrivent un thème pour un fond clair ou pour un fond sombre ; ceux de Textchum portent les deux. L'import remplit le côté que la source déclare et laisse l'autre à la palette par défaut, en disant lequel il a rempli. Importer un thème sombre alors que l'éditeur est en apparence claire ne change rien de visible.
  • Les portées sans destination sont nommées. Tout ce que la source a coloré et à quoi aucune capture ne répond est listé à la fin. Ces couleurs restent inutilisées.

Le résultat est un fichier de thème ordinaire dans le dossier des thèmes, modifiable comme un autre.

Icônes de fichier

L'arborescence dessine une icône par ligne. Sans pack, c'est celle que le bureau propose pour le type du fichier, qui distingue Python de Markdown et ne va guère plus loin — et n'a jamais entendu parler d'un fichier nommé Dockerfile.

Réglages → Général → Icônes de fichier accepte un pack d'icônes VS Code. Les packs déjà vus sont sur la liste, séparés entre ceux importés ici et ceux ouverts là où ils sont ; System icons est le retour en arrière.

Import… copie le pack dans le dossier propre à Textchum — ~/Library/Application Support/Textchum/icons/ sur macOS, ~/.local/share/textchum/icons/ sur Linux — déplacer ou supprimer l'original n'emporte donc pas les icônes. Open… pointe vers un pack là où il est et s'en souvient, ce qui convient à un pack que vous maintenez vous-même. Les deux acceptent le fichier JSON du thème d'icônes ou le dossier d'extension qui le contient (son package.json dit lequel). Delete supprime un pack importé ; un pack ouvert ailleurs appartient à qui l'a mis là, il ne peut donc que sortir de la liste.

Le choix est un chemin dans config.json, et les packs ouverts ailleurs sont retenus à côté :

{
  "icon_pack": "~/packs/material-icon-theme/dist/material-icons.json",
  "icon_packs": ["~/packs/material-icon-theme/dist/material-icons.json"]
}

Un pack dont le dossier a disparu quitte la liste au lieu d'y rester pour échouer une fois choisi. Un pack illisible est signalé une fois et l'arborescence garde les icônes du système.

La recherche suit celle de VS Code, du plus précis au moins précis :

  1. Le nom entier du fichier (Dockerfile, cargo.toml), en minuscules.
  2. L'extension la plus longue qui corresponde : component.test.ts essaie test.ts avant ts.
  3. Le langage que Textchum a retenu pour le fichier — c'est aussi par là qu'un langage fixé à la main dans Propriétés du fichier atteint l'icône.
  4. La valeur par défaut du pack lui-même.

La section light d'un pack remplace n'importe laquelle de ces réponses sur fond clair, une recherche à la fois : un pack qui n'en redessine qu'une poignée garde le reste.

Deux choses restent dehors. Les icônes de dossier : l'arborescence dessine les siennes. Les icônes tracées avec une police — les définitions fontCharacter qu'utilisent Seti et ses descendants — demandent la police installée et un texte là où va une image ; un pack qui n'a que cela est refusé avec cette raison, plutôt que chargé pour ne rien dessiner.

Projets

L'onglet Projects décide où un projet commence et finit — la frontière selon laquelle le navigateur regroupe et sur laquelle le pool de serveurs de langage indexe ses instances. Chaque interrupteur existe en deux exemplaires : comme valeur par défaut pour tous les projets, et par racine de projet. Une ligne ajoutée avec le champ de chemin (qui complète les noms de répertoire pendant la frappe et porte un bouton Browse…) remplace les valeurs par défaut pour cette racine seulement.

  • Manifest projects — normalement le dépôt le plus externe l'emporte : ouvrir un fichier n'importe où dans un dépôt fait du dépôt le projet, quel que soit le nombre de Cargo.toml ou pyproject.toml entre les deux. L'activer redécoupe une racine aux manifestes de langage, si bien que les modules imbriqués redeviennent des projets à part entière.
  • Recursive config — fait que les réglages par projet d'une racine (ses commandes de serveur de langage et ces interrupteurs eux-mêmes) s'appliquent aux projets imbriqués qu'elle contient, l'ancêtre le plus proche d'abord. Utile pour les monorepos : une configuration en haut, beaucoup de projets en dessous.
  • Ctags fallback — répond à Aller à la Définition depuis un index Universal Ctags quand aucun serveur de langage n'est disponible ; voir serveurs de langage.

Dans le fichier, tout cela vit dans une section workspace :

{
  "workspace": {
    "manifest_projects": false,
    "recursive_config": false,
    "ctags_fallback": false,
    "projects": {
      "/Users/you/code/monorepo": {
        "manifest_projects": true,
        "recursive_config": true
      }
    }
  }
}

Préprocesseurs de sauvegarde

Les formateurs et correcteurs peuvent s'exécuter automatiquement avant chaque sauvegarde, par langage — pour tous les projets ou pour une racine précise, exactement comme les serveurs de langage. Chaque entrée est une chaîne : une commande par ligne, dans l'ordre, où chaque commande lit le document sur l'entrée standard et réécrit le document entier sur la sortie standard (la convention - que suivent presque tous les formateurs). Si un maillon échoue — code de sortie non nul, sortie vide, ou plus de dix secondes sans répondre — rien n'est appliqué, l'erreur (avec le stderr de l'outil) s'affiche, et la sauvegarde demande s'il faut continuer sans traitement.

{
  "preprocessors": {
    "defaults": {
      "python": ["ruff check --fix -", "black -"],
      "go": ["gofmt"]
    },
    "projects": {
      "/work/site": { "javascript": ["prettier --stdin-filepath {filename}"] }
    }
  }
}

{path} et {filename} n'importe où dans une commande se développent en le chemin absolu du document et son nom — pour les outils qui lisent stdin mais déduisent leur comportement du nom, comme le --stdin-filepath de Prettier. Un document sans titre offre Untitled plus l'extension de son langage.

Une entrée de projet remplace la chaîne par défaut pour ce langage, elle ne s'y ajoute jamais. La fenêtre Réglages édite cette même section sous Serveurs de langage, et Édition ▸ Lancer les préprocesseurs (⌃⌥⌘F, nom d'action runPreprocessors) lance la chaîne à la demande sans sauvegarder — formater avec vos outils plutôt qu'avec le formateur du serveur. Le résultat arrive en une seule édition, donc ⌘Z l'annule.

Correction orthographique

La prose passe par le correcteur du système — les dictionnaires que partagent toutes les apps du Mac — restreint à là où la prose vit vraiment : les commentaires dans le code, et le document entier en Markdown, dans les messages de commit git et le texte brut. Les identifiants et les littéraux de chaîne ne sont jamais signalés. Les fautes portent une teinte violette, distincte du rouge/orange/bleu des diagnostics.

Choisissez la langue dans Réglages ▸ Général ▸ « Spell check prose » — Désactivé (le défaut), automatique selon le contenu, ou un dictionnaire précis — ou réglez editor.spell à la main : "auto" ou un identifiant comme "fr" ou "en_US". Les dictionnaires disponibles sont ceux activés dans Réglages Système ▸ Clavier ▸ Saisie de texte.

{ "editor": { "spell": "auto" } }

Plusieurs dictionnaires peuvent s'appliquer à la fois : nommez-les séparés par des virgules. Un mot que l'un d'eux connaît est bien orthographié, ce dont a besoin un texte qui change de langue au milieu d'un paragraphe :

{ "editor": { "spell": "en_US, fr_FR" } }

editor.spell_words est votre propre liste : noms de projet, sigles, et tout ce qu'aucun dictionnaire ne fournit. Un clic droit sur un mot signalé propose les suggestions, Ajouter au dictionnaire, qui écrit le mot ici, et Ignorer, qui l'accepte jusqu'à la fermeture de l'éditeur. La liste s'édite aussi dans les préférences.

{ "editor": { "spell_words": ["SBX", "Textchum"] } }

Sous Linux les mêmes réglages passent par hunspell : installez hunspell plus un paquet de dictionnaire (hunspell-fr, hunspell-en-us, …) et les marques apparaissent ; "auto" suit $LANG, et les dictionnaires que hunspell trouve sont listés à côté du champ dans les préférences.

Enregistrement automatique

Désactivé par défaut. editor.autosave est un nombre de secondes ; le compte repart à chaque frappe, donc l'enregistrement a lieu une fois la saisie terminée et non au milieu d'une phrase.

{ "editor": { "autosave": 30 } }

Deux choses qu'il ne fait délibérément pas. Il n'enregistre jamais un document sans nom : il n'y a nulle part où le mettre, et lui en inventer un n'appartient pas à l'éditeur. Et il n'exécute pas les préprocesseurs d'enregistrement : un formateur qui reflue la ligne que vous êtes en train d'écrire ne rend pas service, cela reste donc l'affaire des enregistrements explicites.

Raccourcis clavier

Réglages ▸ Clavier les tient : un profil, et chaque commande avec le raccourci auquel elle répond, modifiable sur place.

Profils. On arrive d'un autre éditeur avec ses raccourcis dans les doigts : les trois pour lesquels ces éditeurs sont connus sont donc fournis avec la compilation — Visual Studio Code, Sublime Text et IntelliJ IDEA. Un profil nomme les commandes qu'il déplace et laisse le reste tranquille : en choisir un change ce pour quoi cet éditeur est connu, et rien d'autre. keys_profile garde le choix ; vide, ce sont les raccourcis propres à Textchum.

Changer un raccourci par-dessus un profil garde le profil : le changement est un remplacement, et Reset changes les abandonne tous. Save as profile transforme ce qui est en vigueur en un profil à vous — la façon de modifier un préréglage, puisque ceux-là sont fournis avec la compilation. Les profils enregistrés vivent dans key_profiles, et un profil qui reprend un nom fourni le remplace.

Le fichier écrit les remplacements dans une section keys : un objet de noms d'action vers des spécifications modificateurs+touche, appliqué par-dessus le profil.

{
  "keys": {
    "openQuickly": "cmd+p",
    "goToBlockEnd": "ctrl+alt+down",
    "findInProject": "cmd+shift+g"
  }
}

Modificateurs : cmd, shift, alt, ctrlcmd est Command sur macOS et Ctrl sur Linux, un profil veut donc dire la même chose des deux côtés. Touches : un caractère, de f1 à f20, ou up/down/left/right/return/escape/space/tab/delete. Parmi les actions : new, open, openQuickly, save, saveAs, close, undo, redo, find, findAndReplace, findNext, findPrevious, useSelectionForFind, findInProject, jumpToDefinition, findReferences, codeActions, renameSymbol, formatDocument, runPreprocessors, documentOutline, goBack, goForward, blameLine, goToLine, goToBlockStart, goToBlockEnd, toggleNavigator, togglePreview, toggleLineNumbers, toggleHover, showHover, serverStatus, newWithFormat, revealInTree, reopenClosed, togglePathDisplay, redraw, commandPalette, settings — un nom inconnu est journalisé avec la liste complète. Aller au début/à la fin du bloc (⌃⌥↑/⌃⌥↓ par défaut) saute par-dessus le bloc syntaxique multiligne le plus interne autour du curseur, grâce à l'arbre qui alimente déjà la coloration. Et quand un raccourci échappe tout à fait à la mémoire, la palette de commandes (⇧⌘P) cherche floue n'importe quelle action de menu par son nom et exécute la sélection.

Rechargement à chaud

Le fichier est surveillé pendant que Textchum tourne : éditez config.json ailleurs et le changement s'applique dès qu'il atterrit — apparence, thème, polices, raccourcis, table des serveurs, tout, y compris la fenêtre Réglages si elle est ouverte. Les sauvegardes de l'app elle-même sont reconnues et ignorées, et un fichier qui échoue momentanément à parser retombe sur les défauts sans être écrasé, exactement comme au lancement.

Réglages d'éditeur par projet

Une racine de projet peut remplacer la police, sa taille et la largeur de tabulation pour toutes les fenêtres qu'elle contient — les lignes de l'onglet Projets portent les trois champs (vide signifie « hériter de la valeur générale »), et le fichier l'écrit comme un objet editor sur l'entrée workspace :

{
  "workspace": {
    "projects": {
      "/work/legacy": { "editor": { "tab_width": 8, "font_size": 12 } }
    }
  }
}

Ajouter un projet

L'onglet Projets liste les racines des documents ouverts : un projet s'ajoute donc en le choisissant, pas en tapant son chemin. Copier les réglages de part d'un projet déjà configuré — ses serveurs, ses commandes d'enregistrement, ses indicateurs et ses réglages d'éditeur, le tout — ce dont a besoin un second service de même disposition. Le même choix figure sur la ligne de chaque projet, pour copier vers un qui existe déjà.

Un champ de remplacement vide montre ce qu'il hérite : une case blanche dit donc ce qui s'applique au lieu de vous laisser aller voir.

Une racine configurée dont le répertoire a disparu est marquée missing, et Remove missing les oublie toutes : plus rien ne correspondra jamais à ces entrées.

Les langages que la compilation ignore

La coloration de Textchum vient de grammaires tree-sitter compilées dans le binaire. Un langage qu'il ne porte pas se nomme dans languages, avec la grammaire comme bibliothèque compilée et sa requête de coloration comme fichier :

{
  "languages": {
    "dockerfile": {
      "grammar": "~/.local/share/textchum/grammars/libtree-sitter-dockerfile.dylib",
      "highlights": "~/.local/share/textchum/grammars/dockerfile/highlights.scm",
      "extensions": ["dockerfile"],
      "filenames": ["Dockerfile", "Containerfile"]
    }
  }
}

aliases, filenames et injections sont facultatifs, symbol aussi : le constructeur est tree_sitter_<nom> sauf mention contraire, tirets et points devenant des soulignés. Une grammaire faite pour un autre tree-sitter est refusée d'après son numéro d'ABI plutôt que suivie jusqu'au plantage, et un nom que la compilation connaît déjà est remplacé par celui de la configuration — de quoi corriger une grammaire dépassée sans attendre une version.

Pour en construire une, depuis le dépôt de la grammaire :

cc -O2 -fPIC -shared -I src -o libtree-sitter-NOM.dylib src/parser.c src/scanner.c

(.so sous Linux, et sans src/scanner.c quand la grammaire n'en a pas.) Une entrée qui ne charge pas coûte ce langage et rien d'autre : l'éditeur dit ce qui s'est passé et continue.

La langue de l'interface

L'interface parle anglais, espagnol ou français ; Interface language dans les Préférences en choisit une, et System suit celle de la machine. Le changement s'applique au démarrage suivant.

Les catalogues sont ceux de gettext et vivent dans le cœur : les deux shells et le cœur disent donc les mêmes choses avec les mêmes mots. La source est core/textchum-core/i18n/<langue>.po — le format que parlent les traducteurs et leurs outils — et la compilation en tire le .mo que lit l'éditeur. Une phrase sans traduction se lit telle qu'elle est écrite en anglais plutôt que comme une clé manquante.

Un catalogue à soi se met dans le profil, et est lu à la place de celui de la compilation :

msgfmt -o ~/.config/textchum/translations/fr.mo mon-fr.po
  • ~/Library/Application Support/Textchum/translations/<langue>.mo
  • ~/.config/textchum/translations/<langue>.mo

Un fichier nommé d'après une langue que la compilation ne porte pas se lit de la même façon : une quatrième langue est un catalogue, pas une version.

Pour travailler les traductions du dépôt, scripts/i18n.sh extrait les chaînes et les fusionne dans chaque catalogue comme gettext l'entend : xgettext les trouve, msgmerge reporte l'existant et marque comme douteux ce dont l'anglais a changé, et msgfmt vérifie le résultat. make check lance scripts/i18n.sh --check : une chaîne ajoutée sans traduction casse la compilation au lieu de sortir en anglais.

Registres de projet

Un fichier se souvient de la façon dont il est divisé, de l'endroit que chaque vue regardait, de ce qui est replié et de ce qu'on lui a dit qu'il était quand son nom ne le dit pas. Ce sont des données du fichier : elles vivent avec le projet plutôt que dans config.json, un registre par racine de projet, en JSON comme le reste.

{
  "version": 1,
  "root": "/work/engine",
  "files": {
    "src/parser.rs": {
      "views": 2,
      "dividers": [0.45],
      "folds": [[12, 48]],
      "language": "rust",
      "places": [{"caret": 812, "scroll": 240.0}]
    }
  }
}

Les registres sont gardés dans le profil, à côté de la session et des thèmes : une exécution pointée sur un profil d'essai écrit les siens. Keep each project's state with the checkout place le registre dans <root>/.tchum, pour une disposition qui voyage avec le clone ; le choix est global, car une réponse par projet devrait de toute façon être notée quelque part de central pour être retrouvée.

Le balayage se fait au démarrage, sur un fil à lui : il oublie les registres des projets qui ne sont plus là et ceux qui n'ont pas été écrits depuis plus longtemps que la fenêtre (90 jours par défaut ; zéro les garde jusqu'à ce qu'on les efface). Forget records at launch l'arrête, et Manage… à côté du dossier des registres liste ce qui existe, ce dont chacun parle et quand il a été écrit, pour les oublier un par un ou d'un coup.

Pas encore là

  • Rien pour le moment — notez la prochaine gêne quand elle se présentera.