1pub mod history;
5
6use history::{Edit, EditKind, History};
7use ropey::Rope;
8
9pub struct Buffer {
11 pub rope: Rope,
12 pub path: Option<String>,
13 pub dirty: bool,
14 pub epoch: u64,
16 pub readonly: bool,
18 pub name: Option<String>,
21 pub history: History,
24 pub replaying: bool,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub struct Range {
31 pub start: usize,
32 pub end: usize,
33 pub linewise: bool,
36}
37
38impl Range {
39 pub fn charwise(start: usize, end: usize) -> Self {
40 debug_assert!(start <= end);
41 Self {
42 start,
43 end,
44 linewise: false,
45 }
46 }
47 pub fn linewise(start: usize, end: usize) -> Self {
48 debug_assert!(start <= end);
49 Self {
50 start,
51 end,
52 linewise: true,
53 }
54 }
55 pub fn len(&self) -> usize {
56 self.end - self.start
57 }
58 pub fn is_empty(&self) -> bool {
59 self.start == self.end
60 }
61}
62
63impl Buffer {
64 pub fn from_text(text: &str) -> Self {
65 Self {
66 rope: Rope::from_str(text),
67 path: None,
68 dirty: false,
69 epoch: 0,
70 readonly: false,
71 name: None,
72 history: History::default(),
73 replaying: false,
74 }
75 }
76
77 pub fn open(path: &str) -> std::io::Result<Self> {
80 let text = match std::fs::read_to_string(path) {
81 Ok(t) => t,
82 Err(e) if e.kind() == std::io::ErrorKind::NotFound => String::new(),
83 Err(e) => return Err(e),
84 };
85 Ok(Self {
86 rope: Rope::from_str(&text),
87 path: Some(path.to_string()),
88 dirty: false,
89 epoch: 0,
90 readonly: false,
91 name: None,
92 history: History::default(),
93 replaying: false,
94 })
95 }
96
97 pub fn save(&mut self) -> std::io::Result<()> {
98 if let Some(path) = &self.path {
99 std::fs::write(path, self.rope.to_string())?;
100 self.dirty = false;
101 }
102 Ok(())
103 }
104
105 pub fn len_bytes(&self) -> usize {
106 self.rope.len_bytes()
107 }
108 pub fn len_lines(&self) -> usize {
109 self.rope.len_lines()
110 }
111
112 pub fn last_content_line(&self) -> usize {
115 let mut l = self.len_lines().saturating_sub(1);
116 if self.len_bytes() > 0 && self.byte(self.len_bytes() - 1) == b'\n' && l > 0 {
117 l -= 1;
118 }
119 l
120 }
121
122 pub fn line_start(&self, line: usize) -> usize {
124 self.rope
125 .line_to_byte(line.min(self.len_lines().saturating_sub(1)))
126 }
127
128 pub fn line_end(&self, line: usize) -> usize {
130 let start = self.line_start(line);
131 let mut end = self.line_start((line + 1).min(self.len_lines().saturating_sub(1)));
132 if line + 1 >= self.len_lines() {
133 end = self.len_bytes();
134 }
135 if end > start && self.byte(end - 1) == b'\n' {
137 end -= 1;
138 }
139 end
140 }
141
142 pub fn line_of(&self, offset: usize) -> usize {
143 self.rope.byte_to_line(offset.min(self.len_bytes()))
144 }
145
146 pub fn col_of(&self, offset: usize) -> usize {
148 offset - self.line_start(self.line_of(offset))
149 }
150
151 pub fn byte(&self, offset: usize) -> u8 {
152 self.rope
153 .byte(offset.min(self.len_bytes().saturating_sub(1)))
154 }
155
156 pub fn byte_at(&self, offset: usize) -> Option<u8> {
157 if offset < self.len_bytes() {
158 Some(self.rope.byte(offset))
159 } else {
160 None
161 }
162 }
163
164 pub fn clamp_boundary(&self, mut offset: usize) -> usize {
167 offset = offset.min(self.len_bytes());
168 while offset > 0 && self.rope.try_byte_to_char(offset).is_err() {
169 offset -= 1;
170 }
171 offset
172 }
173
174 pub fn slice_string(&self, range: Range) -> String {
176 self.rope.byte_slice(range.start..range.end).to_string()
177 }
178
179 pub fn apply_history(&mut self, ops: Vec<Edit>) {
181 self.replaying = true;
182 for op in ops {
183 match op.kind {
184 EditKind::Insert => {
185 let at = self.clamp_boundary(op.at.min(self.len_bytes()));
186 self.rope.insert(self.rope.byte_to_char(at), &op.text);
187 }
188 EditKind::Delete => {
189 let end = self.clamp_boundary((op.at + op.text.len()).min(self.len_bytes()));
192 let start = self.clamp_boundary(op.at.min(end));
193 if start < end {
194 self.rope
195 .remove(self.rope.byte_to_char(start)..self.rope.byte_to_char(end));
196 }
197 }
198 }
199 }
200 self.replaying = false;
201 self.dirty = true;
202 self.epoch += 1;
203 }
204
205 pub fn replace_all(&mut self, text: &str) {
207 self.rope = Rope::from_str(text);
208 self.epoch += 1;
209 }
210
211 pub fn delete(&mut self, range: Range) -> String {
213 let start = self.clamp_boundary(range.start.min(self.len_bytes()));
215 let end = self.clamp_boundary(range.end.min(self.len_bytes()));
216 if start >= end {
217 return String::new();
218 }
219 let text = self.rope.byte_slice(start..end).to_string();
220 let cstart = self.rope.byte_to_char(start);
222 let cend = self.rope.byte_to_char(end);
223 self.rope.remove(cstart..cend);
224 self.dirty = true;
225 self.epoch += 1;
226 if !self.replaying && !self.readonly {
227 self.history.record(
228 Edit {
229 at: range.start,
230 text: text.clone(),
231 kind: EditKind::Insert,
232 },
233 Edit {
234 at: range.start,
235 text: text.clone(),
236 kind: EditKind::Delete,
237 },
238 );
239 }
240 text
241 }
242
243 pub fn insert(&mut self, at: usize, text: &str) {
244 let at = self.clamp_boundary(at);
245 self.rope.insert(self.rope.byte_to_char(at), text);
246 self.dirty = true;
247 self.epoch += 1;
248 if !self.replaying && !self.readonly {
249 self.history.record(
250 Edit {
251 at,
252 text: text.into(),
253 kind: EditKind::Delete,
254 },
255 Edit {
256 at,
257 text: text.into(),
258 kind: EditKind::Insert,
259 },
260 );
261 }
262 }
263
264 pub fn line_text(&self, line: usize) -> String {
265 let start = self.line_start(line);
266 let end = self.line_end(line);
267 self.rope.byte_slice(start..end).to_string()
268 }
269}