4 // not sure why - but extending Gtk.SourceCompletionProvider seems to give an error..
7 public class CompletionProvider : Object, GtkSource.CompletionProvider
10 //public WindowState windowstate;
11 public CompletionModel model;
13 public CompletionProvider(Editor editor)
16 // this.windowstate = null; // not ready until the UI is built.
20 public string get_name ()
22 return "roojsbuilder";
25 public int get_priority (GtkSource.CompletionContext context)
30 public void activate (GtkSource.CompletionContext context, GtkSource.CompletionProposal proposal)
32 var p = (CompletionProposal) proposal;
33 TextMark end_mark = null;
36 if (!context.get_bounds(out begin, out end)) {
39 var buffer = begin.get_buffer();
41 var word = p.get_typed_text();
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.
48 if (!end.ends_line() &&
49 !end.get_char().isspace() &&
54 if (word_end.forward_word_end ()) {
55 var text = end.get_slice(word_end);
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);
65 buffer.begin_user_action();
66 buffer.delete (ref begin, ref end);
67 buffer.insert ( ref begin, word, len);
68 buffer.end_user_action ();
72 buffer.get_iter_at_mark(out end, end_mark);
73 buffer.select_range(end, end);
74 buffer.delete_mark(end_mark);
81 public void display (GtkSource.CompletionContext context, GtkSource.CompletionProposal proposal, GtkSource.CompletionCell cell)
83 var col = cell.get_column();
84 //var p = (CompletionProposal) proposal;
86 case GtkSource.CompletionColumn.TYPED_TEXT:
87 cell.set_icon_name("completion-snippet-symbolic");
89 case GtkSource.CompletionColumn.ICON:
90 cell.set_text(cell.text);
92 case GtkSource.CompletionColumn.COMMENT:
93 cell.set_text(cell.text);
95 case GtkSource.CompletionColumn.DETAILS:
96 cell.set_text(cell.text);
99 cell.set_text(cell.text);
104 public async GLib.ListModel populate_async (GtkSource.CompletionContext context, GLib.Cancellable? cancelleble)
107 this.model = new CompletionModel(this, context, cancelleble);
112 public void refilter (GtkSource.CompletionContext context, GLib.ListModel in_model)
116 //GtkFilterListModel *filter_model = NULL;
117 //G//tkExpression *expression = NULL;
118 //GtkStringFilter *filter = NULL;
119 //GListModel *replaced_model = NULL;
122 var model = in_model;
124 var word = context.get_word();
125 if (model is FilterListModel) {
126 model = model.get_model ();
130 if (!this.model.can_filter(word)) {
132 var replaced_model = new CompletionModel(this, context, this.model.cancellable);
133 context.set_proposals_for_provider(this, replaced_model);
135 context.set_proposals_for_provider(this, replaced_model);
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);
152 public bool activate_proposal (GtkSource.CompletionProposal proposal, TextIter iter)
155 istart.backward_find_char(is_space, null);
156 istart.forward_char();
158 // var search = iter.get_text(istart);
160 var buffer = iter.get_buffer();
161 buffer.delete(ref istart, ref iter);
162 buffer.insert(ref istart, proposal.get_text(), -1);
169 private bool is_space(unichar space){
170 return space.isspace() || space.to_string() == "";
175 public class CompletionModel : Object, GLib.ListModel
177 CompletionProvider provider;
178 Gee.ArrayList<CompletionProposal> items;
180 int minimum_word_size = 2;
181 public Cancellable cancellable;
183 public CompletionModel(CompletionProvider provider, GtkSource.CompletionContext context, Cancellable cancellable)
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) {
192 var prov = this.provider;
194 if (prov.editor.window.windowstate == null) {
195 GLib.debug("Warning - provider windowstate not set?");
198 // now do our magic..
199 this.items = prov.editor.window.windowstate.file.palete().suggestComplete(
200 prov.editor.window.windowstate.file,
206 print("GOT %d results\n", (int) items.size);
208 if (this.items.size < this.minimum_word_size) {
212 items.sort((a, b) => {
213 return ((string)(a.text)).collate((string)(b.text));
220 public GLib.Object? get_item (uint pos)
222 return (Object) this.items.get((int) pos);
224 public GLib.Type get_item_type ()
226 return typeof(GtkSource.CompletionProposal);
228 public uint get_n_items ()
230 return this.items.size;
232 public bool can_filter (string word)
234 if (word == null || word[0] == 0) {
238 if (word.length < this.minimum_word_size) {
242 /* If the new word starts with our initial word, then we can simply
243 * refilter outside this model using a GtkFilterListModel.
245 return word.has_prefix(this.search);
247 public void cancel ()
249 this.cancellable.cancel();
255 public class CompletionProposal : Object, GtkSource.CompletionProposal
262 public CompletionProposal(string label, string text, string info)