perl_source_editing/
lib.rs1#![deny(unsafe_code)]
7#![warn(rust_2018_idioms)]
8#![warn(missing_docs)]
9#![warn(clippy::all)]
10
11#[must_use]
13pub fn find_statement_start(source: &str, pos: usize) -> usize {
14 let search_pos = pos.min(source.len());
15 source[..search_pos]
16 .char_indices()
17 .rev()
18 .find_map(|(idx, ch)| ((ch == ';') || (ch == '\n')).then_some(idx + ch.len_utf8()))
19 .unwrap_or(0)
20}
21
22#[must_use]
24pub fn get_indent_at(source: &str, pos: usize) -> String {
25 let clamped_pos = pos.min(source.len());
26 let line_start = source[..clamped_pos].rfind('\n').map_or(0, |idx| idx + 1);
27
28 source[line_start..].chars().take_while(|ch| *ch == ' ' || *ch == '\t').collect()
29}
30
31#[must_use]
33pub fn find_pragma_insert_position(source: &str) -> usize {
34 if source.starts_with("#!") { source.find('\n').map_or(source.len(), |idx| idx + 1) } else { 0 }
35}
36
37#[must_use]
39pub fn find_import_insert_position(source: &str, lines: &[String]) -> usize {
40 let mut pos = find_pragma_insert_position(source);
41
42 for line in lines {
43 if line.starts_with("use ") || line.starts_with("require ") {
44 if let Some(idx) = source.find(line) {
45 pos = idx + line.len() + 1;
46 }
47 } else if !line.is_empty() && !line.starts_with('#') {
48 break;
49 }
50 }
51
52 pos
53}
54
55#[must_use]
59pub fn truncate_expr(expr: &str, max_len: usize) -> String {
60 let expr_len = expr.chars().count();
61 if expr_len <= max_len {
62 return expr.to_string();
63 }
64
65 if max_len <= 3 {
66 return "...".chars().take(max_len).collect();
67 }
68
69 let prefix: String = expr.chars().take(max_len - 3).collect();
70 format!("{prefix}...")
71}
72
73#[must_use]
75pub fn has_non_ascii_content(source: &str) -> bool {
76 !source.is_ascii()
77}