From af70266f6adfbaac1a09bba96d1c45bb424d5eb2 Mon Sep 17 00:00:00 2001 From: pagedmov Date: Wed, 18 Feb 2026 11:29:16 -0500 Subject: [PATCH] Some highlighter bug fixes --- src/main.rs | 5 ++ src/prompt/mod.rs | 1 - src/prompt/readline/mod.rs | 94 +++++++++++++++++++++++++++++++------- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index d16e80f..51f0775 100644 --- a/src/main.rs +++ b/src/main.rs @@ -191,6 +191,7 @@ fn fern_interactive() -> ShResult<()> { // Process any available input match readline.process_input() { Ok(ReadlineEvent::Line(input)) => { + let start = Instant::now(); write_meta(|m| m.start_timer()); if let Err(e) = exec_input(input, None, true) { match e.kind() { @@ -201,10 +202,14 @@ fn fern_interactive() -> ShResult<()> { _ => eprintln!("{e}"), } } + let command_run_time = start.elapsed(); write_meta(|m| m.stop_timer()); // Reset for next command with fresh prompt readline.reset(get_prompt().ok()); + let real_end = start.elapsed(); + log::info!("Command execution time: {:.2?}", command_run_time); + log::info!("Total round trip time: {:.2?}", real_end); } Ok(ReadlineEvent::Eof) => { // Ctrl+D on empty line diff --git a/src/prompt/mod.rs b/src/prompt/mod.rs index 27e6190..cac53b7 100644 --- a/src/prompt/mod.rs +++ b/src/prompt/mod.rs @@ -1,4 +1,3 @@ -pub mod highlight; pub mod readline; pub mod statusline; diff --git a/src/prompt/readline/mod.rs b/src/prompt/readline/mod.rs index 3abf378..91d4aa5 100644 --- a/src/prompt/readline/mod.rs +++ b/src/prompt/readline/mod.rs @@ -52,6 +52,16 @@ pub mod markers { pub const GLOB: char = '\u{fdde}'; pub const RESET: char = '\u{fde2}'; + + pub const END_MARKERS: [char;7] = [ + VAR_SUB_END, + CMD_SUB_END, + PROC_SUB_END, + STRING_DQ_END, + STRING_SQ_END, + SUBSH_END, + RESET + ]; } /// Non-blocking readline result @@ -161,6 +171,8 @@ impl FernVi { } if cmd.should_submit() { + self.editor.set_hint(None); + self.print_line()?; self.writer.flush_write("\n")?; let buf = self.editor.take_buf(); // Save command to history @@ -512,6 +524,63 @@ pub fn marker_for(class: &TkRule) -> Option { } pub fn annotate_token(input: &mut String, token: Tk) { + let sort_insertions = |insertions: &mut Vec<(usize, char)>| { + insertions.sort_by(|a, b| { + match b.0.cmp(&a.0) { + std::cmp::Ordering::Equal => { + let priority = |m: char| -> u8 { + match m { + markers::RESET => 0, + markers::VAR_SUB_END | + markers::CMD_SUB_END | + markers::PROC_SUB_END | + markers::STRING_DQ_END | + markers::STRING_SQ_END | + markers::SUBSH_END => 2, + _ => 1, + } + }; + priority(a.1).cmp(&priority(b.1)) + } + other => other, + } + }); + }; + + let in_context = |c: char, insertions: &[(usize, char)]| -> bool { + let mut stack = insertions.to_vec(); + stack.sort_by(|a, b| { + match b.0.cmp(&a.0) { + std::cmp::Ordering::Equal => { + let priority = |m: char| -> u8 { + match m { + markers::RESET => 0, + markers::VAR_SUB_END | + markers::CMD_SUB_END | + markers::PROC_SUB_END | + markers::STRING_DQ_END | + markers::STRING_SQ_END | + markers::SUBSH_END => 2, + _ => 1, + } + }; + priority(a.1).cmp(&priority(b.1)) + } + other => other, + } + }); + stack.retain(|(i, m)| *i <= token.span.start && !markers::END_MARKERS.contains(m)); + + log::error!("Checking context for token '{}', looking for '{}'", token.span.as_str(), c); + let Some(ctx) = stack.last() else { + return false; + }; + log::error!("Context stack for token '{}': {:?}", token.span.as_str(), stack); + log::error!("Found context marker '{}' at position {}", ctx.1, ctx.0); + + ctx.1 == c + }; + if token.class != TkRule::Str && let Some(marker) = marker_for(&token.class) { input.insert(token.span.end, markers::RESET); @@ -545,6 +614,8 @@ pub fn annotate_token(input: &mut String, token: Tk) { insertions.insert(0, (span_start, markers::BUILTIN)); } else if token.flags.contains(TkFlags::IS_CMD) { insertions.insert(0, (span_start, markers::COMMAND)); + } else if !token.flags.contains(TkFlags::KEYWORD) && !token.flags.contains(TkFlags::ASSIGN) { + insertions.insert(0, (span_start, markers::ARG)); } if token.flags.contains(TkFlags::KEYWORD) { @@ -590,7 +661,7 @@ pub fn annotate_token(input: &mut String, token: Tk) { '{' if cmd_sub_depth == 0 => { insertions.push((span_start + dollar_pos, markers::VAR_SUB)); token_chars.next(); // consume the brace - let mut end_pos = dollar_pos + 2; // position after ${ + let mut end_pos; // position after ${ while let Some((cur_i, br_ch)) = token_chars.peek() { end_pos = *cur_i; // TODO: implement better parameter expansion awareness here @@ -705,7 +776,10 @@ pub fn annotate_token(input: &mut String, token: Tk) { } } '*' | '?' if (!in_dub_qt && !in_sng_qt) => { - insertions.push((span_start + *i, markers::GLOB)); + if !in_context(markers::COMMAND, &insertions) { + insertions.push((span_start + *i + 1, markers::RESET)); + insertions.push((span_start + *i, markers::GLOB)); + } token_chars.next(); // consume the glob char } _ => { @@ -719,21 +793,7 @@ pub fn annotate_token(input: &mut String, token: Tk) { // - Regular markers middle // - END markers last (inserted last, ends up leftmost) // Result: [END][TOGGLE][RESET] - insertions.sort_by(|a, b| { - match b.0.cmp(&a.0) { - std::cmp::Ordering::Equal => { - let priority = |m: char| -> u8 { - match m { - markers::RESET => 0, - markers::VAR_SUB_END | markers::CMD_SUB_END => 2, - _ => 1, - } - }; - priority(a.1).cmp(&priority(b.1)) - } - other => other, - } - }); + sort_insertions(&mut insertions); for (pos, marker) in insertions { let pos = pos.max(0).min(input.len());