This source file includes following definitions.
- edit_collect_completions_get_current_word
- edit_collect_completion_from_one_buffer
- edit_collect_completions
- edit_complete_word_insert_recoded_completion
- edit_completion_string_free
- edit_completion_dialog_show
- edit_complete_word_cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #include <config.h>
27
28 #include <ctype.h>
29 #include <string.h>
30
31 #include "lib/global.h"
32 #include "lib/search.h"
33 #include "lib/strutil.h"
34 #include "lib/charsets.h"
35 #include "lib/tty/tty.h"
36 #include "lib/widget.h"
37
38 #include "src/setup.h"
39
40 #include "editwidget.h"
41 #include "edit-impl.h"
42 #include "editsearch.h"
43
44 #include "editcomplete.h"
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 static GString *
71 edit_collect_completions_get_current_word (edit_search_status_msg_t *esm, mc_search_t *srch,
72 off_t word_start)
73 {
74 WEdit *edit = esm->edit;
75 gsize len = 0;
76 GString *temp = NULL;
77
78 if (mc_search_run (srch, (void *) esm, word_start, edit->buffer.size, &len))
79 {
80 off_t i;
81
82 for (i = 0; i < (off_t) len; i++)
83 {
84 int chr;
85
86 chr = edit_buffer_get_byte (&edit->buffer, word_start + i);
87 if (!isspace (chr))
88 {
89 if (temp == NULL)
90 temp = g_string_sized_new (len);
91
92 g_string_append_c (temp, chr);
93 }
94 }
95 }
96
97 return temp;
98 }
99
100
101
102
103
104
105 static void
106 edit_collect_completion_from_one_buffer (gboolean active_buffer, GQueue * * compl,
107 mc_search_t *srch, edit_search_status_msg_t *esm,
108 off_t word_start, gsize word_len, off_t last_byte,
109 GString *current_word, int *max_width)
110 {
111 GString *temp = NULL;
112 gsize len = 0;
113 off_t start = -1;
114
115 while (mc_search_run (srch, (void *) esm, start + 1, last_byte, &len))
116 {
117 gsize i;
118 int width;
119
120 if (temp == NULL)
121 temp = g_string_sized_new (8);
122 else
123 g_string_set_size (temp, 0);
124
125 start = srch->normal_offset;
126
127
128 for (i = 0; i < len; i++)
129 {
130 int ch;
131
132 ch = edit_buffer_get_byte (&esm->edit->buffer, start + i);
133 if (isspace (ch))
134 continue;
135
136
137 if (start + (off_t) i == word_start)
138 break;
139
140 g_string_append_c (temp, ch);
141 }
142
143 if (temp->len == 0)
144 continue;
145
146 if (current_word != NULL && g_string_equal (current_word, temp))
147 continue;
148
149 if (*compl== NULL)
150 *compl = g_queue_new ();
151 else
152 {
153 GList *l;
154
155 for (l = g_queue_peek_head_link (*compl); l != NULL; l = g_list_next (l))
156 {
157 GString *s = (GString *) l->data;
158
159
160 if (strncmp (s->str + word_len, temp->str + word_len, MAX (len, s->len) - word_len)
161 == 0)
162 break;
163 }
164
165 if (l != NULL)
166 {
167
168
169 if (!active_buffer && l != g_queue_peek_tail_link (*compl))
170 {
171
172 g_queue_unlink (*compl, l);
173 g_queue_push_tail_link (*compl, l);
174 }
175
176 continue;
177 }
178 }
179
180 {
181 GString *recoded;
182
183 recoded = str_nconvert_to_display (temp->str, temp->len);
184 if (recoded != NULL)
185 {
186 if (recoded->len != 0)
187 mc_g_string_copy (temp, recoded);
188
189 g_string_free (recoded, TRUE);
190 }
191 }
192
193 if (active_buffer)
194 g_queue_push_tail (*compl, temp);
195 else
196 g_queue_push_head (*compl, temp);
197
198 start += len;
199
200
201 width = str_term_width1 (temp->str);
202 *max_width = MAX (*max_width, width);
203
204 temp = NULL;
205 }
206
207 if (temp != NULL)
208 g_string_free (temp, TRUE);
209 }
210
211
212
213
214
215
216 static GQueue *
217 edit_collect_completions (WEdit *edit, off_t word_start, gsize word_len, const char *match_expr,
218 int *max_width)
219 {
220 GQueue *compl = NULL;
221 mc_search_t *srch;
222 off_t last_byte;
223 GString *current_word;
224 gboolean entire_file, all_files;
225 edit_search_status_msg_t esm;
226
227 srch = mc_search_new (match_expr, cp_source);
228 if (srch == NULL)
229 return NULL;
230
231 entire_file = mc_config_get_bool (mc_global.main_config, CONFIG_APP_SECTION,
232 "editor_wordcompletion_collect_entire_file", FALSE);
233
234 last_byte = entire_file ? edit->buffer.size : word_start;
235
236 srch->search_type = MC_SEARCH_T_REGEX;
237 srch->is_case_sensitive = TRUE;
238 srch->search_fn = edit_search_cmd_callback;
239 srch->update_fn = edit_search_update_callback;
240
241 esm.first = TRUE;
242 esm.edit = edit;
243 esm.offset = entire_file ? 0 : word_start;
244
245 status_msg_init (STATUS_MSG (&esm), _ ("Collect completions"), 1.0, simple_status_msg_init_cb,
246 edit_search_status_update_cb, NULL);
247
248 current_word = edit_collect_completions_get_current_word (&esm, srch, word_start);
249
250 *max_width = 0;
251
252
253 edit_collect_completion_from_one_buffer (TRUE, &compl, srch, &esm, word_start, word_len,
254 last_byte, current_word, max_width);
255
256
257 all_files = mc_config_get_bool (mc_global.main_config, CONFIG_APP_SECTION,
258 "editor_wordcompletion_collect_all_files", TRUE);
259 if (all_files)
260 {
261 const WGroup *owner = CONST_GROUP (CONST_WIDGET (edit)->owner);
262 gboolean saved_verbose;
263 GList *w;
264
265
266 saved_verbose = verbose;
267 verbose = FALSE;
268
269 for (w = owner->widgets; w != NULL; w = g_list_next (w))
270 {
271 Widget *ww = WIDGET (w->data);
272 WEdit *e;
273
274 if (!edit_widget_is_editor (ww))
275 continue;
276
277 e = EDIT (ww);
278
279 if (e == edit)
280 continue;
281
282
283 word_start = 0;
284 last_byte = e->buffer.size;
285 esm.edit = e;
286 esm.offset = 0;
287
288 edit_collect_completion_from_one_buffer (FALSE, &compl, srch, &esm, word_start,
289 word_len, last_byte, current_word, max_width);
290 }
291
292 verbose = saved_verbose;
293 }
294
295 status_msg_deinit (STATUS_MSG (&esm));
296 mc_search_free (srch);
297 if (current_word != NULL)
298 g_string_free (current_word, TRUE);
299
300 return compl;
301 }
302
303
304
305
306
307
308
309
310
311
312
313 static void
314 edit_complete_word_insert_recoded_completion (WEdit *edit, char *completion, gsize word_len)
315 {
316 GString *temp;
317
318 temp = str_convert_to_input (completion);
319 if (temp != NULL)
320 {
321 for (completion = temp->str + word_len; *completion != '\0'; completion++)
322 edit_insert (edit, *completion);
323 g_string_free (temp, TRUE);
324 }
325 }
326
327
328
329 static void
330 edit_completion_string_free (gpointer data)
331 {
332 g_string_free ((GString *) data, TRUE);
333 }
334
335
336
337
338
339
340
341 char *
342 edit_completion_dialog_show (const WEdit *edit, GQueue * compl, int max_width)
343 {
344 const WRect *we = &CONST_WIDGET (edit)->rect;
345 int start_x, start_y, offset;
346 char *curr = NULL;
347 WDialog *compl_dlg;
348 WListbox *compl_list;
349 int compl_dlg_h;
350 int compl_dlg_w;
351 GList *i;
352
353
354 compl_dlg_h = g_queue_get_length (compl) + 2;
355 compl_dlg_w = max_width + 4;
356 start_x = we->x + edit->curs_col + edit->start_col + EDIT_TEXT_HORIZONTAL_OFFSET
357 + (edit->fullscreen != 0 ? 0 : 1) + edit_options.line_state_width;
358 start_y =
359 we->y + edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen != 0 ? 0 : 1) + 1;
360
361 if (start_x < 0)
362 start_x = 0;
363 if (start_x < we->x + 1)
364 start_x = we->x + 1 + edit_options.line_state_width;
365 if (compl_dlg_w > COLS)
366 compl_dlg_w = COLS;
367 if (compl_dlg_h > LINES - 2)
368 compl_dlg_h = LINES - 2;
369
370 offset = start_x + compl_dlg_w - COLS;
371 if (offset > 0)
372 start_x -= offset;
373 offset = start_y + compl_dlg_h - LINES;
374 if (offset > 0)
375 start_y -= offset;
376
377
378 compl_dlg = dlg_create (TRUE, start_y, start_x, compl_dlg_h, compl_dlg_w, WPOS_KEEP_DEFAULT,
379 TRUE, dialog_colors, NULL, NULL, "[Completion]", NULL);
380
381
382 compl_list = listbox_new (1, 1, compl_dlg_h - 2, compl_dlg_w - 2, FALSE, NULL);
383
384
385 for (i = g_queue_peek_tail_link (compl); i != NULL; i = g_list_previous (i))
386 listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, ((GString *) i->data)->str, NULL,
387 FALSE);
388
389 group_add_widget (GROUP (compl_dlg), compl_list);
390
391
392 if (dlg_run (compl_dlg) == B_ENTER)
393 {
394 listbox_get_current (compl_list, &curr, NULL);
395 curr = g_strdup (curr);
396 }
397
398
399 widget_destroy (WIDGET (compl_dlg));
400
401 return curr;
402 }
403
404
405
406
407
408
409
410
411 void
412 edit_complete_word_cmd (WEdit *edit)
413 {
414 off_t word_start = 0;
415 gsize word_len = 0;
416 GString *match_expr;
417 gsize i;
418 GQueue * compl;
419 int max_width;
420
421
422 if (!edit_buffer_find_word_start (&edit->buffer, &word_start, &word_len))
423 return;
424
425
426
427 match_expr = g_string_new ("(^|\\s+|\\b)");
428 for (i = 0; i < word_len; i++)
429 g_string_append_c (match_expr, edit_buffer_get_byte (&edit->buffer, word_start + i));
430 g_string_append (
431 match_expr,
432 "[^\\s\\.=\\+\\[\\]\\(\\)\\,\\;\\:\\\"\\'\\-\\?\\/\\|\\\\\\{\\}\\*\\&\\^\\%%\\$#@\\!]+");
433
434
435 compl = edit_collect_completions (edit, word_start, word_len, match_expr->str, &max_width);
436
437 g_string_free (match_expr, TRUE);
438
439 if (compl== NULL)
440 return;
441
442 if (g_queue_get_length (compl) == 1)
443 {
444
445
446 GString *curr_compl;
447
448 curr_compl = (GString *) g_queue_peek_head (compl);
449 edit_complete_word_insert_recoded_completion (edit, curr_compl->str, word_len);
450 }
451 else
452 {
453
454
455 char *curr_compl;
456
457
458 curr_compl = edit_completion_dialog_show (edit, compl, max_width);
459 if (curr_compl != NULL)
460 {
461 edit_complete_word_insert_recoded_completion (edit, curr_compl, word_len);
462 g_free (curr_compl);
463 }
464 }
465
466 g_queue_free_full (compl, edit_completion_string_free);
467 }
468
469