teehee/
buffer.rs

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}