makepad_code_editor/
code_editor.rs

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           // draw_depth: 0.0,
121            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           // draw_depth: 1.0,
143            color: #5,
144        }
145        draw_decoration: {
146          //  draw_depth: 2.0,
147        }
148        draw_selection: {
149           // draw_depth: 3.0,
150        }
151        
152        draw_cursor: {
153          //  draw_depth: 4.0,
154            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        // This needs to be called first to ensure the session is up to date.
341        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                // make a cursor bounding box
357                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                // only scroll into
361                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                // lets get the on screen position
368                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                // ok so we want to keep cursor pos at the same screen position
390                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                //self.keep_cursor_in_view = KeepCursorInView::Locked(cursor_pos);
395            }
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                //self.keep_cursor_in_view = KeepCursorInView::Locked(cursor_pos);
406            }
407            KeepCursorInView::JumpToPosition => {
408                // alright so we need to make sure that cursor_pos
409                // is in view.
410                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        // Get the last added selection.
484        // Get the normalized cursor position. To go from normalized to screen position, multiply by
485        // the cell size, then shift by the viewport origin.
486        
487        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                    // alright how are we going to do scrolling
816                    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}