From e096eb2095ce279f5fd097d8e15905b7fb591c0e Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Mon, 25 Apr 2022 11:43:42 +0900 Subject: [PATCH 1/3] fix: Fix misalignment in report highlight and indent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous method misaligns highlights when there are double width asian characters ``` 39 | 한글 eglish | ^^^^^^ ``` This commit fixes the highlight to have correct alignment. ``` 39 | 한글 eglish | ^^^^^^ ``` `unicode-rs` crate is used by the Rust compiler [1]. [1]: https://github.com/rust-lang/rust/blob/34a6c9f26e2ce32cad0d71f5e342365b09f4d12c/compiler/rustc_errors/src/emitter.rs#L861 --- Cargo.lock | 1 + Cargo.toml | 1 + src/bin/typos-cli/report.rs | 9 +++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 563a70d..3fdc389 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1576,6 +1576,7 @@ dependencies = [ "typos-vars", "unicase", "unicode-segmentation", + "unicode-width", "varcon-core", "yansi", ] diff --git a/Cargo.toml b/Cargo.toml index 4756e6d..7b6c86c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,7 @@ encoding = "0.2" kstring = { version = "2.0.0", features = ["serde"] } typed-arena = "2.0.1" maplit = "1.0" +unicode-width = "0.1.9" [dev-dependencies] assert_fs = "1.0" diff --git a/src/bin/typos-cli/report.rs b/src/bin/typos-cli/report.rs index 1eb6318..87e7e75 100644 --- a/src/bin/typos-cli/report.rs +++ b/src/bin/typos-cli/report.rs @@ -3,6 +3,8 @@ use std::io::{self, Write}; use std::sync::atomic; +use unicode_width::UnicodeWidthStr; + use typos_cli::report::{Context, Message, Report, Typo}; #[derive(Copy, Clone, Debug)] @@ -218,8 +220,11 @@ fn print_long_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::Er let line_num = context.line_num.to_string(); let line_indent: String = itertools::repeat_n(" ", line_num.len()).collect(); - let hl_indent: String = itertools::repeat_n(" ", column).collect(); - let hl: String = itertools::repeat_n("^", msg.typo.len()).collect(); + let visible_column = UnicodeWidthStr::width(start.as_ref()); + let visible_len = UnicodeWidthStr::width(msg.typo); + + let hl_indent: String = itertools::repeat_n(" ", visible_column).collect(); + let hl: String = itertools::repeat_n("^", visible_len).collect(); writeln!(handle, "{} |", line_indent)?; writeln!( From d34c8e64c325a5214ab84c08d19840a12126f674 Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 26 Apr 2022 14:58:33 +0900 Subject: [PATCH 2/3] test: Add e2e test for multiwidth characters --- tests/cmd/stdin-failure-multiwidth.stdin | 5 ++++ tests/cmd/stdin-failure-multiwidth.stdout | 30 +++++++++++++++++++++++ tests/cmd/stdin-failure-multiwidth.toml | 3 +++ 3 files changed, 38 insertions(+) create mode 100644 tests/cmd/stdin-failure-multiwidth.stdin create mode 100644 tests/cmd/stdin-failure-multiwidth.stdout create mode 100644 tests/cmd/stdin-failure-multiwidth.toml diff --git a/tests/cmd/stdin-failure-multiwidth.stdin b/tests/cmd/stdin-failure-multiwidth.stdin new file mode 100644 index 0000000..0c451e2 --- /dev/null +++ b/tests/cmd/stdin-failure-multiwidth.stdin @@ -0,0 +1,5 @@ +한 Apropriate world +한 Apropriate world +😵‍💫 Apropriate world +👁️‍🗨️ Apropriate world + Apropriate world \ No newline at end of file diff --git a/tests/cmd/stdin-failure-multiwidth.stdout b/tests/cmd/stdin-failure-multiwidth.stdout new file mode 100644 index 0000000..08fc6ec --- /dev/null +++ b/tests/cmd/stdin-failure-multiwidth.stdout @@ -0,0 +1,30 @@ +error: `Apropriate` should be `Appropriate` + --> -:1:2 + | +1 | 한 Apropriate world + | ^^^^^^^^^^ + | +error: `Apropriate` should be `Appropriate` + --> -:2:2 + | +2 | 한 Apropriate world + | ^^^^^^^^^^ + | +error: `Apropriate` should be `Appropriate` + --> -:3:2 + | +3 | 😵‍💫 Apropriate world + | ^^^^^^^^^^ + | +error: `Apropriate` should be `Appropriate` + --> -:4:2 + | +4 | 👁️‍🗨️ Apropriate world + | ^^^^^^^^^^ + | +error: `Apropriate` should be `Appropriate` + --> -:5:1 + | +5 | Apropriate world + | ^^^^^^^^^^ + | diff --git a/tests/cmd/stdin-failure-multiwidth.toml b/tests/cmd/stdin-failure-multiwidth.toml new file mode 100644 index 0000000..18f517f --- /dev/null +++ b/tests/cmd/stdin-failure-multiwidth.toml @@ -0,0 +1,3 @@ +bin.name = "typos" +args = "-" +status.code = 2 \ No newline at end of file From f4396739e68a9d3518c5875e8db7f6bee3818009 Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Wed, 27 Apr 2022 11:20:53 +0900 Subject: [PATCH 3/3] test: Add descriptions to multiwidth test fixtures --- tests/cmd/stdin-failure-multiwidth.stdin | 33 +++++++++++++++-- tests/cmd/stdin-failure-multiwidth.stdout | 44 +++++++++++------------ 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/tests/cmd/stdin-failure-multiwidth.stdin b/tests/cmd/stdin-failure-multiwidth.stdin index 0c451e2..1af6419 100644 --- a/tests/cmd/stdin-failure-multiwidth.stdin +++ b/tests/cmd/stdin-failure-multiwidth.stdin @@ -1,5 +1,34 @@ +--- +Korean character (NFC) +Grapheme clusters: 1, codepoints: 1, UnicodeWidthStr::width() == 2 + 한 Apropriate world + ^^^^^^^^^^ highlight here + +--- +Korean character (NFD). +Grapheme clusters: 1, codepoints: 3, UnicodeWidthStr::width() == 2 + 한 Apropriate world -😵‍💫 Apropriate world + ^^^^^^^^^^ highlight here + +--- +Eye in Speech Bubble Emoji (U+1F441 U+FE0F U+200D U+1F5E8 U+FE0F, Recommended Emoji ZWJ Sequences, v2.0) +Grapheme clusters: 1, codepoints: 5, UnicodeWidthStr::width() == 2 (Read NOTE: https://github.com/unicode-rs/unicode-width) + 👁️‍🗨️ Apropriate world - Apropriate world \ No newline at end of file + ^^^^^^^^^^ highlight here + +--- +Face with spiral eyes (U+1F635 U+200D U+1F4AB, Recommended Emoji ZWJ Sequence, v13.1) +Grapheme clusters: 1, codepoints: 3, UnicodeWidthStr::width() == 4 (Read NOTE: https://github.com/unicode-rs/unicode-width) + +😵‍💫 Apropriate world + ^^^^^^^^^^ highlight here + +--- +Horizontal tab (\t, U+09) +Grapheme clusters: 1, codepoints: 1, UnicodeWidthStr::width() == 0 + + Apropriate world +^^^^^^^^^^ highlight here \ No newline at end of file diff --git a/tests/cmd/stdin-failure-multiwidth.stdout b/tests/cmd/stdin-failure-multiwidth.stdout index 08fc6ec..e6cf44a 100644 --- a/tests/cmd/stdin-failure-multiwidth.stdout +++ b/tests/cmd/stdin-failure-multiwidth.stdout @@ -1,30 +1,30 @@ error: `Apropriate` should be `Appropriate` - --> -:1:2 + --> -:5:2 | -1 | 한 Apropriate world +5 | 한 Apropriate world | ^^^^^^^^^^ | error: `Apropriate` should be `Appropriate` - --> -:2:2 - | -2 | 한 Apropriate world - | ^^^^^^^^^^ - | + --> -:12:2 + | +12 | 한 Apropriate world + | ^^^^^^^^^^ + | error: `Apropriate` should be `Appropriate` - --> -:3:2 - | -3 | 😵‍💫 Apropriate world - | ^^^^^^^^^^ - | + --> -:19:2 + | +19 | 👁️‍🗨️ Apropriate world + | ^^^^^^^^^^ + | error: `Apropriate` should be `Appropriate` - --> -:4:2 - | -4 | 👁️‍🗨️ Apropriate world - | ^^^^^^^^^^ - | + --> -:26:2 + | +26 | 😵‍💫 Apropriate world + | ^^^^^^^^^^ + | error: `Apropriate` should be `Appropriate` - --> -:5:1 - | -5 | Apropriate world - | ^^^^^^^^^^ - | + --> -:33:1 + | +33 | Apropriate world + | ^^^^^^^^^^ + |