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
This commit is contained in:
Ed Page 2021-05-27 13:10:42 -05:00
parent b4e198a280
commit 9859e60077
3 changed files with 58 additions and 15 deletions

View file

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
<!-- next-header --> <!-- next-header -->
## [Unreleased] - ReleaseDate ## [Unreleased] - ReleaseDate
#### Bug Fixes
- Don't panic when rendering typos on lines with non-ASCII character
## [1.0.1] - 2021-05-27 ## [1.0.1] - 2021-05-27
#### Bug Fixes #### Bug Fixes

View file

@ -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 = String::from_utf8_lossy(msg.buffer.as_ref());
let line = line.replace("\t", " "); let line = line.replace("\t", " ");
let column = unicode_segmentation::UnicodeSegmentation::graphemes( let start = String::from_utf8_lossy(&msg.buffer[0..msg.byte_offset]);
line.get(0..msg.byte_offset).unwrap(), let column = unicode_segmentation::UnicodeSegmentation::graphemes(start.as_ref(), true).count();
true,
)
.count();
match &msg.corrections { match &msg.corrections {
typos::Status::Valid => {} typos::Status::Valid => {}
typos::Status::Invalid => { typos::Status::Invalid => {

View file

@ -702,36 +702,78 @@ mod test {
#[test] #[test]
fn test_extract_line_single_line() { fn test_extract_line_single_line() {
let (line, offset) = extract_line(b"hello world", 6); let buffer = b"hello world";
assert_eq!(line, 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!(offset, 6);
assert_eq!(line[offset], buffer[buffer_offset]);
} }
#[test] #[test]
fn test_extract_line_first() { fn test_extract_line_first() {
let (line, offset) = extract_line(b"1\n2\n3", 0); let buffer = b"1\n2\n3";
assert_eq!(line, b"1"); 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!(offset, 0);
assert_eq!(line[offset], buffer[buffer_offset]);
} }
#[test] #[test]
fn test_extract_line_middle() { fn test_extract_line_middle() {
let (line, offset) = extract_line(b"1\n2\n3", 2); let buffer = b"1\n2\n3";
assert_eq!(line, b"2"); 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!(offset, 0);
assert_eq!(line[offset], buffer[buffer_offset]);
} }
#[test] #[test]
fn test_extract_line_end() { fn test_extract_line_end() {
let (line, offset) = extract_line(b"1\n2\n3", 4); let buffer = b"1\n2\n3";
assert_eq!(line, b"3"); 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!(offset, 0);
assert_eq!(line[offset], buffer[buffer_offset]);
} }
#[test] #[test]
fn test_extract_line_offset_change() { fn test_extract_line_offset_change() {
let (line, offset) = extract_line(b"1\nhello world\n2", 8); let buffer = b"1\nhello world\n2";
assert_eq!(line, b"hello world"); 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!(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]);
} }
} }