makepad_code_editor/
code_editor.rs

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