f71cb435147b7b3a8cef1da5ce4357c31a67e43a
[roobuilder] / src / Palete / CompletionProvider.vala
1  
2 using Gtk;
3
4 // not sure why - but extending Gtk.SourceCompletionProvider seems to give an error..
5 namespace Palete {
6
7     public class CompletionProvider : Object, GtkSource.CompletionProvider
8     {
9                 public Editor editor; 
10                 //public WindowState windowstate;
11                 public CompletionModel model;
12
13                 public CompletionProvider(Editor editor)
14                 {
15                     this.editor  = editor;
16                    // this.windowstate = null; // not ready until the UI is built.
17                     
18                 }
19
20                 public string get_name ()
21                 {
22                   return  "roojsbuilder";
23                 }
24
25                 public int get_priority (GtkSource.CompletionContext context)
26                 {
27                   return 200;
28                 }
29                 
30                 public  void activate (GtkSource.CompletionContext context, GtkSource.CompletionProposal proposal)
31                 {
32                         var  p = (CompletionProposal) proposal;
33                         TextMark end_mark = null;
34                         TextIter begin, end;
35
36                         if (!context.get_bounds(out begin, out end)) {
37                                 return;
38                         }  
39                         var buffer = begin.get_buffer();
40                 
41                         var  word = p.get_typed_text();
42                         var len = -1;
43
44                         /* If the insertion cursor is within a word and the trailing characters
45                          * of the word match the suffix of the proposal, then limit how much
46                          * text we insert so that the word is completed properly.
47                          */
48                         if (!end.ends_line() &&
49                                 !end.get_char().isspace() &&
50                                 !end.ends_word ())
51                         {
52                                 var word_end = end;
53
54                                 if (word_end.forward_word_end ()) {
55                                         var text = end.get_slice(word_end);
56
57                                         if (word.has_suffix (text)) {
58                                                 //g_assert (strlen (word) >= strlen (text));
59                                                 len = word.length - text.length;
60                                                 end_mark = buffer.create_mark (null, word_end, false); 
61                                         }
62                                 }
63                         }
64
65                         buffer.begin_user_action();
66                         buffer.delete (ref begin, ref end);
67                         buffer.insert ( ref begin, word, len);
68                         buffer.end_user_action ();
69
70                         if (end_mark != null)
71                         {
72                                 buffer.get_iter_at_mark(out end, end_mark);
73                                 buffer.select_range(end,  end);
74                                 buffer.delete_mark(end_mark);
75                         }
76                 
77
78                 }
79
80
81                 public  void display (GtkSource.CompletionContext context, GtkSource.CompletionProposal proposal, GtkSource.CompletionCell cell)
82                 {
83                         var col = cell.get_column();
84                         //var p = (CompletionProposal) proposal;
85                         switch(col) {
86                                 case GtkSource.CompletionColumn.TYPED_TEXT:
87                                         cell.set_icon_name("completion-snippet-symbolic");
88                                         break;
89                                 case GtkSource.CompletionColumn.ICON:
90                                         cell.set_text(cell.text);
91                                         break;
92                                 case  GtkSource.CompletionColumn.COMMENT:
93                                         cell.set_text(cell.text);
94                                         break;
95                                 case GtkSource.CompletionColumn.DETAILS:
96                                         cell.set_text(cell.text);
97                                         break;
98                                 default:
99                                         cell.set_text(cell.text);
100                                         break;
101                         }       
102                 }
103
104                 public  async GLib.ListModel populate_async (GtkSource.CompletionContext context, GLib.Cancellable? cancelleble)
105                 {
106                         
107                         this.model = new CompletionModel(this, context, cancelleble); 
108                         return this.model;
109                         
110                 }
111
112                 public  void refilter (GtkSource.CompletionContext context, GLib.ListModel in_model)
113                 {
114  
115  
116                         //GtkFilterListModel *filter_model = NULL;
117                         //G//tkExpression *expression = NULL;
118                         //GtkStringFilter *filter = NULL;
119                         //GListModel *replaced_model = NULL;
120                         //char *word;
121
122                         var model = in_model;
123
124                         var word = context.get_word();
125                         if (model is FilterListModel) { 
126                                 model = model.get_model ();
127                         }
128  
129
130                         if (!this.model.can_filter(word)) {
131                                 this.model.cancel(); 
132                                 var replaced_model = new CompletionModel(this, context, this.model.cancellable);
133                                 context.set_proposals_for_provider(this, replaced_model);
134                                 
135                                 context.set_proposals_for_provider(this, replaced_model);
136                                 return;
137                         }
138                          
139                         var expression = new PropertyExpression(typeof(CompletionProposal), null, "word");
140                         var filter = new StringFilter(expression);
141                         filter.set_search( word);
142                         var  filter_model = new FilterListModel(in_model, filter); 
143                         filter_model.set_incremental(true);
144                         context.set_proposals_for_provider(this, filter_model); 
145                  
146
147                 
148                 }
149
150
151 /*
152                 public bool activate_proposal (GtkSource.CompletionProposal proposal, TextIter iter)
153                 {
154                         var istart = iter;
155                         istart.backward_find_char(is_space, null);
156                         istart.forward_char();
157
158                 //    var search = iter.get_text(istart);           
159                 
160                         var buffer = iter.get_buffer();
161                         buffer.delete(ref istart, ref iter);
162                         buffer.insert(ref istart, proposal.get_text(), -1);
163                 
164                         return true;
165                 }
166   
167          
168
169                 private bool is_space(unichar space){
170                         return space.isspace() || space.to_string() == "";
171                 }
172                 */
173                  
174         }
175         public class CompletionModel : Object, GLib.ListModel 
176         {
177                 CompletionProvider provider;
178                 Gee.ArrayList<CompletionProposal> items;
179                 string search;
180                 int minimum_word_size = 2;
181                 public Cancellable cancellable;
182                 
183                 public CompletionModel(CompletionProvider provider, GtkSource.CompletionContext context, Cancellable cancellable)
184                 {
185                         this.provider = provider;
186                         this.cancellable = cancellable;
187                         this.items = new Gee.ArrayList<CompletionProposal>();
188                         this.search = context.get_word();
189                     if (this.search.length < this.minimum_word_size) {
190                             return;
191                     }
192                     var prov  =  this.provider;
193                         
194                         if (prov.editor.window.windowstate == null) {
195                                 GLib.debug("Warning - provider windowstate not set?");
196                                 return;
197                         }
198                     // now do our magic..
199                     this.items = prov.editor.window.windowstate.file.palete().suggestComplete(
200                             prov.editor.window.windowstate.file,
201                             prov.editor.node,
202                             prov.editor.prop,
203                             this.search
204                     ); 
205                 
206                     print("GOT %d results\n", (int) items.size); 
207                         // WHY TWICE?
208                     if (this.items.size < this.minimum_word_size) {
209                                 return;
210                     }
211                 
212                     items.sort((a, b) => {
213                             return ((string)(a.text)).collate((string)(b.text));
214                     });
215                 
216                 }
217                 
218                  
219                 
220                 public GLib.Object? get_item (uint pos)
221                 {
222                         return (Object) this.items.get((int) pos);
223                 }
224                 public GLib.Type  get_item_type ()
225                 {
226                         return typeof(GtkSource.CompletionProposal);
227                 }
228                 public   uint get_n_items () 
229                 {
230                         return this.items.size;
231                 }
232                 public bool can_filter (string word) 
233                 {
234                         if (word == null || word[0] == 0) {
235                                 return false;
236                         }
237  
238                         if (word.length < this.minimum_word_size) {
239                                 return false;
240                         }
241
242                         /* If the new word starts with our initial word, then we can simply
243                          * refilter outside this model using a GtkFilterListModel.
244                          */
245                          return word.has_prefix(this.search); 
246                 }
247                 public void  cancel ()
248                 {
249                         this.cancellable.cancel();
250                 }
251
252
253                 
254         }
255         public class CompletionProposal : Object, GtkSource.CompletionProposal 
256         {
257                 
258                 string label;
259                 
260                 public string text;
261                 string info;
262                 public CompletionProposal(string label, string text, string info)
263                 {
264                         this.text = text;
265                         this.label = label;
266                         this.info = info;
267                 }
268                 
269         }
270
271
272