Skip to content

Commit d528bb7

Browse files
authored
Fix UTF-8 multibyte handling in explore inputs (#16325)
# Description `explore` was reading the byte length for computing: - `:` command input cursor positions - `/`/`?` search mode cursor positions - `:try` input box cursor positions - search highlighting Fixed this for the majority of cases by using `unicode_width`, this is only best effort as terminals don't need to follow those expectations but for the most cases (traditional language scripts etc.) this should lead to better result. The only way around the uncertainty would be to perform the highlighting/cursor marking as we go, but this may not be as compatible with the `ratatui` framework. Closes #16312 # User-Facing Changes Fixed cursor position and search highlighting for non-ASCII characters, with the caveat mentioned above. # Tests + Formatting Manually tested
1 parent 7cc1a86 commit d528bb7

File tree

2 files changed

+10
-6
lines changed

2 files changed

+10
-6
lines changed

crates/nu-explore/src/pager/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use std::{
3737
io::{self, Stdout},
3838
result,
3939
};
40+
use unicode_width::UnicodeWidthStr;
4041

4142
pub type Frame<'a> = ratatui::Frame<'a>;
4243
pub type Terminal = ratatui::Terminal<CrosstermBackend<Stdout>>;
@@ -450,14 +451,14 @@ fn run_command(
450451
fn set_cursor_cmd_bar(f: &mut Frame, area: Rect, pager: &Pager) {
451452
if pager.cmd_buf.is_cmd_input {
452453
// todo: deal with a situation where we exceed the bar width
453-
let next_pos = (pager.cmd_buf.buf_cmd2.len() + 1) as u16;
454+
let next_pos = (pager.cmd_buf.buf_cmd2.width() + 1) as u16;
454455
// 1 skips a ':' char
455456
if next_pos < area.width {
456457
f.set_cursor_position((next_pos, area.height - 1));
457458
}
458459
} else if pager.search_buf.is_search_input {
459460
// todo: deal with a situation where we exceed the bar width
460-
let next_pos = (pager.search_buf.buf_cmd_input.len() + 1) as u16;
461+
let next_pos = (pager.search_buf.buf_cmd_input.width() + 1) as u16;
461462
// 1 skips a ':' char
462463
if next_pos < area.width {
463464
f.set_cursor_position((next_pos, area.height - 1));
@@ -558,7 +559,8 @@ fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, config: &
558559

559560
fn render_cmd_bar_cmd(f: &mut Frame, area: Rect, pager: &Pager, config: &ExploreConfig) {
560561
let mut input = pager.cmd_buf.buf_cmd2.as_str();
561-
if input.len() > area.width as usize + 1 {
562+
// UnicodeWidthStr::width is a best guess
563+
if input.width() > area.width as usize + 1 {
562564
// in such case we take last max_cmd_len chars
563565
let take_bytes = input
564566
.chars()
@@ -591,7 +593,8 @@ fn highlight_search_results(f: &mut Frame, pager: &Pager, layout: &Layout, style
591593
if let Some(p) = text.find(&pager.search_buf.buf_cmd_input) {
592594
let p = covert_bytes_to_chars(&text, p);
593595

594-
let w = pager.search_buf.buf_cmd_input.len() as u16;
596+
// this width is a best guess
597+
let w = pager.search_buf.buf_cmd_input.width() as u16;
595598
let area = Rect::new(e.area.x + p as u16, e.area.y, w, 1);
596599

597600
f.render_widget(highlight_block.clone(), area);

crates/nu-explore/src/views/try.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use ratatui::{
1616
widgets::{BorderType, Borders, Paragraph},
1717
};
1818
use std::cmp::min;
19+
use unicode_width::UnicodeWidthStr;
1920

2021
pub struct TryView {
2122
input: Value,
@@ -87,8 +88,8 @@ impl View for TryView {
8788

8889
let mut input = self.command.as_str();
8990

90-
let max_cmd_len = min(input.len() as u16, cmd_input_area.width);
91-
if input.len() as u16 > max_cmd_len {
91+
let max_cmd_len = min(input.width() as u16, cmd_input_area.width);
92+
if input.width() as u16 > max_cmd_len {
9293
// in such case we take last max_cmd_len chars
9394
let take_bytes = input
9495
.chars()

0 commit comments

Comments
 (0)