1use makepad_render::*;
2
3use crate::textbuffer::*;
4
5#[derive(Clone, Debug, PartialEq)]
6pub struct TextCursor {
7 pub head: usize,
8 pub tail: usize,
9 pub max: usize
10}
11
12impl TextCursor {
13 pub fn has_selection(&self) -> bool {
14 self.head != self.tail
15 }
16
17 pub fn order(&self) -> (usize, usize) {
18 if self.head > self.tail {
19 (self.tail, self.head)
20 }
21 else {
22 (self.head, self.tail)
23 }
24 }
25
26 pub fn clamp_range(&mut self, range: &Option<(usize, usize)>) {
27 if let Some((off, len)) = range {
28 if self.head >= self.tail {
29 if self.head < off + len {self.head = off + len}
30 if self.tail > *off {self.tail = *off}
31 }
32 else {
33 if self.tail < off + len {self.tail = off + len}
34 if self.head > *off {self.head = *off}
35 }
36 }
37 }
38
39
40 pub fn delta(&self, delta: isize) -> (usize, usize) {
41 let (start, end) = self.order();
42 (((start as isize) + delta) as usize, ((end as isize) + delta) as usize)
43 }
44
45 pub fn collapse(&mut self, start: usize, end: usize, new_len: usize) -> isize {
46 self.head = start + new_len;
47 self.tail = self.head;
48 ((new_len as isize) - (end - start) as isize)
49 }
50
51
52 pub fn calc_max(&mut self, text_buffer: &TextBuffer, old: (TextPos, usize)) -> (TextPos, usize) {
53 let pos = text_buffer.offset_to_text_pos_next(self.head, old.0, old.1);
54 self.max = pos.col;
55 return (pos, self.head)
56 }
57
58 pub fn move_home(&mut self, text_buffer: &TextBuffer) {
59 let pos = text_buffer.offset_to_text_pos(self.head);
60
61 for (index, ch) in text_buffer.lines[pos.row].iter().enumerate() {
63 if *ch != '\t' && *ch != ' ' {
64 self.head = text_buffer.text_pos_to_offset(TextPos {row: pos.row, col: index});
65 return
66 }
67 }
68 }
69
70 pub fn move_end(&mut self, text_buffer: &TextBuffer) {
71 let pos = text_buffer.offset_to_text_pos(self.head);
72 self.head = text_buffer.text_pos_to_offset(TextPos {row: pos.row, col: text_buffer.lines[pos.row].len()});
74 }
75
76 pub fn move_left(&mut self, char_count: usize, _text_buffer: &TextBuffer) {
77 if self.head >= char_count {
78 self.head -= char_count;
79 }
80 else {
81 self.head = 0;
82 }
83 }
84
85 pub fn move_right(&mut self, char_count: usize, total_char_count: usize, _text_buffer: &TextBuffer) {
86 if self.head + char_count < total_char_count {
87 self.head += char_count;
88 }
89 else {
90 self.head = total_char_count;
91 }
92 }
93
94 pub fn move_up(&mut self, line_count: usize, text_buffer: &TextBuffer) {
95 let pos = text_buffer.offset_to_text_pos(self.head);
96 if pos.row >= line_count {
97 self.head = text_buffer.text_pos_to_offset(TextPos {row: pos.row - line_count, col: self.max});
98 }
99 else {
100 self.head = 0;
101 }
102 }
103
104 pub fn move_down(&mut self, line_count: usize, total_char_count: usize, text_buffer: &TextBuffer) {
105 let pos = text_buffer.offset_to_text_pos(self.head);
106
107 if pos.row + line_count < text_buffer.get_line_count() - 1 {
108
109 self.head = text_buffer.text_pos_to_offset(TextPos {row: pos.row + line_count, col: self.max});
110 }
111 else {
112 self.head = total_char_count;
113 }
114 }
115}
116
117#[derive(Clone)]
118pub struct TextCursorSet {
119 pub set: Vec<TextCursor>,
120 pub last_cursor: usize,
121 pub insert_undo_group: u64,
122 pub last_clamp_range: Option<(usize, usize)>
123}
124
125impl TextCursorSet {
126 pub fn new() -> TextCursorSet {
127 TextCursorSet {
128 set: vec![TextCursor {head: 0, tail: 0, max: 0}],
129 last_cursor: 0,
130 insert_undo_group: 0,
131 last_clamp_range: None
132 }
133 }
134
135 pub fn get_all_as_string(&self, text_buffer: &TextBuffer) -> String {
136 let mut ret = String::new();
137 for cursor in &self.set {
138 let (start, end) = cursor.order();
139 text_buffer.get_range_as_string(start, end - start, &mut ret);
140 }
141 ret
142 }
143
144 fn fuse_adjacent(&mut self, text_buffer: &TextBuffer) {
145 let mut index = 0;
146 let mut old_calc = (TextPos {row: 0, col: 0}, 0);
147 loop {
148 if self.set.len() < 2 || index >= self.set.len() - 1 { return
150 }
151 let (my_start, my_end) = self.set[index].order();
153 let (next_start, next_end) = self.set[index + 1].order();
154 if my_end >= next_start { if my_end < next_end { if self.set[index].tail>self.set[index].head { self.set[index].head = my_start;
159 self.set[index].tail = next_end;
160 }
161 else { self.set[index].head = next_end;
163 self.set[index].tail = my_start;
164 }
165 old_calc = self.set[index].calc_max(text_buffer, old_calc);
166 }
168 if self.last_cursor > index {
169 self.last_cursor -= 1;
170 }
171 self.set.remove(index + 1);
172 }
173 index += 1;
174 }
175 }
176
177 fn remove_collisions(&mut self, offset: usize, len: usize) -> usize {
178 let mut index = 0;
180 loop {
181 if index >= self.set.len() {
182 return index
183 }
184 let (start, end) = self.set[index].order();
185 if start > offset + len {
186 return index
187 }
188 if offset + len >= start && offset <= end {
189 self.set.remove(index);
190 }
192 else {
193 index += 1;
194 }
195 }
196 }
197
198 fn set_last_cursor(&mut self, head: usize, tail: usize, text_buffer: &TextBuffer) {
200 let (off, len) = if let Some((off, len)) = &self.last_clamp_range {
202 (*off, *len)
203 }
204 else {
205 (head, 0)
206 };
207
208 let index = self.remove_collisions(off, len);
210
211 let mut cursor = TextCursor {
213 head: head,
214 tail: tail,
215 max: 0
216 };
217
218 cursor.clamp_range(&self.last_clamp_range);
220 cursor.calc_max(text_buffer, (TextPos {row: 0, col: 0}, 0));
222 self.set.insert(index, cursor);
224 self.last_cursor = index;
225 }
226
227 pub fn add_last_cursor_head_and_tail(&mut self, offset: usize, text_buffer: &TextBuffer) {
228 self.insert_undo_group += 1;
229 if self.set.len()>1 {
231 for i in 0..self.set.len() {
232 if self.set[i].head == self.set[i].tail && self.set[i].head == offset {
233 self.set.remove(i);
234 self.last_cursor = self.set.len() - 1;
235 return
236 }
237 }
238 }
239 self.set_last_cursor(offset, offset, text_buffer);
240 }
241
242 pub fn clear_and_set_last_cursor_head_and_tail(&mut self, offset: usize, text_buffer: &TextBuffer) {
243 self.insert_undo_group += 1;
244 self.set.truncate(0);
245 self.set_last_cursor(offset, offset, text_buffer);
246 }
247
248 pub fn set_last_cursor_head(&mut self, offset: usize, text_buffer: &TextBuffer) -> bool {
249 self.insert_undo_group += 1;
250 if self.set[self.last_cursor].head != offset {
251 let cursor_tail = self.set[self.last_cursor].tail;
252 self.set.remove(self.last_cursor);
253 self.set_last_cursor(offset, cursor_tail, text_buffer);
254 true
255 }
256 else {
257 false
258 }
259 }
260
261 pub fn clear_and_set_last_cursor_head(&mut self, offset: usize, text_buffer: &TextBuffer) {
262 self.insert_undo_group += 1;
263 let cursor_tail = self.set[self.last_cursor].tail;
264 self.set.truncate(0);
265 self.set_last_cursor(offset, cursor_tail, text_buffer);
266 }
267
268 pub fn get_last_cursor_text_pos(&self, text_buffer: &TextBuffer) -> TextPos {
269 text_buffer.offset_to_text_pos(self.set[self.last_cursor].head)
270 }
271
272 pub fn get_last_cursor_order(&self) -> (usize, usize) {
273 self.set[self.last_cursor].order()
274 }
275
276 pub fn get_last_cursor_singular(&self) -> Option<usize> {
277 let cursor = &self.set[self.last_cursor];
278 if cursor.head != cursor.tail {
279 None
280 }
281 else {
282 Some(cursor.head)
283 }
284 }
285
286 pub fn is_last_cursor_singular(&self) -> bool {
287 let cursor = &self.set[self.last_cursor];
288 cursor.head == cursor.tail
289 }
290
291 pub fn grid_select_corner(&mut self, new_pos: TextPos, text_buffer: &TextBuffer) -> TextPos {
292 self.insert_undo_group += 1;
293 let mut max_dist = 0.0;
295 let mut max_pos = TextPos {row: 0, col: 0};
296 for cursor in &self.set {
297 let head_pos = text_buffer.offset_to_text_pos(cursor.head);
298 let tail_pos = text_buffer.offset_to_text_pos(cursor.tail);
299 let head_dist = head_pos.dist(&new_pos);
300 let tail_dist = tail_pos.dist(&new_pos);
301 if head_dist > tail_dist {
302 if head_dist >= max_dist {
303 max_dist = head_dist;
304 max_pos = head_pos;
305 }
306 }
307 else {
308 if tail_dist >= max_dist {
309 max_dist = tail_dist;
310 max_pos = tail_pos;
311 }
312 }
313 }
314 return max_pos;
315 }
316
317 pub fn grid_select(&mut self, start_pos: TextPos, end_pos: TextPos, text_buffer: &TextBuffer) -> bool {
318 self.insert_undo_group += 1;
319 let (left, right) = if start_pos.col < end_pos.col {(start_pos.col, end_pos.col)}
320 else {(end_pos.col, start_pos.col)};
321
322 let (top, bottom) = if start_pos.row < end_pos.row {(start_pos.row, end_pos.row)}
323 else {(end_pos.row, start_pos.row)};
324
325 let change_check = self.set.clone();
326 self.set.truncate(0);
327 let mut offset = text_buffer.text_pos_to_offset(TextPos {row: top, col: 0});
329 for row in top..(bottom + 1) {
330 let line = &text_buffer.lines[row];
331 if left < line.len() {
332 if start_pos.col < end_pos.col {
333 self.set.push(TextCursor {
334 tail: offset + left,
335 head: offset + line.len().min(right),
336 max: line.len().min(right)
337 });
338 }
339 else {
340 self.set.push(TextCursor {
341 head: offset + left,
342 tail: offset + line.len().min(right),
343 max: line.len().min(right)
344 });
345 }
346 }
347 offset += line.len() + 1;
348 }
349 if self.set.len() == 0{
351 let offset = text_buffer.text_pos_to_offset(end_pos);
352 self.set.push(TextCursor{
353 head:offset,
354 tail:offset,
355 max:0
356 })
357 }
358 self.last_cursor = 0;
359 self.set != change_check
360 }
361
362 pub fn set_last_clamp_range(&mut self, range: (usize, usize)) {
363 self.last_clamp_range = Some(range);
364 }
365
366 pub fn clear_last_clamp_range(&mut self) {
367 self.last_clamp_range = None;
368 }
369
370 pub fn insert_newline_with_indent(&mut self, text_buffer: &mut TextBuffer) {
371 let mut delta: isize = 0;
372 let mut ops = Vec::new();
374 let cursors_clone = self.clone();
375 let mut old_max = (TextPos {row: 0, col: 0}, 0);
376 for cursor in &mut self.set {
377 let (start, end) = cursor.delta(delta);
378 if start == end && start > 0 && start < text_buffer.flat_text.len() {
380 let (pre_base, pre_spaces) = text_buffer.calc_next_line_indent_depth(start, 4);
382
383 let pch = text_buffer.flat_text[start - 1];
384 let nch = text_buffer.flat_text[start];
385 if pch == '{' && nch == '}' || pch == '(' && nch == ')' || pch == '[' && nch == ']' {
387 let mut text = String::new();
388 text.push_str("\n");
389 for _ in 0..pre_spaces {
390 text.push_str(" ");
391 }
392 let post_spaces = pre_spaces.max(4) - 4;
393 text.push_str("\n");
394 for _ in 0..post_spaces {
395 text.push_str(" ");
396 };
397 let op = text_buffer.replace_lines_with_string(start, end - start, &text);
398 cursor.head += pre_spaces + 1;
399 cursor.tail = cursor.head;
400 delta += (pre_spaces + post_spaces + 2) as isize;
401 ops.push(op);
402 }
403 else if pre_spaces != (start - pre_base) && nch == '}' || nch == ')' || nch == ']' { let mut text = String::new();
405 text.push_str("\n");
406 for _ in 0..(pre_spaces.max(4) - 4) {
407 text.push_str(" ");
408 }
409 let op = text_buffer.replace_lines_with_string(start, end - start, &text);
410 delta += cursor.collapse(start, end, op.len);
411 ops.push(op);
412 }
413 else { let mut text = String::new();
415 text.push_str("\n");
416 for _ in 0..pre_spaces {
417 text.push_str(" ");
418 }
419 let op = text_buffer.replace_lines_with_string(start, end - start, &text);
420 delta += cursor.collapse(start, end, op.len);
421 ops.push(op);
422 }
423 }
424 else {
425 let op = text_buffer.replace_lines_with_string(start, end - start, "\n");
426 delta += cursor.collapse(start, end, op.len);
427 ops.push(op);
428 };
429
430 old_max = cursor.calc_max(text_buffer, old_max);
431 }
432 text_buffer.redo_stack.truncate(0);
433 text_buffer.undo_stack.push(TextUndo {
434 ops: ops,
435 grouping: TextUndoGrouping::Newline,
436 cursors: cursors_clone
437 })
438 }
439
440 pub fn replace_text(&mut self, text: &str, text_buffer: &mut TextBuffer) {
441 let grouping = if text.len() == 1 {
442 let ch = text.chars().next().unwrap();
444 if ch == ' ' {
445 TextUndoGrouping::Space
446 }
447 else if ch == '\n' {
448 TextUndoGrouping::Newline
449 }
450 else {
451 TextUndoGrouping::Character(self.insert_undo_group)
452 }
453 }
454 else if text.len() == 0 {
455 TextUndoGrouping::Cut
456 }
457 else {
458 TextUndoGrouping::Block
459 };
460
461 let mut delta: isize = 0;
462 let mut ops = Vec::new();
464 let mut old_max = (TextPos {row: 0, col: 0}, 0);
465 let cursors_clone = self.clone();
466 for cursor in &mut self.set {
467 let (start, end) = cursor.delta(delta);
468 let op = text_buffer.replace_lines_with_string(start, end - start, text);
469 delta += cursor.collapse(start, end, op.len);
470 ops.push(op);
471 old_max = cursor.calc_max(text_buffer, old_max);
472 }
473 text_buffer.redo_stack.truncate(0);
474 text_buffer.undo_stack.push(TextUndo {
475 ops: ops,
476 grouping: grouping,
477 cursors: cursors_clone
478 })
479 }
480
481 pub fn insert_around(&mut self, pre: &str, post: &str, text_buffer: &mut TextBuffer) {
482 let mut delta: isize = 0;
483 let mut ops = Vec::new();
485 let mut old_max = (TextPos {row: 0, col: 0}, 0);
486 let cursors_clone = self.clone();
487 for cursor in &mut self.set {
488 let (start, end) = cursor.delta(delta);
489 let pre_chars = pre.chars().count();
490 let post_chars = post.chars().count();
491
492 if start != end {
494 let mut text = String::new();
496 text.push_str(pre);
497 text_buffer.get_range_as_string(start, end - start, &mut text);
498 text.push_str(post);
499 let op = text_buffer.replace_lines_with_string(start, end - start, &text);
500 cursor.head += pre_chars + delta as usize;
502 cursor.tail += pre_chars + delta as usize;
503 delta += (pre_chars + post_chars) as isize;
504 ops.push(op);
505 }
506 else { let ch = text_buffer.get_char(start);
508 if ch == ' ' || ch == ',' || ch == '.'
509 || ch == ';' || ch == '\n' || ch == '\0'
510 || ch == '}' || ch == ']' || ch == ')' {
511 let mut text = String::new();
512 text.push_str(pre);
513 text.push_str(post);
514 let op = text_buffer.replace_lines_with_string(start, 0, &text);
515 cursor.head += pre_chars + delta as usize;
516 cursor.tail += pre_chars + delta as usize;
517 delta += (pre_chars + post_chars) as isize;
518 ops.push(op);
519 }
520 else {
521 let op = text_buffer.replace_lines_with_string(start, 0, pre);
522 cursor.head += pre_chars + delta as usize;
523 cursor.tail += pre_chars + delta as usize;
524 delta += (pre_chars + post_chars) as isize;
525 ops.push(op);
526 }
527 }
528 old_max = cursor.calc_max(text_buffer, old_max);
529 }
530 text_buffer.redo_stack.truncate(0);
531 text_buffer.undo_stack.push(TextUndo {
532 ops: ops,
533 grouping: TextUndoGrouping::Block,
534 cursors: cursors_clone
535 })
536 }
537
538 pub fn overwrite_if_exists_or_deindent(&mut self, thing: &str, deindent: usize, text_buffer: &mut TextBuffer) {
539 let mut delta: isize = 0;
540 let mut ops = Vec::new();
542 let mut old_max = (TextPos {row: 0, col: 0}, 0);
543 let cursors_clone = self.clone();
544 for cursor in &mut self.set {
545 let (start, end) = cursor.delta(delta);
546 let mut next = String::new();
548 let thing_chars = thing.chars().count();
549 text_buffer.get_range_as_string(start, thing_chars, &mut next);
550
551 if start == end && thing == next {
552 let op = text_buffer.replace_lines_with_string(start, thing_chars, thing);
554 delta += cursor.collapse(start, end, op.len);
555 ops.push(op);
556 }
557 else {
558 if start == end {
559 let deindented = if let Some((rstart, l1ws, l1len)) = text_buffer.calc_deindent_whitespace(start) {
560 if start - rstart == l1len && l1ws == l1len && l1ws >= deindent { let op = text_buffer.replace_lines_with_string(
562 start - deindent,
563 deindent,
564 thing
565 );
566 delta += cursor.collapse(
567 start - deindent,
568 start - deindent,
569 op.len
570 );
571 ops.push(op);
572 true
573 }
574 else {false}
575 }
576 else {false};
577 if !deindented {
578 let op = text_buffer.replace_lines_with_string(start, 0, thing);
579 delta += cursor.collapse(start, start, op.len);
580 ops.push(op);
581
582 }
583 }
584 else {
585 let op = text_buffer.replace_lines_with_string(start, end - start, thing);
586 delta += cursor.collapse(start, end, op.len);
587 ops.push(op);
588 }
589 };
590 old_max = cursor.calc_max(text_buffer, old_max);
591 }
592 text_buffer.redo_stack.truncate(0);
593 text_buffer.undo_stack.push(TextUndo {
594 ops: ops,
595 grouping: TextUndoGrouping::Block,
596 cursors: cursors_clone
597 })
598 }
599
600 pub fn delete(&mut self, text_buffer: &mut TextBuffer) {
601 let mut delta: isize = 0;
602 let mut ops = Vec::new();
604 let cursors_clone = self.clone();
605 let mut old_max = (TextPos {row: 0, col: 0}, 0);
606 for cursor in &mut self.set {
607 let (start, end) = cursor.delta(delta);
608 if start == end {
609 let op = if let Some((rstart, l1ws, l1len, l2ws)) = text_buffer.calc_deletion_whitespace(start) {
610 if l1ws == l1len { delta -= l1len as isize + 1;
612 cursor.head = rstart + l2ws;
613 cursor.tail = cursor.head;
614 text_buffer.replace_lines_with_string(rstart, l1len + 1, "")
615 }
616 else if start == rstart + l1len { delta -= l2ws as isize + 1;
618 text_buffer.replace_lines_with_string(start, l2ws + 1, "")
619 }
620 else {
621 delta += cursor.collapse(start, start + 1, 0);
622 text_buffer.replace_lines_with_string(start, 1, "")
623 }
624 }
625 else {
626 delta += cursor.collapse(start, start + 1, 0);
627 text_buffer.replace_lines_with_string(start, 1, "")
628 };
629 if op.lines.len()>0 {
630 ops.push(op);
631 }
632 }
633 else if start != end {
634 let op = text_buffer.replace_lines_with_string(start, end - start, "");
635 if op.lines.len()>0 {
636 ops.push(op);
637 }
638 delta += cursor.collapse(start, end, 0);
639 }
640 old_max = cursor.calc_max(text_buffer, old_max);
641 }
642 let del_pos = self.set[self.last_cursor].head;
643 text_buffer.redo_stack.truncate(0);
644 if ops.len()>0 {
645 text_buffer.undo_stack.push(TextUndo {
646 ops: ops,
647 grouping: TextUndoGrouping::Delete(del_pos),
648 cursors: cursors_clone
649 })
650 }
651 }
652
653 pub fn backspace(&mut self, text_buffer: &mut TextBuffer, undo_id: u64) {
654 let mut delta: isize = 0;
655 let mut ops = Vec::new();
657 let cursors_clone = self.clone();
658 let mut old_max = (TextPos {row: 0, col: 0}, 0);
659 for cursor in &mut self.set {
660 let (start, end) = cursor.delta(delta);
661 if start == end && start > 0 {
662 let (new_start, new_len) = text_buffer.calc_backspace_line_indent_depth_and_pair(start);
664 let op = text_buffer.replace_lines_with_string(new_start, new_len, "");
665 if op.lines.len()>0 {
666 ops.push(op);
667 }
668 delta += cursor.collapse(new_start, new_start + new_len, 0);
669 }
671 else if start != end {
672 let op = text_buffer.replace_lines_with_string(start, end - start, "");
673 if op.lines.len()>0 {
674 ops.push(op);
675 }
676 delta += cursor.collapse(start, end, 0);
677 }
678 old_max = cursor.calc_max(text_buffer, old_max);
679 }
680 text_buffer.redo_stack.truncate(0);
681 if ops.len()>0 {
682 text_buffer.undo_stack.push(TextUndo {
683 ops: ops,
684 grouping: TextUndoGrouping::Backspace(undo_id),
685 cursors: cursors_clone
686 })
687 }
688 }
689
690 pub fn insert_tab(&mut self, text_buffer: &mut TextBuffer, tab_str: &str) {
691 let mut delta: usize = 0;
692 let mut ops = Vec::new();
694 let tab_str_chars = tab_str.chars().count();
695 let cursors_clone = self.clone();
696 let mut old_max = (TextPos {row: 0, col: 0}, 0);
697 for cursor in &mut self.set {
698 let (start, end) = cursor.delta(delta as isize);
699 let start_pos = text_buffer.offset_to_text_pos_next(start, old_max.0, old_max.1);
718 let end_pos = text_buffer.offset_to_text_pos_next(end, start_pos, start);
719 let mut off = start - start_pos.col;
720 let last_line = if start_pos.row == end_pos.row || end_pos.col>0 {1}else {0};
721 for row in start_pos.row..(end_pos.row + last_line) {
722 let op = text_buffer.replace_line_with_string(off, row, 0, 0, tab_str);
724 off += text_buffer.lines[row].len() + 1;
725 ops.push(op);
726 }
727 if cursor.head > cursor.tail {
729 cursor.tail += tab_str_chars + delta;
730 cursor.head += (end_pos.row - start_pos.row + last_line) * tab_str_chars + delta;
731 }
732 else {
733 cursor.tail += (end_pos.row - start_pos.row + last_line) * tab_str_chars + delta;
734 cursor.head += tab_str_chars + delta;
735 }
736 delta += ((end_pos.row - start_pos.row) + 1) * tab_str_chars;
737 old_max = cursor.calc_max(text_buffer, old_max);
740 }
741 text_buffer.redo_stack.truncate(0);
742 text_buffer.undo_stack.push(TextUndo {
743 ops: ops,
744 grouping: TextUndoGrouping::Tab,
745 cursors: cursors_clone
746 })
747 }
748
749 pub fn replace_lines_formatted(&mut self, mut out_lines: Vec<Vec<char>>, text_buffer: &mut TextBuffer) {
750
751 let mut top_row = 0;
752 while top_row < text_buffer.lines.len() && top_row < out_lines.len() && text_buffer.lines[top_row] == out_lines[top_row] {
753 top_row += 1;
754 }
755
756 let mut bottom_row_old = text_buffer.get_line_count();
757 let mut bottom_row_new = out_lines.len();
758 while bottom_row_old > top_row && bottom_row_new > top_row && text_buffer.lines[bottom_row_old - 1] == out_lines[bottom_row_new - 1] {
759 bottom_row_old -= 1;
760 bottom_row_new -= 1;
761 }
762 if top_row != bottom_row_new {
764 let changed = out_lines.splice(top_row..(bottom_row_new + 1).min(out_lines.len()), vec![]).collect();
765
766 let cursors_clone = self.clone();
767 let op = text_buffer.replace_lines(top_row, bottom_row_old + 1, changed);
768 text_buffer.redo_stack.truncate(0);
769 text_buffer.undo_stack.push(TextUndo {
770 ops: vec![op],
771 grouping: TextUndoGrouping::Format,
772 cursors: cursors_clone
773 })
774 }
775 }
776 pub fn remove_tab(&mut self, text_buffer: &mut TextBuffer, num_spaces: usize) {
818
819 let mut delta: usize = 0;
820 let mut ops = Vec::new();
822 let cursors_clone = self.clone();
823 let mut old_max = (TextPos {row: 0, col: 0}, 0);
824 for cursor in &mut self.set {
825 let (start, end) = cursor.delta(-(delta as isize));
826 let start_pos = text_buffer.offset_to_text_pos_next(start, old_max.0, old_max.1);
827 let end_pos = text_buffer.offset_to_text_pos_next(end, start_pos, start);
828 let mut off = start - start_pos.col;
829 let mut total_cut_len = 0;
830
831 let last_line = if start_pos.row == end_pos.row || end_pos.col>0 {1}else {0};
832 for row in start_pos.row..(end_pos.row + last_line) {
833 let indents = text_buffer.calc_line_indent_depth(row);
834 let cut_len = num_spaces.min(indents);
835 if cut_len > 0 {
836 total_cut_len += cut_len;
837 let op = text_buffer.replace_line_with_string(off, row, 0, num_spaces, "");
838 if cursor.head > off {
839 cursor.head -= cut_len;
840 }
841 if cursor.tail > off {
842 cursor.tail -= cut_len;
843 }
844 ops.push(op);
845 }
846 off += text_buffer.lines[row].len() + 1;
847 }
848 cursor.head -= delta;
849 cursor.tail -= delta;
850 delta += total_cut_len;
851 old_max = cursor.calc_max(text_buffer, old_max);
852 }
853 text_buffer.redo_stack.truncate(0);
854 text_buffer.undo_stack.push(TextUndo {
855 ops: ops,
856 grouping: TextUndoGrouping::Tab,
857 cursors: cursors_clone
858 })
859
860 }
861
862
863 pub fn select_all(&mut self, text_buffer: &mut TextBuffer) {
864 self.set.truncate(0);
865 self.insert_undo_group += 1;
866 let mut cursor = TextCursor {
867 head: 0,
868 tail: text_buffer.calc_char_count(),
869 max: 0
870 };
871 self.last_cursor = 0;
872 cursor.calc_max(text_buffer, (TextPos {row: 0, col: 0}, 0));
873 self.set.push(cursor);
874 }
875
876 pub fn move_home(&mut self, only_head: bool, text_buffer: &TextBuffer) {
877 self.insert_undo_group += 1;
878 for cursor in &mut self.set {
879 cursor.move_home(text_buffer);
880 if !only_head {cursor.tail = cursor.head}
881 }
882 self.fuse_adjacent(text_buffer)
883 }
884
885 pub fn move_end(&mut self, only_head: bool, text_buffer: &TextBuffer) {
886 self.insert_undo_group += 1;
887 for cursor in &mut self.set {
888 cursor.move_end(text_buffer);
889 if !only_head {cursor.tail = cursor.head}
890 }
891 self.fuse_adjacent(text_buffer)
892 }
893
894 pub fn move_up(&mut self, line_count: usize, only_head: bool, text_buffer: &TextBuffer) {
895 self.insert_undo_group += 1;
896 for cursor in &mut self.set {
897 cursor.move_up(line_count, text_buffer);
898 if !only_head {cursor.tail = cursor.head}
899 }
900 self.fuse_adjacent(text_buffer)
901 }
902
903 pub fn move_down(&mut self, line_count: usize, only_head: bool, text_buffer: &TextBuffer) {
904 self.insert_undo_group += 1;
905 let total_char_count = text_buffer.calc_char_count();
906 for cursor in &mut self.set {
907 cursor.move_down(line_count, total_char_count, text_buffer);
908 if !only_head {cursor.tail = cursor.head}
909 }
910 self.fuse_adjacent(text_buffer)
911 }
912
913 pub fn move_left(&mut self, char_count: usize, only_head: bool, text_buffer: &TextBuffer) {
914 self.insert_undo_group += 1;
915 let mut old_max = (TextPos {row: 0, col: 0}, 0);
916 for cursor in &mut self.set {
917 if cursor.head != cursor.tail && !only_head {
918 cursor.head = cursor.head.min(cursor.tail)
919 }
920 else {
921 cursor.move_left(char_count, text_buffer);
922 }
923 if !only_head {cursor.tail = cursor.head}
924 old_max = cursor.calc_max(text_buffer, old_max);
925 }
926 self.fuse_adjacent(text_buffer)
927 }
928
929 pub fn move_right(&mut self, char_count: usize, only_head: bool, text_buffer: &TextBuffer) {
930 let mut old_max = (TextPos {row: 0, col: 0}, 0);
931 let total_char_count = text_buffer.calc_char_count();
932 for cursor in &mut self.set {
933 if cursor.head != cursor.tail && !only_head {
934 cursor.head = cursor.head.max(cursor.tail)
935 }
936 else {
937 cursor.move_right(char_count, total_char_count, text_buffer);
938 }
939 if !only_head {cursor.tail = cursor.head}
940 old_max = cursor.calc_max(text_buffer, old_max);
941 }
942 self.fuse_adjacent(text_buffer)
943 }
944
945 pub fn get_nearest_token_chunk_boundary(left: bool, offset: usize, text_buffer: &TextBuffer) -> usize {
946 let token_chunks = &text_buffer.token_chunks;
947 for i in 0..token_chunks.len() {
948 if offset >= token_chunks[i].offset && offset < token_chunks[i].offset + token_chunks[i].len {
950 if left { if offset > token_chunks[i].offset {
952 return token_chunks[i].offset
953 }
954 if i == 0 {
955 return 0
956 }
957 if offset == token_chunks[i].offset {
958 if token_chunks[i - 1].token_type == TokenType::Whitespace && i>1 {
959 return token_chunks[i - 2].offset }
961 return token_chunks[i - 1].offset
962 }
963 return token_chunks[i - 1].offset + token_chunks[i - 1].len
964 }
965 else { if i < token_chunks.len() - 1 && token_chunks[i].token_type == TokenType::Whitespace {
968 return token_chunks[i + 1].offset + token_chunks[i + 1].len;
969 }
970 return token_chunks[i].offset + token_chunks[i].len
971 }
972 }
973 };
974 0
975 }
976
977 pub fn get_nearest_token_chunk(offset: usize, text_buffer: &TextBuffer) -> Option<(usize, usize)> {
978 let token_chunks = &text_buffer.token_chunks;
979 for i in 0..token_chunks.len() {
980 if token_chunks[i].token_type == TokenType::Whitespace {
981 if offset == token_chunks[i].offset && i > 0 { return Some((token_chunks[i - 1].offset, token_chunks[i - 1].len))
983 }
984 else if offset == token_chunks[i].offset + token_chunks[i].len && i < token_chunks.len() - 1 {
985 return Some((token_chunks[i + 1].offset, token_chunks[i + 1].len))
986 }
987 };
988
989 if offset >= token_chunks[i].offset && offset < token_chunks[i].offset + token_chunks[i].len {
990 let i = if token_chunks[i].token_type == TokenType::Newline && i > 0 {i - 1}else {i};
991 let pair_token = token_chunks[i].pair_token;
992 if pair_token > i {
993 return Some((token_chunks[i].offset, token_chunks[pair_token].len + (token_chunks[pair_token].offset - token_chunks[i].offset)));
994 }
995 if token_chunks[i].token_type == TokenType::String || token_chunks[i].token_type == TokenType::CommentChunk {
996 if token_chunks[i].len <= 2 {
997 return Some((token_chunks[i].offset, token_chunks[i].len));
998 }
999 else { let mut scan_left = offset;
1001 let boundary_tokens = "' :(){}[]+-|/<,.>;\"'!%^&*=";
1002 while scan_left > 0 && scan_left > token_chunks[i].offset {
1003 if let Some(_) = boundary_tokens.find(text_buffer.flat_text[scan_left]) {
1004 scan_left += 1;
1005 break
1006 }
1007 scan_left -= 1;
1008 }
1009 if let Some(_) = boundary_tokens.find(text_buffer.flat_text[scan_left]) {
1010 scan_left += 1;
1011 }
1012 let mut scan_right = offset;
1013 while scan_right < token_chunks[i].offset + token_chunks[i].len {
1014 if let Some(_) = boundary_tokens.find(text_buffer.flat_text[scan_right]) {
1015 break
1017 }
1018 scan_right += 1;
1019 }
1020 if scan_right <= scan_left {
1021 return Some((token_chunks[i].offset, token_chunks[i].len))
1022 }
1023 else {
1024 return Some((scan_left, scan_right - scan_left))
1025 }
1026 }
1027 }
1028 return Some((token_chunks[i].offset, token_chunks[i].len));
1029 }
1030 };
1031 None
1032 }
1033
1034 pub fn move_left_nearest_token(&mut self, only_head: bool, text_buffer: &TextBuffer) {
1035 self.insert_undo_group += 1;
1036 for cursor in &mut self.set {
1037 let pos = TextCursorSet::get_nearest_token_chunk_boundary(true, cursor.head, text_buffer);
1039 cursor.head = pos;
1040 if !only_head {cursor.tail = cursor.head}
1041 }
1042 self.fuse_adjacent(text_buffer)
1043 }
1044
1045 pub fn move_right_nearest_token(&mut self, only_head: bool, text_buffer: &TextBuffer) {
1046 self.insert_undo_group += 1;
1047 for cursor in &mut self.set {
1048 let pos = TextCursorSet::get_nearest_token_chunk_boundary(false, cursor.head, text_buffer);
1050 cursor.head = pos;
1051 if !only_head {cursor.tail = cursor.head}
1052 }
1053 self.fuse_adjacent(text_buffer)
1054 }
1055
1056 pub fn get_token_highlight(&self, text_buffer: &TextBuffer) -> Vec<char> {
1057 let cursor = &self.set[self.last_cursor];
1058 if cursor.head != cursor.tail {
1059 return vec![]
1060 }
1061 if let Some((offset, len)) = TextCursorSet::get_nearest_token_chunk(cursor.head, text_buffer) {
1062 let start_pos = text_buffer.offset_to_text_pos(offset);
1099
1100 text_buffer.copy_line(start_pos.row, start_pos.col, len)
1101 }
1103 else {
1104 vec![]
1105 }
1106 }
1107
1108 pub fn get_selection_highlight(&self, text_buffer: &TextBuffer) -> Vec<char> {
1109 let cursor = &self.set[self.last_cursor];
1110 if cursor.head != cursor.tail {
1111 let (start, end) = cursor.order();
1112 let start_pos = text_buffer.offset_to_text_pos(start);
1113 let end_pos = text_buffer.offset_to_text_pos_next(end, start_pos, start);
1114 if start_pos.row != end_pos.row || end_pos.col <= start_pos.col {
1115 return vec![]
1116 };
1117 let buf = text_buffer.copy_line(start_pos.row, start_pos.col, end_pos.col - start_pos.col);
1118 let mut only_spaces = true;
1119 for ch in &buf {
1120 if *ch != ' ' {
1121 only_spaces = false;
1122 break;
1123 }
1124 };
1125 if only_spaces {
1126 return vec![]
1127 }
1128 return buf
1129 }
1130 else {
1131 return vec![]
1132 }
1133 }
1134}
1135
1136#[derive(Clone)]
1137pub struct DrawSel {
1138 pub index: usize,
1139 pub rc: Rect,
1140}
1141
1142#[derive(Clone)]
1143pub struct DrawCursors {
1144 pub head: usize,
1145 pub start: usize,
1146 pub end: usize,
1147 pub next_index: usize,
1148 pub left_top: Vec2,
1149 pub right_bottom: Vec2,
1150 pub last_w: f32,
1151 pub first: bool,
1152 pub empty: bool,
1153 pub cursors: Vec<CursorRect>,
1154 pub last_cursor: Option<usize>,
1155 pub selections: Vec<DrawSel>
1156}
1157
1158#[derive(Clone, Copy)]
1159pub struct CursorRect {
1160 pub x: f32,
1161 pub y: f32,
1162 pub w: f32,
1163 pub h: f32,
1164 pub z: f32
1165}
1166
1167impl DrawCursors {
1168 pub fn new() -> DrawCursors {
1169 DrawCursors {
1170 start: 0,
1171 end: 0,
1172 head: 0,
1173 first: true,
1174 empty: true,
1175 next_index: 0,
1176 left_top: Vec2::default(),
1177 right_bottom: Vec2::default(),
1178 last_w: 0.0,
1179 cursors: Vec::new(),
1180 selections: Vec::new(),
1181 last_cursor: None
1182 }
1183 }
1184
1185 pub fn term(&mut self, cursors: &Vec<TextCursor>) {
1186 self.next_index = cursors.len();
1187 }
1188
1189 pub fn set_next(&mut self, cursors: &Vec<TextCursor>) -> bool {
1190 if self.next_index < cursors.len() {
1191 self.emit_selection();
1192 let cursor = &cursors[self.next_index];
1193 let (start, end) = cursor.order();
1194 self.start = start;
1195 self.end = end;
1196 self.head = cursor.head;
1197 self.next_index += 1;
1198 self.last_w = 0.0;
1199 self.right_bottom.y = 0.;
1200 self.first = true;
1201 self.empty = true;
1202 true
1203 }
1204 else {
1205 false
1206 }
1207 }
1208
1209 pub fn emit_cursor(&mut self, x: f32, y: f32, h: f32, z: f32) {
1210 self.cursors.push(CursorRect {
1211 x: x,
1212 y: y,
1213 w: 1.5,
1214 h: h,
1215 z: z
1216 })
1217 }
1218
1219 pub fn emit_selection(&mut self) {
1220 if !self.first {
1221 self.first = true;
1222 if !self.empty {
1223 self.selections.push(DrawSel {
1224 index: self.next_index - 1,
1225 rc: Rect {
1226 x: self.left_top.x,
1227 y: self.left_top.y,
1228 w: (self.right_bottom.x - self.left_top.x),
1229 h: self.right_bottom.y - self.left_top.y
1230 }
1231 })
1232 }
1233 self.right_bottom.y = 0.;
1234 }
1235 }
1236
1237 pub fn emit_selection_new_line(&mut self) {
1238 if !self.first {
1239 self.first = true;
1240 self.selections.push(DrawSel {
1241 index: self.next_index - 1,
1242 rc: Rect {
1243 x: self.left_top.x,
1244 y: self.left_top.y,
1245 w: (self.right_bottom.x - self.left_top.x) + self.last_w,
1246 h: self.right_bottom.y - self.left_top.y
1247 }
1248 });
1249 self.right_bottom.y = 0.;
1250 }
1251 }
1252
1253 pub fn process_cursor(&mut self, last_cursor: usize, offset: usize, x: f32, y: f32, h: f32, z: f32) {
1254 if offset == self.head { if self.next_index > 0 && self.next_index - 1 == last_cursor {
1256 self.last_cursor = Some(self.cursors.len());
1257 }
1258 self.emit_cursor(x, y, h, z);
1259 }
1260 }
1261
1262 pub fn process_geom(&mut self, x: f32, y: f32, w: f32, h: f32) {
1263 if self.first { self.first = false;
1265 self.left_top.x = x;
1266 self.left_top.y = y;
1267 self.empty = true;
1268 }
1269 else {
1270 self.empty = false;
1271 }
1272 self.last_w = w;
1274 self.right_bottom.x = x;
1275 if y + h > self.right_bottom.y {
1276 self.right_bottom.y = y + h;
1277 }
1278 }
1279
1280 pub fn process_newline(&mut self) {
1281 if !self.first { self.emit_selection_new_line();
1283 self.first = true;
1284 }
1285 }
1286
1287 pub fn mark_text_select_only(&mut self, cursors: &Vec<TextCursor>, offset: usize, x: f32, y: f32, w: f32, h: f32) {
1288 while offset >= self.end { if offset == self.end { self.process_geom(x, y, w, h);
1292 self.emit_selection();
1293 }
1294 if !self.set_next(cursors) { return
1296 }
1297 }
1298 if offset >= self.start && offset <= self.end {
1300 self.process_geom(x, y, w, h);
1301 if offset == self.end {
1302 self.emit_selection();
1303 }
1304 }
1305 }
1306
1307 pub fn mark_text_with_cursor(&mut self, cursors: &Vec<TextCursor>, ch: char, offset: usize, x: f32, y: f32, w: f32, h: f32, z: f32, last_cursor: usize, mark_spaces: f32) -> f32 {
1308 while offset >= self.end { if offset == self.end { self.process_cursor(last_cursor, offset, x, y, h, z);
1312 self.process_geom(x, y, w, h);
1313 self.emit_selection();
1314 }
1315 if !self.set_next(cursors) { return mark_spaces
1317 }
1318 }
1319 if offset >= self.start && offset <= self.end {
1321 self.process_cursor(last_cursor, offset, x, y, h, z);
1322 self.process_geom(x, y, w, h);
1323 if offset == self.end {
1324 self.emit_selection();
1325 }
1326 if ch == '\n' {
1327 return 0.0
1328 }
1329 else if ch == ' ' && offset < self.end {
1330 return 2.0
1331 }
1332 }
1333 return mark_spaces
1334 }
1335}