- Accueil
- Documentation
- TUI
- Référence de la thématisation
Référence de la thématisation
Ce document décrit le fonctionnement de la thématisation dans le coding-agent aujourd’hui : schéma, chargement, comportement à l’exécution et modes de défaillance.
Ce que le système de thèmes contrôle
Section intitulée « Ce que le système de thèmes contrôle »Le système de thèmes pilote :
- les jetons de couleur premier plan/arrière-plan utilisés dans l’ensemble du TUI
- les adaptateurs de style markdown (
getMarkdownTheme()) - les adaptateurs de sélecteur/éditeur/liste de paramètres (
getSelectListTheme(),getEditorTheme(),getSettingsListTheme()) - le préréglage de symboles + les surcharges de symboles (
unicode,nerd,ascii) - les couleurs de coloration syntaxique utilisées par le surligneur natif (
@f5-sales-demo/pi-natives) - les couleurs des segments de la barre d’état
Implémentation principale : src/modes/theme/theme.ts.
Structure JSON du thème
Section intitulée « Structure JSON du thème »Les fichiers de thème sont des objets JSON validés par rapport au schéma d’exécution dans theme.ts (ThemeJsonSchema) et reflétés par src/modes/theme/theme-schema.json.
Champs de niveau supérieur :
name(requis)colors(requis ; tous les jetons de couleur sont requis)vars(optionnel ; variables de couleur réutilisables)export(optionnel ; couleurs d’export HTML)symbols(optionnel)preset(optionnel :unicode | nerd | ascii)overrides(optionnel : surcharges clé/valeur pourSymbolKey)
Les valeurs de couleur acceptent :
- chaîne hexadécimale (
"#RRGGBB") - index de couleur 256 (
0..255) - chaîne de référence de variable (résolue via
vars) - chaîne vide (
"") signifiant la valeur par défaut du terminal (\x1b[39mpremier plan,\x1b[49marrière-plan)
Jetons de couleur requis (actuels)
Section intitulée « Jetons de couleur requis (actuels) »Tous les jetons ci-dessous sont requis dans colors.
Texte principal et bordures (11)
Section intitulée « Texte principal et bordures (11) »accent, border, borderAccent, borderMuted, success, error, warning, muted, dim, text, thinkingText
Blocs d’arrière-plan (7)
Section intitulée « Blocs d’arrière-plan (7) »selectedBg, userMessageBg, customMessageBg, toolPendingBg, toolSuccessBg, toolErrorBg, statusLineBg
Texte des messages/outils (5)
Section intitulée « Texte des messages/outils (5) »userMessageText, customMessageText, customMessageLabel, toolTitle, toolOutput
Markdown (10)
Section intitulée « Markdown (10) »mdHeading, mdLink, mdLinkUrl, mdCode, mdCodeBlock, mdCodeBlockBorder, mdQuote, mdQuoteBorder, mdHr, mdListBullet
Diff d’outils + coloration syntaxique (12)
Section intitulée « Diff d’outils + coloration syntaxique (12) »toolDiffAdded, toolDiffRemoved, toolDiffContext,
syntaxComment, syntaxKeyword, syntaxFunction, syntaxVariable, syntaxString, syntaxNumber, syntaxType, syntaxOperator, syntaxPunctuation
Bordures de mode/réflexion (8)
Section intitulée « Bordures de mode/réflexion (8) »thinkingOff, thinkingMinimal, thinkingLow, thinkingMedium, thinkingHigh, thinkingXhigh, bashMode, pythonMode
Couleurs des segments de la barre d’état (14)
Section intitulée « Couleurs des segments de la barre d’état (14) »statusLineSep, statusLineModel, statusLinePath, statusLineGitClean, statusLineGitDirty, statusLineContext, statusLineSpend, statusLineStaged, statusLineDirty, statusLineUntracked, statusLineOutput, statusLineCost, statusLineSubagents
Jetons optionnels
Section intitulée « Jetons optionnels »Section export (optionnelle)
Section intitulée « Section export (optionnelle) »Utilisée pour les aides à la thématisation de l’export HTML :
export.pageBgexport.cardBgexport.infoBg
Si omis, le code d’export dérive les valeurs par défaut à partir des couleurs résolues du thème.
Section symbols (optionnelle)
Section intitulée « Section symbols (optionnelle) »symbols.presetdéfinit un jeu de symboles par défaut au niveau du thème.symbols.overridespeut surcharger des valeurs individuelles deSymbolKey.
Ordre de priorité à l’exécution :
- surcharge
symbolPresetdes paramètres (si définie) symbols.presetdu JSON du thème- valeur de repli
"unicode"
Les clés de surcharge invalides sont ignorées et journalisées (logger.debug).
Sources de thèmes intégrés vs personnalisés
Section intitulée « Sources de thèmes intégrés vs personnalisés »Ordre de recherche des thèmes (loadThemeJson) :
- thèmes intégrés embarqués (
defaults/xcsh-dark.jsonetdefaults/xcsh-light.jsoncompilés dansdefaultThemes) - fichier de thème personnalisé :
<customThemesDir>/<name>.json
Le répertoire des thèmes personnalisés provient de getCustomThemesDir() :
- par défaut :
~/.xcsh/agent/themes - surchargé par
PI_CODING_AGENT_DIR($PI_CODING_AGENT_DIR/themes)
getAvailableThemes() retourne les noms fusionnés intégrés + personnalisés, triés, avec priorité aux intégrés en cas de collision de noms.
Chargement, validation et résolution
Section intitulée « Chargement, validation et résolution »Pour les fichiers de thèmes personnalisés :
- lecture du JSON
- analyse du JSON
- validation par rapport au
ThemeJsonSchema - résolution récursive des références
vars - conversion des valeurs résolues en ANSI selon le mode de capacité du terminal
Comportement de validation :
- jetons de couleur requis manquants : message d’erreur groupé explicite
- types/valeurs de jetons incorrects : erreurs de validation avec chemin JSON
- fichier de thème inconnu :
Theme not found: <name>
Comportement des références de variables :
- prend en charge les références imbriquées
- lève une exception en cas de référence de variable manquante
- lève une exception en cas de références circulaires
Comportement du mode de couleur du terminal
Section intitulée « Comportement du mode de couleur du terminal »Détection du mode de couleur (detectColorMode) :
COLORTERM=truecolor|24bit=> truecolorWT_SESSION=> truecolorTERMdansdumb,linux, ou vide => 256color- sinon => truecolor
Comportement de conversion :
- hex ->
Bun.color(..., "ansi-16m" | "ansi-256") - numérique -> ANSI
38;5/48;5 ""-> réinitialisation premier plan/arrière-plan par défaut
Comportement de changement à l’exécution
Section intitulée « Comportement de changement à l’exécution »Thème initial (initTheme)
Section intitulée « Thème initial (initTheme) »main.ts initialise le thème avec les paramètres :
symbolPresetcolorBlindModetheme.darktheme.light
La sélection automatique du créneau de thème utilise la détection de l’arrière-plan via COLORFGBG :
- analyse de l’index d’arrière-plan depuis
COLORFGBG < 8=> créneau sombre (theme.dark)>= 8=> créneau clair (theme.light)- échec de l’analyse => créneau sombre
Valeurs par défaut actuelles du schéma de paramètres :
theme.dark = "xcsh-dark"theme.light = "xcsh-light"symbolPreset = "unicode"colorBlindMode = false
Changement explicite (setTheme)
Section intitulée « Changement explicite (setTheme) »- charge le thème sélectionné
- met à jour le singleton global
theme - démarre optionnellement l’observateur
- déclenche le callback
onThemeChange
En cas d’échec :
- retombe sur le thème intégré
dark - retourne
{ success: false, error }
Changement de prévisualisation (previewTheme)
Section intitulée « Changement de prévisualisation (previewTheme) »- applique temporairement le thème de prévisualisation au
themeglobal - ne modifie pas les paramètres persistés en lui-même
- retourne succès/erreur sans remplacement de repli
L’interface des paramètres utilise ceci pour la prévisualisation en direct et restaure le thème précédent en cas d’annulation.
Observateurs et rechargement en direct
Section intitulée « Observateurs et rechargement en direct »Lorsque l’observateur est activé (setTheme(..., true) / initialisation interactive) :
- observe uniquement le chemin du fichier personnalisé
<customThemesDir>/<currentTheme>.json - les thèmes intégrés ne sont effectivement pas observés
changedu fichier : tente un rechargement (avec anti-rebond)rename/suppression du fichier : retombe surdark, ferme l’observateur
Le mode automatique installe également un écouteur SIGWINCH et peut réévaluer le mappage du créneau sombre/clair lorsque l’état du terminal change.
Comportement du mode daltonien
Section intitulée « Comportement du mode daltonien »colorBlindMode ne modifie qu’un seul jeton à l’exécution :
toolDiffAddedest ajusté en HSV (le vert est décalé vers le bleu)- l’ajustement n’est appliqué que lorsque la valeur résolue est une chaîne hexadécimale
Les autres jetons restent inchangés.
Où les paramètres de thème sont persistés
Section intitulée « Où les paramètres de thème sont persistés »Les paramètres liés aux thèmes sont persistés par Settings dans le fichier YAML de configuration globale :
- chemin :
<agentDir>/config.yml - répertoire agent par défaut :
~/.xcsh/agent - fichier effectif par défaut :
~/.xcsh/agent/config.yml
Clés persistées :
theme.darktheme.lightsymbolPresetcolorBlindMode
Une migration héritée existe : l’ancien format plat theme: "name" est migré vers le format imbriqué theme.dark ou theme.light basé sur la détection de luminance.
Créer un thème personnalisé (pratique)
Section intitulée « Créer un thème personnalisé (pratique) »- Créez un fichier dans le répertoire des thèmes personnalisés, par exemple
~/.xcsh/agent/themes/my-theme.json. - Incluez
name, desvarsoptionnels, et tous les jetonscolorsrequis. - Incluez optionnellement
symbolsetexport. - Sélectionnez le thème dans les Paramètres (
Affichage -> Thème sombreouAffichage -> Thème clair) selon le créneau automatique souhaité.
Squelette minimal. Chaque clé dans colors est requise — le validateur à l’exécution
(additionalProperties: false) rejette à la fois les clés manquantes et les clés inconnues.
Pour les implémentations de référence fournies, consultez
packages/coding-agent/src/modes/theme/defaults/xcsh-dark.json
et xcsh-light.json.
La barre d’état possède deux systèmes de couleurs parallèles documentés dans l’issue #242 :
- Les couleurs de texte hexadécimales (
statusLinePath,statusLineGitClean,statusLineGitDirty,statusLineStaged,statusLineDirty,statusLineUntracked) pilotent le rendu non-powerline. - Les indices de palette 256 couleurs (
statusLine<Segment>Bg/statusLine<Segment>Fg) pilotent le remplissage des segments powerline. Ils sont indépendants des clés hexadécimales ci-dessus — les deux doivent être définis.
{ "name": "my-theme", "vars": { "accent": "#7aa2f7", "muted": 244 }, "colors": { "accent": "accent", "chromeAccent": "accent", "spinnerAccent": "accent", "contentAccent": "muted", "border": "#4c566a", "borderAccent": "accent", "borderMuted": "muted", "success": "#9ece6a", "error": "#f7768e", "warning": "#e0af68", "muted": "muted", "dim": 240, "gutterSuccess": "#7dcfff", "gutterWarning": "#e0af68", "text": "", "thinkingText": "muted",
"selectedBg": "#2a2f45", "userMessageBg": "#1f2335", "userMessageText": "", "customMessageBg": "#24283b", "customMessageText": "", "customMessageLabel": "accent", "toolPendingBg": "#1f2335", "toolSuccessBg": "#1f2d2a", "toolErrorBg": "#2d1f2a", "toolTitle": "", "toolOutput": "muted",
"mdHeading": "accent", "mdLink": "accent", "mdLinkUrl": "muted", "mdCode": "#c0caf5", "mdCodeBlock": "#c0caf5", "mdCodeBlockBorder": "muted", "mdQuote": "muted", "mdQuoteBorder": "muted", "mdHr": "muted", "mdListBullet": "accent",
"toolDiffAdded": "#9ece6a", "toolDiffRemoved": "#f7768e", "toolDiffContext": "muted",
"syntaxComment": "#565f89", "syntaxKeyword": "#bb9af7", "syntaxFunction": "#7aa2f7", "syntaxVariable": "#c0caf5", "syntaxString": "#9ece6a", "syntaxNumber": "#ff9e64", "syntaxType": "#2ac3de", "syntaxOperator": "#89ddff", "syntaxPunctuation": "#9aa5ce", "syntaxControl": "#bb9af7",
"thinkingOff": 240, "thinkingMinimal": 244, "thinkingLow": "#7aa2f7", "thinkingMedium": "#2ac3de", "thinkingHigh": "#bb9af7", "thinkingXhigh": "#f7768e",
"bashMode": "#2ac3de", "pythonMode": "#bb9af7",
"statusLineBg": "#16161e", "statusLineSep": 240, "statusLineModel": "#bb9af7", "statusLinePath": "#7aa2f7", "statusLineGitClean": "#9ece6a", "statusLineGitDirty": "#e0af68", "statusLineContext": "#2ac3de", "statusLineSpend": "#7dcfff", "statusLineStaged": "#9ece6a", "statusLineDirty": "#e0af68", "statusLineUntracked": "#f7768e", "statusLineOutput": "#c0caf5", "statusLineCost": "#ff9e64", "statusLineSubagents": "#bb9af7",
"statusLineOsIconBg": 7, "statusLineOsIconFg": 232, "statusLinePathBg": 4, "statusLinePathFg": 254, "statusLineGitCleanBg": 2, "statusLineGitCleanFg": 0, "statusLineGitDirtyBg": 3, "statusLineGitDirtyFg": 0, "statusLineGitStagedBg": 64, "statusLineGitStagedFg": 0, "statusLineGitUntrackedBg": 39, "statusLineGitUntrackedFg": 0, "statusLineGitConflictBg": 1, "statusLineGitConflictFg": 7, "statusLinePlanModeBg": 236, "statusLinePlanModeFg": 117, "statusLineProfileXcshBg": "accent", "statusLineProfileXcshFg": 231 }}Tester les thèmes personnalisés
Section intitulée « Tester les thèmes personnalisés »Utilisez ce flux de travail :
- Démarrez le mode interactif (l’observateur est activé dès le démarrage).
- Ouvrez les paramètres et prévisualisez les valeurs du thème (
previewThemeen direct). - Pour les fichiers de thèmes personnalisés, modifiez le JSON pendant l’exécution et confirmez le rechargement automatique à la sauvegarde.
- Exercez les surfaces critiques :
- rendu markdown
- blocs d’outils (en attente/succès/erreur)
- rendu des diffs (ajouté/supprimé/contexte)
- lisibilité de la barre d’état
- changements de bordure selon le niveau de réflexion
- couleurs de bordure des modes bash/python
- Validez les deux préréglages de symboles si votre thème dépend de la largeur/apparence des glyphes.
Contraintes réelles et mises en garde
Section intitulée « Contraintes réelles et mises en garde »- Tous les jetons
colorssont requis pour les thèmes personnalisés. exportetsymbolssont optionnels.$schemadans le JSON du thème est informatif ; la validation à l’exécution est imposée par le schéma TypeBox compilé dans le code.- L’échec de
setThemeretombe surdark; l’échec depreviewThemene remplace pas le thème actuel. - Les erreurs de rechargement de l’observateur de fichiers conservent le thème actuellement chargé jusqu’à un rechargement réussi ou le déclenchement du chemin de repli.