feat(faces): the TUI draws axis, wizard-field, mode and minibuffer colours through face_style (improvise-nn4s.2)

axis_fg, minibuf_fg, field_kind_fg and mode_style are gone, and AxisColor
leaves improvise-core. The category-add prompt turns green, ADR 004
clause 8's one declared exception.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Claude (agent-faces)
2026-09-24 21:58:01 -07:00
committed by Edward Langley
parent abff562360
commit 12d976b432
9 changed files with 206 additions and 107 deletions
-33
View File
@@ -12,17 +12,6 @@ pub enum Axis {
None,
}
/// Accent color for an axis. Semantic palette only; `draw.rs::axis_fg` maps
/// each variant to a terminal color, so `Axis` names no ratatui type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AxisColor {
Row,
Column,
Page,
Filter,
Inactive,
}
impl Axis {
/// The next axis in the Row → Column → Page → None → Row rotation.
/// `Filter` is outside it and cycling one is a no-op (improvise-dz8).
@@ -48,17 +37,6 @@ impl Axis {
!matches!(self, Axis::Filter)
}
/// Accent color. The single source for axis coloring: the tile bar and the
/// category panel each carried a copy before (improvise-rml).
pub fn color(self) -> AxisColor {
match self {
Axis::Row => AxisColor::Row,
Axis::Column => AxisColor::Column,
Axis::Page => AxisColor::Page,
Axis::Filter => AxisColor::Filter,
Axis::None => AxisColor::Inactive,
}
}
/// Name with no decoration: "Row", "Col", "Page", "None".
pub fn plain_label(self) -> &'static str {
@@ -176,15 +154,4 @@ mod tests {
assert!(!Axis::Column.filters_data());
assert!(!Axis::None.filters_data());
}
/// A collision defeats the only reason `AxisColor` exists.
#[test]
fn every_axis_gets_its_own_color() {
let colors = ALL.map(Axis::color);
for (i, a) in colors.iter().enumerate() {
for b in &colors[i + 1..] {
assert_ne!(a, b, "two axes share an accent color");
}
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ pub mod axis;
pub mod layout;
pub mod types;
pub use axis::{Axis, AxisColor};
pub use axis::Axis;
pub use layout::{
AxisEntry, GridEval, GridLayout, NEW_CATEGORY_COL, NEW_MEASURE_COL, RecordCol, RecordRow,
ViewStep, drill_constraint, drill_snapshot, drill_steps, record_row, records_spine,
+12
View File
@@ -575,6 +575,18 @@ mod tests {
}
}
/// A collision defeats the reason the axis faces exist (improvise-rml).
#[test]
fn every_axis_gets_its_own_accent_in_the_shipped_theme() {
let theme = Theme::shipped();
let accents = AXES.map(|axis| theme.resolve(Face::Axis(axis)));
for (i, a) in accents.iter().enumerate() {
for b in &accents[i + 1..] {
assert_ne!(a, b, "two axes share an accent");
}
}
}
/// A child overrides what it states and inherits what it does not, from
/// the nearest ancestor that states it — `context/test-evidence/protocol.md`.
#[test]
+1 -1
View File
@@ -396,7 +396,7 @@ impl AppMode {
minibuf: MinibufferConfig {
buffer_key: "category".into(),
prompt: "new category: ".into(),
color: MinibufColor::Yellow,
color: MinibufColor::Green,
},
}
}
+2 -2
View File
@@ -75,8 +75,8 @@ pub struct RenderModel {
pub struct RenderMinibuffer {
pub prompt: String,
pub value: String,
/// Semantic, as `MinibufColor` is: the last translation to a CSS class is
/// the page's, exactly as `draw.rs::minibuf_fg` is the TUI's (gotcha 26).
/// A colour, not a role: the TUI now draws a face per text-entry mode, and
/// improvise-nn4s.4 moves the page onto the same faces (ADR 004).
pub color: improvise_protocol::MinibufColor,
}