5036ec2dbb
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
72 lines
2.0 KiB
Rust
72 lines
2.0 KiB
Rust
//! Cursor position and document statistics — pure helpers over the text.
|
|
|
|
/// (line, column) of `cursor` (byte offset), both 0-based; column counts
|
|
/// characters of the line, not bytes.
|
|
#[must_use]
|
|
pub fn line_col(text: &str, cursor: usize) -> (usize, usize) {
|
|
let floored = if text.is_char_boundary(cursor) {
|
|
usize::min(cursor, text.len())
|
|
} else {
|
|
let mut p = cursor;
|
|
while p > 0 && !text.is_char_boundary(p) {
|
|
p -= 1;
|
|
}
|
|
p
|
|
};
|
|
let before = text.get(..floored).unwrap_or("");
|
|
let line = before.matches('\n').count();
|
|
let col = before.chars().rev().take_while(|c| *c != '\n').count();
|
|
(line, col)
|
|
}
|
|
|
|
/// Words in the text: runs of characters that are alphanumeric or `_`.
|
|
#[must_use]
|
|
pub fn word_count(text: &str) -> usize {
|
|
let mut count = 0usize;
|
|
let mut in_word = false;
|
|
for c in text.chars() {
|
|
if c.is_alphanumeric() || c == '_' {
|
|
if !in_word {
|
|
count += 1;
|
|
}
|
|
in_word = true;
|
|
} else {
|
|
in_word = false;
|
|
}
|
|
}
|
|
count
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn line_col_counts_chars() {
|
|
let text = "ab é\nxyz";
|
|
let byte_x = text.find('x').unwrap_or(0);
|
|
assert_eq!(line_col(text, byte_x), (1, 0));
|
|
assert_eq!(line_col(text, 0), (0, 0));
|
|
let end = text.len();
|
|
assert_eq!(line_col(text, end), (1, 3));
|
|
}
|
|
|
|
#[test]
|
|
fn line_col_at_char_start() {
|
|
let mut text = String::from("éx");
|
|
let byte_after_e = text.find('x').unwrap_or(0);
|
|
assert_eq!(line_col(&text, byte_after_e), (0, 1));
|
|
text.push_str("\nq");
|
|
let byte_q = text.find('q').unwrap_or(0);
|
|
assert_eq!(line_col(&text, byte_q), (1, 0));
|
|
}
|
|
|
|
#[test]
|
|
fn word_count_runs() {
|
|
assert_eq!(word_count(""), 0);
|
|
assert_eq!(word_count("hello world"), 2);
|
|
assert_eq!(word_count("éx_ one-two #tag"), 4);
|
|
assert_eq!(word_count("...,,, "), 0);
|
|
}
|
|
}
|