1use {
2 crate::{
3 decoration::Decoration,
4 layout::{BlockElement, WrappedElement},
5 selection::Affinity,
6 session::Session,
7 settings::Settings,
8 str::StrExt,
9 text::Position,
10 token::TokenKind,
11 text::Length,
12 Line,
13 Selection,
14 Token,
15 },
16 makepad_widgets::*,
17 std::fmt::Write,
18 std::{mem, slice::Iter},
19};
20
21live_design!{
22 import makepad_draw::shader::std::*;
23 import makepad_widgets::theme_desktop_dark::*;
24
25 TokenColors = {{TokenColors}} {
26 unknown: #C0C0C0,
27 branch_keyword: #C485BE,
28 comment: #638D54,
29 constant: #CC917B,
30 delimiter: #a,
31 identifier: #D4D4D4,
32 loop_keyword: #FF8C00,
33 number: #B6CEAA,
34 other_keyword: #5B9BD3,
35 punctuator: #D4D4D4,
36 string: #CC917B,
37 typename: #56C9B1;
38 whitespace: #6E6E6E,
39 delimiter_highlight: #f,
40 }
41
42 DrawIndentGuide = {{DrawIndentGuide}} {
43 fn pixel(self) -> vec4 {
44 let thickness = 0.8 + self.dpi_dilate * 0.5;
45 let sdf = Sdf2d::viewport(self.pos * self.rect_size);
46 sdf.move_to(1., -1.);
47 sdf.line_to(1., self.rect_size.y + 1.);
48 return sdf.stroke(self.color, thickness);
49 }
50 }
51
52 DrawDecoration = {{DrawDecoration}} {
53 fn pixel(self) -> vec4 {
54 let transformed_pos = vec2(self.pos.x, self.pos.y + 0.03 * sin(self.pos.x * self.rect_size.x));
55 let cx = Sdf2d::viewport(transformed_pos * self.rect_size);
56 cx.move_to(0.0, self.rect_size.y - 1.0);
57 cx.line_to(self.rect_size.x, self.rect_size.y - 1.0);
58 return cx.stroke(vec4(1.0, 0.0, 0.0, 1.0), 0.8);
59 }
60 }
61
62 DrawSelection = {{DrawSelection}} {
63 uniform gloopiness: 8.0
64 uniform border_radius: 2.0
65 uniform focus: 1.0
66 fn vertex(self) -> vec4 {
67 let clipped: vec2 = clamp(
68 self.geom_pos * vec2(self.rect_size.x + 16., self.rect_size.y) + self.rect_pos - vec2(8., 0.),
69 self.draw_clip.xy,
70 self.draw_clip.zw
71 );
72 self.pos = (clipped - self.rect_pos) / self.rect_size;
73 return self.camera_projection * (self.camera_view * (
74 self.view_transform * vec4(clipped.x, clipped.y, self.draw_depth + self.draw_zbias, 1.)
75 ));
76 }
77
78 fn pixel(self) -> vec4 {
79 let sdf = Sdf2d::viewport(self.rect_pos + self.pos * self.rect_size);
80 sdf.box(
81 self.rect_pos.x,
82 self.rect_pos.y,
83 self.rect_size.x,
84 self.rect_size.y,
85 self.border_radius
86 );
87 if self.prev_w > 0.0 {
88 sdf.box(
89 self.prev_x,
90 self.rect_pos.y - self.rect_size.y,
91 self.prev_w,
92 self.rect_size.y,
93 self.border_radius
94 );
95 sdf.gloop(self.gloopiness);
96 }
97 if self.next_w > 0.0 {
98 sdf.box(
99 self.next_x,
100 self.rect_pos.y + self.rect_size.y,
101 self.next_w,
102 self.rect_size.y,
103 self.border_radius
104 );
105 sdf.gloop(self.gloopiness);
106 }
107 return sdf.fill(mix(#5558,#08f8,self.focus));
108 }
109 }
110
111 DrawCodeText = {{DrawCodeText}} {
112 }
113
114 CodeEditor = {{CodeEditor}} {
115 width: Fill,
116 height: Fill,
117 margin: 0,
118 scroll_bars: <ScrollBars> {}
119 draw_bg: {
120 color: #2a
122 }
123 draw_gutter: {
124 draw_depth: 1.0,
125 text_style: <THEME_FONT_CODE> {},
126 color: #5,
127 }
128 draw_text: {
129 draw_depth: 1.0,
130 text_style: <THEME_FONT_CODE> {}
131 fn blend_color(self, incol: vec4) -> vec4 {
132 if self.outline < 0.5 {
133 return incol
134 }
135 if self.pos.y<0.12 {
136 return #f
137 }
138 return incol
139 }
140 }
141 draw_indent_guide: {
142 color: #5,
144 }
145 draw_decoration: {
146 }
148 draw_selection: {
149 }
151
152 draw_cursor: {
153 instance blink: 0.0
155 instance focus: 0.0
156 fn pixel(self) -> vec4 {
157 let color = mix(#0000,mix(self.color, #0000, self.blink),self.focus);
158 return vec4(color.rgb*color.a, color.a);
159 }
160 color: #C0C0C0,
161 }
162
163 draw_cursor_bg: {
164 instance focus: 0.0
165 fn pixel(self) -> vec4 {
166 let color = mix(#0000,#4447,self.focus);
167 return vec4(color.rgb*color.a, color.a);
168 }
169 }
170
171 animator: {
172 blink = {
173 default: off
174 off = {
175 from: {all: Forward {duration:0.05}}
176 apply: {
177 draw_cursor: {blink:0.0}
178 }
179 }
180 on = {
181 from: {all: Forward {duration: 0.05}}
182 apply: {
183 draw_cursor: {blink:1.0}
184 }
185 }
186 }
187 focus = {
188 default: off
189 off = {
190 from: {all: Forward {duration:0.05}}
191 apply: {
192 draw_cursor: {focus:0.0}
193 draw_cursor_bg: {focus:0.0}
194 draw_selection: {focus:0.0}
195 }
196 }
197 on = {
198 from: {all: Forward {duration: 0.05}}
199 apply: {
200 draw_cursor: {focus:1.0}
201 draw_cursor_bg: {focus:1.0}
202 draw_selection: {focus:1.0}
203 }
204 }
205 }
206 }
207 }
208
209}
210
211#[derive(Live, LiveHook)]#[repr(C)]
212struct DrawCodeText {
213 #[deref] draw_super: DrawText,
214 #[live] outline: f32,
215}
216
217#[derive(Live)]
218pub struct CodeEditor {
219 #[walk]
220 walk: Walk,
221 #[live]
222 scroll_bars: ScrollBars,
223 #[rust]
224 draw_state: DrawStateWrap<Walk>,
225 #[live]
226 draw_gutter: DrawText,
227
228 #[live]
229 draw_text: DrawCodeText,
230
231
232 #[live]
233 token_colors: TokenColors,
234 #[live]
235 draw_indent_guide: DrawIndentGuide,
236 #[live]
237 draw_decoration: DrawDecoration,
238 #[live]
239 draw_selection: DrawSelection,
240 #[live]
241 draw_cursor: DrawColor,
242 #[live]
243 draw_cursor_bg: DrawColor,
244 #[live]
245 draw_bg: DrawColor,
246 #[rust(KeepCursorInView::Off)]
247 keep_cursor_in_view: KeepCursorInView,
248 #[rust]
249 last_cursor_screen_pos: Option<DVec2>,
250
251 #[rust]
252 cell_size: DVec2,
253 #[rust]
254 gutter_rect: Rect,
255 #[rust]
256 viewport_rect: Rect,
257 #[rust]
258 unscrolled_rect: Rect,
259 #[rust]
260 line_start: usize,
261 #[live(true)]
262 word_wrap: bool,
263
264 #[live(0.5)]
265 blink_speed: f64,
266
267 #[animator]
268 animator: Animator,
269
270 #[rust]
271 blink_timer: Timer,
272
273 #[rust]
274 line_end: usize,
275}
276
277enum KeepCursorInView {
278 Once,
279 Always(DVec2, NextFrame),
280 LockStart,
281 Locked(DVec2),
282 LockedCenter(DVec2, Position, Affinity),
283 FontResize(DVec2),
284 JumpToPosition,
285 Off
286}
287
288impl KeepCursorInView {
289 fn is_once(&self) -> bool {
290 match self {
291 Self::Once => true,
292 _ => false
293 }
294 }
295 fn is_locked(&self) -> bool {
296 match self {
297 Self::LockStart | Self::Locked(_) | Self::LockedCenter(_,_,_)=> true,
298 _ => false
299 }
300 }
301}
302
303impl LiveHook for CodeEditor {
304 fn before_live_design(cx: &mut Cx) {
305 register_widget!(cx, CodeEditor)
306 }
307}
308
309impl Widget for CodeEditor {
310 fn redraw(&mut self, cx: &mut Cx) {
311 self.scroll_bars.redraw(cx);
312 }
313
314 fn handle_widget_event_with(
315 &mut self,
316 _cx: &mut Cx,
317 _event: &Event,
318 _dispatch_action: &mut dyn FnMut(&mut Cx, WidgetActionItem),
319 ) {
320 }
321
322 fn walk(&mut self, _cx: &mut Cx) -> Walk {
323 self.walk
324 }
325
326 fn draw_walk_widget(&mut self, cx: &mut Cx2d, walk: Walk) -> WidgetDraw {
327 if self.draw_state.begin(cx, walk) {
328 return WidgetDraw::hook_above();
329 }
330 self.draw_state.end();
331 WidgetDraw::done()
332 }
333}
334
335#[derive(Clone, PartialEq, WidgetRef)]
336pub struct CodeEditorRef(WidgetRef);
337
338impl CodeEditor {
339 pub fn draw(&mut self, cx: &mut Cx2d, session: &mut Session) {
340 session.handle_changes();
342
343 self.cell_size =
344 self.draw_text.text_style.font_size * self.draw_text.get_monospace_base(cx);
345
346 let last_added_selection =
347 session.selections()[session.last_added_selection_index().unwrap()];
348 let (cursor_x, cursor_y) = session.layout().logical_to_normalized_position(
349 last_added_selection.cursor.position,
350 last_added_selection.cursor.affinity,
351 );
352 let cursor_pos = dvec2(cursor_x, cursor_y) * self.cell_size;
353 self.last_cursor_screen_pos = Some(cursor_pos - self.scroll_bars.get_scroll_pos());
354 match self.keep_cursor_in_view {
355 KeepCursorInView::Once | KeepCursorInView::Always(_, _) => {
356 let pad_above = dvec2(self.cell_size.x * 8.0, self.cell_size.y);
358 let pad_below = dvec2(self.cell_size.x * 8.0, self.cell_size.y * 2.0);
359 let rect = Rect {pos: cursor_pos - pad_above, size: pad_above + pad_below};
360 self.scroll_bars.scroll_into_view(cx, rect);
362 if self.keep_cursor_in_view.is_once() {
363 self.keep_cursor_in_view = KeepCursorInView::Off
364 }
365 }
366 KeepCursorInView::LockStart => {
367 let screen_pos = cursor_pos - self.scroll_bars.get_scroll_pos();
369 let rect = Rect{pos:dvec2(0.0,0.0),size:self.viewport_rect.size};
370 if rect.contains(screen_pos){
371 self.keep_cursor_in_view = KeepCursorInView::Locked(screen_pos);
372 }
373 else{
374 let center = rect.size*0.5 + self.unscrolled_rect.pos;
375 if let Some((pos, aff)) = self.pick(session, center){
376 let (cursor_x, cursor_y) = session.layout().logical_to_normalized_position(
377 pos,
378 aff,
379 );
380 let screen_pos = dvec2(cursor_x, cursor_y)* self.cell_size - self.scroll_bars.get_scroll_pos();
381 self.keep_cursor_in_view = KeepCursorInView::LockedCenter(screen_pos, pos, aff);
382 }
383 else{
384 self.keep_cursor_in_view = KeepCursorInView::Off
385 }
386 }
387 }
388 KeepCursorInView::Locked(pos) => {
389 let new_pos = cursor_pos - self.scroll_bars.get_scroll_pos();
391 let delta = pos - new_pos;
392 let new_pos = self.scroll_bars.get_scroll_pos() - dvec2(0.0, delta.y);
393 self.scroll_bars.set_scroll_pos_no_clip(cx, new_pos);
394 }
396 KeepCursorInView::LockedCenter(screen_pos, pos, aff) => {
397 let (cursor_x, cursor_y) = session.layout().logical_to_normalized_position(
398 pos,
399 aff,
400 );
401 let new_pos = dvec2(cursor_x, cursor_y)* self.cell_size - self.scroll_bars.get_scroll_pos();
402 let delta = screen_pos - new_pos;
403 let new_pos = self.scroll_bars.get_scroll_pos() - dvec2(0.0, delta.y);
404 self.scroll_bars.set_scroll_pos_no_clip(cx, new_pos);
405 }
407 KeepCursorInView::JumpToPosition => {
408 let padd = dvec2(self.cell_size.x*10.0,self.cell_size.y*10.0);
411 self.scroll_bars.scroll_into_view(cx,
412 Rect{
413 pos: cursor_pos-padd,
414 size: 2.0*padd
415 }
416 );
417 self.keep_cursor_in_view = KeepCursorInView::Off;
418 }
419 KeepCursorInView::FontResize(last_pos) => {
420 let new_pos = cursor_pos - self.scroll_bars.get_scroll_pos();
421 let delta = last_pos - new_pos;
422 let new_pos = self.scroll_bars.get_scroll_pos() - dvec2(0.0, delta.y);
423 self.scroll_bars.set_scroll_pos_no_clip(cx, new_pos);
424 self.keep_cursor_in_view = KeepCursorInView::Off
425 }
426 KeepCursorInView::Off => {
427
428 }
429 }
430
431 let walk = self.draw_state.get().unwrap();
432 self.scroll_bars.begin(cx, walk, Layout::default());
433
434 let turtle_rect = cx.turtle().rect();
435 let gutter_width = (session .document() .as_text() .as_lines() .len() .to_string() .column_count() + 3) as f64
436 * self.cell_size.x;
437 self.gutter_rect = Rect {
438 pos: turtle_rect.pos,
439 size: DVec2 {
440 x: gutter_width,
441 y: turtle_rect.size.y,
442 },
443 };
444 self.viewport_rect = Rect {
445 pos: DVec2 {
446 x: turtle_rect.pos.x + gutter_width,
447 y: turtle_rect.pos.y,
448 },
449 size: DVec2 {
450 x: turtle_rect.size.x - gutter_width,
451 y: turtle_rect.size.y,
452 },
453 };
454
455
456 let pad_left_top = dvec2(10., 10.);
457 self.gutter_rect.pos += pad_left_top;
458 self.gutter_rect.size -= pad_left_top;
459 self.viewport_rect.pos += pad_left_top;
460 self.viewport_rect.size -= pad_left_top;
461
462 session.set_wrap_column(if self.word_wrap {Some(
463 (self.viewport_rect.size.x / self.cell_size.x) as usize,
464 )} else {None});
465
466 let scroll_pos = self.scroll_bars.get_scroll_pos();
467
468 self.line_start = session
469 .layout()
470 .find_first_line_ending_after_y(scroll_pos.y / self.cell_size.y - self.cell_size.y);
471 self.line_end = session.layout().find_first_line_starting_after_y(
472 (scroll_pos.y + self.viewport_rect.size.y) / self.cell_size.y,
473 );
474 self.unscrolled_rect = cx.turtle().unscrolled_rect();
475 self.draw_bg.draw_abs(cx, cx.turtle().unscrolled_rect());
476
477 self.draw_gutter(cx, session);
478 self.draw_selection_layer(cx, session);
479 self.draw_text_layer(cx, session);
480 self.draw_indent_guide_layer(cx, session);
481 self.draw_decoration_layer(cx, session);
482
483 cx.turtle_mut().set_used(
488 session.layout().width() * self.cell_size.x,
489 session.layout().height() * self.cell_size.y + (self.viewport_rect.size.y),
490 );
491
492 self.scroll_bars.end(cx);
493 if session.update_folds() {
494 self.scroll_bars.area().redraw(cx);
495 }
496 else if self.keep_cursor_in_view.is_locked() {
497 self.keep_cursor_in_view = KeepCursorInView::Off;
498 }
499 }
500
501 pub fn set_key_focus(&mut self, cx:&mut Cx){
502 cx.set_key_focus(self.scroll_bars.area());
503 }
504
505 pub fn set_cursor_and_scroll(&mut self, cx:&mut Cx, pos:Position, _lenght:Length, session: &mut Session){
506 session.set_selection(pos, Affinity::Before, 1);
507 self.keep_cursor_in_view = KeepCursorInView::JumpToPosition;
508 self.redraw(cx);
509 }
510
511 pub fn reset_font_size(&mut self) {
512 self.draw_gutter.text_style.font_size = 9.0;
513 self.draw_text.text_style.font_size = 9.0;
514 if let Some(pos) = self.last_cursor_screen_pos {
515 self.keep_cursor_in_view = KeepCursorInView::FontResize(pos);
516 }
517 }
518
519 pub fn decrease_font_size(&mut self) {
520 if self.draw_text.text_style.font_size > 3.0 {
521 self.draw_text.text_style.font_size -= 1.0;
522 self.draw_gutter.text_style.font_size =
523 self.draw_text.text_style.font_size;
524 if let Some(pos) = self.last_cursor_screen_pos {
525 self.keep_cursor_in_view = KeepCursorInView::FontResize(pos);
526 }
527 }
528 }
529
530 pub fn increase_font_size(&mut self) {
531 if self.draw_text.text_style.font_size < 20.0 {
532 self.draw_text.text_style.font_size += 1.0;
533 self.draw_gutter.text_style.font_size =
534 self.draw_text.text_style.font_size;
535 if let Some(pos) = self.last_cursor_screen_pos {
536 self.keep_cursor_in_view = KeepCursorInView::FontResize(pos);
537 }
538 }
539 }
540
541
542 pub fn handle_event(
543 &mut self,
544 cx: &mut Cx,
545 event: &Event,
546 session: &mut Session,
547 ) -> Vec<CodeEditorAction> {
548 let mut a = Vec::new();
549 self.handle_event_with(cx, event, session, &mut | _, v | a.push(v));
550 a
551 }
552
553 pub fn reset_cursor_blinker(&mut self, cx:&mut Cx){
554 self.animator_cut(cx, id!(blink.off));
555 cx.stop_timer(self.blink_timer);
556 self.blink_timer = cx.start_timeout(self.blink_speed)
557 }
558
559 pub fn handle_event_with(
560 &mut self,
561 cx: &mut Cx,
562 event: &Event,
563 session: &mut Session,
564 dispatch_action: &mut dyn FnMut(&mut Cx, CodeEditorAction),
565 ) {
566 self.animator_handle_event(cx, event);
567
568 session.handle_changes();
569
570 self.scroll_bars.handle_event_with(cx, event, &mut | cx, _ | {
571 cx.redraw_all();
572 });
573 if self.blink_timer.is_event(event).is_some(){
574 if self.animator_in_state(cx, id!(blink.off)){
575 self.animator_play(cx, id!(blink.on));
576 }
577 else{
578 self.animator_play(cx, id!(blink.off));
579 }
580 self.blink_timer = cx.start_timeout(self.blink_speed)
581 }
582 let mut keyboard_moved_cursor = false;
583 match event.hits(cx, self.scroll_bars.area()) {
584 Hit::KeyFocusLost(_) => {
585 self.animator_play(cx, id!(focus.off));
586 }
587 Hit::KeyFocus(_) => {
588 self.animator_play(cx, id!(focus.on));
589 }
590 Hit::KeyDown(KeyEvent {
591 key_code: KeyCode::Escape,
592 is_repeat: false,
593 ..
594 }) => {
595 session.fold();
596 if !self.keep_cursor_in_view.is_locked() {
597 self.keep_cursor_in_view = KeepCursorInView::LockStart;
598 }
599 self.redraw(cx);
600 }
601 Hit::KeyUp(KeyEvent {
602 key_code: KeyCode::Escape,
603 ..
604 }) => {
605 session.unfold();
606 if !self.keep_cursor_in_view.is_locked() {
607 self.keep_cursor_in_view = KeepCursorInView::LockStart;
608 }
609 self.redraw(cx);
610 }
611 Hit::KeyDown(KeyEvent {
612 key_code: KeyCode::Minus,
613 modifiers: KeyModifiers {control, logo, ..},
614 ..
615 }) => {
616 if control || logo {
617 self.decrease_font_size();
618 self.redraw(cx);
619 }
620 }
621 Hit::KeyDown(KeyEvent {
622 key_code: KeyCode::Key0,
623 modifiers: KeyModifiers {control, logo, ..},
624 ..
625 }) => {
626 if control || logo {
627 self.reset_font_size();
628 self.redraw(cx);
629 }
630 }
631 Hit::KeyDown(KeyEvent {
632 key_code: KeyCode::Equals,
633 modifiers: KeyModifiers {control, logo, ..},
634 ..
635 }) => {
636 if control || logo {
637 self.increase_font_size();
638 self.redraw(cx);
639 }
640 }
641 Hit::KeyDown(KeyEvent {
642 key_code: KeyCode::KeyW,
643 modifiers: KeyModifiers {control, logo, ..},
644 ..
645 }) => {
646 if control || logo {
647 self.word_wrap = !self.word_wrap;
648 self.redraw(cx);
649 }
650 }
651 Hit::KeyDown(KeyEvent {
652 key_code: KeyCode::ArrowLeft,
653 modifiers: KeyModifiers {shift, ..},
654 ..
655 }) => {
656 session.move_left(!shift);
657 keyboard_moved_cursor = true;
658 self.redraw(cx);
659 }
660 Hit::KeyDown(KeyEvent {
661 key_code: KeyCode::ArrowRight,
662 modifiers: KeyModifiers {shift, ..},
663 ..
664 }) => {
665 session.move_right(!shift);
666 keyboard_moved_cursor = true;
667 self.redraw(cx);
668 }
669 Hit::KeyDown(KeyEvent {
670 key_code: KeyCode::ArrowUp,
671 modifiers: KeyModifiers {shift, ..},
672 ..
673 }) => {
674 session.move_up(!shift);
675 keyboard_moved_cursor = true;
676 self.redraw(cx);
677 }
678 Hit::KeyDown(KeyEvent {
679 key_code: KeyCode::ArrowDown,
680 modifiers: KeyModifiers {shift, ..},
681 ..
682 }) => {
683 session.move_down(!shift);
684 keyboard_moved_cursor = true;
685 self.redraw(cx);
686 }
687 Hit::TextInput(TextInputEvent {ref input, ..}) if input.len() > 0 => {
688 session.insert(input.into());
689 self.redraw(cx);
690 keyboard_moved_cursor = true;
691 dispatch_action(cx, CodeEditorAction::TextDidChange);
692 }
693 Hit::KeyDown(KeyEvent {
694 key_code: KeyCode::ReturnKey,
695 ..
696 }) => {
697 session.enter();
698 self.redraw(cx);
699 keyboard_moved_cursor = true;
700 dispatch_action(cx, CodeEditorAction::TextDidChange);
701 }
702 Hit::KeyDown(KeyEvent {
703 key_code: KeyCode::Tab,
704 modifiers: KeyModifiers {shift: false, ..},
705 ..
706 }) => {
707 session.indent();
708 self.redraw(cx);
709 keyboard_moved_cursor = true;
710 dispatch_action(cx, CodeEditorAction::TextDidChange);
711 }
712 Hit::KeyDown(KeyEvent {
713 key_code: KeyCode::Tab,
714 modifiers: KeyModifiers {shift: true, ..},
715 ..
716 }) => {
717 session.outdent();
718 self.redraw(cx);
719 keyboard_moved_cursor = true;
720 dispatch_action(cx, CodeEditorAction::TextDidChange);
721 }
722 Hit::KeyDown(KeyEvent {
723 key_code: KeyCode::Delete,
724 ..
725 }) => {
726 session.delete();
727 self.redraw(cx);
728 keyboard_moved_cursor = true;
729 dispatch_action(cx, CodeEditorAction::TextDidChange);
730 }
731 Hit::KeyDown(KeyEvent {
732 key_code: KeyCode::Backspace,
733 ..
734 }) => {
735 session.backspace();
736 self.redraw(cx);
737 keyboard_moved_cursor = true;
738 dispatch_action(cx, CodeEditorAction::TextDidChange);
739 }
740 Hit::TextCopy(ce) => {
741 *ce.response.borrow_mut() = Some(session.copy());
742 keyboard_moved_cursor = true;
743 }
744 Hit::TextCut(ce) => {
745 *ce.response.borrow_mut() = Some(session.copy());
746 session.delete();
747 keyboard_moved_cursor = true;
748 self.redraw(cx);
749 }
750 Hit::KeyDown(KeyEvent {
751 key_code: KeyCode::KeyZ,
752 modifiers:
753 KeyModifiers {
754 logo: true,
755 shift: false,
756 ..
757 },
758 ..
759 }) => {
760 if session.undo() {
761 cx.redraw_all();
762 dispatch_action(cx, CodeEditorAction::TextDidChange);
763 keyboard_moved_cursor = true;
764 }
765 }
766 Hit::KeyDown(KeyEvent {
767 key_code: KeyCode::KeyZ,
768 modifiers:
769 KeyModifiers {
770 logo: true,
771 shift: true,
772 ..
773 },
774 ..
775 }) => {
776 if session.redo() {
777 self.redraw(cx);
778 dispatch_action(cx, CodeEditorAction::TextDidChange);
779 keyboard_moved_cursor = true;
780 }
781 }
782 Hit::FingerDown(FingerDownEvent {
783 abs,
784 modifiers: KeyModifiers {alt, ..},
785 tap_count,
786 ..
787 }) => {
788 cx.set_key_focus(self.scroll_bars.area());
789 if let Some((cursor, affinity)) = self.pick(session, abs) {
790 if alt {
791 session.add_selection(cursor, affinity, tap_count);
792 } else {
793 session.set_selection(cursor, affinity, tap_count);
794 }
795 self.redraw(cx);
796 }
797 self.reset_cursor_blinker(cx);
798 self.keep_cursor_in_view = KeepCursorInView::Always(abs, cx.new_next_frame());
799 }
800 Hit::FingerUp(_) => {
801 self.reset_cursor_blinker(cx);
802 self.keep_cursor_in_view = KeepCursorInView::Off;
803 }
804 Hit::FingerHoverIn(_) | Hit::FingerHoverOver(_) => {
805 cx.set_cursor(MouseCursor::Text);
806 }
807 Hit::FingerMove(FingerMoveEvent {abs, ..}) => {
808 self.reset_cursor_blinker(cx);
809 if let KeepCursorInView::Always(old_abs, _) = &mut self.keep_cursor_in_view {
810 *old_abs = abs;
811 }
812 cx.set_cursor(MouseCursor::Text);
813 if let Some((cursor, affinity)) = self.pick(session, abs) {
814 session.move_to(cursor, affinity);
815 self.redraw(cx);
817 }
818 }
819 _ => {}
820 }
821 if keyboard_moved_cursor{
822 self.keep_cursor_in_view = KeepCursorInView::Once;
823 self.reset_cursor_blinker(cx);
824 }
825 if let KeepCursorInView::Always(abs, next) = &mut self.keep_cursor_in_view {
826 if next.is_event(event).is_some() {
827 *next = cx.new_next_frame();
828 let abs = *abs;
829 if let Some((cursor, affinity)) = self.pick(session, abs) {
830 session.move_to(cursor, affinity);
831 self.redraw(cx);
832 }
833 }
834 }
835 }
836
837 fn draw_gutter(&mut self, cx: &mut Cx2d, session: &Session) {
838 let mut line_index = self.line_start;
839 let mut origin_y = session.layout().line(self.line_start).y();
840 let mut buf = String::new();
841 for element in session
842 .layout()
843 .block_elements(self.line_start, self.line_end)
844 {
845 match element {
846 BlockElement::Line {line, ..} => {
847 self.draw_gutter.font_scale = line.scale();
848 buf.clear();
849 let _ = write!(buf,"{: >4}", line_index + 1);
850 self.draw_gutter.draw_abs(
851 cx,
852 DVec2 {
853 x: 0.0,
854 y: origin_y,
855 } *self.cell_size
856 + self.gutter_rect.pos
857 + dvec2((1.0-line.scale()) * -self.cell_size.x + self.gutter_rect.size.x - line.scale() * self.gutter_rect.size.x,0.0),
858 &buf
859 );
860 line_index += 1;
861 origin_y += line.height();
862 }
863 BlockElement::Widget(widget) => {
864 origin_y += widget.height;
865 }
866 }
867 }
868 }
869
870 fn draw_text_layer(&mut self, cx: &mut Cx2d, session: &Session) {
871 let highlighted_delimiter_positions = session.highlighted_delimiter_positions();
872 let mut line_index = self.line_start;
873 let mut origin_y = session.layout().line(self.line_start).y();
874 for element in session
875 .layout()
876 .block_elements(self.line_start, self.line_end)
877 {
878 match element {
879 BlockElement::Line {line, ..} => {
880 self.draw_text.font_scale = line.scale();
881 let mut token_iter = line.tokens().iter().copied();
882 let mut token_slot = token_iter.next();
883 let mut row_index = 0;
884 let mut byte_index = 0;
885 let mut column_index = 0;
886 for element in line.wrapped_elements() {
887 match element {
888 WrappedElement::Text {
889 is_inlay: false,
890 mut text,
891 } => {
892 while !text.is_empty() {
893 let token = match token_slot {
894 Some(token) => {
895 if text.len() < token.len {
896 token_slot = Some(Token {
897 len: token.len - text.len(),
898 kind: token.kind,
899 });
900 Token {
901 len: text.len(),
902 kind: token.kind,
903 }
904 } else {
905 token_slot = token_iter.next();
906 token
907 }
908 }
909 None => Token {
910 len: text.len(),
911 kind: TokenKind::Unknown,
912 },
913 };
914 let (text_0, text_1) = text.split_at(token.len);
915 text = text_1;
916 self.draw_text.color = match token.kind {
917 TokenKind::Unknown => self.token_colors.unknown,
918 TokenKind::BranchKeyword => {
919 self.token_colors.branch_keyword
920 }
921 TokenKind::Comment => self.token_colors.comment,
922 TokenKind::Constant => self.token_colors.constant,
923 TokenKind::Delimiter => self.token_colors.delimiter,
924 TokenKind::Identifier => self.token_colors.identifier,
925 TokenKind::LoopKeyword => self.token_colors.loop_keyword,
926 TokenKind::Number => self.token_colors.number,
927 TokenKind::OtherKeyword => self.token_colors.other_keyword,
928 TokenKind::Punctuator => self.token_colors.punctuator,
929 TokenKind::String => self.token_colors.string,
930 TokenKind::Typename => self.token_colors.typename,
931 TokenKind::Whitespace => self.token_colors.whitespace,
932 };
933 self.draw_text.outline = 0.0;
934 if let TokenKind::Delimiter = token.kind {
935 if highlighted_delimiter_positions.contains(&Position {
936 line_index,
937 byte_index,
938 }) {
939 self.draw_text.outline = 1.0;
940 self.draw_text.color = self.token_colors.delimiter_highlight
941 }
942 }
943 for grapheme in text_0.graphemes() {
944 let (x, y) = line
945 .grid_to_normalized_position(row_index, column_index);
946 self.draw_text.draw_abs(
947 cx,
948 DVec2 {x, y: origin_y + y} *self.cell_size
949 + self.viewport_rect.pos,
950 grapheme,
951 );
952 byte_index += grapheme.len();
953 column_index += grapheme.column_count();
954 }
955 }
956 }
957 WrappedElement::Text {
958 is_inlay: true,
959 text,
960 } => {
961 let (x, y) =
962 line.grid_to_normalized_position(row_index, column_index);
963 self.draw_text.draw_abs(
964 cx,
965 DVec2 {x, y: origin_y + y} *self.cell_size
966 + self.viewport_rect.pos,
967 text,
968 );
969 column_index += text.column_count();
970 }
971 WrappedElement::Widget(widget) => {
972 column_index += widget.column_count;
973 }
974 WrappedElement::Wrap => {
975 column_index = line.wrap_indent_column_count();
976 row_index += 1;
977 }
978 }
979 }
980 line_index += 1;
981 origin_y += line.height();
982 }
983 BlockElement::Widget(widget) => {
984 origin_y += widget.height;
985 }
986 }
987 }
988 }
989
990 fn draw_indent_guide_layer(&mut self, cx: &mut Cx2d<'_>, session: &Session) {
991 let mut origin_y = session.layout().line(self.line_start).y();
992 for element in session
993 .layout()
994 .block_elements(self.line_start, self.line_end)
995 {
996 let Settings {
997 tab_column_count,
998 ..
999 } = **session.settings();
1000 match element {
1001 BlockElement::Line {line, ..} => {
1002 for row_index in 0..line.row_count() {
1003 for column_index in
1004 (0..line.indent_column_count()).step_by(tab_column_count)
1005 {
1006 let (x, y) = line.grid_to_normalized_position(row_index, column_index);
1007 self.draw_indent_guide.draw_abs(
1008 cx,
1009 Rect {
1010 pos: DVec2 {x, y: origin_y + y} *self.cell_size
1011 + self.viewport_rect.pos,
1012 size: DVec2 {
1013 x: 2.0,
1014 y: line.scale() * self.cell_size.y,
1015 },
1016 },
1017 );
1018 }
1019 }
1020 origin_y += line.height();
1021 }
1022 BlockElement::Widget(widget) => {
1023 origin_y += widget.height;
1024 }
1025 }
1026 }
1027 }
1028
1029 fn draw_decoration_layer(&mut self, cx: &mut Cx2d<'_>, session: &Session) {
1030 let mut active_decoration = None;
1031 let decorations = session.document().decorations();
1032 let mut decorations = decorations.iter();
1033 while decorations.as_slice().first().map_or(false, | decoration | {
1034 decoration.end().line_index < self.line_start
1035 }) {
1036 decorations.next().unwrap();
1037 }
1038 if decorations.as_slice().first().map_or(false, | decoration | {
1039 decoration.start().line_index < self.line_start
1040 }) {
1041 active_decoration = Some(ActiveDecoration {
1042 decoration: *decorations.next().unwrap(),
1043 start_x: 0.0,
1044 });
1045 }
1046 DrawDecorationLayer {
1047 code_editor: self,
1048 active_decoration,
1049 decorations,
1050 }
1051 .draw_decoration_layer(cx, session)
1052 }
1053
1054 fn draw_selection_layer(&mut self, cx: &mut Cx2d<'_>, session: &Session) {
1055 let mut active_selection = None;
1056 let selections = session.selections();
1057 let mut selections = selections.iter();
1058 while selections.as_slice().first().map_or(false, | selection | {
1059 selection.end().line_index < self.line_start
1060 }) {
1061 selections.next().unwrap();
1062 }
1063 if selections.as_slice().first().map_or(false, | selection | {
1064 selection.start().line_index < self.line_start
1065 }) {
1066 active_selection = Some(ActiveSelection {
1067 selection: *selections.next().unwrap(),
1068 start_x: 0.0,
1069 });
1070 }
1071 DrawSelectionLayer {
1072 code_editor: self,
1073 active_selection,
1074 selections,
1075 }
1076 .draw_selection_layer(cx, session)
1077 }
1078
1079 fn pick(&self, session: &Session, position: DVec2) -> Option<(Position, Affinity)> {
1080 let position = (position - self.viewport_rect.pos) / self.cell_size;
1081 let mut line_index = session.layout().find_first_line_ending_after_y(position.y);
1082 let mut origin_y = session.layout().line(line_index).y();
1083 for block in session.layout().block_elements(line_index, line_index + 1) {
1084 match block {
1085 BlockElement::Line {
1086 is_inlay: false,
1087 line,
1088 } => {
1089 let mut byte_index = 0;
1090 let mut row_index = 0;
1091 let mut column_index = 0;
1092 for element in line.wrapped_elements() {
1093 match element {
1094 WrappedElement::Text {
1095 is_inlay: false,
1096 text,
1097 } => {
1098 for grapheme in text.graphemes() {
1099 let (start_x, y) =
1100 line.grid_to_normalized_position(row_index, column_index);
1101 let start_y = origin_y + y;
1102 let (end_x, _) = line.grid_to_normalized_position(
1103 row_index,
1104 column_index + grapheme.column_count(),
1105 );
1106 let end_y = start_y + line.scale();
1107 if (start_y..=end_y).contains(&position.y) {
1108 let mid_x = (start_x + end_x) / 2.0;
1109 if (start_x..=mid_x).contains(&position.x) {
1110 return Some((
1111 Position {
1112 line_index,
1113 byte_index,
1114 },
1115 Affinity::After,
1116 ));
1117 }
1118 if (mid_x..=end_x).contains(&position.x) {
1119 return Some((
1120 Position {
1121 line_index,
1122 byte_index: byte_index + grapheme.len(),
1123 },
1124 Affinity::Before,
1125 ));
1126 }
1127 }
1128 byte_index += grapheme.len();
1129 column_index += grapheme.column_count();
1130 }
1131 }
1132 WrappedElement::Text {
1133 is_inlay: true,
1134 text,
1135 } => {
1136 let (start_x, y) =
1137 line.grid_to_normalized_position(row_index, column_index);
1138 let start_y = origin_y + y;
1139 let (end_x, _) = line.grid_to_normalized_position(
1140 row_index,
1141 column_index + text.column_count(),
1142 );
1143 let end_y = origin_y + line.scale();
1144 if (start_y..=end_y).contains(&position.y)
1145 && (start_x..=end_x).contains(&position.x)
1146 {
1147 return Some((
1148 Position {
1149 line_index,
1150 byte_index,
1151 },
1152 Affinity::Before,
1153 ));
1154 }
1155 column_index += text.column_count();
1156 }
1157 WrappedElement::Widget(widget) => {
1158 column_index += widget.column_count;
1159 }
1160 WrappedElement::Wrap => {
1161 let (_, y) =
1162 line.grid_to_normalized_position(row_index, column_index);
1163 let start_y = origin_y + y;
1164 let end_y = start_y + line.scale();
1165 if (start_y..=end_y).contains(&position.y) {
1166 return Some((
1167 Position {
1168 line_index,
1169 byte_index,
1170 },
1171 Affinity::Before,
1172 ));
1173 }
1174 column_index = line.wrap_indent_column_count();
1175 row_index += 1;
1176 }
1177 }
1178 }
1179 let (_, y) = line.grid_to_normalized_position(row_index, column_index);
1180 let start_y = origin_y + y;
1181 let end_y = start_y + line.scale();
1182 if (start_y..=end_y).contains(&position.y) {
1183 return Some((
1184 Position {
1185 line_index,
1186 byte_index,
1187 },
1188 Affinity::After,
1189 ));
1190 }
1191 line_index += 1;
1192 origin_y += line.height();
1193 }
1194 BlockElement::Line {
1195 is_inlay: true,
1196 line,
1197 } => {
1198 let start_y = origin_y;
1199 let end_y = start_y + line.height();
1200 if (start_y..=end_y).contains(&position.y) {
1201 return Some((
1202 Position {
1203 line_index,
1204 byte_index: 0,
1205 },
1206 Affinity::Before,
1207 ));
1208 }
1209 origin_y += line.height();
1210 }
1211 BlockElement::Widget(widget) => {
1212 origin_y += widget.height;
1213 }
1214 }
1215 }
1216 None
1217 }
1218}
1219
1220#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1221pub enum CodeEditorAction {
1222 TextDidChange,
1223}
1224
1225struct DrawDecorationLayer<'a> {
1226 code_editor: &'a mut CodeEditor,
1227 active_decoration: Option<ActiveDecoration>,
1228 decorations: Iter<'a, Decoration>,
1229}
1230
1231impl<'a> DrawDecorationLayer<'a> {
1232 fn draw_decoration_layer(&mut self, cx: &mut Cx2d, session: &Session) {
1233 let mut line_index = self.code_editor.line_start;
1234 let mut origin_y = session.layout().line(line_index).y();
1235 for block in session
1236 .layout()
1237 .block_elements(self.code_editor.line_start, self.code_editor.line_end)
1238 {
1239 match block {
1240 BlockElement::Line {
1241 is_inlay: false,
1242 line,
1243 } => {
1244 let mut byte_index = 0;
1245 let mut row_index = 0;
1246 let mut column_index = 0;
1247 self.handle_event(
1248 cx,
1249 line_index,
1250 line,
1251 byte_index,
1252 Affinity::Before,
1253 origin_y,
1254 row_index,
1255 column_index,
1256 );
1257 for element in line.wrapped_elements() {
1258 match element {
1259 WrappedElement::Text {
1260 is_inlay: false,
1261 text,
1262 } => {
1263 for grapheme in text.graphemes() {
1264 self.handle_event(
1265 cx,
1266 line_index,
1267 line,
1268 byte_index,
1269 Affinity::After,
1270 origin_y,
1271 row_index,
1272 column_index,
1273 );
1274 byte_index += grapheme.len();
1275 column_index += grapheme.column_count();
1276 self.handle_event(
1277 cx,
1278 line_index,
1279 line,
1280 byte_index,
1281 Affinity::Before,
1282 origin_y,
1283 row_index,
1284 column_index,
1285 );
1286 }
1287 }
1288 WrappedElement::Text {
1289 is_inlay: true,
1290 text,
1291 } => {
1292 column_index += text.column_count();
1293 }
1294 WrappedElement::Widget(widget) => {
1295 column_index += widget.column_count;
1296 }
1297 WrappedElement::Wrap => {
1298 if self.active_decoration.is_some() {
1299 self.draw_decoration(
1300 cx,
1301 line,
1302 origin_y,
1303 row_index,
1304 column_index,
1305 );
1306 }
1307 column_index = line.wrap_indent_column_count();
1308 row_index += 1;
1309 }
1310 }
1311 }
1312 self.handle_event(
1313 cx,
1314 line_index,
1315 line,
1316 byte_index,
1317 Affinity::After,
1318 origin_y,
1319 row_index,
1320 column_index,
1321 );
1322 if self.active_decoration.is_some() {
1323 self.draw_decoration(cx, line, origin_y, row_index, column_index);
1324 }
1325 line_index += 1;
1326 origin_y += line.height();
1327 }
1328 BlockElement::Line {
1329 is_inlay: true,
1330 line,
1331 } => {
1332 origin_y += line.height();
1333 }
1334 BlockElement::Widget(widget) => {
1335 origin_y += widget.height;
1336 }
1337 }
1338 }
1339 }
1340
1341 fn handle_event(
1342 &mut self,
1343 cx: &mut Cx2d,
1344 line_index: usize,
1345 line: Line<'_>,
1346 byte_index: usize,
1347 affinity: Affinity,
1348 origin_y: f64,
1349 row_index: usize,
1350 column_index: usize,
1351 ) {
1352 let position = Position {
1353 line_index,
1354 byte_index,
1355 };
1356 if self.active_decoration.as_ref().map_or(false, | decoration | {
1357 decoration.decoration.end() == position && affinity == Affinity::Before
1358 }) {
1359 self.draw_decoration(cx, line, origin_y, row_index, column_index);
1360 self.active_decoration = None;
1361 }
1362 if self
1363 .decorations
1364 .as_slice()
1365 .first()
1366 .map_or(false, | decoration | {
1367 decoration.start() == position && affinity == Affinity::After
1368 })
1369 {
1370 let decoration = *self.decorations.next().unwrap();
1371 if !decoration.is_empty() {
1372 let (start_x, _) = line.grid_to_normalized_position(row_index, column_index);
1373 self.active_decoration = Some(ActiveDecoration {
1374 decoration,
1375 start_x,
1376 });
1377 }
1378 }
1379 }
1380
1381 fn draw_decoration(
1382 &mut self,
1383 cx: &mut Cx2d,
1384 line: Line<'_>,
1385 origin_y: f64,
1386 row_index: usize,
1387 column_index: usize,
1388 ) {
1389 let start_x = mem::take(&mut self.active_decoration.as_mut().unwrap().start_x);
1390 let (x, y) = line.grid_to_normalized_position(row_index, column_index);
1391 self.code_editor.draw_decoration.draw_abs(
1392 cx,
1393 Rect {
1394 pos: DVec2 {
1395 x: start_x,
1396 y: origin_y + y,
1397 } *self.code_editor.cell_size
1398 + self.code_editor.viewport_rect.pos,
1399 size: DVec2 {
1400 x: x - start_x,
1401 y: line.scale(),
1402 } *self.code_editor.cell_size,
1403 },
1404 );
1405 }
1406}
1407
1408struct ActiveDecoration {
1409 decoration: Decoration,
1410 start_x: f64,
1411}
1412
1413struct DrawSelectionLayer<'a> {
1414 code_editor: &'a mut CodeEditor,
1415 active_selection: Option<ActiveSelection>,
1416 selections: Iter<'a, Selection>,
1417}
1418
1419impl<'a> DrawSelectionLayer<'a> {
1420 fn draw_selection_layer(&mut self, cx: &mut Cx2d, session: &Session) {
1421 let mut line_index = self.code_editor.line_start;
1422 let mut origin_y = session.layout().line(line_index).y();
1423 for block in session
1424 .layout()
1425 .block_elements(self.code_editor.line_start, self.code_editor.line_end)
1426 {
1427 match block {
1428 BlockElement::Line {
1429 is_inlay: false,
1430 line,
1431 } => {
1432 let mut byte_index = 0;
1433 let mut row_index = 0;
1434 let mut column_index = 0;
1435 self.handle_event(
1436 cx,
1437 line_index,
1438 line,
1439 byte_index,
1440 Affinity::Before,
1441 origin_y,
1442 row_index,
1443 column_index,
1444 );
1445 for element in line.wrapped_elements() {
1446 match element {
1447 WrappedElement::Text {
1448 is_inlay: false,
1449 text,
1450 } => {
1451 for grapheme in text.graphemes() {
1452 self.handle_event(
1453 cx,
1454 line_index,
1455 line,
1456 byte_index,
1457 Affinity::After,
1458 origin_y,
1459 row_index,
1460 column_index,
1461 );
1462 byte_index += grapheme.len();
1463 column_index += grapheme.column_count();
1464 self.handle_event(
1465 cx,
1466 line_index,
1467 line,
1468 byte_index,
1469 Affinity::Before,
1470 origin_y,
1471 row_index,
1472 column_index,
1473 );
1474 }
1475 }
1476 WrappedElement::Text {
1477 is_inlay: true,
1478 text,
1479 } => {
1480 column_index += text.column_count();
1481 }
1482 WrappedElement::Widget(widget) => {
1483 column_index += widget.column_count;
1484 }
1485 WrappedElement::Wrap => {
1486 if self.active_selection.is_some() {
1487 self.draw_selection(
1488 cx,
1489 line,
1490 origin_y,
1491 row_index,
1492 column_index,
1493 );
1494 }
1495 column_index = line.wrap_indent_column_count();
1496 row_index += 1;
1497 }
1498 }
1499 }
1500 self.handle_event(
1501 cx,
1502 line_index,
1503 line,
1504 byte_index,
1505 Affinity::After,
1506 origin_y,
1507 row_index,
1508 column_index,
1509 );
1510 column_index += 1;
1511 if self.active_selection.is_some() {
1512 self.draw_selection(cx, line, origin_y, row_index, column_index);
1513 }
1514 line_index += 1;
1515 origin_y += line.height();
1516 }
1517 BlockElement::Line {
1518 is_inlay: true,
1519 line,
1520 } => {
1521 origin_y += line.height();
1522 }
1523 BlockElement::Widget(widget) => {
1524 origin_y += widget.height;
1525 }
1526 }
1527 }
1528 if self.active_selection.is_some() {
1529 self.code_editor.draw_selection.end(cx);
1530 }
1531 }
1532
1533 fn handle_event(
1534 &mut self,
1535 cx: &mut Cx2d,
1536 line_index: usize,
1537 line: Line<'_>,
1538 byte_index: usize,
1539 affinity: Affinity,
1540 origin_y: f64,
1541 row_index: usize,
1542 column_index: usize,
1543 ) {
1544 let position = Position {
1545 line_index,
1546 byte_index,
1547 };
1548 if self.active_selection.as_ref().map_or(false, | selection | {
1549 selection.selection.end() == position && selection.selection.end_affinity() == affinity
1550 }) {
1551 self.draw_selection(cx, line, origin_y, row_index, column_index);
1552 self.code_editor.draw_selection.end(cx);
1553 let selection = self.active_selection.take().unwrap().selection;
1554 if selection.cursor.position == position && selection.cursor.affinity == affinity {
1555 self.draw_cursor(cx, line, origin_y, row_index, column_index);
1556 }
1557 }
1558 if self
1559 .selections
1560 .as_slice()
1561 .first()
1562 .map_or(false, | selection | {
1563 selection.start() == position && selection.start_affinity() == affinity
1564 })
1565 {
1566 let selection = *self.selections.next().unwrap();
1567 if selection.cursor.position == position && selection.cursor.affinity == affinity {
1568 self.draw_cursor(cx, line, origin_y, row_index, column_index);
1569 }
1570 if !selection.is_empty() {
1571 let (start_x, _) = line.grid_to_normalized_position(row_index, column_index);
1572 self.active_selection = Some(ActiveSelection {selection, start_x});
1573 }
1574 self.code_editor.draw_selection.begin();
1575 }
1576 }
1577
1578 fn draw_selection(
1579 &mut self,
1580 cx: &mut Cx2d,
1581 line: Line<'_>,
1582 origin_y: f64,
1583 row_index: usize,
1584 column_index: usize,
1585 ) {
1586 let start_x = mem::take(&mut self.active_selection.as_mut().unwrap().start_x);
1587 let (x, y) = line.grid_to_normalized_position(row_index, column_index);
1588 self.code_editor.draw_selection.draw(
1589 cx,
1590 Rect {
1591 pos: DVec2 {
1592 x: start_x,
1593 y: origin_y + y,
1594 } *self.code_editor.cell_size
1595 + self.code_editor.viewport_rect.pos,
1596 size: DVec2 {
1597 x: x - start_x,
1598 y: line.scale(),
1599 } *self.code_editor.cell_size,
1600 },
1601 );
1602 }
1603
1604 fn draw_cursor(
1605 &mut self,
1606 cx: &mut Cx2d<'_>,
1607 line: Line<'_>,
1608 origin_y: f64,
1609 row_index: usize,
1610 column_index: usize,
1611 ) {
1612 let (x, y) = line.grid_to_normalized_position(row_index, column_index);
1613
1614 self.code_editor.draw_cursor_bg.draw_abs(cx, Rect {
1615 pos: DVec2 {
1616 x:self.code_editor.unscrolled_rect.pos.x,
1617 y: (origin_y + y)*self.code_editor.cell_size.y+ self.code_editor.viewport_rect.pos.y
1618 },
1619 size: DVec2 {
1620 x: self.code_editor.unscrolled_rect.size.x,
1621 y: line.scale() *self.code_editor.cell_size.y,
1622 },
1623 });
1624
1625 self.code_editor.draw_cursor.draw_abs(
1626 cx,
1627 Rect {
1628 pos: DVec2 {x, y: origin_y + y} *self.code_editor.cell_size
1629 + self.code_editor.viewport_rect.pos,
1630 size: DVec2 {
1631 x: 2.0,
1632 y: line.scale() * self.code_editor.cell_size.y,
1633 },
1634 },
1635 );
1636 }
1637}
1638
1639struct ActiveSelection {
1640 selection: Selection,
1641 start_x: f64,
1642}
1643
1644#[derive(Live, LiveHook)]
1645struct TokenColors {
1646 #[live]
1647 unknown: Vec4,
1648 #[live]
1649 branch_keyword: Vec4,
1650 #[live]
1651 comment: Vec4,
1652 #[live]
1653 constant: Vec4,
1654 #[live]
1655 delimiter: Vec4,
1656 #[live]
1657 delimiter_highlight: Vec4,
1658 #[live]
1659 identifier: Vec4,
1660 #[live]
1661 loop_keyword: Vec4,
1662 #[live]
1663 number: Vec4,
1664 #[live]
1665 other_keyword: Vec4,
1666 #[live]
1667 punctuator: Vec4,
1668 #[live]
1669 string: Vec4,
1670 #[live]
1671 typename: Vec4,
1672 #[live]
1673 whitespace: Vec4,
1674}
1675
1676#[derive(Live, LiveHook)]
1677#[repr(C)]
1678pub struct DrawIndentGuide {
1679 #[deref]
1680 draw_super: DrawQuad,
1681 #[live]
1682 color: Vec4,
1683}
1684
1685#[derive(Live, LiveHook)]
1686struct DrawDecoration {
1687 #[deref]
1688 draw_super: DrawQuad,
1689}
1690
1691#[derive(Live, LiveHook)]
1692#[repr(C)]
1693struct DrawSelection {
1694 #[deref]
1695 draw_super: DrawQuad,
1696 #[live]
1697 prev_x: f32,
1698 #[live]
1699 prev_w: f32,
1700 #[live]
1701 next_x: f32,
1702 #[live]
1703 next_w: f32,
1704 #[rust]
1705 prev_prev_rect: Option<Rect>,
1706 #[rust]
1707 prev_rect: Option<Rect>,
1708}
1709
1710impl DrawSelection {
1711 fn begin(&mut self) {
1712 debug_assert!(self.prev_rect.is_none());
1713 }
1714
1715 fn end(&mut self, cx: &mut Cx2d) {
1716 self.draw_rect_internal(cx, None);
1717 self.prev_prev_rect = None;
1718 self.prev_rect = None;
1719 }
1720
1721 fn draw(&mut self, cx: &mut Cx2d, rect: Rect) {
1722 self.draw_rect_internal(cx, Some(rect));
1723 self.prev_prev_rect = self.prev_rect;
1724 self.prev_rect = Some(rect);
1725 }
1726
1727 fn draw_rect_internal(&mut self, cx: &mut Cx2d, rect: Option<Rect>) {
1728 if let Some(prev_rect) = self.prev_rect {
1729 if let Some(prev_prev_rect) = self.prev_prev_rect {
1730 self.prev_x = prev_prev_rect.pos.x as f32;
1731 self.prev_w = prev_prev_rect.size.x as f32;
1732 } else {
1733 self.prev_x = 0.0;
1734 self.prev_w = 0.0;
1735 }
1736 if let Some(rect) = rect {
1737 self.next_x = rect.pos.x as f32;
1738 self.next_w = rect.size.x as f32;
1739 } else {
1740 self.next_x = 0.0;
1741 self.next_w = 0.0;
1742 }
1743 self.draw_abs(cx, prev_rect);
1744 }
1745 }
1746}