feat(ctld-tools): TUI polish — i18n_lang setting, descriptions, double-click (CTLD-TOOLS-TUI-POLISH)#55
Conversation
…e-click (CTLD-TOOLS-TUI-POLISH)
Improvements surfaced while testing the interactive TUI (follow-up to CTLD-TOOLS-TUI).
Runtime fix:
- i18n_lang (the CTLD interface language) is now a first-class setting: added to the
engine defaults, and ctld.tr resolves the active language via ctld.gs("i18n_lang")
(config wins), falling back to the module global then "en". It was a bare global read
only by tr, so setting it from the user-config silently did nothing; it now works and
appears in the TUI with a value list (schema choices en/fr/es/ko).
Tooling:
- Setting descriptions: CTLD_config_schema.yaml carries a bilingual `description` per
setting (73 seeded once from the mission-maker config docs); the "Set setting" picker
shows each description in the current language and is searchable by it. Embedded in the
reference bundle; the schema is now their source of truth.
- FilterablePicker takes (value, label, search) items so the displayed label differs from
the returned value and the searchable text.
- Double-click launch: a command-less invocation in an interactive terminal (an Explorer
double-click is one — a fresh console) opens the TUI (VMCT approach). Docs note the
Windows Unblock step for a downloaded .exe.
Parity fixture and embedded bundle regenerated; CTLD.lua rebuilt. busted spec covers the
i18n_lang selection. Docs (EN+FR), CHANGELOG, PRD/roadmap/backlog index updated.
Reviewer's GuideMakes CTLD interface language a real, configurable setting, adds bilingual setting descriptions that are shown and searchable in the TUI, and introduces a double-click bridge so ctld-tools.exe opens the TUI directly, with supporting tests and documentation updates. Sequence diagram for double-click CLI bridge to TUIsequenceDiagram
actor User
participant ctld_tools_exe as ctld_tools.exe
participant cli_main as cli.main
participant bridge as _bridge_target
participant TyperApp as app
participant TUI as tui
User->>ctld_tools_exe: double-click
ctld_tools_exe->>cli_main: main()
cli_main->>cli_main: parse argv for --lang
cli_main->>bridge: _bridge_target(argv, sys.stdout.isatty())
alt [non-tty or --help or explicit command]
bridge-->>cli_main: return None
cli_main->>TyperApp: app()
TyperApp->>User: CLI help/command output
else [interactive, no command]
bridge-->>cli_main: return ["tui", *argv]
cli_main->>cli_main: sys.argv = [prog] + target
cli_main->>TyperApp: app()
TyperApp->>TUI: run tui command
TUI->>User: interactive editor UI
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The
_bridge_targethelper assumes--langis the only value-taking global option; if you later introduce other global flags with values, this logic will need updating or generalizing to avoid misclassifying commands. - In
FilterablePicker._item, non-string options are assumed to be(value, label, search)triples; consider validating tuple length or type to fail fast if callers pass an unexpected structure.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `_bridge_target` helper assumes `--lang` is the only value-taking global option; if you later introduce other global flags with values, this logic will need updating or generalizing to avoid misclassifying commands.
- In `FilterablePicker._item`, non-string options are assumed to be `(value, label, search)` triples; consider validating tuple length or type to fail fast if callers pass an unexpected structure.
## Individual Comments
### Comment 1
<location path="src/CTLD_i18n.lua" line_range="67-73" />
<code_context>
+--- Active language: the config setting wins (so the MM can set it from the user-config),
+--- then the module global `ctld.i18n_lang` (pre-config default), then "en". Guarded so a
+--- very early tr() call — before CTLDConfig exists — cannot throw.
+local function _activeLang()
+ local ok, fromSetting = pcall(function() return ctld.gs and ctld.gs("i18n_lang") end)
+ return (ok and fromSetting) or ctld.i18n_lang or "en"
+end
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** The broad `pcall` around `ctld.gs("i18n_lang")` can hide real configuration errors and makes debugging harder.
Because the `pcall` wraps all of `ctld.gs`, any exception (including real bugs or misconfigurations) is silently converted into a fallback to `ctld.i18n_lang`/"en". That can hide problems in `ctld.gs` or the settings backend and just surface as "language keeps defaulting to EN" with no signal of the underlying error. Consider restricting what you catch (e.g., a specific "config not ready" error) or at least logging failures so genuine issues aren’t masked.
```suggestion
--- Active language: the config setting wins (so the MM can set it from the user-config),
--- then the module global `ctld.i18n_lang` (pre-config default), then "en".
--- Guarded so a very early tr() call — before CTLDConfig exists — cannot throw, but
--- configuration/backend errors are logged instead of being silently swallowed.
local function _activeLang()
-- If the settings getter is not available yet, fall back to the pre-config default/English.
if not ctld.gs then
return ctld.i18n_lang or "en"
end
-- Read the language from config. Errors are logged so misconfigurations are visible.
local ok, fromSetting = pcall(ctld.gs, "i18n_lang")
if not ok then
ctld.utils.log(
"ERROR",
"CTLDi18n._activeLang: failed to read 'i18n_lang' from settings: %s",
tostring(fromSetting)
)
end
return (ok and fromSetting) or ctld.i18n_lang or "en"
end
```
</issue_to_address>
### Comment 2
<location path="docs/mission-maker/ctld-tools.fr.md" line_range="29" />
<code_context>
## L'éditeur interactif (`ctld-tools tui`) — recommandé { #the-interactive-editor-ctld-tools-tui-recommended }
+**Double-cliquer `ctld-tools.exe`** ouvre directement cet éditeur (aucun argument requis). Depuis un
+terminal :
+
</code_context>
<issue_to_address>
**suggestion (typo):** Infinitive form here is slightly awkward; consider an imperative or noun phrase.
The wording "**Double-cliquer `ctld-tools.exe`**" sounds unnatural in French because of the infinitive used as the subject. Consider "**Double-cliquez sur `ctld-tools.exe`**" or "**Le double-clic sur `ctld-tools.exe`** ouvre directement cet éditeur" for more idiomatic phrasing.
Suggested implementation:
```
**Double-cliquez sur `ctld-tools.exe`** pour ouvrir directement cet éditeur (aucun argument requis). Depuis un
terminal :
```
Le fichier semble déjà contenir des instructions similaires (« Double-cliquez dessus ») avant et après le bloc concerné. Il peut être utile, pour harmoniser la documentation, de vérifier que toutes les occurrences utilisent la même forme impérative (« Double-cliquez sur … » ou « Double-cliquez dessus ») et d’éviter les répétitions exactes si ce bloc est dupliqué ailleurs dans le fichier.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| --- Active language: the config setting wins (so the MM can set it from the user-config), | ||
| --- then the module global `ctld.i18n_lang` (pre-config default), then "en". Guarded so a | ||
| --- very early tr() call — before CTLDConfig exists — cannot throw. | ||
| local function _activeLang() | ||
| local ok, fromSetting = pcall(function() return ctld.gs and ctld.gs("i18n_lang") end) | ||
| return (ok and fromSetting) or ctld.i18n_lang or "en" | ||
| end |
There was a problem hiding this comment.
suggestion (bug_risk): The broad pcall around ctld.gs("i18n_lang") can hide real configuration errors and makes debugging harder.
Because the pcall wraps all of ctld.gs, any exception (including real bugs or misconfigurations) is silently converted into a fallback to ctld.i18n_lang/"en". That can hide problems in ctld.gs or the settings backend and just surface as "language keeps defaulting to EN" with no signal of the underlying error. Consider restricting what you catch (e.g., a specific "config not ready" error) or at least logging failures so genuine issues aren’t masked.
| --- Active language: the config setting wins (so the MM can set it from the user-config), | |
| --- then the module global `ctld.i18n_lang` (pre-config default), then "en". Guarded so a | |
| --- very early tr() call — before CTLDConfig exists — cannot throw. | |
| local function _activeLang() | |
| local ok, fromSetting = pcall(function() return ctld.gs and ctld.gs("i18n_lang") end) | |
| return (ok and fromSetting) or ctld.i18n_lang or "en" | |
| end | |
| --- Active language: the config setting wins (so the MM can set it from the user-config), | |
| --- then the module global `ctld.i18n_lang` (pre-config default), then "en". | |
| --- Guarded so a very early tr() call — before CTLDConfig exists — cannot throw, but | |
| --- configuration/backend errors are logged instead of being silently swallowed. | |
| local function _activeLang() | |
| -- If the settings getter is not available yet, fall back to the pre-config default/English. | |
| if not ctld.gs then | |
| return ctld.i18n_lang or "en" | |
| end | |
| -- Read the language from config. Errors are logged so misconfigurations are visible. | |
| local ok, fromSetting = pcall(ctld.gs, "i18n_lang") | |
| if not ok then | |
| ctld.utils.log( | |
| "ERROR", | |
| "CTLDi18n._activeLang: failed to read 'i18n_lang' from settings: %s", | |
| tostring(fromSetting) | |
| ) | |
| end | |
| return (ok and fromSetting) or ctld.i18n_lang or "en" | |
| end |
|
|
||
| ## L'éditeur interactif (`ctld-tools tui`) — recommandé { #the-interactive-editor-ctld-tools-tui-recommended } | ||
|
|
||
| **Double-cliquer `ctld-tools.exe`** ouvre directement cet éditeur (aucun argument requis). Depuis un |
There was a problem hiding this comment.
suggestion (typo): Infinitive form here is slightly awkward; consider an imperative or noun phrase.
The wording "Double-cliquer ctld-tools.exe" sounds unnatural in French because of the infinitive used as the subject. Consider "Double-cliquez sur ctld-tools.exe" or "Le double-clic sur ctld-tools.exe ouvre directement cet éditeur" for more idiomatic phrasing.
Suggested implementation:
**Double-cliquez sur `ctld-tools.exe`** pour ouvrir directement cet éditeur (aucun argument requis). Depuis un
terminal :
Le fichier semble déjà contenir des instructions similaires (« Double-cliquez dessus ») avant et après le bloc concerné. Il peut être utile, pour harmoniser la documentation, de vérifier que toutes les occurrences utilisent la même forme impérative (« Double-cliquez sur … » ou « Double-cliquez dessus ») et d’éviter les répétitions exactes si ce bloc est dupliqué ailleurs dans le fichier.
…-only)
Putting i18n_lang in the engine defaults made ctld.gs("i18n_lang") always return "en",
shadowing the legacy `ctld.i18n_lang = "fr"` method and breaking the F-103 i18n specs.
Declare it in CTLD_config_schema.yaml with `default: en` instead; Reference surfaces
schema settings with a default into scalar_settings. gs stays nil unless the user-config
sets it, so the legacy global still works and the user-config wins when present. busted
i18n_lang spec adjusted; parity fixture reverts to no i18n_lang.
The new i18n_lang describe nulled CTLDConfig._instance without reloading, so later specs inherited an empty instance (36 failures). after_each now reloads the defaults.
Lot CTLD-TOOLS-TUI-POLISH
Improvements surfaced while testing the interactive TUI (follow-up to
CTLD-TOOLS-TUI, PR #52). One lot, three parts.1. Runtime fix — interface language is a real setting
i18n_lang(en/fr/es/ko) is now a first-class setting: added to the engine defaults;ctld.trresolves the active language viactld.gs("i18n_lang")(config wins), falling back to the module global then"en".tr, so setting it from the user-config silently did nothing. It now works, and appears in the TUI with a value list. busted spec covers selection / default / fallback / user-config-driven.2. Setting descriptions (shown + searchable)
CTLD_config_schema.yamlgains a bilingualdescriptionper setting — 73 seeded once from the mission-maker config docs (markdown stripped). The schema is now their source of truth (roadmap: generate the doc tables from it).FilterablePickernow takes(value, label, search)items (label ≠ returned value ≠ searchable text). Descriptions embedded inreference.json.3. Double-click launch + Unblock doc
_bridge_target, pure + tested);--helpand non-tty stdout are left to Typer.ctld-tools.mdEN+FR) note the Windows Unblock step for a downloaded.exeand that double-clicking opens the editor.Tests / build
i18n_lang) and embedded bundle regenerated;CTLD.luarebuilt. Lua lint/busted run in CI.Closes
CTLD-TOOLS-TUI-POLISH(PRD in.backlog/).Summary by Sourcery
Polish the ctld-tools TUI by making the CTLD interface language a configurable setting, enriching settings with bilingual descriptions that are searchable in the editor, and improving usability with double‑click launch behavior and updated mission‑maker documentation.
New Features:
Enhancements:
Documentation:
Tests: