W79: MC parity — editor gutter removed, margin+char info, viewer Enter/F3
MC has no line number gutter in editor. Removed: - Gutter rendering in editor/render.rs (body_area = inner, no gutter_area) - relative_lines field from Editor struct (both constructors) - ToggleRelativeLines enum variant from EditorCmd + menubar item - Alt-N keybinding in handlers.rs + help overlay entry - Updated 3 column-offset tests (gutter_chars was 3 chars wide) Editor additions (MC parity): - Right-margin indicator: vertical '│' at word_wrap_line_length (default 72) - Character info in status bar: '0x41 065 A' format Viewer additions (MC parity): - Enter key bound to cursor-down - F3 key bound to quit - Viewer ruler removed (never existed in MC) 1433 tests passing, zero warnings.
This commit is contained in:
@@ -230,7 +230,7 @@ All previously deferred items are now resolved:
|
||||
- Removed column ruler (Alt-R/ToggleRuler) — CK_Ruler is an MC editor-only
|
||||
feature, not present in MC viewer at all.
|
||||
|
||||
**W79b Editor:** Two MC parity improvements:
|
||||
**W79b Editor:** Three MC parity improvements:
|
||||
- Right-margin indicator: draws a vertical `│` at the word-wrap column
|
||||
(default 72) in every visible body row when word-wrap is active.
|
||||
Uses `word_wrap_line_length: usize` field (new in Editor struct,
|
||||
@@ -239,6 +239,10 @@ All previously deferred items are now resolved:
|
||||
displayable char) at cursor position between Bytes and mode tag,
|
||||
mirroring MC's `editdraw.c` status-line char display. Falls back
|
||||
to `.` for non-printable characters.
|
||||
- Removed line number gutter — MC editor has no gutter or line numbers.
|
||||
This was a TLC-only addition incompatible with MC parity. Removed:
|
||||
gutter rendering, `relative_lines` field, `ToggleRelativeLines` Cmd,
|
||||
Alt-N keybinding, and the Options-menu "Relative line numbers" item.
|
||||
|
||||
**Documented intentional divergences:**
|
||||
- Viewer encoding: TLC is UTF-8 native; MC's codepage display does not
|
||||
|
||||
@@ -287,15 +287,6 @@ impl Editor {
|
||||
});
|
||||
return Some(EditorResult::Running);
|
||||
}
|
||||
0x6E => {
|
||||
self.relative_lines = !self.relative_lines;
|
||||
self.message = Some(if self.relative_lines {
|
||||
"Line numbers: ON".to_string()
|
||||
} else {
|
||||
"Line numbers: OFF".to_string()
|
||||
});
|
||||
return Some(EditorResult::Running);
|
||||
}
|
||||
0x74 => {
|
||||
let new_width = self.cycle_tab_width();
|
||||
self.message = Some(format!("Tab width: {new_width}"));
|
||||
|
||||
@@ -75,8 +75,6 @@ pub enum EditorCmd {
|
||||
ToggleWordWrap,
|
||||
/// Toggle syntax highlighting (Ctrl-S).
|
||||
ToggleSyntax,
|
||||
/// Toggle relative line numbers (Alt-N).
|
||||
ToggleRelativeLines,
|
||||
/// Edit the user menu file (MC `CK_EditUserMenu`).
|
||||
EditUserMenu,
|
||||
/// Alt-P — reformat the paragraph at the cursor.
|
||||
@@ -277,7 +275,6 @@ impl EditorMenuBar {
|
||||
MenuItem::item("Show whitespace", 'w', EditorCmd::ToggleShowWhitespace),
|
||||
MenuItem::item("Word wrap", 'p', EditorCmd::ToggleWordWrap),
|
||||
MenuItem::item("Syntax highlight", 'h', EditorCmd::ToggleSyntax),
|
||||
MenuItem::item("Relative line numbers", 'r', EditorCmd::ToggleRelativeLines),
|
||||
MenuItem::separator(),
|
||||
MenuItem::item("Insert/Overwrite", 'i', EditorCmd::ToggleOverwrite),
|
||||
MenuItem::item("Spell check", 's', EditorCmd::SpellCheck),
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
//!
|
||||
//! All rendering goes through [`Editor::render`], which writes to a
|
||||
//! ratatui `Frame` at the given `Rect`. The view is a simple
|
||||
//! top-line/left-column scroller with line numbers in the gutter.
|
||||
//! top-line/left-column scroller.
|
||||
//!
|
||||
//! All key handling goes through [`Editor::handle_key`], which
|
||||
//! dispatches to [`Editor::handle_key_normal`],
|
||||
@@ -188,9 +188,6 @@ pub struct Editor {
|
||||
history_popup_selected: Option<usize>,
|
||||
/// Visual shape of the editing cursor (Block/Bar/Underline).
|
||||
cursor_shape: CursorShape,
|
||||
/// When true, the gutter shows each non-cursor line's distance
|
||||
/// from the cursor line instead of its absolute number.
|
||||
relative_lines: bool,
|
||||
/// When false, syntax highlighting is disabled even if a
|
||||
/// highlighter exists. Toggled by Ctrl-S (MC parity).
|
||||
syntax_enabled: bool,
|
||||
@@ -219,8 +216,7 @@ pub struct Editor {
|
||||
last_macro: Vec<macros::NamedKey>,
|
||||
/// Code-fold state. `Ctrl-F1` toggles a fold at the cursor
|
||||
/// line; the renderer hides lines covered by collapsed folds
|
||||
/// and shows a `+` marker in the gutter on the fold's start
|
||||
/// line.
|
||||
/// and shows a `+` marker on the fold's start line.
|
||||
folds: folding::FoldSet,
|
||||
/// Tag-stack: positions saved before each `Ctrl-]` jump so
|
||||
/// `Ctrl-T` can pop back. Each entry is `(byte_offset, line)`.
|
||||
@@ -299,7 +295,6 @@ impl Editor {
|
||||
search: SearchState::new(),
|
||||
history_popup_selected: None,
|
||||
cursor_shape: CursorShape::default(),
|
||||
relative_lines: false,
|
||||
syntax_enabled: true,
|
||||
auto_indent: true,
|
||||
show_whitespace: false,
|
||||
@@ -352,7 +347,6 @@ impl Editor {
|
||||
search: SearchState::new(),
|
||||
history_popup_selected: None,
|
||||
cursor_shape: CursorShape::default(),
|
||||
relative_lines: false,
|
||||
syntax_enabled: true,
|
||||
auto_indent: true,
|
||||
show_whitespace: false,
|
||||
@@ -1433,22 +1427,13 @@ impl Editor {
|
||||
"Syntax: OFF".to_string()
|
||||
});
|
||||
}
|
||||
EditorCmd::ToggleRelativeLines => {
|
||||
self.relative_lines = !self.relative_lines;
|
||||
self.message = Some(if self.relative_lines {
|
||||
"Relative line numbers: ON".to_string()
|
||||
} else {
|
||||
"Relative line numbers: OFF".to_string()
|
||||
});
|
||||
}
|
||||
EditorCmd::Settings => {
|
||||
let ai = if self.auto_indent { "ON" } else { "OFF" };
|
||||
let ww = if self.word_wrap { "ON" } else { "OFF" };
|
||||
let ws = if self.show_whitespace { "ON" } else { "OFF" };
|
||||
let sy = if self.syntax_enabled { "ON" } else { "OFF" };
|
||||
let rl = if self.relative_lines { "ON" } else { "OFF" };
|
||||
self.message = Some(format!(
|
||||
"Settings: auto-indent={ai} wrap={ww} whitespace={ws} syntax={sy} relative-lines={rl} (Alt-A/Alt-W/Alt-E/Ctrl-S toggle)"
|
||||
"Settings: auto-indent={ai} wrap={ww} whitespace={ws} syntax={sy} (Alt-A/Alt-W/Alt-E/Ctrl-S toggle)"
|
||||
));
|
||||
}
|
||||
EditorCmd::New => {
|
||||
@@ -2895,11 +2880,11 @@ mod tests {
|
||||
})
|
||||
.unwrap();
|
||||
let buffer = terminal.backend().buffer();
|
||||
assert_eq!(buffer.cell((4, 1)).expect("a cell").symbol(), "a");
|
||||
assert_eq!(buffer.cell((5, 1)).expect("space cell").symbol(), "·");
|
||||
assert_eq!(buffer.cell((6, 1)).expect("tab cell").symbol(), "→");
|
||||
assert_eq!(buffer.cell((7, 1)).expect("b cell").symbol(), "b");
|
||||
assert_eq!(buffer.cell((8, 1)).expect("caret cell").symbol(), "^");
|
||||
assert_eq!(buffer.cell((1, 1)).expect("a cell").symbol(), "a");
|
||||
assert_eq!(buffer.cell((2, 1)).expect("space cell").symbol(), "·");
|
||||
assert_eq!(buffer.cell((3, 1)).expect("tab cell").symbol(), "→");
|
||||
assert_eq!(buffer.cell((4, 1)).expect("b cell").symbol(), "b");
|
||||
assert_eq!(buffer.cell((5, 1)).expect("caret cell").symbol(), "^");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2928,7 +2913,7 @@ mod tests {
|
||||
})
|
||||
})
|
||||
.expect("must find 'b' from beta");
|
||||
let cell = buffer.cell((4, beta_y)).expect("beta line cell");
|
||||
let cell = buffer.cell((1, beta_y)).expect("beta line cell");
|
||||
assert_eq!(cell.symbol(), "b");
|
||||
assert_eq!(cell.fg, bookmarkfound.fg);
|
||||
assert_eq!(cell.bg, bookmarkfound.bg);
|
||||
@@ -3214,8 +3199,8 @@ mod tests {
|
||||
fg: theme.marked_fg,
|
||||
bg: theme.marked_bg,
|
||||
});
|
||||
let f_cell = buffer.cell((4, 1)).expect("'f' cell");
|
||||
let n_cell = buffer.cell((5, 1)).expect("'n' cell");
|
||||
let f_cell = buffer.cell((1, 1)).expect("'f' cell");
|
||||
let n_cell = buffer.cell((2, 1)).expect("'n' cell");
|
||||
assert_eq!(f_cell.symbol(), "f");
|
||||
assert_eq!(n_cell.symbol(), "n");
|
||||
assert_eq!(f_cell.bg, marked_pair.bg, "selected 'f' cell bg");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! [`Editor::render`] writes the editor into a ratatui `Frame` at
|
||||
//! the given `Rect`. The view is a simple top-line/left-column
|
||||
//! scroller with line numbers in the gutter. The status line shows
|
||||
//! scroller. The status line shows
|
||||
//! position, modification state, and active mode.
|
||||
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
@@ -21,7 +21,7 @@ use super::Editor;
|
||||
impl Editor {
|
||||
/// Render the editor into a ratatui frame at the given area.
|
||||
///
|
||||
/// `theme` supplies the title, gutter, body, prompt-overlay, and
|
||||
/// `theme` supplies the title, body, prompt-overlay, and
|
||||
/// status-line colours so the editor follows the active skin.
|
||||
pub(crate) fn render(&mut self, frame: &mut Frame, area: Rect, theme: &Theme) {
|
||||
// When the F9 menu bar is open, reserve the top row for it
|
||||
@@ -89,7 +89,7 @@ impl Editor {
|
||||
};
|
||||
let marked_fg = editor_marked.map(|p| p.fg).unwrap_or(theme.marked_fg);
|
||||
let marked_bg = editor_marked.map(|p| p.bg).unwrap_or(theme.marked_bg);
|
||||
let linestate_fg = editor_linestate.map(|p| p.fg).unwrap_or(theme.cursor_fg);
|
||||
let cur_line_fg = editor_linestate.map(|p| p.fg).unwrap_or(theme.cursor_fg);
|
||||
let frame_fg = editor_frameactive.map(|p| p.fg).unwrap_or(theme.title_fg);
|
||||
let margin_fg = editor_rightmargin.map(|p| p.fg).unwrap_or(frame_fg);
|
||||
let margin_bg = editor_rightmargin.map(|p| p.bg).unwrap_or(body_bg);
|
||||
@@ -119,23 +119,7 @@ impl Editor {
|
||||
frame.render_widget(block, editor_area);
|
||||
|
||||
let line_count = self.buffer.line_count();
|
||||
let gutter_chars = line_count.max(1).to_string().len().max(3) as u16;
|
||||
let body_area = if gutter_chars < inner.width {
|
||||
Rect::new(
|
||||
inner.x + gutter_chars,
|
||||
inner.y,
|
||||
inner.width - gutter_chars,
|
||||
inner.height,
|
||||
)
|
||||
} else {
|
||||
inner
|
||||
};
|
||||
let gutter_area = Rect::new(
|
||||
inner.x,
|
||||
inner.y,
|
||||
gutter_chars.min(inner.width),
|
||||
inner.height,
|
||||
);
|
||||
let body_area = inner;
|
||||
|
||||
self.view.ensure_cursor_visible(
|
||||
&self.buffer,
|
||||
@@ -205,7 +189,7 @@ impl Editor {
|
||||
Style::default().fg(bookmark_fg).bg(bookmark_bg)
|
||||
}
|
||||
} else if cursor_line == line_idx {
|
||||
Style::default().fg(linestate_fg).bg(cur_line_bg)
|
||||
Style::default().fg(cur_line_fg).bg(cur_line_bg)
|
||||
} else {
|
||||
Style::default().fg(body_fg).bg(body_bg)
|
||||
};
|
||||
@@ -319,38 +303,6 @@ impl Editor {
|
||||
}
|
||||
frame.render_widget(Paragraph::new(body_lines), body_area);
|
||||
|
||||
if gutter_chars < inner.width {
|
||||
let gutter_lines: Vec<Line> = visible_wrapped
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|(line_idx, wrap_row)| {
|
||||
if line_idx >= line_count {
|
||||
return Line::from(Span::styled(
|
||||
"~",
|
||||
Style::default().fg(frame_fg).bg(body_bg),
|
||||
));
|
||||
}
|
||||
let text = if wrap_row > 0 {
|
||||
" ".repeat(gutter_chars as usize)
|
||||
} else {
|
||||
let num = if self.relative_lines {
|
||||
(line_idx as i64 - cursor_line as i64).unsigned_abs()
|
||||
} else {
|
||||
line_idx as u64 + 1
|
||||
};
|
||||
format!("{:>w$}", num, w = gutter_chars as usize)
|
||||
};
|
||||
let style = if line_idx == cursor_line {
|
||||
Style::default().fg(linestate_fg).bg(cur_line_bg)
|
||||
} else {
|
||||
Style::default().fg(frame_fg).bg(body_bg)
|
||||
};
|
||||
Line::from(Span::styled(text, style))
|
||||
})
|
||||
.collect();
|
||||
frame.render_widget(Paragraph::new(gutter_lines), gutter_area);
|
||||
}
|
||||
|
||||
if body_area.width > 0 {
|
||||
let margin_area = Rect::new(
|
||||
body_area.x + body_area.width - 1,
|
||||
@@ -712,7 +664,6 @@ impl Editor {
|
||||
]),
|
||||
("View", &[
|
||||
("Ctrl-S", "Toggle syntax highlight"),
|
||||
("Alt-N", "Toggle line numbers"),
|
||||
("Ctrl-F1", "Toggle code fold"),
|
||||
("Alt-R", "Redo"),
|
||||
("Alt-Tab", "Word completion"),
|
||||
@@ -1114,7 +1065,7 @@ fn visual_width(ch: char, col: usize, tab_width: usize) -> usize {
|
||||
/// mid-word at the current column.
|
||||
///
|
||||
/// Tabs are counted as their visual width (next `tab_width` boundary).
|
||||
/// Empty lines always count as 1 visual row (so the gutter shows `~`).
|
||||
/// Empty lines always count as 1 visual row.
|
||||
fn count_wrapped_rows(line_bytes: &[u8], body_width: usize, tab_width: usize) -> usize {
|
||||
if body_width == 0 {
|
||||
return 1;
|
||||
|
||||
+1
-1
Submodule local/sources/relibc updated: fc158b3611...01807f6fa7
+1
-1
Submodule local/sources/syscall updated: c59951c038...9fad5e653c
Reference in New Issue
Block a user