makepad_widget/
texteditor.rs

1use makepad_render::*;
2use crate::scrollview::*;
3use crate::textbuffer::*;
4use crate::textcursor::*;
5use crate::widgetstyle::*;
6use crate::scrollshadow::*;
7
8#[derive(Clone)]
9pub struct TextEditor {
10    pub view: ScrollView,
11    pub view_layout: Layout,
12    pub bg: Quad,
13    pub gutter_bg: Quad,
14    pub cursor: Quad,
15    pub selection: Quad,
16    pub token_highlight: Quad,
17    //pub select_highlight: Quad,
18    pub cursor_row: Quad,
19    pub paren_pair: Quad,
20    pub indent_lines: Quad,
21    pub shadow: ScrollShadow,
22    pub message_marker: Quad,
23    pub text: Text,
24    pub line_number_text: Text,
25    pub cursors: TextCursorSet,
26    
27    //pub base_font_size: f32,
28    pub open_font_scale: f32,
29    pub folded_font_scale: f32,
30    pub line_number_width: f32,
31    pub line_number_click_margin: f32,
32    pub draw_line_numbers: bool,
33    pub top_padding: f32,
34    //pub colors: CodeEditorColors,
35    pub cursor_blink_speed: f64,
36    pub _undo_id: u64,
37    pub highlight_area_on: bool,
38    
39    pub mark_unmatched_parens: bool,
40    pub draw_cursor_row: bool,
41    pub folding_depth: usize,
42    pub colors: CodeEditorColors,
43    
44    pub read_only: bool,
45    pub multiline: bool,
46    
47    //pub _bg_area: Area,
48    pub _scroll_pos_on_load: Option<Vec2>,
49    pub _jump_to_offset: bool,
50    pub _view_area: Area,
51    pub _highlight_area: Area,
52    pub _text_inst: Option<AlignedInstance>,
53    pub _line_number_inst: Option<AlignedInstance>,
54    pub _line_number_chunk: Vec<char>,
55    pub _text_area: Area,
56    pub _scroll_pos: Vec2,
57    pub _last_finger_move: Option<Vec2>,
58    pub _paren_stack: Vec<ParenItem>,
59    pub _indent_stack: Vec<(Color, f32)>,
60    pub _indent_id_alloc: f32,
61    pub _indent_line_inst: Option<InstanceArea>,
62    pub _bg_inst: Option<InstanceArea>,
63    pub _last_indent_color: Color,
64    
65    pub _line_geometry: Vec<LineGeom>,
66    pub _anim_select: Vec<AnimSelect>,
67    pub _visible_lines: usize,
68    
69    pub _select_scroll: Option<SelectScroll>,
70    pub _grid_select_corner: Option<TextPos>,
71    pub _is_row_select: bool,
72    pub _line_chunk: Vec<(f32, char)>,
73    
74    pub _highlight_selection: Vec<char>,
75    pub _highlight_token: Vec<char>,
76    pub _last_cursor_pos: TextPos,
77    
78    pub _anim_font_scale: f32,
79    pub _line_largest_font: f32,
80    pub _anim_folding: AnimFolding,
81    
82    pub _monospace_size: Vec2,
83    pub _monospace_base: Vec2,
84    
85    pub _tokens_on_line: usize,
86    pub _line_was_folded: bool,
87    //pub _line_was_visible: bool,
88    pub _final_fill_height: f32,
89    pub _draw_cursors: DrawCursors,
90    pub _draw_search: DrawCursors,
91    pub _draw_messages: DrawCursors,
92    
93    pub _cursor_blink_timer: Timer,
94    pub _cursor_blink_flipflop: f32,
95    pub _cursor_area: Area,
96    pub _highlight_visibility: f32,
97    
98    pub _last_tabs: usize,
99    pub _newline_tabs: usize,
100    
101    pub _jump_to_offset_id: u64,
102    
103    pub _last_lag_mutation_id: u64
104}
105
106#[derive(Clone, PartialEq)]
107pub enum TextEditorEvent {
108    None,
109    AutoFormat,
110    LagChange,
111    Change
112}
113
114#[derive(Default, Clone)]
115pub struct CodeEditorColors {
116    indent_line_unknown: Color,
117    indent_line_fn: Color,
118    indent_line_typedef: Color,
119    indent_line_looping: Color,
120    indent_line_flow: Color,
121    paren_pair_match: Color,
122    paren_pair_fail: Color,
123    marker_error: Color,
124    marker_warning: Color,
125    marker_log: Color,
126    line_number_normal: Color,
127    line_number_highlight: Color,
128    whitespace: Color,
129    keyword: Color,
130    flow: Color,
131    looping: Color,
132    identifier: Color,
133    call: Color,
134    type_name: Color,
135    theme_name: Color,
136    string: Color,
137    number: Color,
138    comment: Color,
139    doc_comment: Color,
140    paren_d1: Color,
141    paren_d2: Color,
142    operator: Color,
143    delimiter: Color,
144    unexpected: Color,
145    warning: Color,
146    error: Color,
147    defocus: Color,
148}
149
150impl TextEditor {
151    
152    pub fn proto(cx: &mut Cx) -> Self {
153        Self {
154            read_only: false,
155            multiline: true,
156            cursors: TextCursorSet::new(),
157            indent_lines: Quad {
158                z: 0.001,
159                ..Quad::proto(cx)
160            },
161            view: ScrollView::proto(cx),
162            bg: Quad ::proto(cx),
163            shadow: ScrollShadow {
164                z: 10.,
165                ..ScrollShadow::proto(cx)
166            },
167            gutter_bg: Quad {
168                z: 9.0,
169                ..Quad::proto(cx)
170            },
171            colors: CodeEditorColors::default(),
172            selection: Quad {
173                z: 0.,
174                ..Quad::proto(cx)
175            },
176            token_highlight: Quad::proto(cx),
177            cursor: Quad::proto(cx),
178            cursor_row: Quad::proto(cx),
179            paren_pair: Quad::proto(cx),
180            message_marker: Quad::proto(cx),
181            //code_icon: CodeIcon::proto(cx),
182            view_layout: Layout::default(),
183            text: Text {
184                z: 2.00,
185                wrapping: Wrapping::Line,
186                ..Text::proto(cx)
187            },
188            line_number_text: Text {
189                z: 9.,
190                wrapping: Wrapping::Line,
191                ..Text::proto(cx)
192            },
193            //base_font_size: 8.0,
194            open_font_scale: 1.0,
195            folded_font_scale: 0.07,
196            line_number_width: 45.,
197            line_number_click_margin: 10.,
198            draw_line_numbers: true,
199            cursor_blink_speed: 0.5,
200            top_padding: 27.,
201            mark_unmatched_parens: true,
202            highlight_area_on: true,
203            draw_cursor_row: true,
204            _scroll_pos_on_load: None,
205            _jump_to_offset: true,
206            _monospace_size: Vec2::default(),
207            _monospace_base: Vec2::default(),
208            _last_finger_move: None,
209            _tokens_on_line: 0,
210            _line_was_folded: false,
211            //_line_was_visible: false,
212            _scroll_pos: Vec2::default(),
213            _visible_lines: 0,
214            _undo_id: 0,
215            
216            
217            _line_geometry: Vec::new(),
218            
219            _anim_select: Vec::new(),
220            _grid_select_corner: None,
221            _is_row_select: false,
222            _view_area: Area::Empty,
223            //_bg_area: Area::Empty,
224            _highlight_area: Area::Empty,
225            _highlight_visibility: 0.,
226            _bg_inst: None,
227            _text_inst: None,
228            _text_area: Area::Empty,
229            _line_number_inst: None,
230            _line_number_chunk: Vec::new(),
231            
232            _anim_font_scale: 1.0,
233            _line_largest_font: 0.,
234            _final_fill_height: 0.,
235            folding_depth: 2,
236            _anim_folding: AnimFolding {
237                state: AnimFoldingState::Open,
238                focussed_line: 0,
239                did_animate: false,
240            },
241            _select_scroll: None,
242            _draw_cursors: DrawCursors::new(),
243            _draw_search: DrawCursors::new(),
244            _draw_messages: DrawCursors::new(),
245            
246            _paren_stack: Vec::new(),
247            _indent_stack: Vec::new(),
248            _indent_id_alloc: 0.0,
249            _indent_line_inst: None,
250            
251            _line_chunk: Vec::new(),
252            _highlight_selection: Vec::new(),
253            _highlight_token: Vec::new(),
254            _last_cursor_pos: TextPos::zero(),
255            _last_indent_color: Color::default(),
256            
257            _cursor_blink_timer: Timer::empty(),
258            _cursor_blink_flipflop: 0.,
259            _cursor_area: Area::Empty,
260            _last_lag_mutation_id: 0,
261            _last_tabs: 0,
262            _newline_tabs: 0,
263            _jump_to_offset_id: 0
264        }
265    }
266    
267    pub fn gutter_width() -> FloatId {uid!()}
268    pub fn padding_top() -> FloatId {uid!()}
269    pub fn shadow_size() -> FloatId {uid!()}
270    
271    pub fn layout_bg() -> LayoutId {uid!()}
272    pub fn text_style_editor_text() -> TextStyleId {uid!()}
273    
274    pub fn color_bg() -> ColorId {uid!()}
275    pub fn color_gutter_bg() -> ColorId {uid!()}
276    
277    pub fn color_selection() -> ColorId {uid!()}
278    pub fn color_selection_defocus() -> ColorId {uid!()}
279    pub fn color_highlight() -> ColorId {uid!()}
280    pub fn color_cursor() -> ColorId {uid!()}
281    pub fn color_cursor_row() -> ColorId {uid!()}
282    
283    pub fn color_indent_line_unknown() -> ColorId {uid!()}
284    pub fn color_indent_line_fn() -> ColorId {uid!()}
285    pub fn color_indent_line_typedef() -> ColorId {uid!()}
286    pub fn color_indent_line_looping() -> ColorId {uid!()}
287    pub fn color_indent_line_flow() -> ColorId {uid!()}
288    pub fn color_paren_pair_match() -> ColorId {uid!()}
289    pub fn color_paren_pair_fail() -> ColorId {uid!()}
290    pub fn color_marker_error() -> ColorId {uid!()}
291    pub fn color_marker_warning() -> ColorId {uid!()}
292    pub fn color_marker_log() -> ColorId {uid!()}
293    pub fn color_line_number_normal() -> ColorId {uid!()}
294    pub fn color_line_number_highlight() -> ColorId {uid!()}
295    
296    pub fn color_whitespace() -> ColorId {uid!()}
297    pub fn color_keyword() -> ColorId {uid!()}
298    pub fn color_flow() -> ColorId {uid!()}
299    pub fn color_looping() -> ColorId {uid!()}
300    pub fn color_identifier() -> ColorId {uid!()}
301    pub fn color_call() -> ColorId {uid!()}
302    pub fn color_type_name() -> ColorId {uid!()}
303    pub fn color_theme_name() -> ColorId {uid!()}
304    pub fn color_string() -> ColorId {uid!()}
305    pub fn color_number() -> ColorId {uid!()}
306    pub fn color_comment() -> ColorId {uid!()}
307    pub fn color_doc_comment() -> ColorId {uid!()}
308    pub fn color_paren_d1() -> ColorId {uid!()}
309    pub fn color_paren_d2() -> ColorId {uid!()}
310    pub fn color_operator() -> ColorId {uid!()}
311    pub fn color_delimiter() -> ColorId {uid!()}
312    pub fn color_unexpected() -> ColorId {uid!()}
313    pub fn color_warning() -> ColorId {uid!()}
314    pub fn color_error() -> ColorId {uid!()}
315    pub fn color_defocus() -> ColorId {uid!()}
316
317    pub fn shader_bg() -> ShaderId {uid!()}
318    pub fn shader_indent_lines() -> ShaderId {uid!()}
319    pub fn shader_cursor() -> ShaderId {uid!()}
320    pub fn shader_selection() -> ShaderId {uid!()}
321    pub fn shader_paren_pair() -> ShaderId {uid!()}
322    pub fn shader_cursor_row() -> ShaderId {uid!()}
323    pub fn shader_token_highlight() -> ShaderId {uid!()}
324    pub fn shader_message_marker() -> ShaderId {uid!()}
325    
326    pub fn instance_indent_id() -> InstanceFloat {uid!()}
327    pub fn uniform_indent_sel() -> UniformFloat {uid!()}
328    pub fn uniform_cursor_blink() -> UniformFloat {uid!()}
329    pub fn instance_select_prev_x() -> InstanceFloat {uid!()}
330    pub fn instance_select_prev_w() -> InstanceFloat {uid!()}
331    pub fn instance_select_next_x() -> InstanceFloat {uid!()}
332    pub fn instance_select_next_w() -> InstanceFloat {uid!()}
333    pub fn uniform_highlight_visible() -> UniformFloat {uid!()}
334    pub fn instance_shadow_dir() -> InstanceFloat {uid!()}
335    
336    pub fn style(cx: &mut Cx, _opt: &StyleOptions) {
337        
338        Self::shadow_size().set(cx, 6.0);
339        Self::gutter_width().set(cx, 45.0);
340        Self::padding_top().set(cx, 27.);
341        Self::text_style_editor_text().set(cx, Theme::text_style_fixed().get(cx));
342        
343        Self::shader_indent_lines().set(cx, Quad::def_quad_shader().compose(shader_ast !({
344            let indent_id: Self::instance_indent_id();
345            // uniforms
346            let indent_sel: Self::uniform_indent_sel();
347            fn pixel() -> vec4 {
348                let col = color;
349                let thickness = 0.8 + dpi_dilate * 0.5;
350                if indent_id == indent_sel {
351                    col *= vec4(1., 1., 1., 1.);
352                    thickness *= 1.3;
353                }
354                else {
355                    col *= vec4(0.75, 0.75, 0.75, 0.75);
356                }
357                df_viewport(pos * vec2(w, h));
358                df_move_to(1., -1.);
359                df_line_to(1., h + 1.);
360                return df_stroke(col, thickness);
361            }
362        })));
363        
364        Self::shader_cursor().set(cx, Quad::def_quad_shader().compose(shader_ast !({
365            let blink: Self::uniform_cursor_blink();
366            fn pixel() -> vec4 {
367                if blink<0.5 {
368                    return vec4(color.rgb * color.a, color.a)
369                }
370                else {
371                    return vec4(0., 0., 0., 0.);
372                }
373            }
374        })));
375        
376        Self::shader_selection().set(cx, Quad::def_quad_shader().compose(shader_ast !({
377            let prev_x: Self::instance_select_prev_x();
378            let prev_w: Self::instance_select_prev_w();
379            let next_x: Self::instance_select_next_x();
380            let next_w: Self::instance_select_next_w();
381            const gloopiness: float = 8.;
382            const border_radius: float = 2.;
383            
384            fn vertex() -> vec4 { // custom vertex shader because we widen the draweable area a bit for the gloopiness
385                let shift: vec2 = -draw_scroll.xy;
386                let clipped: vec2 = clamp(
387                    geom * vec2(w + 16., h) + vec2(x, y) + shift - vec2(8., 0.),
388                    draw_clip.xy,
389                    draw_clip.zw
390                );
391                pos = (clipped - shift - vec2(x, y)) / vec2(w, h);
392                return camera_projection * (camera_view * (view_transform * vec4(clipped.x, clipped.y, z + draw_zbias, 1.)));
393            }
394            
395            fn pixel() -> vec4 {
396                df_viewport(pos * vec2(w, h));
397                df_box(0., 0., w, h, border_radius);
398                if prev_w > 0. {
399                    df_box(prev_x, -h, prev_w, h, border_radius);
400                    df_gloop(gloopiness);
401                }
402                if next_w > 0. {
403                    df_box(next_x, h, next_w, h, border_radius);
404                    df_gloop(gloopiness);
405                }
406                //df_shape *= cos(pos.x*8.)+cos(pos.y*16.);
407                return df_fill(color);
408            }
409        })));
410        
411        Self::shader_paren_pair().set(cx, Quad::def_quad_shader().compose(shader_ast!({
412            fn pixel() -> vec4 {
413                df_viewport(pos * vec2(w, h));
414                //df_rect(0.,0.,w,h);
415                //df_rect(0.5,0.5,w-1.,h-1.);
416                //return df_stroke(color, 0.75 + dpi_dilate*0.75);
417                //df_rect(0.,h-1.-dpi_dilate,w,1.+dpi_dilate);
418                df_rect(0., h - 1.5 - dpi_dilate, w, 1.5 + dpi_dilate);
419                return df_fill(color);
420                //df_rect(0.01,0.,w,h);
421                //return df_fill(color);
422            }
423        })));
424        
425        Self::shader_cursor_row().set(cx, Quad::def_quad_shader().compose(shader_ast!({
426            fn pixel() -> vec4 {
427                df_viewport(pos * vec2(w, h));
428                df_rect(0., 0., w, h);
429                return df_fill(color);
430                /*
431                df_move_to(0.,0.5);
432                df_line_to(w,0.5);
433                df_move_to(0.,h-0.5);
434                df_line_to(w,h-0.5);
435                returndf_stroke(color,0.75+dpi_dilate*0.75);*/
436            }
437        })));
438        /*
439        Self::shader_select_highlight().set(cx,   Quad::def_quad_shader().compose(shader_ast!({
440            fn pixel() -> vec4 {
441                df_viewport(pos * vec2(w, h));
442                df_box(0.5, 0.5, w - 1., h - 1., 1.);
443                return df_fill(color);
444            }
445        })));*/
446        
447        Self::shader_token_highlight().set(cx, Quad::def_quad_shader().compose(shader_ast!({
448            let visible: Self::uniform_highlight_visible();
449            fn pixel() -> vec4 {
450                if visible<0.5 {
451                    return vec4(0., 0., 0., 0.)
452                }
453                df_viewport(pos * vec2(w, h));
454                df_box(0.5, 0.5, w - 1., h - 1., 1.);
455                return df_fill(color);
456            }
457        })));
458        
459        Self::shader_message_marker().set(cx, Quad::def_quad_shader().compose(shader_ast!({
460            fn pixel() -> vec4 {
461                let pos2 = vec2(pos.x, pos.y + 0.03 * sin(pos.x * w));
462                df_viewport(pos2 * vec2(w, h));
463                //df_rect(0.,0.,w,h);
464                df_move_to(0., h - 1.);
465                df_line_to(w, h - 1.);
466                return df_stroke(color, 0.8);
467            }
468        })));
469        
470        Self::shader_bg().set(cx, Quad::def_quad_shader().compose(shader_ast!({
471            fn pixel() -> vec4 {
472                return vec4(color.rgb * color.a, color.a);
473            }
474        })));
475    }
476    
477    pub fn apply_style(&mut self, cx: &mut Cx) {
478        // copy over colors
479        self.colors.indent_line_unknown = Self::color_indent_line_unknown().get(cx);
480        self.colors.indent_line_fn = Self::color_indent_line_fn().get(cx);
481        self.colors.indent_line_typedef = Self::color_indent_line_typedef().get(cx);
482        self.colors.indent_line_looping = Self::color_indent_line_looping().get(cx);
483        self.colors.indent_line_flow = Self::color_indent_line_flow().get(cx);
484        
485        self.colors.paren_pair_match = Self::color_paren_pair_match().get(cx);
486        self.colors.paren_pair_fail = Self::color_paren_pair_fail().get(cx);
487        self.colors.marker_error = Self::color_marker_error().get(cx);
488        self.colors.marker_warning = Self::color_marker_warning().get(cx);
489        self.colors.marker_log = Self::color_marker_log().get(cx);
490        self.colors.line_number_normal = Self::color_line_number_normal().get(cx);
491        self.colors.line_number_highlight = Self::color_line_number_highlight().get(cx);
492        self.colors.whitespace = Self::color_whitespace().get(cx);
493        self.colors.keyword = Self::color_keyword().get(cx);
494        self.colors.flow = Self::color_flow().get(cx);
495        self.colors.looping = Self::color_looping().get(cx);
496        self.colors.identifier = Self::color_identifier().get(cx);
497        self.colors.call = Self::color_call().get(cx);
498        self.colors.type_name = Self::color_type_name().get(cx);
499        self.colors.theme_name = Self::color_theme_name().get(cx);
500        self.colors.string = Self::color_string().get(cx);
501        self.colors.number = Self::color_number().get(cx);
502        self.colors.comment = Self::color_comment().get(cx);
503        self.colors.doc_comment = Self::color_doc_comment().get(cx);
504        self.colors.paren_d1 = Self::color_paren_d1().get(cx);
505        self.colors.paren_d2 = Self::color_paren_d2().get(cx);
506        self.colors.operator = Self::color_operator().get(cx);
507        self.colors.delimiter = Self::color_delimiter().get(cx);
508        self.colors.unexpected = Self::color_unexpected().get(cx);
509        self.colors.warning = Self::color_warning().get(cx);
510        self.colors.error = Self::color_error().get(cx);
511        self.colors.defocus = Self::color_defocus().get(cx);
512        self.bg.color = Self::color_bg().get(cx);
513        self.gutter_bg.color = Self::color_gutter_bg().get(cx);
514        
515        self.line_number_width = Self::gutter_width().get(cx);
516        self.top_padding = Self::padding_top().get(cx);
517        
518        self.selection.color = if self.has_key_focus(cx) {
519            Self::color_selection().get(cx)
520        }else {
521            Self::color_selection_defocus().get(cx)
522        };
523        self.token_highlight.color = Self::color_highlight().get(cx);
524        self.cursor.color = Self::color_cursor().get(cx);
525        self.cursor_row.color = Self::color_cursor_row().get(cx);
526        self.text.text_style = Self::text_style_editor_text().get(cx);
527        self.line_number_text.text_style = Self::text_style_editor_text().get(cx);
528
529        self.bg.shader = Self::shader_bg().get(cx);
530        self.indent_lines.shader = Self::shader_indent_lines().get(cx);
531        self.cursor.shader = Self::shader_cursor().get(cx);
532        self.selection.shader = Self::shader_selection().get(cx);
533        self.paren_pair.shader = Self::shader_paren_pair().get(cx);
534        self.cursor_row.shader = Self::shader_cursor_row().get(cx);
535        self.token_highlight.shader = Self::shader_token_highlight().get(cx);
536        self.message_marker.shader = Self::shader_message_marker().get(cx);
537    }
538    
539    fn reset_highlight_visible(&mut self, cx: &mut Cx) {
540        self._highlight_visibility = 0.0;
541        self._highlight_area.write_uniform_float(cx, Self::uniform_highlight_visible(), self._highlight_visibility);
542    }
543    
544    fn reset_cursor_blinker(&mut self, cx: &mut Cx) {
545        cx.stop_timer(&mut self._cursor_blink_timer);
546        self._cursor_blink_timer = cx.start_timer(self.cursor_blink_speed * 0.5, false);
547        self._cursor_blink_flipflop = 0.;
548        self._cursor_area.write_uniform_float(cx, Self::uniform_cursor_blink(), self._cursor_blink_flipflop);
549    }
550    
551    fn handle_finger_down(&mut self, cx: &mut Cx, fe: &FingerDownEvent, text_buffer: &mut TextBuffer) {
552        cx.set_down_mouse_cursor(MouseCursor::Text);
553        // give us the focus
554        self.set_key_focus(cx);
555        self._undo_id += 1;
556        
557        let offset;
558        //let scroll_pos = self._bg_area.get_scroll_pos(cx);
559        if fe.rel.x < self.line_number_width - self.line_number_click_margin {
560            offset = self.compute_offset_from_ypos(cx, fe.abs.y, text_buffer, false);
561            let range = text_buffer.get_nearest_line_range(offset);
562            self.cursors.set_last_clamp_range(range);
563            self._is_row_select = true;
564        }
565        else {
566            offset = self.text.find_closest_offset(cx, &self._text_area, fe.abs);
567            match fe.tap_count {
568                1 => {
569                },
570                2 => {
571                    if let Some((coffset, len)) = TextCursorSet::get_nearest_token_chunk(offset, &text_buffer) {
572                        self.cursors.set_last_clamp_range((coffset, len));
573                    }
574                },
575                3 => {
576                    if let Some((coffset, len)) = TextCursorSet::get_nearest_token_chunk(offset, &text_buffer) {
577                        //self.cursors.set_last_clamp_range((coffset, len));
578                        let (start, line_len) = text_buffer.get_nearest_line_range(offset);
579                        let mut chunk_offset = coffset;
580                        let mut chunk_len = len;
581                        if start < chunk_offset {
582                            chunk_len += chunk_offset - start;
583                            chunk_offset = start;
584                            if line_len > chunk_len {
585                                chunk_len = line_len;
586                            }
587                        }
588                        self.cursors.set_last_clamp_range((chunk_offset, chunk_len));
589                    }
590                    else {
591                        let range = text_buffer.get_nearest_line_range(offset);
592                        self.cursors.set_last_clamp_range(range);
593                    }
594                },
595                _ => {
596                    //let range = (0, text_buffer.calc_char_count());
597                    //self.cursors.set_last_clamp_range(range);
598                }
599            }
600            // ok so we should scan a range
601        }
602        
603        if fe.modifiers.shift {
604            if fe.modifiers.logo || fe.modifiers.control { // grid select
605                let pos = self.compute_grid_text_pos_from_abs(cx, fe.abs);
606                self._grid_select_corner = Some(self.cursors.grid_select_corner(pos, text_buffer));
607                self.cursors.grid_select(self._grid_select_corner.unwrap(), pos, text_buffer);
608                if self.cursors.set.len() == 0 {
609                    self.cursors.clear_and_set_last_cursor_head_and_tail(offset, text_buffer);
610                }
611            }
612            else { // simply place selection
613                self.cursors.clear_and_set_last_cursor_head(offset, text_buffer);
614            }
615        }
616        else { // cursor drag with possible add
617            if fe.modifiers.logo || fe.modifiers.control {
618                self.cursors.add_last_cursor_head_and_tail(offset, text_buffer);
619            }
620            else {
621                self.cursors.clear_and_set_last_cursor_head_and_tail(offset, text_buffer);
622            }
623        }
624        
625        self.view.redraw_view_area(cx);
626        self._last_finger_move = Some(fe.abs);
627        self.update_highlight(cx, text_buffer);
628        self.reset_cursor_blinker(cx);
629    }
630    
631    fn handle_finger_move(&mut self, cx: &mut Cx, fe: &FingerMoveEvent, text_buffer: &mut TextBuffer) {
632        let cursor_moved = if let Some(grid_select_corner) = self._grid_select_corner {
633            let pos = self.compute_grid_text_pos_from_abs(cx, fe.abs);
634            self.cursors.grid_select(grid_select_corner, pos, text_buffer)
635        }
636        else if self._is_row_select {
637            let offset = self.compute_offset_from_ypos(cx, fe.abs.y, text_buffer, true);
638            self.cursors.set_last_cursor_head(offset, text_buffer)
639        }
640        else {
641            let offset = self.text.find_closest_offset(cx, &self._text_area, fe.abs);
642            self.cursors.set_last_cursor_head(offset, text_buffer)
643        };
644        self._last_finger_move = Some(fe.abs);
645        // determine selection drag scroll dynamics
646        let repaint_scroll = self.check_select_scroll_dynamics(&fe);
647        if cursor_moved {
648            self.update_highlight(cx, text_buffer);
649        };
650        if repaint_scroll || cursor_moved {
651            self.view.redraw_view_area(cx);
652        }
653        if cursor_moved {
654            self.reset_cursor_blinker(cx);
655        }
656    }
657    
658    fn handle_finger_up(&mut self, cx: &mut Cx, _fe: &FingerUpEvent, text_buffer: &mut TextBuffer) {
659        self.cursors.clear_last_clamp_range();
660        self._select_scroll = None;
661        self._last_finger_move = None;
662        self._grid_select_corner = None;
663        self._is_row_select = false;
664        self.update_highlight(cx, text_buffer);
665        self.reset_cursor_blinker(cx);
666    }
667    
668    fn handle_key_down(&mut self, cx: &mut Cx, ke: &KeyEvent, text_buffer: &mut TextBuffer) {
669        let cursor_moved = match ke.key_code {
670            KeyCode::ArrowUp => {
671                if ke.modifiers.logo || ke.modifiers.control {
672                    false
673                }
674                else {
675                    if self._anim_folding.state.is_folded() && self.cursors.set.len() == 1 {
676                        // compute the nearest nonfolded line up
677                        let delta = self.compute_next_unfolded_line_up(text_buffer);
678                        self.cursors.move_up(delta, ke.modifiers.shift, text_buffer);
679                    }
680                    else {
681                        self.cursors.move_up(1, ke.modifiers.shift, text_buffer);
682                    }
683                    self._undo_id += 1;
684                    true
685                }
686            },
687            KeyCode::ArrowDown => {
688                if ke.modifiers.logo || ke.modifiers.control {
689                    false
690                }
691                else {
692                    if self._anim_folding.state.is_folded() && self.cursors.set.len() == 1 {
693                        // compute the nearest nonfolded line down
694                        let delta = self.compute_next_unfolded_line_down(text_buffer);
695                        self.cursors.move_down(delta, ke.modifiers.shift, text_buffer);
696                    }
697                    else {
698                        self.cursors.move_down(1, ke.modifiers.shift, text_buffer);
699                    }
700                    self._undo_id += 1;
701                    true
702                }
703            },
704            KeyCode::ArrowLeft => {
705                if ke.modifiers.logo || ke.modifiers.control { // token skipping
706                    self.cursors.move_left_nearest_token(ke.modifiers.shift, text_buffer)
707                }
708                else {
709                    self.cursors.move_left(1, ke.modifiers.shift, text_buffer);
710                }
711                self._undo_id += 1;
712                true
713            },
714            KeyCode::ArrowRight => {
715                if ke.modifiers.logo || ke.modifiers.control { // token skipping
716                    self.cursors.move_right_nearest_token(ke.modifiers.shift, text_buffer)
717                }
718                else {
719                    self.cursors.move_right(1, ke.modifiers.shift, text_buffer);
720                }
721                self._undo_id += 1;
722                true
723            },
724            KeyCode::PageUp => {
725                self.cursors.move_up(self._visible_lines.max(5) - 4, ke.modifiers.shift, text_buffer);
726                self._undo_id += 1;
727                true
728            },
729            KeyCode::PageDown => {
730                self.cursors.move_down(self._visible_lines.max(5) - 4, ke.modifiers.shift, text_buffer);
731                self._undo_id += 1;
732                true
733            },
734            KeyCode::Home => {
735                self.cursors.move_home(ke.modifiers.shift, text_buffer);
736                self._undo_id += 1;
737                true
738            },
739            KeyCode::End => {
740                self.cursors.move_end(ke.modifiers.shift, text_buffer);
741                self._undo_id += 1;
742                true
743            },
744            KeyCode::Backspace => {
745                if !self.read_only {
746                    self.cursors.backspace(text_buffer, self._undo_id);
747                    true
748                }
749                else {
750                    false
751                }
752            },
753            KeyCode::Delete => {
754                if !self.read_only {
755                    self.cursors.delete(text_buffer);
756                    true
757                }
758                else {
759                    false
760                }
761            },
762            KeyCode::KeyZ => {
763                if !self.read_only {
764                    if ke.modifiers.logo || ke.modifiers.control {
765                        if ke.modifiers.shift { // redo
766                            text_buffer.redo(true, &mut self.cursors);
767                            true
768                        }
769                        else { // undo
770                            text_buffer.undo(true, &mut self.cursors);
771                            true
772                        }
773                    }
774                    else {
775                        false
776                    }
777                }
778                else {
779                    false
780                }
781            },
782            KeyCode::KeyX => { // cut, the actual copy comes from the TextCopy event from the platform layer
783                if !self.read_only && (ke.modifiers.logo || ke.modifiers.control) { // cut
784                    self.cursors.replace_text("", text_buffer);
785                    true
786                }
787                else {
788                    false
789                }
790            },
791            KeyCode::KeyA => { // select all
792                if ke.modifiers.logo || ke.modifiers.control { // cut
793                    self.cursors.select_all(text_buffer);
794                    // don't scroll!
795                    self.view.redraw_view_area(cx);
796                    false
797                }
798                else {
799                    false
800                }
801            },
802            KeyCode::Alt => {
803                // how do we find the center line of the view
804                // its simply the top line
805                self.start_code_folding(cx, text_buffer);
806                false
807                //return CodeEditorEvent::FoldStart
808            },
809            KeyCode::Tab => {
810                if !self.read_only {
811                    if ke.modifiers.shift {
812                        self.cursors.remove_tab(text_buffer, 4);
813                    }
814                    else {
815                        self.cursors.insert_tab(text_buffer, "    ");
816                    }
817                    true
818                }
819                else {
820                    false
821                }
822            },
823            KeyCode::Return => {
824                if !self.read_only && self.multiline {
825                    if !ke.modifiers.control && !ke.modifiers.logo {
826                        self.cursors.insert_newline_with_indent(text_buffer);
827                    }
828                    true
829                }
830                else {
831                    false
832                }
833            },
834            _ => false
835        };
836        if cursor_moved {
837            self.update_highlight(cx, text_buffer);
838            self.scroll_last_cursor_visible(cx, text_buffer, 0.);
839            self.view.redraw_view_area(cx);
840            self.reset_cursor_blinker(cx);
841        }
842    }
843    
844    fn handle_text_input(&mut self, cx: &mut Cx, te: &TextInputEvent, text_buffer: &mut TextBuffer) {
845        if te.replace_last {
846            text_buffer.undo(false, &mut self.cursors);
847        }
848        
849        if !te.was_paste && te.input.len() == 1 {
850            match te.input.chars().next().unwrap() {
851                '(' => {
852                    self.cursors.insert_around("(", ")", text_buffer);
853                },
854                '[' => {
855                    self.cursors.insert_around("[", "]", text_buffer);
856                },
857                '{' => {
858                    self.cursors.insert_around("{", "}", text_buffer);
859                },
860                '"' => {
861                    self.cursors.insert_around("\"", "\"", text_buffer);
862                },
863                ')' => {
864                    self.cursors.overwrite_if_exists_or_deindent(")", 4, text_buffer);
865                },
866                ']' => {
867                    self.cursors.overwrite_if_exists_or_deindent("]", 4, text_buffer);
868                },
869                '}' => {
870                    self.cursors.overwrite_if_exists_or_deindent("}", 4, text_buffer);
871                },
872                _ => {
873                    self.cursors.replace_text(&te.input, text_buffer);
874                }
875            }
876            // lets insert a newline
877        }
878        else {
879            if !self.multiline {
880                let replaced = te.input.replace("\n", "");
881                self.cursors.replace_text(&replaced, text_buffer);
882            }
883            else {
884                self.cursors.replace_text(&te.input, text_buffer);
885            }
886        }
887        self.update_highlight(cx, text_buffer);
888        self.scroll_last_cursor_visible(cx, text_buffer, 0.);
889        self.view.redraw_view_area(cx);
890        self.reset_cursor_blinker(cx);
891        
892        cx.send_signal(text_buffer.signal, TextBuffer::status_data_update());
893        
894    }
895    
896    pub fn handle_text_editor(&mut self, cx: &mut Cx, event: &mut Event, text_buffer: &mut TextBuffer) -> TextEditorEvent {
897        if self.view.handle_scroll_bars(cx, event) {
898            if let Some(last_finger_move) = self._last_finger_move {
899                if let Some(grid_select_corner) = self._grid_select_corner {
900                    let pos = self.compute_grid_text_pos_from_abs(cx, last_finger_move);
901                    self.cursors.grid_select(grid_select_corner, pos, text_buffer);
902                }
903                else {
904                    let offset = self.text.find_closest_offset(cx, &self._text_area, last_finger_move);
905                    self.cursors.set_last_cursor_head(offset, text_buffer);
906                }
907            }
908            // the editor actually redraws on scroll, its because we don't actually
909            // generate the entire file as GPU text-buffer just the visible area
910            // in JS this wasn't possible performantly but in Rust its a breeze.
911            self.view.redraw_view_area(cx);
912        }
913        let last_mutation_id = text_buffer.mutation_id;
914        // global events
915        match event {
916            Event::Timer(te) => if self._cursor_blink_timer.is_timer(te) {
917                if self.has_key_focus(cx) {
918                    self._cursor_blink_timer = cx.start_timer(self.cursor_blink_speed, false);
919                }
920                // update the cursor uniform to blink it.
921                self._cursor_blink_flipflop = 1.0 - self._cursor_blink_flipflop;
922                self._undo_id += 1;
923                self._highlight_visibility = 1.0;
924                self._cursor_area.write_uniform_float(cx, Self::uniform_cursor_blink(), self._cursor_blink_flipflop);
925                if self.highlight_area_on {
926                    self._highlight_area.write_uniform_float(cx, Self::uniform_highlight_visible(), self._highlight_visibility);
927                }
928                // ok see if we changed.
929                if self._last_lag_mutation_id != text_buffer.mutation_id {
930                    let was_filechange = self._last_lag_mutation_id != 0;
931                    self._last_lag_mutation_id = text_buffer.mutation_id;
932                    if was_filechange {
933                        return TextEditorEvent::LagChange;
934                    }
935                }
936            },
937            Event::Signal(se) => if text_buffer.signal == se.signal {
938                if se.status == TextBuffer::status_loaded()
939                 || se.status == TextBuffer::status_message_update()
940                  || se.status == TextBuffer::status_data_update(){
941                    self.view.redraw_view_area(cx);
942                }
943                else if se.status == TextBuffer::status_jump_to_offset(){
944                    if !text_buffer.is_loaded {
945                        self._jump_to_offset = true;
946                    }
947                    else {
948                        self.do_jump_to_offset(cx, text_buffer);
949                    }
950                }
951                else if se.status == TextBuffer::status_keyboard_update(){
952                    if let Some(key_down) = &text_buffer.keyboard.key_down {
953                        match key_down {
954                            KeyCode::Alt => {
955                                self.start_code_folding(cx, text_buffer);
956                            },
957                            _ => ()
958                        }
959                    }
960                    if let Some(key_up) = &text_buffer.keyboard.key_up {
961                        match key_up {
962                            KeyCode::Alt => {
963                                self.start_code_unfolding(cx, text_buffer);
964                            },
965                            _ => ()
966                        }
967                    }
968                }
969            },
970            _ => ()
971        }
972        // editor local
973        match event.hits(cx, self.view.get_view_area(cx), HitOpt::default()) {
974            Event::KeyFocusLost(_kf) => {
975                self.view.redraw_view_area(cx)
976            },
977            Event::FingerDown(fe) => {
978                self.handle_finger_down(cx, &fe, text_buffer);
979            },
980            Event::FingerHover(_fe) => {
981                cx.set_hover_mouse_cursor(MouseCursor::Text);
982            },
983            Event::FingerUp(fe) => {
984                self.handle_finger_up(cx, &fe, text_buffer);
985            },
986            Event::FingerMove(fe) => {
987                self.handle_finger_move(cx, &fe, text_buffer);
988            },
989            Event::KeyDown(ke) => {
990                if ke.key_code == KeyCode::Return && (ke.modifiers.logo || ke.modifiers.control) {
991                    return TextEditorEvent::AutoFormat
992                }
993                self.handle_key_down(cx, &ke, text_buffer);
994            },
995            Event::KeyUp(ke) => {
996                match ke.key_code {
997                    KeyCode::Alt => {
998                        self.start_code_unfolding(cx, text_buffer);
999                    },
1000                    _ => (),
1001                }
1002                self.reset_cursor_blinker(cx);
1003            },
1004            Event::TextInput(te) => {
1005                if !self.read_only {
1006                    self.handle_text_input(cx, &te, text_buffer);
1007                }
1008            },
1009            Event::TextCopy(_) => match event { // access the original event
1010                Event::TextCopy(req) => {
1011                    req.response = Some(self.cursors.get_all_as_string(text_buffer));
1012                },
1013                _ => ()
1014            },
1015            _ => ()
1016        };
1017        if last_mutation_id != text_buffer.mutation_id{
1018            TextEditorEvent::Change
1019        }
1020        else{
1021            TextEditorEvent::None
1022        }
1023    }
1024    
1025    pub fn has_key_focus(&self, cx: &Cx) -> bool {
1026        cx.has_key_focus(self._view_area)
1027    }
1028    
1029    pub fn set_key_focus(&mut self, cx: &mut Cx) {
1030        cx.set_key_focus(self._view_area);
1031        self.reset_cursor_blinker(cx);
1032    }
1033    
1034    
1035    pub fn begin_text_editor(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) -> Result<(), ()> {
1036        // adjust dilation based on DPI factor
1037        self.view.begin_view(cx, self.view_layout) ?;
1038        
1039        self.apply_style(cx);
1040        
1041        self._last_indent_color = self.colors.indent_line_unknown;
1042        //self.select_highlight.color = self.colors.highlight;
1043        
1044        if !text_buffer.is_loaded {
1045            //et bg_inst = self.bg.begin_quad(cx, &Layout {
1046            //    align: Align::left_top(),
1047            //    ..self.bg_layout.clone()
1048            //});
1049            self.text.color = color("#666");
1050            self.text.draw_text(cx, "...");
1051            //self.bg.end_quad(cx, &bg_inst);
1052            //self._bg_area = bg_inst.into_area();
1053            self.view.end_view(cx);
1054            return Err(())
1055        }
1056        else {
1057            let inst = self.bg.begin_quad_fill(cx);
1058            inst.set_do_scroll(cx, false, false); // don't scroll the bg
1059            self._bg_inst = Some(inst);
1060            
1061            //let bg_area = bg_inst.into_area();
1062            let view_area = self.view.get_view_area(cx);
1063            cx.update_area_refs(self._view_area, view_area);
1064            //self._bg_area = bg_area;
1065            self._view_area = view_area;
1066            // layering, this sets the draw call order
1067            self._highlight_area = cx.new_instance_draw_call(&self.token_highlight.shader, 0).into();
1068            //cx.new_instance_layer(self.select_highlight.shader_id, 0);
1069            cx.new_instance_draw_call(&self.cursor_row.shader, 0);
1070            cx.new_instance_draw_call(&self.selection.shader, 0);
1071            cx.new_instance_draw_call(&self.message_marker.shader, 0);
1072            cx.new_instance_draw_call(&self.paren_pair.shader, 0);
1073            
1074            // force next begin_text in another drawcall
1075            self._text_inst = Some(self.text.begin_text(cx));
1076            self._indent_line_inst = Some(cx.new_instance_draw_call(&self.indent_lines.shader, 0));
1077            
1078            self._cursor_area = cx.new_instance_draw_call(&self.cursor.shader, 0).into();
1079            
1080            if self.draw_line_numbers {
1081                let inst = self.gutter_bg.draw_quad_rel(cx, Rect {x: 0., y: 0., w: self.line_number_width, h: cx.get_height_total()});
1082                inst.set_do_scroll(cx, false, false);
1083                cx.new_instance_draw_call(&self.text.shader, 0);
1084                let inst = self.line_number_text.begin_text(cx);
1085                inst.inst.set_do_scroll(cx, false, true);
1086                self._line_number_inst = Some(inst);
1087            }
1088            
1089            if let Some(select_scroll) = &mut self._select_scroll {
1090                let scroll_pos = self.view.get_scroll_pos(cx);
1091                if self.view.set_scroll_pos(cx, Vec2 {
1092                    x: scroll_pos.x + select_scroll.delta.x,
1093                    y: scroll_pos.y + select_scroll.delta.y
1094                }) {
1095                    self.view.redraw_view_area(cx);
1096                }
1097                else {
1098                    select_scroll.at_end = true;
1099                }
1100            }
1101            
1102            // initialize all drawing counters/stacks
1103            self._monospace_base = self.text.get_monospace_base(cx);
1104            self.set_font_scale(cx, self.open_font_scale);
1105            self._draw_cursors = DrawCursors::new();
1106            self._draw_messages = DrawCursors::new();
1107            self._tokens_on_line = 0;
1108            self._visible_lines = 0;
1109            self._newline_tabs = 0;
1110            self._last_tabs = 0;
1111            self._indent_stack.truncate(0);
1112            self._indent_id_alloc = 1.0;
1113            self._paren_stack.truncate(0);
1114            self._draw_cursors.set_next(&self.cursors.set);
1115            if text_buffer.messages.mutation_id != text_buffer.mutation_id {
1116                self._draw_messages.term(&text_buffer.messages.cursors);
1117            }
1118            else {
1119                self._draw_messages.set_next(&text_buffer.messages.cursors);
1120            }
1121            self._last_cursor_pos = self.cursors.get_last_cursor_text_pos(text_buffer);
1122            
1123            // indent
1124            cx.move_turtle(self.line_number_width, self.top_padding);
1125            
1126            // lets compute our scroll line position and keep it where it is
1127            self.do_folding_animation_step(cx);
1128            
1129            self._line_geometry.truncate(0);
1130            self._line_largest_font = self.text.text_style.font_size;
1131            self._scroll_pos = self.view.get_scroll_pos(cx);
1132            
1133            return Ok(())
1134        }
1135    }
1136    
1137    fn do_folding_animation_step(&mut self, cx: &mut Cx) {
1138        // run the folding animation
1139        let anim_folding = &mut self._anim_folding;
1140        if anim_folding.state.is_animating() {
1141            anim_folding.state.next_anim_step();
1142            if anim_folding.state.is_animating() {
1143                self.view.redraw_view_area(cx);
1144            }
1145            anim_folding.did_animate = true;
1146        }
1147        else {
1148            anim_folding.did_animate = false;
1149        }
1150        //let new_anim_font_size =
1151        self._anim_font_scale = anim_folding.state.get_font_size(self.open_font_scale, self.folded_font_scale);
1152        
1153        if self._anim_folding.did_animate {
1154            let mut ypos = self.top_padding;
1155            let mut ypos_at_line = ypos;
1156            let focus_line = self._anim_folding.focussed_line;
1157            if focus_line < self._line_geometry.len() {
1158                for (line, geom) in self._line_geometry.iter().enumerate() {
1159                    if focus_line == line {
1160                        ypos_at_line = ypos;
1161                    }
1162                    ypos += if geom.was_folded {
1163                        self._monospace_base.y * self.text.text_style.font_size * self._anim_font_scale
1164                    }
1165                    else {
1166                        self._monospace_base.y * self.text.text_style.font_size
1167                    }
1168                }
1169                ypos += self._final_fill_height;
1170                let dy = self._line_geometry[focus_line].walk.y - ypos_at_line;
1171                let sv = self.view.get_scroll_view_total();
1172                self.view.set_scroll_view_total(cx, Vec2 {x: sv.x, y: ypos});
1173                let scroll_pos = self.view.get_scroll_pos(cx);
1174                self.view.set_scroll_pos(cx, Vec2 {
1175                    x: scroll_pos.x,
1176                    y: scroll_pos.y - dy
1177                });
1178            }
1179        }
1180    }
1181    
1182    fn update_highlight(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1183        self._highlight_selection = self.cursors.get_selection_highlight(text_buffer);
1184        let new_token = self.cursors.get_token_highlight(text_buffer);
1185        if new_token != self._highlight_token {
1186            self.reset_highlight_visible(cx);
1187        }
1188        self._highlight_token = new_token;
1189        
1190    }
1191    
1192    fn draw_new_line(&mut self, cx: &mut Cx) {
1193        // line geometry is used for scrolling look up of cursors
1194        let line_geom = LineGeom {
1195            walk: cx.get_rel_turtle_pos(),
1196            font_size: self._line_largest_font,
1197            was_folded: self._line_was_folded,
1198            indent_id: if let Some((_, id)) = self._indent_stack.last() {*id}else {0.}
1199        };
1200        
1201        // draw a linenumber if we are visible
1202        let origin = cx.get_turtle_origin();
1203        if self.draw_line_numbers && cx.turtle_line_is_visible(self._monospace_size.y, self._scroll_pos) {
1204            // lets format a number, we go to 4 numbers
1205            // yes this is dumb as rocks. but we need to be cheapnfast
1206            let chunk = &mut self._line_number_chunk;
1207            chunk.truncate(0);
1208            let line_num = self._line_geometry.len() + 1;
1209            let mut scale = 10000;
1210            let mut fill = false;
1211            loop {
1212                let digit = ((line_num / scale) % 10) as u8;
1213                if digit != 0 {
1214                    fill = true;
1215                }
1216                if fill {
1217                    chunk.push((48 + digit) as char);
1218                }
1219                else {
1220                    chunk.push(' ');
1221                }
1222                if scale <= 1 {
1223                    break
1224                }
1225                scale /= 10;
1226            }
1227            if line_num == self._last_cursor_pos.row + 1 {
1228                self.line_number_text.color = self.colors.line_number_highlight;
1229            }
1230            else {
1231                self.line_number_text.color = self.colors.line_number_normal;
1232            }
1233            let chunk_width = self._monospace_size.x * 5.0;
1234            self.line_number_text.add_text(cx, origin.x + (self.line_number_width - chunk_width - self.line_number_click_margin), origin.y + line_geom.walk.y, 0, self._line_number_inst.as_mut().unwrap(), chunk, | _, _, _, _ | {0.});
1235        }
1236        
1237        cx.turtle_new_line_min_height(self._monospace_size.y);
1238        
1239        cx.move_turtle(self.line_number_width, 0.);
1240        
1241        self._tokens_on_line = 0;
1242        //self._line_was_visible = false;
1243        
1244        self._draw_cursors.process_newline();
1245        self._draw_messages.process_newline();
1246        
1247        // highlighting the selection
1248        let hl_len = self._highlight_selection.len();
1249        if hl_len != 0 {
1250            for bp in 0..self._line_chunk.len().max(hl_len) - hl_len {
1251                let mut found = true;
1252                for ip in 0..hl_len {
1253                    if self._highlight_selection[ip] != self._line_chunk[bp + ip].1 {
1254                        found = false;
1255                        break;
1256                    }
1257                }
1258                if found { // output a rect
1259                    let origin = cx.get_turtle_origin();
1260                    let min_x = self._line_chunk[bp].0;
1261                    let max_x = self._line_chunk[bp + hl_len].0;
1262                    self.draw_token_highlight_quad(cx, Rect {
1263                        x: min_x,
1264                        y: line_geom.walk.y + origin.y,
1265                        w: max_x - min_x,
1266                        h: self._monospace_size.y,
1267                    });
1268                }
1269            }
1270            self._line_chunk.truncate(0);
1271        }
1272        
1273        // search for all markings
1274        self._line_geometry.push(line_geom);
1275        self._line_largest_font = self.text.text_style.font_size;
1276    }
1277    
1278    fn draw_indent_lines(&mut self, cx: &mut Cx, geom_y: f32, tabs: usize) {
1279        let y_pos = geom_y - cx.get_turtle_origin().y;
1280        let tab_variable_width = self._monospace_base.x * 4. * self.text.text_style.font_size * self._anim_font_scale;
1281        let tab_fixed_width = self._monospace_base.x * 4. * self.text.text_style.font_size;
1282        let mut off = self.line_number_width;
1283        for i in 0..tabs {
1284            let (indent_color, indent_id) = if i < self._indent_stack.len() {self._indent_stack[i]}else {
1285                (self.colors.indent_line_unknown, 0.)
1286            };
1287            let tab_width = if i < self.folding_depth {tab_fixed_width}else {tab_variable_width};
1288            self.indent_lines.color = indent_color;
1289            let inst = self.indent_lines.draw_quad_rel(cx, Rect {
1290                x: off,
1291                y: y_pos,
1292                w: tab_width,
1293                h: self._monospace_size.y
1294            });
1295            off += tab_width;
1296            inst.push_float(cx, indent_id);
1297        }
1298    }
1299    
1300    pub fn draw_chunk(&mut self, cx: &mut Cx, token_chunks_index: usize, flat_text: &Vec<char>, token_chunk: &TokenChunk, message_cursors: &Vec<TextCursor>) {
1301        if token_chunk.len == 0 {
1302            return
1303        }
1304        
1305        let token_type = token_chunk.token_type;
1306        let chunk = &flat_text[token_chunk.offset..(token_chunk.offset + token_chunk.len)]; //chunk;
1307        let offset = token_chunk.offset; // end_offset - chunk.len() - 1;
1308        let next_char = token_chunk.next;
1309        
1310        // maintain paren stack
1311        if token_type == TokenType::ParenOpen {
1312            self.draw_paren_open(token_chunks_index, offset, next_char, chunk);
1313        }
1314        
1315        // do indent depth walking
1316        if self._tokens_on_line == 0 {
1317            let font_scale = match token_type {
1318                TokenType::Whitespace => {
1319                    let tabs = chunk.len()>>2;
1320                    while tabs > self._indent_stack.len() {
1321                        self._indent_stack.push((self._last_indent_color, self._indent_id_alloc));
1322                        // allocating an indent_id, we also need to
1323                        self._indent_id_alloc += 1.0;
1324                    }
1325                    while tabs < self._indent_stack.len() {
1326                        self._indent_stack.pop();
1327                        if let Some(indent) = self._indent_stack.last() {
1328                            self._last_indent_color = indent.0;
1329                        }
1330                    }
1331                    // lets do the code folding here. if we are tabs > fold line
1332                    // lets change the fontsize
1333                    if tabs >= self.folding_depth || next_char == '\n' {
1334                        // ok lets think. we need to move it over by the delta of 8 spaces * _anim_font_size
1335                        let dx = (self._monospace_base.x * self.text.text_style.font_size * 4. * (self.folding_depth as f32)) - (self._monospace_base.x * self.text.text_style.font_size * self._anim_font_scale * 4. * (self.folding_depth as f32));
1336                        cx.move_turtle(dx, 0.0);
1337                        self._line_was_folded = true;
1338                        self._anim_font_scale
1339                    }
1340                    else {
1341                        self._line_was_folded = false;
1342                        self.open_font_scale
1343                    }
1344                }
1345                TokenType::Newline | TokenType::CommentLine | TokenType::CommentChunk | TokenType::CommentMultiBegin | TokenType::CommentMultiEnd | TokenType::Hash => {
1346                    self._line_was_folded = true;
1347                    self._anim_font_scale
1348                }
1349                _ => {
1350                    self._indent_stack.truncate(0);
1351                    self._line_was_folded = false;
1352                    self.open_font_scale
1353                }
1354            };
1355            self.set_font_scale(cx, font_scale);
1356        }
1357        // colorise indent lines properly
1358        if self._tokens_on_line < 4 {
1359            match token_type {
1360                TokenType::Flow => {
1361                    self._last_indent_color = self.colors.indent_line_flow;
1362                },
1363                TokenType::Looping => {
1364                    self._last_indent_color = self.colors.indent_line_looping;
1365                },
1366                TokenType::TypeDef => {
1367                    self._last_indent_color = self.colors.indent_line_typedef;
1368                },
1369                TokenType::Fn | TokenType::Call => {
1370                    self._last_indent_color = self.colors.indent_line_fn;
1371                }
1372                _ => ()
1373            }
1374        }
1375        // lets check if the geom is visible
1376        if let Some(geom) = cx.walk_turtle_right_no_wrap(
1377            self._monospace_size.x * (chunk.len() as f32),
1378            self._monospace_size.y,
1379            self._scroll_pos
1380        ) {
1381            let mut mark_spaces = 0.0;
1382            // determine chunk color
1383            self.text.color = match token_type {
1384                TokenType::Whitespace => {
1385                    if self._tokens_on_line == 0 && chunk[0] == ' ' {
1386                        let tabs = chunk.len()>>2;
1387                        // if self._last_tabs
1388                        self._last_tabs = tabs;
1389                        self._newline_tabs = tabs;
1390                        self.draw_indent_lines(cx, geom.y, tabs);
1391                    }
1392                    else if next_char == '\n' {
1393                        mark_spaces = 1.0;
1394                    }
1395                    self.colors.whitespace
1396                },
1397                TokenType::Newline => {
1398                    if self._tokens_on_line == 0 {
1399                        self._newline_tabs = 0;
1400                        self.draw_indent_lines(cx, geom.y, self._last_tabs);
1401                    }
1402                    else {
1403                        self._last_tabs = self._newline_tabs;
1404                        self._newline_tabs = 0;
1405                    }
1406                    self.colors.whitespace
1407                },
1408                TokenType::BuiltinType => self.colors.keyword,
1409                TokenType::Keyword => self.colors.keyword,
1410                TokenType::Bool => self.colors.keyword,
1411                TokenType::Error => self.colors.error,
1412                TokenType::Warning => self.colors.warning,
1413                TokenType::Defocus => self.colors.defocus,
1414                TokenType::Flow => {
1415                    self.colors.flow
1416                }
1417                TokenType::Looping => {
1418                    self.colors.looping
1419                }
1420                TokenType::TypeDef => {
1421                    self.colors.keyword
1422                }
1423                TokenType::Fn => {
1424                    self.colors.keyword
1425                }
1426                TokenType::Identifier => {
1427                    if chunk == &self._highlight_token[0..] {
1428                        self.draw_token_highlight_quad(cx, geom);
1429                        
1430                    }
1431                    self.colors.identifier
1432                }
1433                TokenType::Call => {
1434                    if chunk == &self._highlight_token[0..] {
1435                        self.draw_token_highlight_quad(cx, geom);
1436                    }
1437                    self.colors.call
1438                },
1439                TokenType::TypeName => {
1440                    if chunk == &self._highlight_token[0..] {
1441                        self.draw_token_highlight_quad(cx, geom);
1442                    }
1443                    self.colors.type_name
1444                },
1445                TokenType::ThemeName => {
1446                    if chunk == &self._highlight_token[0..] {
1447                        self.draw_token_highlight_quad(cx, geom);
1448                    }
1449                    self.colors.theme_name
1450                },
1451                TokenType::Regex => self.colors.string,
1452                TokenType::String => self.colors.string,
1453                TokenType::Number => self.colors.number,
1454
1455                TokenType::StringMultiBegin => self.colors.string,
1456                TokenType::StringChunk => self.colors.string,
1457                TokenType::StringMultiEnd => self.colors.string,
1458
1459                TokenType::CommentMultiBegin => self.colors.comment,
1460                TokenType::CommentMultiEnd => self.colors.comment,
1461                TokenType::CommentLine => self.colors.comment,
1462                TokenType::CommentChunk => self.colors.comment,
1463                TokenType::ParenOpen => {
1464                    let depth = self._paren_stack.len();
1465                    self._paren_stack.last_mut().unwrap().geom_open = Some(geom);
1466                    match depth % 2 {
1467                        0 => self.colors.paren_d1,
1468                        _ => self.colors.paren_d2,
1469                    }
1470                },
1471                TokenType::ParenClose => {
1472                    if let Some(paren) = self._paren_stack.last_mut() {
1473                        paren.geom_close = Some(geom);
1474                    }
1475                    else {
1476                        self.paren_pair.color = self.colors.paren_pair_fail;
1477                        self.paren_pair.draw_quad_abs(cx, geom);
1478                    }
1479                    let depth = self._paren_stack.len();
1480                    match depth % 2 {
1481                        0 => self.colors.paren_d1,
1482                        _ => self.colors.paren_d2,
1483                        //_=>self.colors.paren_d3
1484                    }
1485                },
1486                TokenType::Operator => self.colors.operator,
1487                TokenType::Namespace => self.colors.operator,
1488                TokenType::Hash => self.colors.operator,
1489                TokenType::Delimiter => self.colors.delimiter,
1490                TokenType::Colon => self.colors.delimiter,
1491                TokenType::Splat => self.colors.operator,
1492                TokenType::Eof => self.colors.unexpected,
1493                TokenType::Unexpected => self.colors.unexpected
1494            };
1495            
1496            if self._tokens_on_line == 0 {
1497                self._visible_lines += 1;
1498                //self._line_was_visible = true;
1499            }
1500            
1501            let cursors = &self.cursors.set;
1502            //let messages_cursors = &text_buffer.message_cursors;
1503            let last_cursor = self.cursors.last_cursor;
1504            let draw_cursors = &mut self._draw_cursors;
1505            let draw_messages = &mut self._draw_messages;
1506            let height = self._monospace_size.y;
1507            
1508            // actually generate the GPU data for the text
1509            let z = 2.0; // + self._paren_stack.len() as f32;
1510            //self.text.z = z;
1511            if self._highlight_selection.len() > 0 { // slow loop
1512                //let draw_search = &mut self._draw_search;
1513                let line_chunk = &mut self._line_chunk;
1514                self.text.add_text(cx, geom.x, geom.y, offset, self._text_inst.as_mut().unwrap(), &chunk, | ch, offset, x, w | {
1515                    line_chunk.push((x, ch));
1516                    //draw_search.mark_text_select_only(cursors, offset, x, geom.y, w, height);
1517                    draw_messages.mark_text_select_only(message_cursors, offset, x, geom.y, w, height);
1518                    draw_cursors.mark_text_with_cursor(cursors, ch, offset, x, geom.y, w, height, z, last_cursor, mark_spaces)
1519                });
1520            }
1521            else { // fast loop
1522                self.text.add_text(cx, geom.x, geom.y, offset, self._text_inst.as_mut().unwrap(), &chunk, | ch, offset, x, w | {
1523                    draw_messages.mark_text_select_only(message_cursors, offset, x, geom.y, w, height);
1524                    draw_cursors.mark_text_with_cursor(cursors, ch, offset, x, geom.y, w, height, z, last_cursor, mark_spaces)
1525                });
1526            }
1527        }
1528        self._tokens_on_line += 1;
1529        
1530        // Do all the Paren matching highlighting drawing
1531        if token_chunk.token_type == TokenType::ParenClose {
1532            self.draw_paren_close(cx, token_chunks_index, offset, next_char, chunk);
1533        }
1534        else {
1535            if token_type == TokenType::Newline {
1536                self.draw_new_line(cx);
1537            }
1538        }
1539    }
1540    
1541    fn draw_token_highlight_quad(&mut self, cx: &mut Cx, geom: Rect) {
1542        let inst = self.token_highlight.draw_quad_abs(cx, geom);
1543        if inst.need_uniforms_now(cx) {
1544            inst.push_uniform_float(cx, self._highlight_visibility);
1545        }
1546    }
1547    
1548    fn draw_paren_open(&mut self, token_chunks_index: usize, offset: usize, next_char: char, chunk: &[char]) {
1549        let marked = if let Some(pos) = self.cursors.get_last_cursor_singular() {
1550            pos == offset || pos == offset + 1 && next_char != '(' && next_char != '{' && next_char != '['
1551        }
1552        else {false};
1553        
1554        self._paren_stack.push(ParenItem {
1555            pair_start: token_chunks_index, //self.token_chunks.len(),
1556            geom_open: None,
1557            geom_close: None,
1558            marked: marked,
1559            exp_paren: chunk[0]
1560        });
1561    }
1562    
1563    fn draw_paren_close(&mut self, cx: &mut Cx, token_chunks_index: usize, offset: usize, next_char: char, chunk: &[char]) {
1564        //let token_chunks_len = self.token_chunks.len();
1565        if self._paren_stack.len() == 0 {
1566            return
1567        }
1568        let last = self._paren_stack.pop().unwrap();
1569        // !!!!self.token_chunks[last.pair_start].pair_token = token_chunks_index;
1570        if last.geom_open.is_none() && last.geom_close.is_none() {
1571            return
1572        }
1573        if !self.has_key_focus(cx) {
1574            return
1575        }
1576        if let Some(pos) = self.cursors.get_last_cursor_singular() {
1577            if self.mark_unmatched_parens {
1578                // cursor is near the last one or its marked
1579                let fail = if last.exp_paren == '(' && chunk[0] != ')' ||
1580                last.exp_paren == '[' && chunk[0] != ']' ||
1581                last.exp_paren == '{' && chunk[0] != '}' {
1582                    self.paren_pair.color = self.colors.paren_pair_fail;
1583                    true
1584                }
1585                else {
1586                    self.paren_pair.color = self.colors.paren_pair_match;
1587                    false
1588                };
1589                if fail || pos == offset || pos == offset + 1 && next_char != ')' && next_char != '}' && next_char != ']' || last.marked {
1590                    // fuse the tokens
1591                    if last.pair_start + 1 == token_chunks_index && !last.geom_open.is_none() && !last.geom_close.is_none() {
1592                        let geom_open = last.geom_open.unwrap();
1593                        let geom_close = last.geom_open.unwrap();
1594                        let geom = Rect {
1595                            x: geom_open.x,
1596                            y: geom_open.y,
1597                            w: geom_open.w + geom_close.w,
1598                            h: geom_close.h
1599                        };
1600                        self.paren_pair.draw_quad_abs(cx, geom);
1601                    }
1602                    else {
1603                        if let Some(rc) = last.geom_open {
1604                            self.paren_pair.draw_quad_abs(cx, rc);
1605                        }
1606                        if let Some(rc) = last.geom_close {
1607                            self.paren_pair.draw_quad_abs(cx, rc);
1608                        }
1609                    }
1610                }
1611            };
1612        }
1613    }
1614    
1615    fn draw_paren_unmatched(&mut self, cx: &mut Cx) {
1616        if !self.mark_unmatched_parens {
1617            return
1618        }
1619        while self._paren_stack.len()>0 {
1620            let last = self._paren_stack.pop().unwrap();
1621            if self.has_key_focus(cx) && !last.geom_open.is_none() {
1622                self.paren_pair.color = self.colors.paren_pair_fail;
1623                if let Some(rc) = last.geom_open {
1624                    self.paren_pair.draw_quad_abs(cx, rc);
1625                }
1626            }
1627        }
1628    }
1629    
1630    pub fn end_text_editor(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1631        
1632        // lets insert an empty newline at the bottom so its nicer to scroll
1633        self.draw_new_line(cx);
1634        if !cx.is_height_computed() {
1635            cx.walk_turtle(Walk::wh(Width::Fix(0.0), Height::Fix(self._monospace_size.y)));
1636        }
1637        
1638        self._text_area = self.text.end_text(cx, self._text_inst.as_ref().unwrap());
1639        
1640        if self.draw_line_numbers {
1641            self.line_number_text.end_text(cx, self._line_number_inst.as_ref().unwrap());
1642        }
1643        
1644        // unmatched highlighting
1645        self.draw_paren_unmatched(cx);
1646        self.draw_cursors(cx);
1647        //self.do_selection_animations(cx);
1648        self.draw_selections(cx);
1649        self.draw_message_markers(cx, text_buffer);
1650        
1651        // inject a final page
1652        self._final_fill_height = cx.get_height_total() - self._monospace_size.y;
1653        if !cx.is_height_computed() {
1654            cx.walk_turtle(Walk::wh(Width::Fix(0.0), Height::Fix(self._final_fill_height)));
1655        }
1656        // last bits
1657        self.do_selection_scrolling(cx, text_buffer);
1658        self.place_ime_and_draw_cursor_row(cx);
1659        self.set_indent_line_highlight_id(cx);
1660        self.draw_shadows(cx);
1661        self.bg.end_quad_fill(cx, &self._bg_inst.take().unwrap());
1662        
1663        self.view.end_view(cx);
1664        
1665        if self._jump_to_offset {
1666            self._jump_to_offset = false;
1667            self._scroll_pos_on_load = None;
1668            self.do_jump_to_offset(cx, text_buffer);
1669        }
1670        else if let Some(scroll_pos_on_load) = self._scroll_pos_on_load {
1671           self.view.set_scroll_pos(cx, scroll_pos_on_load);
1672           self._scroll_pos_on_load = None;
1673        }
1674    }
1675    
1676    fn do_jump_to_offset(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1677        let offset = text_buffer.messages.jump_to_offset;
1678        // make one cursor, and start scrolling towards it
1679        self.cursors.clear_and_set_last_cursor_head_and_tail(offset, text_buffer);
1680        self.scroll_last_cursor_visible(cx, text_buffer, self._final_fill_height * 0.8);
1681        self.view.redraw_view_area(cx);
1682    }
1683    
1684    fn draw_cursors(&mut self, cx: &mut Cx) {
1685        if self.has_key_focus(cx) {
1686            let origin = cx.get_turtle_origin();
1687            for rc in &self._draw_cursors.cursors {
1688                self.cursor.z = rc.z + 0.1;
1689                
1690                let inst = self.cursor.draw_quad_rel(cx, Rect {x: rc.x - origin.x, y: rc.y - origin.y, w: rc.w, h: rc.h});
1691                if inst.need_uniforms_now(cx) {
1692                    inst.push_uniform_float(cx, self._cursor_blink_flipflop);
1693                    //blink
1694                }
1695            }
1696        }
1697    }
1698    
1699    fn draw_shadows(&mut self, cx: &mut Cx) {
1700        let gutter_width = Self::gutter_width().get(cx);
1701        self.shadow.draw_shadow_left_at(cx, Rect {
1702            x: gutter_width,
1703            y: 0.,
1704            w: 0.,
1705            h: cx.get_height_total()
1706        });
1707        
1708        self.shadow.draw_shadow_top(cx);
1709    }
1710    
1711    fn draw_message_markers(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1712        let origin = cx.get_turtle_origin();
1713        let message_markers = &mut self._draw_messages.selections;
1714        
1715        for i in 0..message_markers.len() {
1716            let mark = &message_markers[i];
1717            let body = &text_buffer.messages.bodies[mark.index];
1718            self.message_marker.color = match body.level {
1719                TextBufferMessageLevel::Warning => self.colors.marker_warning,
1720                TextBufferMessageLevel::Error => self.colors.marker_error,
1721                TextBufferMessageLevel::Log => self.colors.marker_log,
1722            };
1723            self.message_marker.draw_quad_rel(cx, Rect {x: mark.rc.x - origin.x, y: mark.rc.y - origin.y, w: mark.rc.w, h: mark.rc.h});
1724        }
1725    }
1726    
1727    fn draw_selections(&mut self, cx: &mut Cx) {
1728        let origin = cx.get_turtle_origin();
1729        let sel = &mut self._draw_cursors.selections;
1730        // draw selections
1731        for i in 0..sel.len() {
1732            let cur = &sel[i];
1733            
1734            let mk_inst = self.selection.draw_quad_rel(cx, Rect {x: cur.rc.x - origin.x, y: cur.rc.y - origin.y, w: cur.rc.w, h: cur.rc.h});
1735            
1736            // do we have a prev?
1737            if i > 0 && sel[i - 1].index == cur.index {
1738                let p_rc = &sel[i - 1].rc;
1739                mk_inst.push_vec2(cx, Vec2 {x: p_rc.x - cur.rc.x, y: p_rc.w});
1740                // prev_x, prev_w
1741            }
1742            else {
1743                mk_inst.push_vec2(cx, Vec2 {x: 0., y: -1.});
1744                // prev_x, prev_w
1745            }
1746            // do we have a next
1747            if i < sel.len() - 1 && sel[i + 1].index == cur.index {
1748                let n_rc = &sel[i + 1].rc;
1749                mk_inst.push_vec2(cx, Vec2 {x: n_rc.x - cur.rc.x, y: n_rc.w});
1750                // prev_x, prev_w
1751            }
1752            else {
1753                mk_inst.push_vec2(cx, Vec2 {x: 0., y: -1.});
1754                // prev_x, prev_w
1755            }
1756        }
1757    }
1758    
1759    fn place_ime_and_draw_cursor_row(&mut self, cx: &mut Cx) {
1760        // place the IME
1761        if let Some(last_cursor) = self._draw_cursors.last_cursor {
1762            let rc = self._draw_cursors.cursors[last_cursor];
1763            if let Some(_) = self.cursors.get_last_cursor_singular() {
1764                // lets draw the cursor line
1765                if self.draw_cursor_row {
1766                    self.cursor_row.draw_quad_abs(cx, Rect {
1767                        x: self.line_number_width + cx.get_turtle_origin().x,
1768                        y: rc.y,
1769                        w: cx.get_width_total().max(cx.get_turtle_bounds().x) - self.line_number_width,
1770                        h: rc.h
1771                    });
1772                }
1773            }
1774            if cx.has_key_focus(self.view.get_view_area(cx)) {
1775                let scroll_pos = self.view.get_scroll_pos(cx);
1776                cx.show_text_ime(rc.x - scroll_pos.x, rc.y - scroll_pos.y);
1777            }
1778            else {
1779                cx.hide_text_ime();
1780            }
1781        }
1782    }
1783    
1784    fn do_selection_scrolling(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1785        // do select scrolling
1786        if let Some(select_scroll) = self._select_scroll.clone() {
1787            if let Some(grid_select_corner) = self._grid_select_corner {
1788                // self.cursors.grid_select(offset, text_buffer);
1789                let pos = self.compute_grid_text_pos_from_abs(cx, select_scroll.abs);
1790                self.cursors.grid_select(grid_select_corner, pos, text_buffer);
1791            }
1792            else {
1793                let offset = self.text.find_closest_offset(cx, &self._text_area, select_scroll.abs);
1794                self.cursors.set_last_cursor_head(offset, text_buffer);
1795            }
1796            if select_scroll.at_end {
1797                self._select_scroll = None;
1798            }
1799            self.view.redraw_view_area(cx);
1800        }
1801    }
1802    
1803    fn _do_selection_animations(&mut self, cx: &mut Cx) {
1804        if !self._anim_folding.state.is_animating() {
1805            let sel = &mut self._draw_cursors.selections;
1806            
1807            let mut anim_select_any = false;
1808            for i in 0..sel.len() {
1809                let cur = &mut sel[i];
1810                let start_time = if self._select_scroll.is_none() && !self._last_finger_move.is_none() {1.}else {0.};
1811                // silly selection animation start
1812                if i < self._anim_select.len() && cur.rc.y < self._anim_select[i].ypos {
1813                    // insert new one at the top
1814                    self._anim_select.insert(i, AnimSelect {time: start_time, invert: true, ypos: cur.rc.y});
1815                }
1816                let (wtime, htime, invert) = if i < self._anim_select.len() {
1817                    let len = self._anim_select.len() - 1;
1818                    let anim = &mut self._anim_select[i];
1819                    anim.ypos = cur.rc.y;
1820                    if anim.time <= 0.0001 {
1821                        anim.time = 0.0
1822                    }
1823                    else {
1824                        anim.time = anim.time * 0.55;
1825                        //= 0.1;
1826                        anim_select_any = true;
1827                    }
1828                    if i == len {
1829                        (anim.time, anim.time, i == 0 && anim.invert)
1830                    }
1831                    else {
1832                        (anim.time, 0., i == 0 && anim.invert)
1833                    }
1834                }
1835                else {
1836                    self._anim_select.push(AnimSelect {time: start_time, invert: i == 0, ypos: cur.rc.y});
1837                    anim_select_any = true;
1838                    (start_time, start_time, false)
1839                };
1840                let wtime = 1.0 - wtime as f32;
1841                let htime = 1.0 - htime as f32;
1842                
1843                if invert {
1844                    cur.rc.w = cur.rc.w * wtime;
1845                    cur.rc.h = cur.rc.h * htime;
1846                }
1847                else {
1848                    cur.rc.x = cur.rc.x + (cur.rc.w * (1. - wtime));
1849                    cur.rc.w = cur.rc.w * wtime;
1850                    cur.rc.h = cur.rc.h * htime;
1851                }
1852            }
1853            self._anim_select.truncate(sel.len());
1854            if anim_select_any {
1855                self.view.redraw_view_area(cx);
1856            }
1857        }
1858    }
1859    
1860    fn set_indent_line_highlight_id(&mut self, cx: &mut Cx) {
1861        // compute the line which our last cursor is on so we can set the highlight id
1862        if let Some(indent_inst) = self._indent_line_inst {
1863            let indent_id = if self.cursors.is_last_cursor_singular() && self._last_cursor_pos.row < self._line_geometry.len() {
1864                self._line_geometry[self._last_cursor_pos.row].indent_id
1865            }else {0.};
1866            let area: Area = indent_inst.clone().into();
1867            area.write_uniform_float(cx, Self::uniform_indent_sel(), indent_id);
1868        }
1869    }
1870    
1871    // set it once per line otherwise the LineGeom stuff isn't really working out.
1872    fn set_font_scale(&mut self, _cx: &Cx, font_scale: f32) {
1873        self.text.font_scale = font_scale;
1874        self.line_number_text.font_scale = font_scale;
1875        if font_scale > self._line_largest_font {
1876            self._line_largest_font = font_scale;
1877        }
1878        self._monospace_size.x = self._monospace_base.x * self.text.text_style.font_size * font_scale;
1879        self._monospace_size.y = self._monospace_base.y * self.text.text_style.font_size * font_scale;
1880    }
1881    
1882    fn scroll_last_cursor_visible(&mut self, cx: &mut Cx, text_buffer: &TextBuffer, height_pad: f32) {
1883        // so we have to compute (approximately) the rect of our cursor
1884        if self.cursors.last_cursor >= self.cursors.set.len() {
1885            panic !("LAST CURSOR INVALID");
1886        }
1887        
1888        let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
1889        
1890        // alright now lets query the line geometry
1891        let row = pos.row.min(self._line_geometry.len() - 1);
1892        if row < self._line_geometry.len() {
1893            let geom = &self._line_geometry[row];
1894            let mono_size = Vec2 {x: self._monospace_base.x * geom.font_size, y: self._monospace_base.y * geom.font_size};
1895            //self.text.get_monospace_size(cx, geom.font_size);
1896            let rect = Rect {
1897                x: (pos.col as f32) * mono_size.x, // - self.line_number_width,
1898                y: geom.walk.y - mono_size.y * 1. - 0.5 * height_pad,
1899                w: mono_size.x * 4. + self.line_number_width,
1900                h: mono_size.y * 4. + height_pad
1901            };
1902            
1903            // scroll this cursor into view
1904            self.view.scroll_into_view(cx, rect);
1905        }
1906    }
1907    
1908    fn compute_grid_text_pos_from_abs(&mut self, cx: &Cx, abs: Vec2) -> TextPos {
1909        //
1910        let rel = self.view.get_view_area(cx).abs_to_rel(cx, abs);
1911        let mut mono_size = Vec2::default();
1912        for (row, geom) in self._line_geometry.iter().enumerate() {
1913            //let geom = &self._line_geometry[pos.row];
1914            mono_size = Vec2 {x: self._monospace_base.x * geom.font_size, y: self._monospace_base.y * geom.font_size};
1915            if rel.y < geom.walk.y || rel.y >= geom.walk.y && rel.y <= geom.walk.y + mono_size.y { // its on the right line
1916                let col = ((rel.x - self.line_number_width).max(0.) / mono_size.x) as usize;
1917                // do a dumb calc
1918                return TextPos {row: row, col: col};
1919            }
1920        }
1921        // otherwise the file is too short, lets use the last line
1922        TextPos {row: self._line_geometry.len() - 1, col: (rel.x.max(0.) / mono_size.x) as usize}
1923    }
1924    
1925    fn compute_offset_from_ypos(&mut self, cx: &Cx, ypos_abs: f32, text_buffer: &TextBuffer, end: bool) -> usize {
1926        let rel = self.view.get_view_area(cx).abs_to_rel(cx, Vec2 {x: 0.0, y: ypos_abs});
1927        let mut mono_size;
1928        // = Vec2::zero();
1929        let end_col = if end {1 << 31}else {0};
1930        for (row, geom) in self._line_geometry.iter().enumerate() {
1931            //let geom = &self._line_geometry[pos.row];
1932            mono_size = Vec2 {x: self._monospace_base.x * geom.font_size, y: self._monospace_base.y * geom.font_size};
1933            if rel.y < geom.walk.y || rel.y >= geom.walk.y && rel.y <= geom.walk.y + mono_size.y { // its on the right line
1934                return text_buffer.text_pos_to_offset(TextPos {row: row, col: end_col})
1935            }
1936        }
1937        return text_buffer.text_pos_to_offset(TextPos {row: self._line_geometry.len() - 1, col: end_col})
1938    }
1939    
1940    fn start_code_folding(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1941        // start code folding anim
1942        let speed = 0.98;
1943        //self._anim_folding.depth = if halfway {1}else {2};
1944        //self._anim_folding.zoom_scale = if halfway {0.5}else {1.};
1945        //if halfway{9.0} else{1.0};
1946        self._anim_folding.state.do_folding(speed, 0.95);
1947        self._anim_folding.focussed_line = self.compute_focussed_line_for_folding(cx, text_buffer);
1948        //println!("FOLDING {}",self._anim_folding.focussed_line);
1949        self.view.redraw_view_area(cx);
1950    }
1951    
1952    fn start_code_unfolding(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1953        let speed = 0.96;
1954        self._anim_folding.state.do_opening(speed, 0.97);
1955        self._anim_folding.focussed_line = self.compute_focussed_line_for_folding(cx, text_buffer);
1956        //println!("UNFOLDING {}",self._anim_folding.focussed_line);
1957        self.view.redraw_view_area(cx);
1958        // return to normal size
1959    }
1960    
1961    fn check_select_scroll_dynamics(&mut self, fe: &FingerMoveEvent) -> bool {
1962        let pow_scale = 0.1;
1963        let pow_fac = 3.;
1964        let max_speed = 40.;
1965        let pad_scroll = 20.;
1966        let rect = Rect {
1967            x: fe.rect.x + pad_scroll,
1968            y: fe.rect.y + pad_scroll,
1969            w: fe.rect.w - 2. * pad_scroll,
1970            h: fe.rect.h - 2. * pad_scroll,
1971        };
1972        let delta = Vec2 {
1973            x: if fe.abs.x < rect.x {
1974                -((rect.x - fe.abs.x) * pow_scale).powf(pow_fac).min(max_speed)
1975            }
1976            else if fe.abs.x > rect.x + rect.w {
1977                ((fe.abs.x - (rect.x + rect.w)) * pow_scale).powf(pow_fac).min(max_speed)
1978            }
1979            else {
1980                0.
1981            },
1982            y: if fe.abs.y < rect.y {
1983                -((rect.y - fe.abs.y) * pow_scale).powf(pow_fac).min(max_speed)
1984            }
1985            else if fe.abs.y > rect.y + rect.h {
1986                ((fe.abs.y - (rect.y + rect.h)) * pow_scale).powf(pow_fac).min(max_speed)
1987            }
1988            else {
1989                0.
1990            }
1991        };
1992        let last_scroll_none = self._select_scroll.is_none();
1993        if delta.x != 0. || delta.y != 0. {
1994            self._select_scroll = Some(SelectScroll {
1995                abs: fe.abs,
1996                delta: delta,
1997                at_end: false
1998            });
1999        }
2000        else {
2001            self._select_scroll = None;
2002        }
2003        last_scroll_none
2004    }
2005    
2006    fn compute_next_unfolded_line_up(&self, text_buffer: &TextBuffer) -> usize {
2007        let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
2008        let mut delta = 1;
2009        if pos.row > 0 && pos.row < self._line_geometry.len() {
2010            let mut scan = pos.row - 1;
2011            while scan >0 {
2012                if !self._line_geometry[scan].was_folded {
2013                    delta = pos.row - scan;
2014                    break;
2015                }
2016                scan -= 1;
2017            }
2018        };
2019        delta
2020    }
2021    
2022    fn compute_next_unfolded_line_down(&self, text_buffer: &TextBuffer) -> usize {
2023        let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
2024        let mut delta = 1;
2025        let mut scan = pos.row + 1;
2026        while scan < self._line_geometry.len() {
2027            if !self._line_geometry[scan].was_folded {
2028                delta = scan - pos.row;
2029                break;
2030            }
2031            scan += 1;
2032        }
2033        delta
2034    }
2035    
2036    
2037    fn compute_focussed_line_for_folding(&self, cx: &Cx, text_buffer: &TextBuffer) -> usize {
2038        let scroll = self.view.get_scroll_pos(cx);
2039        let rect = self.view.get_view_area(cx).get_rect(cx);
2040        
2041        // first try if our last cursor is in view
2042        let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
2043        if pos.row < self._line_geometry.len() {
2044            let geom = &self._line_geometry[pos.row];
2045            // check if cursor is visible
2046            if geom.walk.y - scroll.y > 0. && geom.walk.y - scroll.y <rect.h { // visible
2047                //println!("FOUND");
2048                return pos.row
2049            }
2050        }
2051        
2052        // scan for the centerline otherwise
2053        let scroll = self.view.get_scroll_pos(cx);
2054        let center_y = rect.h * 0.5 + scroll.y;
2055        for (line, geom) in self._line_geometry.iter().enumerate() {
2056            if geom.walk.y > center_y {
2057                //println!("CENTER");
2058                return line
2059            }
2060        }
2061        
2062        // if we cant find the centerline, use the view top
2063        for (line, geom) in self._line_geometry.iter().enumerate() {
2064            if geom.walk.y > scroll.y {
2065                //println!("TOP");
2066                return line
2067            }
2068        }
2069        
2070        // cant find anything
2071        return 0
2072    }
2073    
2074    
2075}
2076
2077#[derive(Clone)]
2078pub enum AnimFoldingState {
2079    Open,
2080    Opening(f32, f32, f32),
2081    Folded,
2082    Folding(f32, f32, f32)
2083}
2084
2085#[derive(Clone)]
2086pub struct AnimFolding {
2087    pub state: AnimFoldingState,
2088    pub focussed_line: usize,
2089    pub did_animate: bool
2090}
2091
2092#[derive(Clone)]
2093pub struct AnimSelect {
2094    pub ypos: f32,
2095    pub invert: bool,
2096    pub time: f64
2097}
2098
2099#[derive(Clone, Default)]
2100pub struct LineGeom {
2101    walk: Vec2,
2102    was_folded: bool,
2103    font_size: f32,
2104    indent_id: f32
2105}
2106
2107#[derive(Clone, Default)]
2108pub struct SelectScroll {
2109    // pub margin:Margin,
2110    pub delta: Vec2,
2111    pub abs: Vec2,
2112    pub at_end: bool
2113}
2114
2115#[derive(Clone)]
2116pub struct ParenItem {
2117    pair_start: usize,
2118    geom_open: Option<Rect>,
2119    geom_close: Option<Rect>,
2120    marked: bool,
2121    exp_paren: char
2122}
2123
2124impl AnimFoldingState {
2125    fn is_animating(&self) -> bool {
2126        match self {
2127            AnimFoldingState::Open => false,
2128            AnimFoldingState::Folded => false,
2129            _ => true
2130        }
2131    }
2132    
2133    fn is_folded(&self) -> bool {
2134        match self {
2135            AnimFoldingState::Folded => true,
2136            AnimFoldingState::Folding(_, _, _) => true,
2137            _ => false
2138        }
2139    }
2140    
2141    fn get_font_size(&self, open_size: f32, folded_size: f32) -> f32 {
2142        match self {
2143            AnimFoldingState::Open => open_size,
2144            AnimFoldingState::Folded => folded_size,
2145            AnimFoldingState::Opening(f, _, _) => f * folded_size + (1. - f) * open_size,
2146            AnimFoldingState::Folding(f, _, _) => f * open_size + (1. - f) * folded_size,
2147        }
2148    }
2149    
2150    fn do_folding(&mut self, speed: f32, speed2: f32) {
2151        *self = match self {
2152            AnimFoldingState::Open => AnimFoldingState::Folding(1.0, speed, speed2),
2153            AnimFoldingState::Folded => AnimFoldingState::Folded,
2154            AnimFoldingState::Opening(f, _, _) => AnimFoldingState::Folding(1.0 - *f, speed, speed2),
2155            AnimFoldingState::Folding(f, _, _) => AnimFoldingState::Folding(*f, speed, speed2),
2156        }
2157    }
2158    
2159    fn do_opening(&mut self, speed: f32, speed2: f32) {
2160        *self = match self {
2161            AnimFoldingState::Open => AnimFoldingState::Open,
2162            AnimFoldingState::Folded => AnimFoldingState::Opening(1.0, speed, speed2),
2163            AnimFoldingState::Opening(f, _, _) => AnimFoldingState::Opening(*f, speed, speed2),
2164            AnimFoldingState::Folding(f, _, _) => AnimFoldingState::Opening(1.0 - *f, speed, speed2),
2165        }
2166    }
2167    
2168    fn next_anim_step(&mut self) {
2169        *self = match self {
2170            AnimFoldingState::Open => AnimFoldingState::Open,
2171            AnimFoldingState::Folded => AnimFoldingState::Folded,
2172            AnimFoldingState::Opening(f, speed, speed2) => {
2173                let new_f = *f * *speed;
2174                if new_f < 0.001 {
2175                    AnimFoldingState::Open
2176                }
2177                else {
2178                    AnimFoldingState::Opening(new_f, *speed * *speed2, *speed2)
2179                }
2180            },
2181            AnimFoldingState::Folding(f, speed, speed2) => {
2182                let new_f = *f * *speed;
2183                if new_f < 0.001 {
2184                    AnimFoldingState::Folded
2185                }
2186                else {
2187                    AnimFoldingState::Folding(new_f, *speed * *speed2, *speed2)
2188                }
2189            },
2190        }
2191    }
2192}
2193