ass_editor/core/fluent/
position.rs1use crate::core::{EditorDocument, Position, Range, Result};
4
5#[cfg(not(feature = "rope"))]
6use crate::core::errors::EditorError;
7
8#[cfg(all(not(feature = "std"), not(feature = "rope")))]
9use alloc::string::ToString;
10
11pub struct AtPosition<'a> {
13 document: &'a mut EditorDocument,
14 position: Position,
15}
16
17impl<'a> AtPosition<'a> {
18 pub(crate) fn new(document: &'a mut EditorDocument, position: Position) -> Self {
20 Self { document, position }
21 }
22
23 pub fn insert_text(self, text: &str) -> Result<&'a mut EditorDocument> {
25 let range = Range::empty(self.position);
26 self.document.replace(range, text)?;
27 Ok(self.document)
28 }
29
30 pub fn insert_line(self) -> Result<&'a mut EditorDocument> {
32 self.insert_text("\n")
33 }
34
35 pub fn delete(self, count: usize) -> Result<&'a mut EditorDocument> {
37 let end = self.position.advance(count);
38 let range = Range::new(self.position, end);
39 self.document.delete(range)?;
40 Ok(self.document)
41 }
42
43 pub fn backspace(self, count: usize) -> Result<&'a mut EditorDocument> {
45 let start = self.position.retreat(count);
46 let range = Range::new(start, self.position);
47 self.document.delete(range)?;
48 Ok(self.document)
49 }
50
51 pub fn replace_to_line_end(self, text: &str) -> Result<&'a mut EditorDocument> {
53 #[cfg(feature = "rope")]
54 {
55 let rope = self.document.rope();
56 let line_idx = rope.byte_to_line(self.position.offset);
57 let line_end_byte = if line_idx + 1 < rope.len_lines() {
58 rope.line_to_byte(line_idx + 1).saturating_sub(1)
59 } else {
60 rope.len_bytes()
61 };
62 let range = Range::new(self.position, Position::new(line_end_byte));
63 self.document.replace(range, text)?;
64 Ok(self.document)
65 }
66
67 #[cfg(not(feature = "rope"))]
68 {
69 Err(EditorError::FeatureNotEnabled {
70 feature: "line-based operations".to_string(),
71 required_feature: "rope".to_string(),
72 })
73 }
74 }
75
76 pub const fn position(&self) -> Position {
78 self.position
79 }
80
81 #[cfg(feature = "rope")]
83 pub fn to_line_column(&self) -> Result<(usize, usize)> {
84 let rope = self.document.rope();
85 let line_idx = rope.byte_to_line(self.position.offset);
86 let line_start = rope.line_to_byte(line_idx);
87 let col_offset = self.position.offset - line_start;
88
89 let line = rope.line(line_idx);
91 let mut char_col = 0;
92 let mut byte_count = 0;
93
94 for ch in line.chars() {
95 if byte_count >= col_offset {
96 break;
97 }
98 byte_count += ch.len_utf8();
99 char_col += 1;
100 }
101
102 Ok((line_idx + 1, char_col + 1)) }
104}