diff --git a/crates/ruff/tests/format.rs b/crates/ruff/tests/format.rs index f4c7269b05..a70142da54 100644 --- a/crates/ruff/tests/format.rs +++ b/crates/ruff/tests/format.rs @@ -1945,11 +1945,10 @@ fn range_end_only() { def foo(arg1, arg2,): print("Should format this" ) -"#), @r###" +"#), @r#" success: true exit_code: 0 ----- stdout ----- - def foo( arg1, arg2, @@ -1958,7 +1957,7 @@ def foo(arg1, arg2,): ----- stderr ----- - "###); + "#); } #[test] diff --git a/crates/ruff_source_file/src/line_index.rs b/crates/ruff_source_file/src/line_index.rs index db4fc44211..a66d6b2f99 100644 --- a/crates/ruff_source_file/src/line_index.rs +++ b/crates/ruff_source_file/src/line_index.rs @@ -222,6 +222,57 @@ impl LineIndex { } /// Returns the [byte offset](TextSize) at `line` and `column`. + /// + /// ## Examples + /// + /// ### ASCII + /// + /// ``` + /// use ruff_source_file::{LineIndex, OneIndexed}; + /// use ruff_text_size::TextSize; + /// let source = r#"a = 4 + /// c = "some string" + /// x = b"#; + /// + /// let index = LineIndex::from_source_text(source); + /// + /// // First line, first column + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(0), OneIndexed::from_zero_indexed(0), source), TextSize::new(0)); + /// + /// // Second line, 4th column + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(1), OneIndexed::from_zero_indexed(4), source), TextSize::new(10)); + /// + /// // Offset past the end of the first line + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(0), OneIndexed::from_zero_indexed(10), source), TextSize::new(6)); + /// + /// // Offset past the end of the file + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(3), OneIndexed::from_zero_indexed(0), source), TextSize::new(29)); + /// ``` + /// + /// ### UTF8 + /// + /// ``` + /// use ruff_source_file::{LineIndex, OneIndexed}; + /// use ruff_text_size::TextSize; + /// let source = r#"a = 4 + /// c = "❤️" + /// x = b"#; + /// + /// let index = LineIndex::from_source_text(source); + /// + /// // First line, first column + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(0), OneIndexed::from_zero_indexed(0), source), TextSize::new(0)); + /// + /// // Third line, 2nd column, after emoji + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(2), OneIndexed::from_zero_indexed(1), source), TextSize::new(20)); + /// + /// // Offset past the end of the second line + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(1), OneIndexed::from_zero_indexed(10), source), TextSize::new(19)); + /// + /// // Offset past the end of the file + /// assert_eq!(index.offset(OneIndexed::from_zero_indexed(3), OneIndexed::from_zero_indexed(0), source), TextSize::new(24)); + /// ``` + /// pub fn offset(&self, line: OneIndexed, column: OneIndexed, contents: &str) -> TextSize { // If start-of-line position after last line if line.to_zero_indexed() > self.line_starts().len() { @@ -233,7 +284,7 @@ impl LineIndex { match self.kind() { IndexKind::Ascii => { line_range.start() - + TextSize::try_from(column.get()) + + TextSize::try_from(column.to_zero_indexed()) .unwrap_or(line_range.len()) .clamp(TextSize::new(0), line_range.len()) } @@ -241,7 +292,7 @@ impl LineIndex { let rest = &contents[line_range]; let column_offset: TextSize = rest .chars() - .take(column.get()) + .take(column.to_zero_indexed()) .map(ruff_text_size::TextLen::text_len) .sum(); line_range.start() + column_offset