redox_core/buffer/text_buffer/
selection.rs1use crate::buffer::{Pos, Selection, TextBuffer};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct VisualSelectionEditPlan {
13 pub delete_start: Pos,
14 pub delete_end: Pos,
15 pub text: String,
16 pub line_mode: bool,
17}
18
19impl TextBuffer {
20 pub fn line_span_char_range(
24 &self,
25 start_line: usize,
26 end_line_inclusive: usize,
27 ) -> std::ops::Range<usize> {
28 let start_line = self.clamp_line(start_line);
29 let end_line = self.clamp_line(end_line_inclusive.max(start_line));
30 let start = self.line_to_char(start_line);
31 let end = self.line_full_end_char(end_line);
32 start..end
33 }
34
35 pub fn line_span_pos_range(&self, start_line: usize, end_line_inclusive: usize) -> (Pos, Pos) {
37 let range = self.line_span_char_range(start_line, end_line_inclusive);
38 (self.char_to_pos(range.start), self.char_to_pos(range.end))
39 }
40
41 pub fn line_span_text(&self, start_line: usize, end_line_inclusive: usize) -> String {
45 let range = self.line_span_char_range(start_line, end_line_inclusive);
46 self.slice_chars(range.start, range.end)
47 }
48
49 pub fn line_span_text_linewise_register(
53 &self,
54 start_line: usize,
55 end_line_inclusive: usize,
56 ) -> String {
57 let mut text = self.line_span_text(start_line, end_line_inclusive);
58 if !text.ends_with('\n') {
59 text.push('\n');
60 }
61 text
62 }
63
64 pub fn visual_charwise_pos_range(&self, selection: Selection) -> (Pos, Pos) {
68 let (start, end_inclusive) = selection.ordered();
69 let end_char = self.pos_to_char(end_inclusive);
70 let end_exclusive = if end_char < self.len_chars() {
71 self.char_to_pos(end_char + 1)
72 } else {
73 end_inclusive
74 };
75 (start, end_exclusive)
76 }
77
78 pub fn visual_linewise_pos_range(&self, selection: Selection) -> (Pos, Pos) {
80 let (start, end_inclusive) = selection.ordered();
81 self.line_span_pos_range(start.line, end_inclusive.line)
82 }
83
84 pub fn visual_charwise_text(&self, selection: Selection) -> String {
86 let (start, end_exclusive) = self.visual_charwise_pos_range(selection);
87 self.slice_pos_range(start, end_exclusive)
88 }
89
90 pub fn visual_linewise_text(&self, selection: Selection) -> String {
92 let (start, end) = selection.ordered();
93 self.line_span_text_linewise_register(start.line, end.line)
94 }
95
96 pub fn visual_selection_pos_range(&self, selection: Selection, line_mode: bool) -> (Pos, Pos) {
98 if line_mode {
99 self.visual_linewise_pos_range(selection)
100 } else {
101 self.visual_charwise_pos_range(selection)
102 }
103 }
104
105 pub fn visual_selection_text(&self, selection: Selection, line_mode: bool) -> String {
107 if line_mode {
108 self.visual_linewise_text(selection)
109 } else {
110 self.visual_charwise_text(selection)
111 }
112 }
113
114 pub fn visual_selection_edit_plan(
116 &self,
117 selection: Selection,
118 line_mode: bool,
119 ) -> VisualSelectionEditPlan {
120 let (delete_start, delete_end) = self.visual_selection_pos_range(selection, line_mode);
121 let text = self.visual_selection_text(selection, line_mode);
122 VisualSelectionEditPlan {
123 delete_start,
124 delete_end,
125 text,
126 line_mode,
127 }
128 }
129
130 pub fn visual_selection_char_range_on_line(
135 &self,
136 selection: Selection,
137 line_mode: bool,
138 line_idx: usize,
139 ) -> Option<std::ops::Range<usize>> {
140 let line_len = self.line_len_chars(line_idx);
141 if line_mode {
142 let (start_line, end_line) = selection.line_range();
143 if line_idx < start_line || line_idx > end_line {
144 return None;
145 }
146 return Some(0..line_len);
147 }
148
149 let (start, end) = selection.ordered();
150 if line_idx < start.line || line_idx > end.line {
151 return None;
152 }
153 if line_len == 0 {
154 return None;
155 }
156
157 let max_char = line_len.saturating_sub(1);
158 let sel_start = if line_idx == start.line {
159 start.col.min(max_char)
160 } else {
161 0
162 };
163 let sel_end_inclusive = if line_idx == end.line {
164 end.col.min(max_char)
165 } else {
166 max_char
167 };
168 if sel_start > sel_end_inclusive {
169 return None;
170 }
171
172 Some(sel_start..sel_end_inclusive.saturating_add(1))
173 }
174}