ass_editor/core/fluent/
selection.rs1use crate::core::{EditorDocument, Range, Result};
4
5#[cfg(feature = "rope")]
6use crate::core::Position;
7
8#[cfg(not(feature = "std"))]
9use alloc::string::{String, ToString};
10
11#[cfg(all(not(feature = "std"), feature = "rope"))]
12use alloc::vec::Vec;
13
14pub struct SelectRange<'a> {
16 document: &'a mut EditorDocument,
17 range: Range,
18}
19
20impl<'a> SelectRange<'a> {
21 pub(crate) fn new(document: &'a mut EditorDocument, range: Range) -> Self {
23 Self { document, range }
24 }
25
26 pub fn replace_with(self, text: &str) -> Result<&'a mut EditorDocument> {
28 self.document.replace(self.range, text)?;
29 Ok(self.document)
30 }
31
32 pub fn delete(self) -> Result<&'a mut EditorDocument> {
34 self.document.delete(self.range)?;
35 Ok(self.document)
36 }
37
38 pub fn wrap_with_tag(self, open_tag: &str, close_tag: &str) -> Result<&'a mut EditorDocument> {
40 let selected = self
42 .document
43 .rope()
44 .byte_slice(self.range.start.offset..self.range.end.offset);
45 let mut wrapped =
46 String::with_capacity(open_tag.len() + selected.len_bytes() + close_tag.len());
47 wrapped.push_str(open_tag);
48 wrapped.push_str(&selected.to_string());
49 wrapped.push_str(close_tag);
50
51 self.document.replace(self.range, &wrapped)?;
52 Ok(self.document)
53 }
54
55 #[cfg(feature = "rope")]
57 pub fn indent(self, spaces: usize) -> Result<&'a mut EditorDocument> {
58 let start_line = self.document.rope().byte_to_line(self.range.start.offset);
60 let end_line = self.document.rope().byte_to_line(self.range.end.offset);
61 let indent = " ".repeat(spaces);
62
63 let mut line_positions = Vec::new();
65 for line_idx in (start_line..=end_line).rev() {
66 let line_start = self.document.rope().line_to_byte(line_idx);
67 line_positions.push(line_start);
68 }
69
70 for line_start in line_positions {
72 let pos = Position::new(line_start);
73 let range = Range::empty(pos);
74 self.document.replace(range, &indent)?;
75 }
76
77 Ok(self.document)
78 }
79
80 #[cfg(feature = "rope")]
82 pub fn unindent(self, spaces: usize) -> Result<&'a mut EditorDocument> {
83 let start_line = self.document.rope().byte_to_line(self.range.start.offset);
85 let end_line = self.document.rope().byte_to_line(self.range.end.offset);
86
87 let mut unindent_ops = Vec::new();
89 for line_idx in (start_line..=end_line).rev() {
90 let line_start = self.document.rope().line_to_byte(line_idx);
91 let line = self.document.rope().line(line_idx);
92
93 let mut space_count = 0;
95 for ch in line.chars().take(spaces) {
96 if ch == ' ' {
97 space_count += 1;
98 } else {
99 break;
100 }
101 }
102
103 if space_count > 0 {
104 unindent_ops.push((line_start, space_count));
105 }
106 }
107
108 for (line_start, space_count) in unindent_ops {
110 let range = Range::new(
111 Position::new(line_start),
112 Position::new(line_start + space_count),
113 );
114 self.document.delete(range)?;
115 }
116
117 Ok(self.document)
118 }
119
120 pub fn text(&self) -> String {
122 self.document
123 .rope()
124 .byte_slice(self.range.start.offset..self.range.end.offset)
125 .to_string()
126 }
127
128 pub const fn range(&self) -> Range {
130 self.range
131 }
132}