nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: martinohmann/hcl-rs
Pull request #353 (2024-05-24 19:00:15)

fix(parser): calculate correct error column in presence of unicode


Patch:
diff --git a/crates/hcl-edit/src/parser/error.rs b/crates/hcl-edit/src/parser/error.rs
index 82e1463..d3a2bea 100644
--- a/crates/hcl-edit/src/parser/error.rs
+++ b/crates/hcl-edit/src/parser/error.rs
@@ -115,21 +115,20 @@ impl Location {
         self.offset
     }
 }
+
 fn locate_error<'a>(err: &'a ParseError<Input<'a>, ContextError>) -> (&'a [u8], Location) {
-    let offset = err.offset();
     let input = err.input().as_bytes();
-    let remaining_input = &input[offset..];
-    let consumed_input = &input[..offset];
+    let offset = err.offset().min(input.len() - 1);
+    let column_offset = err.offset() - offset;
 
-    // Find the line that includes the subslice:
-    // Find the *last* newline before the remaining input starts
-    let line_begin = consumed_input
+    // Find the start of the line containing the error.
+    let line_begin = input[..offset]
         .iter()
         .rev()
         .position(|&b| b == b'\n')
         .map_or(0, |pos| offset - pos);
 
-    // Find the full line after that newline
+    // Use the full line containing the error as context for later printing.
     let line_context = input[line_begin..]
         .iter()
         .position(|&b| b == b'\n')
@@ -137,11 +136,16 @@ fn locate_error<'a>(err: &'a ParseError<Input<'a>, ContextError>) -> (&'a [u8],
             &input[line_begin..line_begin + pos]
         });
 
-    // Count the number of newlines in the first `offset` bytes of input
-    let line = consumed_input.iter().filter(|&&b| b == b'\n').count() + 1;
+    // Count the number of newlines in the input before the line containing the error to calculate
+    // the line number.
+    let line = input[..line_begin].iter().filter(|&&b| b == b'\n').count() + 1;
 
     // The (1-indexed) column number is the offset of the remaining input into that line.
-    let column = remaining_input.offset_from(&line_context) + 1;
+    // This also takes multi-byte unicode characters into account.
+    let column = std::str::from_utf8(&input[line_begin..=offset])
+        .map(|s| s.chars().count())
+        .unwrap_or_else(|_| offset - line_begin + 1)
+        + column_offset;
 
     (
         line_context,


Test patch:
diff --git a/crates/hcl-edit/tests/parse.rs b/crates/hcl-edit/tests/parse.rs
index fe4f300..2064b69 100644
--- a/crates/hcl-edit/tests/parse.rs
+++ b/crates/hcl-edit/tests/parse.rs
@@ -150,4 +150,15 @@ fn invalid_exprs() {
               |
               = expected `)` or expression"#}
     );
+
+    assert_error!(
+        "unicodé_ident = '4",
+        indoc! {r#"
+             --> HCL parse error in line 1, column 17
+              |
+            1 | unicodé_ident = '4
+              |                 ^---
+              |
+              = invalid expression; expected `"`, `[`, `{`, `-`, `!`, `(`, `_`, `<`, letter or digit"#}
+    );
 }