makepad_widget/
textbuffer.rs

1use makepad_render::*;
2
3use crate::textcursor::*;
4
5#[derive(Clone, Default)]
6pub struct TextBuffer {
7    // Vec<Vec<char>> was chosen because, for all practical use (code) most lines are short
8    // Concatenating the total into a utf8 string is trivial, and O(1) for windowing into the lines is handy.
9    // Also inserting lines is pretty cheap even approaching 100k lines.
10    // If you want to load a 100 meg single line file or something with >100k lines
11    // other options are better. But these are not usecases for this editor.
12    pub lines: Vec<Vec<char>>,
13    pub undo_stack: Vec<TextUndo>,
14    pub redo_stack: Vec<TextUndo>,
15    
16    //pub load_file_read: FileRead,
17    pub is_loaded: bool,
18    pub signal: Signal,
19    
20    pub mutation_id: u64,
21    pub is_crlf: bool,
22    pub messages: TextBufferMessages,
23    pub flat_text: Vec<char>,
24    pub token_chunks: Vec<TokenChunk>,
25    pub token_chunks_id: u64,
26    pub keyboard: TextBufferKeyboard,
27}
28
29impl TextBuffer{
30    pub fn status_loaded()->StatusId{uid!()}
31    pub fn status_message_update()->StatusId{uid!()}
32    pub fn status_jump_to_offset()->StatusId{uid!()}
33    pub fn status_data_update()->StatusId{uid!()}
34    pub fn status_keyboard_update()->StatusId{uid!()}
35}
36
37#[derive(Clone, Default)]
38pub struct TextBufferKeyboard {
39    pub modifiers: KeyModifiers,
40    pub key_down: Option<KeyCode>,
41    pub key_up: Option<KeyCode>
42}
43
44#[derive(Clone, Default)]
45pub struct TextBufferMessages {
46    //pub gc_id: u64,
47    // gc id for the update pass
48    pub mutation_id: u64,
49    // only if this matches the textbuffer mutation id are the messages valid
50    pub cursors: Vec<TextCursor>,
51    pub bodies: Vec<TextBufferMessage>,
52    pub jump_to_offset: usize
53}
54
55#[derive(Clone, PartialEq)]
56pub enum TextBufferMessageLevel {
57    Error,
58    Warning,
59    Log
60}
61
62#[derive(Clone)]
63pub struct TextBufferMessage {
64    pub level: TextBufferMessageLevel,
65    pub body: String
66}
67
68/*
69impl TextBuffers {
70    pub fn from_path(&mut self, cx: &mut Cx, path: &str) -> &mut TextBuffer {
71        let root_path = &self.root_path;
72        self.storage.entry(path.to_string()).or_insert_with( || {
73            TextBuffer {
74                signal: cx.new_signal(),
75                mutation_id: 1,
76                load_file_read: cx.file_read(&format!("{}{}", root_path, path)),
77                ..Default::default()
78            }
79        })
80    }
81    
82    pub fn save_file(&mut self, cx: &mut Cx, path: &str) {
83        let text_buffer = self.storage.get(path);
84        if let Some(text_buffer) = text_buffer {
85            let string = text_buffer.get_as_string();
86            cx.file_write(&format!("{}{}", self.root_path, path), string.as_bytes());
87            //cx.http_send("POST", path, "192.168.0.20", "2001", &string);
88        }
89    }
90    
91    pub fn handle_file_read(&mut self, cx: &mut Cx, fr: &FileReadEvent) -> bool {
92        for (_path, text_buffer) in &mut self.storage {
93            if let Some(utf8_data) = text_buffer.load_file_read.resolve_utf8(fr) {
94                if let Ok(utf8_data) = utf8_data {
95                    // TODO HANDLE ERROR CASE
96                    text_buffer.is_crlf = !utf8_data.find("\r\n").is_none();
97                    text_buffer.lines = TextBuffer::split_string_to_lines(&utf8_data.to_string());
98                    cx.send_signal(text_buffer.signal, SIGNAL_TEXTBUFFER_LOADED);
99                }
100                return true
101            }
102        }
103        return false;
104    }
105}
106*/
107#[derive(Clone, Copy)]
108pub struct TextPos {
109    pub row: usize,
110    pub col: usize
111}
112
113impl TextPos {
114    pub fn dist(&self, other: &TextPos) -> f64 {
115        let dr = (self.row as f64) - (other.row as f64);
116        let dc = (self.col as f64) - (other.col as f64);
117        (dr * dr + dc * dc).sqrt()
118    }
119    
120    pub fn zero() -> TextPos {
121        TextPos {row: 0, col: 0}
122    }
123}
124
125#[derive(Clone, PartialEq)]
126pub enum TextUndoGrouping {
127    Space,
128    Newline,
129    Character(u64),
130    Backspace(u64),
131    Delete(usize),
132    Block,
133    Tab,
134    Cut,
135    Format,
136    Other
137}
138
139impl Default for TextUndoGrouping {
140    fn default() -> TextUndoGrouping {
141        TextUndoGrouping::Other
142    }
143}
144
145impl TextUndoGrouping {
146    fn wants_grouping(&self) -> bool {
147        match self {
148            TextUndoGrouping::Space => true,
149            TextUndoGrouping::Newline => false,
150            TextUndoGrouping::Character(_) => true,
151            TextUndoGrouping::Backspace(_) => true,
152            TextUndoGrouping::Delete(_) => true,
153            TextUndoGrouping::Block => false,
154            TextUndoGrouping::Tab => false,
155            TextUndoGrouping::Format => false,
156            TextUndoGrouping::Cut => false,
157            TextUndoGrouping::Other => false
158        }
159    }
160}
161
162#[derive(Clone)]
163pub struct TextUndo {
164    pub ops: Vec<TextOp>,
165    pub grouping: TextUndoGrouping,
166    pub cursors: TextCursorSet
167}
168
169#[derive(Clone)]
170pub struct TextOp {
171    pub start: usize,
172    pub len: usize,
173    pub lines: Vec<Vec<char>>,
174}
175
176fn calc_char_count(lines: &Vec<Vec<char>>) -> usize {
177    let mut char_count = 0;
178    for line in lines {
179        char_count += line.len()
180    }
181    char_count += lines.len() - 1;
182    // invisible newline chars
183    char_count
184}
185
186impl TextBuffer {
187    pub fn with_signal(cx:&mut Cx)->Self{
188        let mut tb = TextBuffer::default();
189        tb.signal = cx.new_signal();
190        tb
191    }
192    
193    pub fn from_utf8(data: &str) -> Self {
194        let mut tb = TextBuffer::default();
195        tb.load_from_utf8(data);
196        tb
197    }
198    
199    pub fn needs_token_chunks(&mut self) -> bool {
200        if self.token_chunks_id != self.mutation_id && self.is_loaded {
201            self.token_chunks_id = self.mutation_id;
202            self.token_chunks.truncate(0);
203            self.flat_text.truncate(0);
204            return true
205        }
206        return false
207    }
208    
209    pub fn offset_to_text_pos(&self, char_offset: usize) -> TextPos {
210        let mut char_count = 0;
211        for (row, line) in self.lines.iter().enumerate() {
212            let next_char_count = char_count + line.len() + 1;
213            if next_char_count > char_offset {
214                return TextPos {row: row, col: char_offset - char_count}
215            }
216            char_count = next_char_count;
217        }
218        TextPos {row: self.lines.len().max(1) - 1, col: 0}
219    }
220    
221    pub fn offset_to_text_pos_next(&self, query_off: usize, old_pos: TextPos, old_off: usize) -> TextPos {
222        let mut row = old_pos.row;
223        let mut iter_off = old_off - old_pos.col;
224        while row < self.lines.len() {
225            let line = &self.lines[row];
226            let next_off = iter_off + line.len() + 1;
227            if next_off > query_off {
228                return TextPos {row: row, col: query_off - iter_off}
229            }
230            iter_off = next_off;
231            row += 1;
232        }
233        TextPos {row: self.lines.len().max(1) - 1, col: 0}
234    }
235    
236    pub fn text_pos_to_offset(&self, pos: TextPos) -> usize {
237        let mut char_count = 0;
238        if pos.row >= self.lines.len() {
239            return self.calc_char_count()
240        }
241        for (ln_row, line) in self.lines.iter().enumerate() {
242            if ln_row == pos.row {
243                return char_count + (line.len()).min(pos.col);
244            }
245            char_count += line.len() + 1;
246        }
247        0
248    }
249    
250    pub fn get_nearest_line_range(&self, offset: usize) -> (usize, usize) {
251        let pos = self.offset_to_text_pos(offset);
252        let line = &self.lines[pos.row];
253        return (offset - pos.col, line.len() + if pos.row < (line.len().max(1) - 1) {1}else {0})
254    }
255    
256    pub fn calc_next_line_indent_depth(&self, offset: usize, tabsize: usize) -> (usize, usize) {
257        let pos = self.offset_to_text_pos(offset);
258        let line = &self.lines[pos.row];
259        let mut prev_index = pos.col;
260        if prev_index == 0 || prev_index > line.len() {
261            return (offset - pos.col, 0);
262        };
263        
264        let mut instep = 0;
265        while prev_index > 0 {
266            let prev = line[prev_index - 1];
267            if prev == ')' || prev == '}' || prev == ']' {
268                break;
269            }
270            if prev == '{' || prev == '(' || prev == '[' {
271                instep = tabsize;
272                break;
273            }
274            prev_index -= 1;
275        }
276        for (i, ch) in line.iter().enumerate() {
277            if *ch != ' ' {
278                return (offset - pos.col, i + instep);
279            }
280        };
281        return (offset - pos.col, line.len());
282    }
283    
284    pub fn calc_line_indent_depth(&self, row: usize) -> usize {
285        let line = &self.lines[row];
286        for (i, ch) in line.iter().enumerate() {
287            if *ch != ' ' {
288                return i
289            }
290        };
291        return line.len()
292    }
293    
294    pub fn calc_backspace_line_indent_depth_and_pair(&self, offset: usize) -> (usize, usize) {
295        let pos = self.offset_to_text_pos(offset);
296        let line = &self.lines[pos.row];
297        for i in 0..line.len() {
298            let ch = line[i];
299            if ch != ' ' {
300                if i == pos.col {
301                    return (offset - (i + 1), 1 + i);
302                }
303                // check pair removal
304                if pos.col >= 1 && pos.col <line.len() {
305                    let pch = line[pos.col - 1];
306                    let nch = line[pos.col];
307                    if pch == '{' && nch == '}'
308                        || pch == '(' && nch == ')'
309                        || pch == '[' && nch == ']' {
310                        return (offset - 1, 2)
311                    }
312                }
313                return (offset - 1, 1);
314            }
315        };
316        return ((offset - pos.col - 1), line.len() + 1);
317    }
318    
319    pub fn calc_deletion_whitespace(&self, offset: usize) -> Option<(usize, usize, usize, usize)> {
320        let pos = self.offset_to_text_pos(offset);
321        if self.lines.len() < 1 || pos.row >= self.lines.len() - 1 {
322            return None
323        }
324        let line1 = &self.lines[pos.row];
325        let mut line1_ws = 0;
326        for ch in line1 {
327            if *ch != ' ' {
328                break;
329            }
330            line1_ws += 1;
331        };
332        
333        let line2 = &self.lines[pos.row + 1];
334        let mut line2_ws = 0;
335        for ch in line2 {
336            if *ch != ' ' {
337                break;
338            }
339            line2_ws += 1;
340        };
341        
342        return Some((offset - pos.col, line1_ws, line1.len(), line2_ws));
343    }
344    
345    
346    pub fn calc_deindent_whitespace(&self, offset: usize) -> Option<(usize, usize, usize)> {
347        let pos = self.offset_to_text_pos(offset);
348        if self.lines.len() < 1 || pos.row >= self.lines.len() {
349            return None
350        }
351        let line1 = &self.lines[pos.row];
352        let mut line1_ws = 0;
353        for ch in line1 {
354            if *ch != ' ' {
355                break;
356            }
357            line1_ws += 1;
358        };
359        
360        return Some((offset - pos.col, line1_ws, line1.len()));
361    }
362    
363    pub fn calc_char_count(&self) -> usize {
364        calc_char_count(&self.lines)
365    }
366    
367    pub fn get_line_count(&self) -> usize {
368        self.lines.len()
369    }
370    
371    pub fn is_empty(&self) -> bool {
372        self.lines.len() == 0 || self.lines.len() == 1 && self.lines[0].len() == 0
373    }
374    
375    pub fn get_range_as_string(&self, start: usize, len: usize, ret: &mut String) {
376        let mut pos = self.offset_to_text_pos(start);
377        for _ in 0..len {
378            let line = &self.lines[pos.row];
379            if pos.col >= line.len() {
380                ret.push('\n');
381                pos.col = 0;
382                pos.row += 1;
383                if pos.row >= self.lines.len() {
384                    return;
385                }
386            }
387            else {
388                ret.push(line[pos.col]);
389                pos.col += 1;
390            }
391        };
392    }
393    
394    
395    pub fn get_char(&self, start: usize) -> char {
396        let pos = self.offset_to_text_pos(start);
397        let line = &self.lines[pos.row];
398        if pos.row == self.lines.len() - 1 && pos.col >= line.len() {
399            return '\0'
400        }
401        if pos.col >= line.len() {
402            return '\n'
403        }
404        return line[pos.col]
405    }
406    
407    pub fn get_as_string(&self) -> String {
408        let mut ret = String::new();
409        for i in 0..self.lines.len() {
410            let line = &self.lines[i];
411            for ch in line {
412                ret.push(*ch);
413            }
414            if i != self.lines.len() - 1 {
415                if self.is_crlf {
416                    ret.push('\r');
417                    ret.push('\n');
418                }
419                else {
420                    ret.push('\n');
421                }
422            }
423        }
424        return ret
425    }
426    
427    pub fn send_textbuffer_loaded_signal(&self, cx: &mut Cx) {
428        cx.send_signal(self.signal, TextBuffer::status_loaded());
429    }
430    
431    pub fn load_from_utf8(&mut self, utf8: &str) {
432        self.is_loaded = true;
433        self.is_crlf = !utf8.find("\r\n").is_none();
434        self.lines = TextBuffer::split_string_to_lines(utf8);
435        self.mutation_id += 1;
436    }
437    
438    pub fn replace_line(&mut self, row: usize, start_col: usize, len: usize, rep_line: Vec<char>) -> Vec<char> {
439        self.mutation_id += 1;
440        self.lines[row].splice(start_col..(start_col + len), rep_line).collect()
441    }
442    
443    pub fn copy_line(&self, row: usize, start_col: usize, len: usize) -> Vec<char> {
444        let line = &self.lines[row];
445        if start_col >= line.len() {
446            return vec![]
447        }
448        if start_col + len > line.len() {
449            self.lines[row][start_col..line.len()].iter().cloned().collect()
450        }
451        else {
452            self.lines[row][start_col..(start_col + len)].iter().cloned().collect()
453        }
454    }
455    
456    pub fn replace_range(&mut self, start: usize, len: usize, mut rep_lines: Vec<Vec<char>>) -> Vec<Vec<char>> {
457        self.mutation_id += 1;
458        let start_pos = self.offset_to_text_pos(start);
459        let end_pos = self.offset_to_text_pos_next(start + len, start_pos, start);
460        
461        if start_pos.row == end_pos.row && rep_lines.len() == 1 { // replace in one line
462            let rep_line_zero = rep_lines.drain(0..1).next().unwrap();
463            
464            if start_pos.col>end_pos.col {
465                return vec![];
466            }
467            let line = self.lines[start_pos.row].splice(start_pos.col..end_pos.col, rep_line_zero).collect();
468            return vec![line];
469        }
470        else {
471            if rep_lines.len() == 1 { // we are replacing multiple lines with one line
472                // drain first line
473                let rep_line_zero = rep_lines.drain(0..1).next().unwrap();
474                
475                // replace it in the first
476                let first = self.lines[start_pos.row].splice(start_pos.col.., rep_line_zero).collect();
477                
478                // collect the middle ones
479                let mut middle: Vec<Vec<char>> = self.lines.drain((start_pos.row + 1)..(end_pos.row)).collect();
480                
481                // cut out the last bit
482                let last: Vec<char> = self.lines[start_pos.row + 1].drain(0..end_pos.col).collect();
483                
484                // last line bit
485                let mut last_line = self.lines.drain((start_pos.row + 1)..(start_pos.row + 2)).next().unwrap();
486                
487                // merge start_row+1 into start_row
488                self.lines[start_pos.row].append(&mut last_line);
489                
490                // concat it all together
491                middle.insert(0, first);
492                middle.push(last);
493                
494                return middle
495            }
496            else if start_pos.row == end_pos.row { // replacing single line with multiple lines
497                let mut last_bit: Vec<char> = self.lines[start_pos.row].drain(end_pos.col..).collect();
498                // but we have co drain end_col..
499                
500                // replaced first line
501                let rep_lines_len = rep_lines.len();
502                let rep_line_first: Vec<char> = rep_lines.drain(0..1).next().unwrap();
503                let line = self.lines[start_pos.row].splice(start_pos.col.., rep_line_first).collect();
504                
505                // splice in middle rest
506                let rep_line_mid = rep_lines.drain(0..(rep_lines.len()));
507                self.lines.splice((start_pos.row + 1)..(start_pos.row + 1), rep_line_mid);
508                
509                // append last bit
510                self.lines[start_pos.row + rep_lines_len - 1].append(&mut last_bit);
511                
512                return vec![line];
513            }
514            else { // replaceing multiple lines with multiple lines
515                // drain and replace last line
516                let rep_line_last = rep_lines.drain((rep_lines.len() - 1)..(rep_lines.len())).next().unwrap();
517                let last = self.lines[end_pos.row].splice(..end_pos.col, rep_line_last).collect();
518                
519                // swap out middle lines and drain them
520                let rep_line_mid = rep_lines.drain(1..(rep_lines.len()));
521                let mut middle: Vec<Vec<char>> = self.lines.splice((start_pos.row + 1)..end_pos.row, rep_line_mid).collect();
522                
523                // drain and replace first line
524                let rep_line_zero = rep_lines.drain(0..1).next().unwrap();
525                let first = self.lines[start_pos.row].splice(start_pos.col.., rep_line_zero).collect();
526                
527                // concat it all together
528                middle.insert(0, first);
529                middle.push(last);
530                return middle
531            }
532        }
533    }
534    
535    pub fn replace_lines(&mut self, start_row: usize, end_row: usize, rep_lines: Vec<Vec<char>>) -> TextOp {
536        let start = self.text_pos_to_offset(TextPos {row: start_row, col: 0});
537        let end = self.text_pos_to_offset(TextPos {row: end_row, col: 0});
538        let end_mark = if end_row >= self.lines.len() {0}else {1};
539        let rep_lines_chars = calc_char_count(&rep_lines);
540        let lines = self.replace_range(start, end - start - end_mark, rep_lines);
541        TextOp {
542            start: start,
543            len: rep_lines_chars,
544            lines: lines
545        }
546    }
547    
548    pub fn split_string_to_lines(string: &str) -> Vec<Vec<char>> {
549        if !string.find("\r\n").is_none() {
550            return string.split("\r\n").map( | s | s.chars().collect()).collect()
551        }
552        else {
553            return string.split("\n").map( | s | s.chars().collect()).collect()
554        }
555    }
556    
557    pub fn replace_lines_with_string(&mut self, start: usize, len: usize, string: &str) -> TextOp {
558        let rep_lines = Self::split_string_to_lines(string);
559        let rep_lines_chars = calc_char_count(&rep_lines);
560        let lines = self.replace_range(start, len, rep_lines);
561        TextOp {
562            start: start,
563            len: rep_lines_chars,
564            lines: lines
565        }
566    }
567    
568    pub fn replace_line_with_string(&mut self, start: usize, row: usize, col: usize, len: usize, string: &str) -> TextOp {
569        let rep_line: Vec<char> = string.chars().collect();
570        let rep_line_chars = rep_line.len();
571        let line = self.replace_line(row, col, len, rep_line);
572        TextOp {
573            start: start,
574            len: rep_line_chars,
575            lines: vec![line]
576        }
577    }
578    
579    pub fn replace_with_textop(&mut self, text_op: TextOp) -> TextOp {
580        let rep_lines_chars = calc_char_count(&text_op.lines);
581        let lines = self.replace_range(text_op.start, text_op.len, text_op.lines);
582        TextOp {
583            start: text_op.start,
584            len: rep_lines_chars,
585            lines: lines
586        }
587    }
588    
589    pub fn save_buffer(&mut self) {
590        //let out = self.lines.join("\n");
591    }
592    
593    pub fn undoredo(&mut self, mut text_undo: TextUndo, cursor_set: &mut TextCursorSet) -> TextUndo {
594        let mut ops = Vec::new();
595        while text_undo.ops.len() > 0 {
596            let op = text_undo.ops.pop().unwrap();
597            //text_undo.ops.len() - 1);
598            ops.push(self.replace_with_textop(op));
599        }
600        let text_undo_inverse = TextUndo {
601            ops: ops,
602            grouping: text_undo.grouping,
603            cursors: cursor_set.clone()
604        };
605        cursor_set.set = text_undo.cursors.set.clone();
606        cursor_set.last_cursor = text_undo.cursors.last_cursor;
607        text_undo_inverse
608    }
609    
610    // todo make more reuse in these functions
611    pub fn undo(&mut self, grouped: bool, cursor_set: &mut TextCursorSet) {
612        
613        if self.undo_stack.len() == 0 {
614            return;
615        }
616        let mut last_grouping = TextUndoGrouping::Other;
617        let mut first = true;
618        while self.undo_stack.len() > 0 {
619            if !first && !grouped {
620                break
621            }
622            if self.undo_stack.last().unwrap().grouping != last_grouping && !first {
623                break
624            }
625            first = false;
626            let text_undo = self.undo_stack.pop().unwrap();
627            let wants_grouping = text_undo.grouping.wants_grouping();
628            last_grouping = text_undo.grouping.clone();
629            let text_redo = self.undoredo(text_undo, cursor_set);
630            self.redo_stack.push(text_redo);
631            if !wants_grouping {
632                break;
633            }
634        }
635    }
636    
637    pub fn redo(&mut self, grouped: bool, cursor_set: &mut TextCursorSet) {
638        if self.redo_stack.len() == 0 {
639            return;
640        }
641        let mut last_grouping = TextUndoGrouping::Other;
642        let mut first = true;
643        while self.redo_stack.len() > 0 {
644            if !first {
645                if self.redo_stack.last().unwrap().grouping != last_grouping || !grouped {
646                    break
647                }
648            }
649            first = false;
650            let text_redo = self.redo_stack.pop().unwrap();
651            let wants_grouping = text_redo.grouping.wants_grouping();
652            last_grouping = text_redo.grouping.clone();
653            let text_undo = self.undoredo(text_redo, cursor_set);
654            self.undo_stack.push(text_undo);
655            if !wants_grouping {
656                break;
657            }
658        }
659    }
660    
661}
662
663pub struct LineTokenizer<'a> {
664    pub prev: char,
665    pub cur: char,
666    pub next: char,
667    iter: std::str::Chars<'a>
668}
669
670impl<'a> LineTokenizer<'a> {
671    pub fn new(st: &'a str) -> Self {
672        let mut ret = Self {
673            prev: '\0',
674            cur: '\0',
675            next: '\0',
676            iter: st.chars()
677        };
678        ret.advance();
679        ret
680    }
681    
682    pub fn advance(&mut self) {
683        if let Some(next) = self.iter.next() {
684            self.next = next;
685        }
686        else {
687            self.next = '\0'
688        }
689    }
690    
691    pub fn next_is_digit(&self) -> bool {
692        self.next >= '0' && self.next <= '9'
693    }
694    
695    pub fn next_is_letter(&self) -> bool {
696        self.next >= 'a' && self.next <= 'z'
697            || self.next >= 'A' && self.next <= 'Z'
698    }
699    
700    pub fn next_is_lowercase_letter(&self) -> bool {
701        self.next >= 'a' && self.next <= 'z'
702    }
703    
704    pub fn next_is_uppercase_letter(&self) -> bool {
705        self.next >= 'A' && self.next <= 'Z'
706    }
707    
708    pub fn next_is_hex(&self) -> bool {
709        self.next >= '0' && self.next <= '9'
710            || self.next >= 'a' && self.next <= 'f'
711            || self.next >= 'A' && self.next <= 'F'
712    }
713    
714    pub fn advance_with_cur(&mut self) {
715        self.cur = self.next;
716        self.advance();
717    }
718    
719    pub fn advance_with_prev(&mut self) {
720        self.prev = self.cur;
721        self.cur = self.next;
722        self.advance();
723    }
724    
725    pub fn keyword(&mut self, chunk: &mut Vec<char>, word: &str) -> bool {
726        for m in word.chars() {
727            if m == self.next {
728                chunk.push(m);
729                self.advance();
730            }
731            else {
732                return false
733            }
734        }
735        return true
736    }
737}
738
739pub struct TokenizerState<'a> {
740    pub prev: char,
741    pub cur: char,
742    pub next: char,
743    pub lines: &'a Vec<Vec<char>>,
744    pub line_counter: usize,
745    pub offset: usize,
746    iter: std::slice::Iter<'a, char>
747}
748
749impl<'a> TokenizerState<'a> {
750    pub fn new(lines: &'a Vec<Vec<char>>) -> Self {
751        let mut ret = Self {
752            lines: lines,
753            line_counter: 0,
754            offset: 0,
755            prev: '\0',
756            cur: '\0',
757            next: '\0',
758            iter: lines[0].iter()
759        };
760        ret.advance_with_cur();
761        ret
762    }
763    
764    pub fn advance(&mut self) {
765        if let Some(next) = self.iter.next() {
766            self.next = *next;
767            self.offset += 1;
768        }
769        else {
770            self.next_line();
771        }
772    }
773    
774    pub fn next_line(&mut self) {
775        if self.line_counter < self.lines.len() - 1 {
776            self.line_counter += 1;
777            self.offset += 1;
778            self.iter = self.lines[self.line_counter].iter();
779            self.next = '\n'
780        }
781        else {
782            self.offset += 1;
783            self.next = '\0'
784        }
785    }
786    
787    pub fn next_is_digit(&self) -> bool {
788        self.next >= '0' && self.next <= '9'
789    }
790    
791    pub fn next_is_letter(&self) -> bool {
792        self.next >= 'a' && self.next <= 'z'
793            || self.next >= 'A' && self.next <= 'Z'
794    }
795    
796    pub fn next_is_lowercase_letter(&self) -> bool {
797        self.next >= 'a' && self.next <= 'z'
798    }
799    
800    pub fn next_is_uppercase_letter(&self) -> bool {
801        self.next >= 'A' && self.next <= 'Z'
802    }
803    
804    pub fn next_is_hex(&self) -> bool {
805        self.next >= '0' && self.next <= '9'
806            || self.next >= 'a' && self.next <= 'f'
807            || self.next >= 'A' && self.next <= 'F'
808    }
809    
810    pub fn advance_with_cur(&mut self) {
811        self.cur = self.next;
812        self.advance();
813    }
814    
815    pub fn advance_with_prev(&mut self) {
816        self.prev = self.cur;
817        self.cur = self.next;
818        self.advance();
819    }
820    
821    pub fn keyword(&mut self, chunk: &mut Vec<char>, word: &str) -> bool {
822        for m in word.chars() {
823            if m == self.next {
824                chunk.push(m);
825                self.advance();
826            }
827            else {
828                return false
829            }
830        }
831        return true
832    }
833}
834
835#[derive(Clone, PartialEq, Copy, Debug)]
836pub enum TokenType {
837    Whitespace,
838    Newline,
839    Keyword,
840    Flow,
841    Fn,
842    TypeDef,
843    Looping,
844    Identifier,
845    Call,
846    TypeName,
847    ThemeName,
848    BuiltinType,
849    Hash,
850    
851    Regex,
852    String,
853    Number,
854    Bool,
855    
856    StringMultiBegin,
857    StringChunk,
858    StringMultiEnd,
859    
860    CommentLine,
861    CommentMultiBegin,
862    CommentChunk,
863    CommentMultiEnd,
864    
865    ParenOpen,
866    ParenClose,
867    Operator,
868    Namespace,
869    Splat,
870    Delimiter,
871    Colon,
872    
873    Warning,
874    Error,
875    Defocus,
876    
877    Unexpected,
878    Eof
879}
880
881impl TokenType {
882    pub fn should_ignore(&self) -> bool {
883        match self {
884            TokenType::Whitespace => true,
885            TokenType::Newline => true,
886            TokenType::CommentLine => true,
887            TokenType::CommentMultiBegin => true,
888            TokenType::CommentChunk => true,
889            TokenType::CommentMultiEnd => true,
890            _ => false
891        }
892    }
893}
894
895#[derive(Clone)]
896pub struct TokenChunk {
897    pub token_type: TokenType,
898    pub offset: usize,
899    pub pair_token: usize,
900    pub len: usize,
901    pub next: char,
902    //    pub chunk: Vec<char>
903}
904
905impl TokenChunk {
906    pub fn scan_last_token(token_chunks: &Vec<TokenChunk>) -> TokenType {
907        let mut prev_tok_index = token_chunks.len();
908        while prev_tok_index > 0 {
909            let tt = &token_chunks[prev_tok_index - 1].token_type;
910            if !tt.should_ignore() {
911                return tt.clone();
912            }
913            prev_tok_index -= 1;
914        }
915        return TokenType::Unexpected
916    }
917    
918    pub fn push_with_pairing(token_chunks: &mut Vec<TokenChunk>, pair_stack: &mut Vec<usize>, next: char, offset: usize, offset2: usize, token_type: TokenType) {
919        let pair_token = if token_type == TokenType::ParenOpen {
920            pair_stack.push(token_chunks.len());
921            token_chunks.len()
922        }
923        else if token_type == TokenType::ParenClose {
924            if pair_stack.len() > 0 {
925                let other = pair_stack.pop().unwrap();
926                token_chunks[other].pair_token = token_chunks.len();
927                other
928            }
929            else {
930                token_chunks.len()
931            }
932        }
933        else {
934            token_chunks.len()
935        };
936        token_chunks.push(TokenChunk {
937            offset: offset,
938            pair_token: pair_token,
939            len: offset2 - offset,
940            next: next,
941            token_type: token_type.clone()
942        })
943    }
944    
945}
946
947pub struct TokenParserItem {
948    pub chunk: Vec<char>,
949    pub token_type: TokenType,
950}
951
952pub struct TokenParser<'a> {
953    pub tokens: &'a Vec<TokenChunk>,
954    pub flat_text: &'a Vec<char>,
955    pub index: usize,
956    pub next_index: usize
957}
958
959impl <'a>TokenParser<'a> {
960    pub fn new(flat_text: &'a Vec<char>, token_chunks: &'a Vec<TokenChunk>) -> TokenParser<'a> {
961        TokenParser {
962            tokens: token_chunks,
963            flat_text: flat_text,
964            index: 0,
965            next_index: 0
966        }
967    }
968    
969    pub fn advance(&mut self) -> bool {
970        if self.next_index >= self.tokens.len() {
971            return false
972        }
973        self.index = self.next_index;
974        self.next_index += 1;
975        return true;
976    }
977    
978    pub fn prev_type(&self) -> TokenType {
979        if self.index > 0 {
980            self.tokens[self.index - 1].token_type
981        }
982        else {
983            TokenType::Unexpected
984        }
985    }
986    
987    pub fn cur_type(&self) -> TokenType {
988        self.tokens[self.index].token_type
989    }
990    
991    pub fn next_type(&self) -> TokenType {
992        if self.index < self.tokens.len() - 1 {
993            self.tokens[self.index + 1].token_type
994        }
995        else {
996            TokenType::Unexpected
997        }
998    }
999    
1000    pub fn prev_char(&self) -> char {
1001        if self.index > 0 {
1002            let len = self.tokens[self.index - 1].len;
1003            let ch = self.flat_text[self.tokens[self.index - 1].offset];
1004            if len == 1 || ch == ' ' {
1005                return ch
1006            }
1007        }
1008        '\0'
1009    }
1010    
1011    pub fn cur_char(&self) -> char {
1012        let len = self.tokens[self.index].len;
1013        let ch = self.flat_text[self.tokens[self.index].offset];
1014        if len == 1 || ch == ' ' {
1015            return ch
1016        }
1017        '\0'
1018    }
1019    
1020    pub fn cur_chunk(&self) -> &[char] {
1021        let offset = self.tokens[self.index].offset;
1022        let len = self.tokens[self.index].len;
1023        &self.flat_text[offset..(offset + len)]
1024    }
1025    
1026    pub fn next_char(&self) -> char {
1027        if self.index < self.tokens.len() - 1 {
1028            let len = self.tokens[self.index + 1].len;
1029            let ch = self.flat_text[self.tokens[self.index + 1].offset];
1030            if len == 1 || ch == ' ' {
1031                return ch
1032            }
1033        }
1034        '\0'
1035    }
1036}
1037
1038pub struct FormatOutput {
1039    pub out_lines: Vec<Vec<char >>
1040}
1041
1042impl FormatOutput {
1043    pub fn new() -> FormatOutput {
1044        FormatOutput {
1045            out_lines: Vec::new()
1046        }
1047    }
1048    
1049    pub fn indent(&mut self, indent_depth: usize) {
1050        let last_line = self.out_lines.last_mut().unwrap();
1051        for _ in 0..indent_depth {
1052            last_line.push(' ');
1053        }
1054    }
1055    
1056    pub fn strip_space(&mut self) {
1057        let last_line = self.out_lines.last_mut().unwrap();
1058        if last_line.len()>0 && *last_line.last().unwrap() == ' ' {
1059            last_line.pop();
1060        }
1061    }
1062    
1063    pub fn new_line(&mut self) {
1064        self.out_lines.push(Vec::new());
1065    }
1066    
1067    pub fn extend(&mut self, chunk: &[char]) {
1068        let last_line = self.out_lines.last_mut().unwrap();
1069        last_line.extend_from_slice(chunk);
1070    }
1071    
1072    pub fn add_space(&mut self) {
1073        let last_line = self.out_lines.last_mut().unwrap();
1074        if last_line.len()>0 {
1075            if *last_line.last().unwrap() != ' ' {
1076                last_line.push(' ');
1077            }
1078        }
1079        else {
1080            last_line.push(' ');
1081        }
1082    }
1083    
1084}