feat(maestro): add [tui] config section + crossterm workspace dep (NAP-277)
Schema-only — adds `TuiSection` with `leader`, `chord_timeout_ms`, and per-mode keymap override maps; pulls crossterm into the workspace deps so the next commit's input layer can consume it. Field set matches `docs/superpowers/specs/2026-05-28-maestro-tui-design.md` §3.9.
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
//! URL derivation helper. Each binary applies its own env-var precedence and
|
||||
//! defaults on top of [`MaestroConfigFile`].
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -76,6 +77,8 @@ pub struct MaestroConfigFile {
|
||||
pub registry: RegistrySection,
|
||||
#[serde(default, skip_serializing_if = "WebSection::is_empty")]
|
||||
pub web: WebSection,
|
||||
#[serde(default, skip_serializing_if = "TuiSection::is_empty")]
|
||||
pub tui: TuiSection,
|
||||
}
|
||||
|
||||
/// Fields consumed by more than one binary (CLI + daemon, daemon + registry).
|
||||
@@ -228,6 +231,38 @@ impl WebSection {
|
||||
}
|
||||
}
|
||||
|
||||
/// `[tui]` — `maestro tui` settings (NAP-275 epic, phase 2 NAP-277).
|
||||
///
|
||||
/// Leader key, chord timeout, and per-mode keymap overrides. The TUI ships
|
||||
/// with a default keymap; entries in `keymap_normal` / `keymap_insert` are
|
||||
/// applied **over** the defaults, so a partial override is enough.
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TuiSection {
|
||||
/// Canonical key form, e.g. `"ctrl-a"`. Default `ctrl-a`.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub leader: Option<String>,
|
||||
/// Maximum interval between chord keys before a held prefix is dropped.
|
||||
/// Default `1000`.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub chord_timeout_ms: Option<u64>,
|
||||
/// Normal-mode bindings: canonical input → action string. Applied over
|
||||
/// the shipped defaults.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub keymap_normal: BTreeMap<String, String>,
|
||||
/// Insert-mode bindings, same semantics as `keymap_normal`.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub keymap_insert: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl TuiSection {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.leader.is_none()
|
||||
&& self.chord_timeout_ms.is_none()
|
||||
&& self.keymap_normal.is_empty()
|
||||
&& self.keymap_insert.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl MaestroConfigFile {
|
||||
/// Strict load — error with [`ConfigError::MissingFile`] if absent.
|
||||
pub fn load(path: &Path) -> Result<Self, ConfigError> {
|
||||
|
||||
@@ -9,4 +9,6 @@ description = "Terminal UI client over the local maestro daemon's `/api/*` surfa
|
||||
|
||||
[dependencies]
|
||||
clap.workspace = true
|
||||
crossterm.workspace = true
|
||||
maestro-config.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
Reference in New Issue
Block a user