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