diff --git a/local/recipes/tui/tlc/source/src/editor/handlers.rs b/local/recipes/tui/tlc/source/src/editor/handlers.rs index 423ea8a8e2..75a23959ca 100644 --- a/local/recipes/tui/tlc/source/src/editor/handlers.rs +++ b/local/recipes/tui/tlc/source/src/editor/handlers.rs @@ -296,6 +296,11 @@ impl Editor { }); return Some(EditorResult::Running); } + 0x74 => { + let new_width = self.cycle_tab_width(); + self.message = Some(format!("Tab width: {new_width}")); + return Some(EditorResult::Running); + } 0x72 => { self.redo(); return Some(EditorResult::Running); diff --git a/local/recipes/tui/tlc/source/src/editor/mod.rs b/local/recipes/tui/tlc/source/src/editor/mod.rs index 6fd45b8e2e..aaa2f8ae7b 100644 --- a/local/recipes/tui/tlc/source/src/editor/mod.rs +++ b/local/recipes/tui/tlc/source/src/editor/mod.rs @@ -655,6 +655,30 @@ bracket_flash: None, self.word_wrap } + /// Current visual tab width in spaces. + #[must_use] + pub fn tab_width(&self) -> usize { + self.tab_width + } + + /// Set the visual tab width in spaces. Used by Tab-to-indent + /// and by the word-wrap renderer. + pub fn set_tab_width(&mut self, width: usize) { + self.tab_width = width.max(1); + } + + /// Cycle through the common tab widths (2 → 4 → 8 → 2). Returns + /// the new width. Bound to Alt-T. + pub fn cycle_tab_width(&mut self) -> usize { + let next = match self.tab_width { + w if w <= 2 => 4, + w if w <= 4 => 8, + _ => 2, + }; + self.tab_width = next; + next + } + /// Whether auto-indent is enabled on Enter. #[must_use] pub fn auto_indent(&self) -> bool { @@ -3240,5 +3264,45 @@ mod tests { // contains a non-whitespace byte → not in indent zone → literal tab. assert_eq!(e.buffer().as_string(), "foo\t bar"); } + + #[test] + fn tab_width_default_is_four() { + let e = make_empty(); + assert_eq!(e.tab_width(), 4); + } + + #[test] + fn set_tab_width_updates_field() { + let mut e = make_empty(); + e.set_tab_width(8); + assert_eq!(e.tab_width(), 8); + e.set_tab_width(0); + assert_eq!(e.tab_width(), 1); // clamped to min 1 + } + + #[test] + fn cycle_tab_width_advances_2_4_8_2() { + let mut e = make_empty(); + assert_eq!(e.tab_width(), 4); + assert_eq!(e.cycle_tab_width(), 8); + assert_eq!(e.cycle_tab_width(), 2); + assert_eq!(e.cycle_tab_width(), 4); + } + + #[test] + fn cycle_tab_width_from_unusual_value_resets_to_2() { + let mut e = make_empty(); + e.set_tab_width(16); + assert_eq!(e.cycle_tab_width(), 2); + } + + #[test] + fn tab_to_indent_uses_current_tab_width() { + let mut e = make_empty(); + e.set_tab_width(8); + e.insert_tab_with_indent(); + assert_eq!(e.buffer().as_string(), " "); + assert_eq!(e.cursor.visual_column(), 8); + } }