1+ mod trie;
2+
13use crate :: { ColorTheme , Syntax , Token , TokenType , format_token} ;
24use egui:: {
3- Event , Frame , Modifiers , Sense , Stroke , TextBuffer , text :: CCursor , text_edit:: TextEditOutput ,
5+ Event , Frame , Modifiers , Sense , Stroke , TextBuffer , text_edit:: TextEditOutput ,
46 text_selection:: text_cursor_state:: ccursor_previous_word,
57} ;
68use trie:: Trie ;
79
8- mod trie {
9- #![ allow( dead_code) ]
10- use std:: { iter:: Peekable , str:: Chars } ;
11-
12- const ROOT_CHAR : char = ' ' ;
13-
14- #[ derive( Debug , Clone ) ]
15- pub struct Trie {
16- root : char ,
17- is_word : bool ,
18- leaves : Vec < Trie > ,
19- }
20-
21- impl PartialEq for Trie {
22- fn eq ( & self , other : & Self ) -> bool {
23- self . root == other. root
24- }
25- }
26- impl PartialOrd for Trie {
27- fn partial_cmp ( & self , other : & Self ) -> Option < std:: cmp:: Ordering > {
28- Some ( self . cmp ( other) )
29- }
30- }
31- impl Ord for Trie {
32- fn cmp ( & self , other : & Self ) -> std:: cmp:: Ordering {
33- self . root . cmp ( & other. root )
34- }
35- }
36- impl Eq for Trie { }
37-
38- impl Default for Trie {
39- fn default ( ) -> Self {
40- Self {
41- root : ROOT_CHAR ,
42- is_word : false ,
43- leaves : vec ! [ ] ,
44- }
45- }
46- }
47-
48- impl Trie {
49- pub fn new ( root : char ) -> Self {
50- Trie {
51- root,
52- ..Default :: default ( )
53- }
54- }
55- pub fn clear ( & mut self ) {
56- self . leaves . clear ( ) ;
57- }
58- pub fn push ( & mut self , word : & str ) {
59- self . push_chars ( & mut word. chars ( ) ) ;
60- }
61-
62- pub fn push_chars ( & mut self , word : & mut Chars ) {
63- if let Some ( first) = word. next ( ) {
64- if let Some ( leaf) = self . leaves . iter_mut ( ) . find ( |l| l. root == first) {
65- leaf. push_chars ( word)
66- } else {
67- let mut new = Trie :: new ( first) ;
68- new. push_chars ( word) ;
69- self . leaves . push ( new) ;
70- }
71- } else {
72- self . is_word = true ;
73- self . leaves . sort ( ) ;
74- self . leaves . reverse ( ) ;
75- }
76- }
77-
78- pub fn from_words ( words : & [ & str ] ) -> Self {
79- let mut trie = Trie :: new ( ROOT_CHAR ) ;
80- words. iter ( ) . for_each ( |w| {
81- trie. push_chars ( & mut w. chars ( ) ) ;
82- } ) ;
83- trie
84- }
85-
86- pub fn words ( & self ) -> Vec < String > {
87- let mut words = vec ! [ ] ;
88- for child in self . leaves . iter ( ) {
89- child. words_recursive ( "" , & mut words) ;
90- }
91- words. reverse ( ) ;
92- words
93- }
94- fn words_recursive ( & self , prefix : & str , words : & mut Vec < String > ) {
95- let mut prefix = prefix. to_string ( ) ;
96- prefix. push ( self . root ) ;
97- if self . is_word {
98- words. push ( prefix. clone ( ) ) ;
99- }
100- for child in self . leaves . iter ( ) {
101- child. words_recursive ( & prefix, words) ;
102- }
103- }
104-
105- pub fn find_completions ( & self , prefix : & str ) -> Vec < String > {
106- self . find_by_prefix ( prefix)
107- . map ( |t| t. words ( ) )
108- . unwrap_or_default ( )
109- }
110- pub fn find_by_prefix ( & self , prefix : & str ) -> Option < & Trie > {
111- let mut found = None ;
112- let mut start = " " . to_string ( ) ;
113- start. push_str ( prefix) ;
114- let mut part = start. chars ( ) . peekable ( ) ;
115- self . find_recursice ( & mut part, & mut found) ;
116- found
117- }
118- fn find_recursice < ' a > ( & ' a self , part : & mut Peekable < Chars > , found : & mut Option < & ' a Trie > ) {
119- if let Some ( c) = part. next ( )
120- && self . root == c
121- {
122- if part. peek ( ) . is_none ( ) {
123- * found = Some ( self ) ;
124- }
125- self . leaves
126- . iter ( )
127- . for_each ( |l| l. find_recursice ( & mut part. clone ( ) , found) )
128- }
129- }
10+ impl From < & Syntax > for Trie {
11+ fn from ( syntax : & Syntax ) -> Trie {
12+ let mut trie = Trie :: default ( ) ;
13+
14+ syntax. keywords . iter ( ) . for_each ( |word| trie. push ( word) ) ;
15+ syntax. types . iter ( ) . for_each ( |word| trie. push ( word) ) ;
16+ syntax. special . iter ( ) . for_each ( |word| trie. push ( word) ) ;
17+ if !syntax. case_sensitive {
18+ syntax
19+ . keywords
20+ . iter ( )
21+ . for_each ( |word| trie. push ( & word. to_lowercase ( ) ) ) ;
22+ syntax
23+ . types
24+ . iter ( )
25+ . for_each ( |word| trie. push ( & word. to_lowercase ( ) ) ) ;
26+ syntax
27+ . special
28+ . iter ( )
29+ . for_each ( |word| trie. push ( & word. to_lowercase ( ) ) ) ;
30+ }
31+ trie
13032 }
13133}
132- pub fn trie_from_syntax ( syntax : & Syntax ) -> Trie {
133- let mut trie = Trie :: default ( ) ;
13434
135- syntax. keywords . iter ( ) . for_each ( |word| trie. push ( word) ) ;
136- syntax. types . iter ( ) . for_each ( |word| trie. push ( word) ) ;
137- syntax. special . iter ( ) . for_each ( |word| trie. push ( word) ) ;
138- if !syntax. case_sensitive {
139- syntax
140- . keywords
141- . iter ( )
142- . for_each ( |word| trie. push ( & word. to_lowercase ( ) ) ) ;
143- syntax
144- . types
145- . iter ( )
146- . for_each ( |word| trie. push ( & word. to_lowercase ( ) ) ) ;
147- syntax
148- . special
149- . iter ( )
150- . for_each ( |word| trie. push ( & word. to_lowercase ( ) ) ) ;
151- }
152- trie
153- }
154-
155- #[ derive( Default , Debug , Clone ) ]
35+ #[ derive( Default , Debug , Clone , PartialEq ) ]
36+ /// Code-completer with pop-up above CodeEditor.
37+ /// In future releases will be replaced with trait.
15638pub struct Completer {
15739 prefix : String ,
158- cursor : CCursor ,
40+ cursor : usize ,
15941 ignore_cursor : Option < usize > ,
16042 trie_syntax : Trie ,
16143 trie_user : Option < Trie > ,
16244 variant_id : usize ,
16345 completions : Vec < String > ,
16446}
16547
166- /// Completer shoud be stored somewhere in your App struct.
167- /// In future releases will be replaced with trait.
16848impl Completer {
49+ /// Completer shoud be stored somewhere in your App struct.
16950 pub fn new_with_syntax ( syntax : & Syntax ) -> Self {
17051 Completer {
171- trie_syntax : trie_from_syntax ( syntax) ,
52+ trie_syntax : Trie :: from ( syntax) ,
17253 ..Default :: default ( )
17354 }
17455 }
@@ -178,6 +59,9 @@ impl Completer {
17859 ..self
17960 }
18061 }
62+ pub fn push_word ( & mut self , word : & str ) {
63+ self . trie_syntax . push ( word) ;
64+ }
18165
18266 /// If using Completer without CodeEditor this method should be called before text-editing widget.
18367 /// Up/Down arrows for selection, Tab for completion, Esc for hiding
@@ -186,7 +70,7 @@ impl Completer {
18670 return ;
18771 }
18872 if let Some ( cursor) = self . ignore_cursor
189- && cursor == self . cursor . index
73+ && cursor == self . cursor
19074 {
19175 return ;
19276 }
@@ -206,7 +90,7 @@ impl Completer {
20690 let last = self . completions . len ( ) . saturating_sub ( 1 ) ;
20791 ctx. input_mut ( |i| {
20892 if i. consume_key ( Modifiers :: NONE , egui:: Key :: Escape ) {
209- self . ignore_cursor = Some ( self . cursor . index ) ;
93+ self . ignore_cursor = Some ( self . cursor ) ;
21094 } else if i. consume_key ( Modifiers :: NONE , egui:: Key :: ArrowDown ) {
21195 self . variant_id = if self . variant_id == last {
21296 0
@@ -238,6 +122,9 @@ impl Completer {
238122 fontsize : f32 ,
239123 editor_output : & mut TextEditOutput ,
240124 ) {
125+ if !editor_output. response . has_focus ( ) {
126+ return ;
127+ }
241128 let ctx = editor_output. response . ctx . clone ( ) ;
242129 let galley = & editor_output. galley ;
243130
@@ -263,15 +150,15 @@ impl Completer {
263150 // let cursor_on_screen = editor_output.response.rect.left_top()
264151 // + cursor_pos_in_galley.left_bottom().to_vec2();
265152 let word_start = ccursor_previous_word ( galley. text ( ) , cursor) ;
266- if self . cursor != cursor {
267- self . cursor = cursor;
153+ if self . cursor != cursor. index {
154+ self . cursor = cursor. index ;
268155 self . prefix . clear ( ) ;
269156 // self.completions.clear();
270157 self . ignore_cursor = None ;
271158 self . variant_id = 0 ;
272159 }
273160
274- if self . ignore_cursor . is_some_and ( |c| c == self . cursor . index ) {
161+ if self . ignore_cursor . is_some_and ( |c| c == self . cursor ) {
275162 editor_output. response . request_focus ( ) ;
276163 return ;
277164 } else {
@@ -341,4 +228,19 @@ impl Completer {
341228 }
342229 }
343230 }
231+
232+ /// Completer on text-editing widget, see demo for example
233+ pub fn show_on_text_widget (
234+ & mut self ,
235+ ui : & mut egui:: Ui ,
236+ syntax : & Syntax ,
237+ theme : & ColorTheme ,
238+ mut widget : impl FnMut ( & mut egui:: Ui ) -> TextEditOutput ,
239+ ) -> TextEditOutput {
240+ self . handle_input ( ui. ctx ( ) ) ;
241+ let fontsize = ui. text_style_height ( & egui:: TextStyle :: Monospace ) ;
242+ let mut output = widget ( ui) ;
243+ self . show ( syntax, theme, fontsize, & mut output) ;
244+ output
245+ }
344246}
0 commit comments