From 9859e6007715ac0ef9d7c1b970c3e2041b685120 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 27 May 2021 13:10:42 -0500 Subject: [PATCH] fix(cli): Don't panic when finding column When rendering typos, we look up what visual column the typoe starts on but I mixed a raw byte offset with the offset into a lossy string. This caused panics when dealing with non-ascii content. Fixes #258 --- CHANGELOG.md | 4 +++ src/bin/typos-cli/report.rs | 7 ++--- src/file.rs | 62 +++++++++++++++++++++++++++++++------ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d0ad28..aa210cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate +#### Bug Fixes + +- Don't panic when rendering typos on lines with non-ASCII character + ## [1.0.1] - 2021-05-27 #### Bug Fixes diff --git a/src/bin/typos-cli/report.rs b/src/bin/typos-cli/report.rs index 53b337b..82c1e67 100644 --- a/src/bin/typos-cli/report.rs +++ b/src/bin/typos-cli/report.rs @@ -190,11 +190,8 @@ fn print_long_correction(msg: &Typo, palette: Palette) -> Result<(), std::io::Er let line = String::from_utf8_lossy(msg.buffer.as_ref()); let line = line.replace("\t", " "); - let column = unicode_segmentation::UnicodeSegmentation::graphemes( - line.get(0..msg.byte_offset).unwrap(), - true, - ) - .count(); + let start = String::from_utf8_lossy(&msg.buffer[0..msg.byte_offset]); + let column = unicode_segmentation::UnicodeSegmentation::graphemes(start.as_ref(), true).count(); match &msg.corrections { typos::Status::Valid => {} typos::Status::Invalid => { diff --git a/src/file.rs b/src/file.rs index 306f11c..54157f9 100644 --- a/src/file.rs +++ b/src/file.rs @@ -702,36 +702,78 @@ mod test { #[test] fn test_extract_line_single_line() { - let (line, offset) = extract_line(b"hello world", 6); - assert_eq!(line, b"hello world"); + let buffer = b"hello world"; + let buffer_offset = 6; + let expected_line = b"hello world"; + let (line, offset) = extract_line(buffer, buffer_offset); + assert_eq!(line, expected_line); assert_eq!(offset, 6); + assert_eq!(line[offset], buffer[buffer_offset]); } #[test] fn test_extract_line_first() { - let (line, offset) = extract_line(b"1\n2\n3", 0); - assert_eq!(line, b"1"); + let buffer = b"1\n2\n3"; + let buffer_offset = 0; + let expected_line = b"1"; + let (line, offset) = extract_line(buffer, buffer_offset); + assert_eq!(line, expected_line); assert_eq!(offset, 0); + assert_eq!(line[offset], buffer[buffer_offset]); } #[test] fn test_extract_line_middle() { - let (line, offset) = extract_line(b"1\n2\n3", 2); - assert_eq!(line, b"2"); + let buffer = b"1\n2\n3"; + let buffer_offset = 2; + let expected_line = b"2"; + let (line, offset) = extract_line(buffer, buffer_offset); + assert_eq!(line, expected_line); assert_eq!(offset, 0); + assert_eq!(line[offset], buffer[buffer_offset]); } #[test] fn test_extract_line_end() { - let (line, offset) = extract_line(b"1\n2\n3", 4); - assert_eq!(line, b"3"); + let buffer = b"1\n2\n3"; + let buffer_offset = 4; + let expected_line = b"3"; + let (line, offset) = extract_line(buffer, buffer_offset); + assert_eq!(line, expected_line); assert_eq!(offset, 0); + assert_eq!(line[offset], buffer[buffer_offset]); } #[test] fn test_extract_line_offset_change() { - let (line, offset) = extract_line(b"1\nhello world\n2", 8); - assert_eq!(line, b"hello world"); + let buffer = b"1\nhello world\n2"; + let buffer_offset = 8; + let expected_line = b"hello world"; + let (line, offset) = extract_line(buffer, buffer_offset); + assert_eq!(line, expected_line); assert_eq!(offset, 6); + assert_eq!(line[offset], buffer[buffer_offset]); + } + + #[test] + fn test_extract_line_windows() { + let buffer = b"1\r\nhello world\r\n2"; + let buffer_offset = 9; + let expected_line = b"hello world"; + let (line, offset) = extract_line(buffer, buffer_offset); + assert_eq!(line, expected_line); + assert_eq!(offset, 6); + assert_eq!(line[offset], buffer[buffer_offset]); + } + + #[test] + fn test_extract_line_slovak() { + let buffer = b"LastErrorMessage=%1.%n%nChyba %2: %3\r\nSetupFileMissing=In\x9Atala\xE8n\xFD adres\xE1r neobsahuje s\xFAbor %1. Opravte, pros\xEDm, t\xFAto chybu alebo si zaobstarajte nov\xFA k\xF3piu tohto produktu.\r\nSetupFileCorrupt=S\xFAbory sprievodcu in\x9Atal\xE1ciou s\xFA po\x9Akoden\xE9. Zaobstarajte si, pros\xEDm, nov\xFA k\xF3piu tohto produktu."; + let buffer_offset = 66; + let expected_line = b"SetupFileMissing=In\x9Atala\xE8n\xFD adres\xE1r neobsahuje s\xFAbor %1. Opravte, pros\xEDm, t\xFAto chybu alebo si zaobstarajte nov\xFA k\xF3piu tohto produktu."; + let (line, offset) = extract_line(buffer, buffer_offset); + assert_eq!(line, expected_line); + assert_eq!(offset, 28); + assert_eq!(line[offset], buffer[buffer_offset]); } }