1use xi_rope::Interval;
2
3use std::collections::HashMap;
4use std::path::{Path, PathBuf};
5
6use super::byte_rope::*;
7use super::history::History;
8use crate::modes::mode::DirtyBytes;
9use crate::selection::{SelRegion, Selection};
10
11#[derive(Debug, PartialEq, Clone, Copy, Eq, Hash)]
12pub enum OverflowSelectionStyle {
13 Cursor,
14 Tail,
15 CursorTail,
16}
17
18#[derive(Default)]
19pub struct Buffer {
20 pub path: Option<PathBuf>,
21 pub data: Rope,
22 pub selection: Selection,
23 pub registers: HashMap<char, Vec<Vec<u8>>>,
24 pub dirty: bool,
25
26 history: History,
27}
28
29impl Buffer {
30 pub fn from_data_and_path(data: Vec<u8>, path: Option<impl Into<PathBuf>>) -> Buffer {
31 Buffer {
32 data: data.into(),
33 selection: Selection::new(),
34 registers: HashMap::new(),
35 dirty: false,
36 path: path.map(Into::into),
37 history: History::new(),
38 }
39 }
40
41 pub fn name(&self) -> String {
42 if let Some(path) = &self.path {
43 format!("{}", path.display())
44 } else {
45 "*scratch*".to_string()
46 }
47 }
48
49 pub fn map_selections(&mut self, mut f: impl FnMut(SelRegion) -> Vec<SelRegion>) -> DirtyBytes {
50 let mut invalidated_ranges = Vec::new();
51 self.selection.map_selections(|region| {
52 invalidated_ranges.push(Interval::from(region.min()..=region.max()));
53 let new = f(region);
54 for new_reg in new.iter() {
55 invalidated_ranges.push(Interval::from(new_reg.min()..=new_reg.max()));
56 }
57 new
58 });
59 invalidated_ranges.sort_by(|a, b| a.start.cmp(&b.start));
60
61 let mut disjoint_invalidated_ranges = Vec::new();
62 for r in invalidated_ranges {
63 if disjoint_invalidated_ranges.is_empty() {
64 disjoint_invalidated_ranges.push(r);
65 continue;
66 }
67 let last = disjoint_invalidated_ranges.last().unwrap();
68 if last.contains(r.start) {
69 *disjoint_invalidated_ranges.last_mut().unwrap() = last.union(r);
70 continue;
71 }
72 disjoint_invalidated_ranges.push(r);
73 }
74 DirtyBytes::ChangeInPlace(disjoint_invalidated_ranges)
75 }
76
77 fn apply_delta_to_buffer(&mut self, delta: RopeDelta, is_final: bool) {
78 let next_data = self.data.apply_delta(&delta);
79 if is_final {
80 self.history
81 .perform_final(&self.data, delta, self.selection.clone());
82 } else {
83 self.history
84 .perform_partial(&self.data, delta, &self.selection);
85 }
86 self.data = next_data;
87 self.dirty = true;
88 }
89
90 pub fn apply_delta(&mut self, delta: RopeDelta) -> DirtyBytes {
91 let max_len = self.data.len();
92 self.apply_delta_to_buffer(delta.clone(), true);
93 self.selection.apply_delta(&delta, max_len);
94
95 DirtyBytes::ChangeLength
96 }
97
98 pub fn apply_delta_offset_carets(
99 &mut self,
100 delta: RopeDelta,
101 caret_offset: isize,
102 tail_offset: isize,
103 ) -> DirtyBytes {
104 let max_len = self.data.len();
105 self.apply_delta_to_buffer(delta.clone(), true);
106 self.selection
107 .apply_delta_offset_carets(&delta, caret_offset, tail_offset, max_len);
108
109 DirtyBytes::ChangeLength
110 }
111
112 pub fn apply_incomplete_delta(&mut self, delta: RopeDelta) -> DirtyBytes {
113 let max_len = self.data.len();
114 self.apply_delta_to_buffer(delta.clone(), false);
115 self.selection.apply_delta(&delta, max_len);
116
117 DirtyBytes::ChangeLength
118 }
119
120 pub fn apply_incomplete_delta_offset_carets(
121 &mut self,
122 delta: RopeDelta,
123 caret_offset: isize,
124 tail_offset: isize,
125 ) -> DirtyBytes {
126 let max_len = self.data.len();
127 self.apply_delta_to_buffer(delta.clone(), false);
128 self.selection
129 .apply_delta_offset_carets(&delta, caret_offset, tail_offset, max_len);
130
131 DirtyBytes::ChangeLength
132 }
133
134 pub fn commit_delta(&mut self) {
135 self.history.commit_partial();
136 }
137
138 pub fn perform_undo(&mut self) -> Option<DirtyBytes> {
139 if let Some((undo_delta, old_selection)) =
140 self.history.undo(&self.data, self.selection.clone())
141 {
142 self.selection = old_selection;
143 self.data = self.data.apply_delta(&undo_delta);
144 self.dirty = true;
145 Some(DirtyBytes::ChangeLength)
146 } else {
147 None
148 }
149 }
150
151 pub fn perform_redo(&mut self) -> Option<DirtyBytes> {
152 if let Some((redo_delta, old_selection)) =
153 self.history.redo(&self.data, self.selection.clone())
154 {
155 self.selection = old_selection;
156 self.data = self.data.apply_delta(&redo_delta);
157 self.dirty = true;
158 Some(DirtyBytes::ChangeLength)
159 } else {
160 None
161 }
162 }
163
164 fn switch_main_sel(&mut self, f: impl FnOnce(&mut Selection)) -> DirtyBytes {
165 let old_main_sel_interval = self.selection.main().into();
166 f(&mut self.selection);
167 let new_main_sel_interval = self.selection.main().into();
168 DirtyBytes::ChangeInPlace(vec![old_main_sel_interval, new_main_sel_interval])
169 }
170
171 fn modify_sels_in_place(&mut self, f: impl FnOnce(&mut Selection)) -> DirtyBytes {
172 let dirty =
173 DirtyBytes::ChangeInPlace(self.selection.iter().copied().map(Into::into).collect());
174 f(&mut self.selection);
175
176 dirty
177 }
178
179 pub fn remove_selection(&mut self, index: usize) -> DirtyBytes {
180 self.modify_sels_in_place(|sel| sel.remove(index % sel.len()))
181 }
182 pub fn retain_selection(&mut self, index: usize) -> DirtyBytes {
183 self.modify_sels_in_place(|sel| sel.retain(index % sel.len()))
184 }
185 pub fn select_next(&mut self, count: usize) -> DirtyBytes {
186 self.switch_main_sel(|sel| sel.select_next(count))
187 }
188 pub fn select_prev(&mut self, count: usize) -> DirtyBytes {
189 self.switch_main_sel(|sel| sel.select_prev(count))
190 }
191
192 pub fn yank_selections(&mut self, reg: char) {
193 if self.data.is_empty() {
194 self.registers
195 .insert(reg, vec![vec![]; self.selection.len()]);
196 return;
197 }
198
199 let selections = self
200 .selection
201 .iter()
202 .map(|region| self.data.slice_to_cow(region.min()..=region.max()).to_vec())
203 .collect();
204 self.registers.insert(reg, selections);
205 }
206
207 pub fn overflow_sel_style(&self) -> Option<OverflowSelectionStyle> {
208 let last_sel = self.selection.iter().last().unwrap();
209 let len = self.data.len();
210 if last_sel.caret == len && last_sel.tail == len {
211 Some(OverflowSelectionStyle::CursorTail)
212 } else if last_sel.caret == len {
213 Some(OverflowSelectionStyle::Cursor)
214 } else if last_sel.tail == len {
215 Some(OverflowSelectionStyle::Tail)
216 } else {
217 None
218 }
219 }
220
221 pub fn update_path_if_missing(&mut self, path: impl Into<PathBuf>) {
222 if self.path.is_none() {
223 self.path = Some(path.into());
224 }
225 }
226}
227
228pub struct Buffers {
229 list: Vec<Buffer>,
230 cur_buf_index: usize,
231}
232
233impl Default for Buffers {
234 fn default() -> Self {
235 Self::new()
236 }
237}
238
239impl Buffers {
240 pub fn new() -> Buffers {
241 Buffers::with_buffer(Buffer::default())
242 }
243
244 pub fn with_buffer(buf: Buffer) -> Buffers {
245 Buffers {
246 cur_buf_index: 0,
247 list: vec![buf],
248 }
249 }
250
251 pub fn current(&self) -> &Buffer {
252 &self.list[self.cur_buf_index]
253 }
254 pub fn current_mut(&mut self) -> &mut Buffer {
255 &mut self.list[self.cur_buf_index]
256 }
257
258 pub fn iter(&self) -> impl Iterator<Item = &Buffer> {
259 self.list.iter()
260 }
261 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Buffer> {
262 self.list.iter_mut()
263 }
264
265 pub fn switch_buffer(&mut self, filename: impl AsRef<Path>) -> Result<(), std::io::Error> {
266 let canon = filename.as_ref().canonicalize()?;
267 for (i, buf) in self.list.iter().enumerate() {
268 if let Some(path) = &buf.path {
269 if path.canonicalize()? == canon {
270 self.cur_buf_index = i;
271 return Ok(());
272 }
273 }
274 }
275
276 self.list.push(Buffer::from_data_and_path(
277 std::fs::read(&filename)?,
278 Some(filename.as_ref().to_owned()),
279 ));
280 self.cur_buf_index = self.list.len() - 1;
281 Ok(())
282 }
283
284 pub fn delete_current(&mut self) {
285 self.list.remove(self.cur_buf_index);
286 self.cur_buf_index = self.cur_buf_index.saturating_sub(1);
287 if self.list.is_empty() {
288 self.list.push(Buffer::default());
289 }
290 }
291}