diff --git a/CHANGELOG.md b/CHANGELOG.md index 19af9fa1..6748ccd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ## [Unreleased] +- Fix incorrect cursor placement when inputting CJK characters. Thanks @phostann (#270) for reporting it! - Removed unused dependency (newline-converter). Thanks @jonassmedegaard (#267) for catching it! ## [0.7.5] - 2024-04-23 diff --git a/inquire/src/input/test.rs b/inquire/src/input/test.rs index 5c3c437e..ad2bfb54 100644 --- a/inquire/src/input/test.rs +++ b/inquire/src/input/test.rs @@ -114,6 +114,17 @@ fn new_with_content_is_correctly_initialized() { let input = Input::new_with(content); assert_eq!(11, input.length()); assert_eq!(11, input.cursor()); + assert_eq!("great idea!", input.pre_cursor()); + assert_eq!(content, input.content()); +} + +#[test] +fn new_with_chinese_content_is_correctly_initialized() { + let content = "请输"; + let input = Input::new_with(content); + assert_eq!(2, input.length()); + assert_eq!(2, input.cursor()); + assert_eq!("请输", input.pre_cursor()); assert_eq!(content, input.content()); } @@ -138,6 +149,15 @@ fn with_cursor_is_correctly_initialized() { assert_eq!("great i", input.pre_cursor()); } +#[test] +fn chinese_with_cursor_is_correctly_initialized() { + let input = Input::new_with("请输入").with_cursor(1); + assert_eq!(3, input.length()); + assert_eq!(1, input.cursor()); + assert_eq!("请输入", input.content()); + assert_eq!("请", input.pre_cursor()); +} + #[test] fn with_placeholder_is_correctly_initialized() { let input = Input::new_with("great idea!").with_placeholder("placeholder"); diff --git a/inquire/src/ui/backend.rs b/inquire/src/ui/backend.rs index 579683a6..233c92f7 100644 --- a/inquire/src/ui/backend.rs +++ b/inquire/src/ui/backend.rs @@ -1,5 +1,7 @@ use std::{collections::BTreeSet, fmt::Display, io::Result}; +use unicode_width::UnicodeWidthStr; + use crate::{ error::InquireResult, input::Input, @@ -185,9 +187,12 @@ where fn print_input(&mut self, input: &Input) -> Result<()> { self.frame_renderer.write(" ")?; - let cursor_offset = input.pre_cursor().chars().count(); + // The cursor is at the beginning of the input line. + // From here it's easier to mark the wanted cursor position + // (based on the underlying input struct), as it's a simple + // cur_pos + offset calculation. self.frame_renderer - .mark_cursor_position(cursor_offset as isize); + .mark_cursor_position(input.pre_cursor().width() as isize); if input.is_empty() { match input.placeholder() {