fix: the minibuffer row carries a pending status message (improvise-mai9)
`draw_bottom_bar` rendered the minibuffer INSTEAD of the status line, so a status message written while any text-entry mode was open was never drawn — not truncated, not overwritten, simply never rendered. A test asserting `app.status_msg == "..."` passed in every one of those cases, which is why this survived improvise-6t3's careful ordering of `CommitBuffer`'s effects so a failure message would win: it won a race to a surface nobody could see. Of the ticket's two candidates, the row is shared. `minibuffer_line` composes the prompt and buffer on the left and any pending `status_msg` right-aligned, so the bottom bar stays ONE row and the exact-frame geometry does not move. The alternative — making the caller structurally unable to report while its minibuffer is open — is what `CommitSave` does by hand today, and generalising it means repeating that at every text-entry commit. The ticket calls that a workaround; sharing the row costs one function and covers all eight modes at once, including the `:w /bad/path` path Copilot found on PR #27. The failure is now loud: `a_status_message_set_while_a_minibuffer_is_open_is_ on_the_bottom_row` asserts the composed row, not the field. Its negative arm is not decoration — a composition that appended unconditionally would pass the first test and draw two spaces of nothing on every minibuffer keystroke. Injected fault: the `false` arm returning `String::new()`, i.e. the old composition. The first test fails naming the missing message; the second passes. Known and out of scope: `fill_line` pads on `left.len()`, which is bytes, so the right-hand text sits two cells right of its mark whenever the left carries the multi-byte cursor glyph. `draw_status` has always done this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
+42
-1
@@ -388,6 +388,17 @@ fn draw_tile_bar(f: &mut Frame, area: Rect, app: &App) {
|
||||
);
|
||||
}
|
||||
|
||||
/// The minibuffer row, with any pending status message riding on its right.
|
||||
/// The minibuffer owns the bottom row and used to hide it — tui.md §3.
|
||||
fn minibuffer_line(prompt: &str, buf: &str, status_msg: &str, width: u16) -> String {
|
||||
let left = format!("{prompt}{buf}▌");
|
||||
let right = match status_msg.is_empty() {
|
||||
true => String::new(),
|
||||
false => format!(" {status_msg} "),
|
||||
};
|
||||
fill_line(left, &right, width)
|
||||
}
|
||||
|
||||
fn draw_bottom_bar(f: &mut Frame, area: Rect, app: &App) {
|
||||
if let Some(mb) = app.view_state.mode.minibuffer() {
|
||||
let buf = app
|
||||
@@ -396,7 +407,7 @@ fn draw_bottom_bar(f: &mut Frame, area: Rect, app: &App) {
|
||||
.get(&mb.buffer_key)
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or("");
|
||||
let text = format!("{}{}▌", mb.prompt, buf);
|
||||
let text = minibuffer_line(&mb.prompt, buf, &app.view_state.status_msg, area.width);
|
||||
f.render_widget(
|
||||
Paragraph::new(text).style(
|
||||
Style::default()
|
||||
@@ -527,6 +538,36 @@ fn draw_welcome(f: &mut Frame, area: Rect) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bottom_bar_tests {
|
||||
use super::minibuffer_line;
|
||||
|
||||
/// improvise-mai9: the message used not to be drawn at all — see
|
||||
/// context/test-evidence/tui.md.
|
||||
#[test]
|
||||
fn a_status_message_set_while_a_minibuffer_is_open_is_on_the_bottom_row() {
|
||||
let line = minibuffer_line("Category: ", "North", "category already exists", 80);
|
||||
assert!(
|
||||
line.contains("Category: North"),
|
||||
"the minibuffer still owns the left of the row: {line:?}"
|
||||
);
|
||||
assert!(
|
||||
line.contains("category already exists"),
|
||||
"the status message must reach the user: {line:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_no_message_pending_the_minibuffer_row_is_only_the_minibuffer() {
|
||||
let line = minibuffer_line("Category: ", "North", "", 80);
|
||||
assert_eq!(
|
||||
line.trim_end(),
|
||||
"Category: North\u{258c}",
|
||||
"an empty status adds nothing but padding"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod key_conversion_tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user