1 | From 41b925152221c864d37f425b7a73ea354cbe197e Mon Sep 17 00:00:00 2001 |
---|
2 | From: Sebastian Gniazdowski <sgniazdowski@gmail.com> |
---|
3 | Date: Sun, 10 Jan 2021 10:41:55 -0600 |
---|
4 | Subject: [PATCH] Selectable listing of various object types from TAGS file. |
---|
5 | |
---|
6 | --- |
---|
7 | lib/keybind.c | 5 + |
---|
8 | lib/keybind.h | 5 + |
---|
9 | lib/strutil.h | 2 + |
---|
10 | lib/strutil/strutil.c | 32 ++++++ |
---|
11 | misc/mc.default.keymap | 5 + |
---|
12 | src/editor/edit-impl.h | 3 +- |
---|
13 | src/editor/edit.c | 17 ++- |
---|
14 | src/editor/editcmd.c | 183 ++++++++++++++++++++++++-------- |
---|
15 | src/editor/editcmd_dialogs.c | 122 +++++++++------------- |
---|
16 | src/editor/editcmd_dialogs.h | 6 +- |
---|
17 | src/editor/etags.c | 197 +++++++++++++++++++++++++++++++++++ |
---|
18 | src/editor/etags.h | 36 ++++++- |
---|
19 | src/keybind-defaults.c | 5 + |
---|
20 | 13 files changed, 491 insertions(+), 127 deletions(-) |
---|
21 | |
---|
22 | diff --git a/lib/keybind.c b/lib/keybind.c |
---|
23 | index abd44d3e2..41a39579b 100644 |
---|
24 | --- a/lib/keybind.c |
---|
25 | +++ b/lib/keybind.c |
---|
26 | @@ -152,6 +152,11 @@ static name_keymap_t command_names[] = { |
---|
27 | ADD_KEYMAP_NAME (ViewRaw), |
---|
28 | ADD_KEYMAP_NAME (ViewFile), |
---|
29 | ADD_KEYMAP_NAME (ViewFiltered), |
---|
30 | + ADD_KEYMAP_NAME (SelectFunction), |
---|
31 | + ADD_KEYMAP_NAME (SelectVariable), |
---|
32 | + ADD_KEYMAP_NAME (SelectType), |
---|
33 | + ADD_KEYMAP_NAME (SelectOther), |
---|
34 | + ADD_KEYMAP_NAME (SelectAllKinds), |
---|
35 | ADD_KEYMAP_NAME (Find), |
---|
36 | ADD_KEYMAP_NAME (DirSize), |
---|
37 | ADD_KEYMAP_NAME (CompareDirs), |
---|
38 | diff --git a/lib/keybind.h b/lib/keybind.h |
---|
39 | index 9638bd651..92f496479 100644 |
---|
40 | --- a/lib/keybind.h |
---|
41 | +++ b/lib/keybind.h |
---|
42 | @@ -139,6 +139,11 @@ enum |
---|
43 | CK_ViewRaw, |
---|
44 | CK_ViewFile, |
---|
45 | CK_ViewFiltered, |
---|
46 | + CK_SelectFunction, |
---|
47 | + CK_SelectVariable, |
---|
48 | + CK_SelectType, |
---|
49 | + CK_SelectOther, |
---|
50 | + CK_SelectAllKinds, |
---|
51 | CK_Find, |
---|
52 | CK_DirSize, |
---|
53 | CK_HotListAdd, |
---|
54 | diff --git a/lib/strutil.h b/lib/strutil.h |
---|
55 | index a091c25aa..abfe4014d 100644 |
---|
56 | --- a/lib/strutil.h |
---|
57 | +++ b/lib/strutil.h |
---|
58 | @@ -582,6 +582,8 @@ strtol_error_t xstrtoumax (const char *s, char **ptr, int base, uintmax_t * val, |
---|
59 | const char *valid_suffixes); |
---|
60 | uintmax_t parse_integer (const char *str, gboolean * invalid); |
---|
61 | |
---|
62 | +char *str_collapse_whitespace(char *s, char overwrite_char); |
---|
63 | + |
---|
64 | /* --------------------------------------------------------------------------------------------- */ |
---|
65 | /*** inline functions ****************************************************************************/ |
---|
66 | /* --------------------------------------------------------------------------------------------- */ |
---|
67 | diff --git a/lib/strutil/strutil.c b/lib/strutil/strutil.c |
---|
68 | index cf11d00d8..adc29c406 100644 |
---|
69 | --- a/lib/strutil/strutil.c |
---|
70 | +++ b/lib/strutil/strutil.c |
---|
71 | @@ -29,6 +29,7 @@ |
---|
72 | #include <langinfo.h> |
---|
73 | #include <string.h> |
---|
74 | #include <errno.h> |
---|
75 | +#include <ctype.h> |
---|
76 | |
---|
77 | #include "lib/global.h" |
---|
78 | #include "lib/util.h" /* MC_PTR_FREE */ |
---|
79 | @@ -1021,3 +1022,34 @@ parse_integer (const char *str, gboolean * invalid) |
---|
80 | } |
---|
81 | |
---|
82 | /* --------------------------------------------------------------------------------------------- */ |
---|
83 | + |
---|
84 | +char *str_collapse_whitespace(char *s, char overwrite_char) |
---|
85 | +{ |
---|
86 | + int i, wi=0, size, span=0; |
---|
87 | + size=strlen(s); |
---|
88 | + |
---|
89 | + /* Skip leading whitespace. */ |
---|
90 | + for (i=0; i<size; i++) { |
---|
91 | + if (!isspace(s[i])) |
---|
92 | + break; |
---|
93 | + } |
---|
94 | + |
---|
95 | + /* Collapse remaining whitespace. */ |
---|
96 | + for (; i<size; i++) { |
---|
97 | + if (isspace(s[i])) // == ' ') |
---|
98 | + span=1; |
---|
99 | + else { |
---|
100 | + if(span) |
---|
101 | + s[wi++] = overwrite_space; |
---|
102 | + |
---|
103 | + s[wi++] = s[i]; |
---|
104 | + span = 0; |
---|
105 | + } |
---|
106 | + } |
---|
107 | + |
---|
108 | + s[wi]='\0'; |
---|
109 | + |
---|
110 | + return s; |
---|
111 | +} |
---|
112 | + |
---|
113 | +/* --------------------------------------------------------------------------------------------- */ |
---|
114 | diff --git a/misc/mc.default.keymap b/misc/mc.default.keymap |
---|
115 | index 1bf68b2df..721e85022 100644 |
---|
116 | --- a/misc/mc.default.keymap |
---|
117 | +++ b/misc/mc.default.keymap |
---|
118 | @@ -387,6 +387,11 @@ SpellCheckCurrentWord = ctrl-p |
---|
119 | # WindowNext = |
---|
120 | # WindowPrev = |
---|
121 | # ExtendedKeyMap = |
---|
122 | +SelectFunction = alt-shift-f |
---|
123 | +SelectVariable = alt-shift-v |
---|
124 | +SelectType = alt-shift-t |
---|
125 | +SelectOther = alt-shift-o |
---|
126 | +SelectAllKinds = alt-shift-a |
---|
127 | |
---|
128 | [viewer] |
---|
129 | Help = f1 |
---|
130 | diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h |
---|
131 | index 3ad04dbea..dd996face 100644 |
---|
132 | --- a/src/editor/edit-impl.h |
---|
133 | +++ b/src/editor/edit-impl.h |
---|
134 | @@ -18,6 +18,7 @@ |
---|
135 | #include "lib/vfs/vfs.h" /* vfs_path_t */ |
---|
136 | |
---|
137 | #include "edit.h" |
---|
138 | +#include "etags.h" |
---|
139 | |
---|
140 | /*** typedefs(not structures) and defined constants **********************************************/ |
---|
141 | |
---|
142 | @@ -202,7 +203,7 @@ mc_search_cbret_t edit_search_cmd_callback (const void *user_data, gsize char_of |
---|
143 | mc_search_cbret_t edit_search_update_callback (const void *user_data, gsize char_offset); |
---|
144 | |
---|
145 | void edit_complete_word_cmd (WEdit * edit); |
---|
146 | -void edit_get_match_keyword_cmd (WEdit * edit); |
---|
147 | +void edit_select_object_from_tags(WEdit * edit, etags_jump_type_t type); |
---|
148 | |
---|
149 | #ifdef HAVE_ASPELL |
---|
150 | int edit_suggest_current_word (WEdit * edit); |
---|
151 | diff --git a/src/editor/edit.c b/src/editor/edit.c |
---|
152 | index e13be389a..0e7e75867 100644 |
---|
153 | --- a/src/editor/edit.c |
---|
154 | +++ b/src/editor/edit.c |
---|
155 | @@ -3860,8 +3860,23 @@ edit_execute_cmd (WEdit * edit, long command, int char_for_insertion) |
---|
156 | else |
---|
157 | edit_complete_word_cmd (edit); |
---|
158 | break; |
---|
159 | + case CK_SelectFunction: |
---|
160 | + edit_select_object_from_tags(edit, TAG_JUMP_KIND_FUNCTION_LIST); |
---|
161 | + break; |
---|
162 | + case CK_SelectVariable: |
---|
163 | + edit_select_object_from_tags(edit, TAG_JUMP_KIND_VAR_LIST); |
---|
164 | + break; |
---|
165 | + case CK_SelectType: |
---|
166 | + edit_select_object_from_tags(edit, TAG_JUMP_KIND_TYPE_LIST); |
---|
167 | + break; |
---|
168 | + case CK_SelectOther: |
---|
169 | + edit_select_object_from_tags(edit, TAG_JUMP_KIND_OTHER_LIST); |
---|
170 | + break; |
---|
171 | + case CK_SelectAllKinds: |
---|
172 | + edit_select_object_from_tags(edit, TAG_JUMP_KIND_ANY_LIST); |
---|
173 | + break; |
---|
174 | case CK_Find: |
---|
175 | - edit_get_match_keyword_cmd (edit); |
---|
176 | + edit_select_object_from_tags(edit, TAG_JUMP_KIND_MATCH_WORD); |
---|
177 | break; |
---|
178 | |
---|
179 | #ifdef HAVE_ASPELL |
---|
180 | diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c |
---|
181 | index e2b904604..4265cd8fc 100644 |
---|
182 | --- a/src/editor/editcmd.c |
---|
183 | +++ b/src/editor/editcmd.c |
---|
184 | @@ -1140,7 +1140,7 @@ edit_find_word_start (const edit_buffer_t * buf, off_t * word_start, gsize * wor |
---|
185 | return FALSE; |
---|
186 | |
---|
187 | c = edit_buffer_get_previous_byte (buf); |
---|
188 | - /* return if not at end or in word */ |
---|
189 | + /* return if the word is empty */ |
---|
190 | if (is_break_char (c)) |
---|
191 | return FALSE; |
---|
192 | |
---|
193 | @@ -1169,6 +1169,37 @@ edit_find_word_start (const edit_buffer_t * buf, off_t * word_start, gsize * wor |
---|
194 | return TRUE; |
---|
195 | } |
---|
196 | |
---|
197 | +/* Gets the word on the left of the cursor. |
---|
198 | + * |
---|
199 | + * @param buf The edit buffer. |
---|
200 | + * @param initial Initial contents of the result. |
---|
201 | + * @param release_on_empty Should the initial g_string be released when returning NULL. |
---|
202 | + * @return g_string with the word or NULL if the word is empty. |
---|
203 | +*/ |
---|
204 | +static GString * |
---|
205 | +edit_get_left_whole_word(const edit_buffer_t * buf, GString *initial, gboolean release_on_empty) |
---|
206 | +{ |
---|
207 | + GString *ret = initial; |
---|
208 | + gsize i, word_len = 0; |
---|
209 | + off_t word_start = 0; |
---|
210 | + |
---|
211 | + /* Search start of word left of cursor. */ |
---|
212 | + if (!edit_find_word_start (buf, &word_start, &word_len)) { |
---|
213 | + if (initial && release_on_empty) |
---|
214 | + g_string_free(initial, TRUE); |
---|
215 | + return NULL; |
---|
216 | + } |
---|
217 | + |
---|
218 | + /* ret = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */ |
---|
219 | + if (!ret) |
---|
220 | + ret = g_string_sized_new (SHORT_DEF_LEN); |
---|
221 | + |
---|
222 | + for (i = 0; i < word_len; i++) |
---|
223 | + g_string_append_c (ret, edit_buffer_get_byte (buf, word_start + i)); |
---|
224 | + |
---|
225 | + return ret; |
---|
226 | +} |
---|
227 | + |
---|
228 | /* --------------------------------------------------------------------------------------------- */ |
---|
229 | /** |
---|
230 | * Get current word under cursor |
---|
231 | @@ -3501,62 +3532,122 @@ edit_load_back_cmd (WEdit * edit) |
---|
232 | /* --------------------------------------------------------------------------------------------- */ |
---|
233 | |
---|
234 | void |
---|
235 | -edit_get_match_keyword_cmd (WEdit * edit) |
---|
236 | +edit_select_object_from_tags(WEdit * edit, etags_jump_type_t type) |
---|
237 | { |
---|
238 | - gsize word_len = 0, max_len = 0; |
---|
239 | - int num_def = 0; |
---|
240 | - gsize i; |
---|
241 | - off_t word_start = 0; |
---|
242 | - GString *match_expr; |
---|
243 | - char *path = NULL; |
---|
244 | - char *ptr = NULL; |
---|
245 | - char *tagfile = NULL; |
---|
246 | + int i, num_obj, max_len; |
---|
247 | |
---|
248 | - etags_hash_t def_hash[MAX_DEFINITIONS]; |
---|
249 | + /* Group 0-initialized pointers into a struct for easy initialization. */ |
---|
250 | + struct { |
---|
251 | + const char *fname0; char *fname, *tagfile, *path, *ptr; |
---|
252 | + GString *match_expr; |
---|
253 | + etags_hash_t found_func[MAX_TAG_OBJECTS], *selected_object; |
---|
254 | + } var = {0}; |
---|
255 | |
---|
256 | - for (i = 0; i < MAX_DEFINITIONS; i++) |
---|
257 | - def_hash[i].filename = NULL; |
---|
258 | - |
---|
259 | - /* search start of word to be completed */ |
---|
260 | - if (!edit_find_word_start (&edit->buffer, &word_start, &word_len)) |
---|
261 | + /* No file means no entries in tags file → exit. */ |
---|
262 | + if (edit->filename_vpath == NULL) |
---|
263 | return; |
---|
264 | |
---|
265 | - /* prepare match expression */ |
---|
266 | - match_expr = g_string_sized_new (word_len); |
---|
267 | - for (i = 0; i < word_len; i++) |
---|
268 | - g_string_append_c (match_expr, edit_buffer_get_byte (&edit->buffer, word_start + i)); |
---|
269 | + /* Set up current directory variable. */ |
---|
270 | + var.ptr = g_get_current_dir (); |
---|
271 | + var.path = g_strconcat (var.ptr, PATH_SEP_STR, (char *) NULL); |
---|
272 | + g_free (var.ptr); |
---|
273 | |
---|
274 | - ptr = g_get_current_dir (); |
---|
275 | - path = g_strconcat (ptr, PATH_SEP_STR, (char *) NULL); |
---|
276 | - g_free (ptr); |
---|
277 | + /* Locate the tags file and its directory. */ |
---|
278 | + etags_locate_tags_file(&var.tagfile, &var.path); |
---|
279 | |
---|
280 | - /* Recursive search file 'TAGS' in parent dirs */ |
---|
281 | - do |
---|
282 | - { |
---|
283 | - ptr = g_path_get_dirname (path); |
---|
284 | - g_free (path); |
---|
285 | - path = ptr; |
---|
286 | - g_free (tagfile); |
---|
287 | - tagfile = mc_build_filename (path, TAGS_NAME, (char *) NULL); |
---|
288 | - if (exist_file (tagfile)) |
---|
289 | - break; |
---|
290 | + if (!var.tagfile) |
---|
291 | + goto exit_jump_tag_obj; |
---|
292 | + |
---|
293 | + if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) { |
---|
294 | + /* Establish the base relative filename of current buffer. */ |
---|
295 | + var.fname0 = vfs_path_as_str (edit->filename_vpath); |
---|
296 | + if (g_str_has_prefix(var.fname0, var.path)) { |
---|
297 | + var.fname0 = var.fname0 + strlen(var.path) + 1; |
---|
298 | + var.fname = g_strdup(var.fname0); |
---|
299 | + } else |
---|
300 | + /* A fallback that shouldn't be needed and is unreliable. */ |
---|
301 | + var.fname = g_path_get_basename(var.fname0); |
---|
302 | + var.match_expr = g_string_new(var.fname); |
---|
303 | + } else if (type == TAG_JUMP_KIND_MATCH_WORD) { |
---|
304 | + // The function releases the string on empty word result. |
---|
305 | + var.match_expr = edit_get_left_whole_word(&edit->buffer, NULL, FALSE); |
---|
306 | + |
---|
307 | + if(!var.match_expr) |
---|
308 | + goto exit_jump_tag_obj; |
---|
309 | + |
---|
310 | + } else |
---|
311 | + goto exit_jump_tag_obj; |
---|
312 | + |
---|
313 | + if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) { |
---|
314 | + num_obj = etags_get_objects_for_file(type, var.tagfile, var.path, var.fname, (etags_hash_t *) |
---|
315 | + &var.found_func, &max_len, MAX_TAG_OBJECTS); |
---|
316 | + } else { |
---|
317 | + max_len = MAX_WIDTH_DEF_DIALOG; |
---|
318 | + num_obj = etags_set_definition_hash (var.tagfile, var.path, var.match_expr->str, (etags_hash_t *) |
---|
319 | +&var.found_func); |
---|
320 | } |
---|
321 | - while (strcmp (path, PATH_SEP_STR) != 0); |
---|
322 | |
---|
323 | - if (tagfile != NULL) |
---|
324 | - { |
---|
325 | - num_def = |
---|
326 | - etags_set_definition_hash (tagfile, path, match_expr->str, (etags_hash_t *) & def_hash); |
---|
327 | - g_free (tagfile); |
---|
328 | + /* Show the list. */ |
---|
329 | + if (num_obj > 0) |
---|
330 | + var.selected_object = editcmd_dialog_select_tags_object_show (edit, var.fname, max_len, |
---|
331 | + (etags_hash_t *) & var.found_func, type, num_obj); |
---|
332 | + |
---|
333 | + if (var.selected_object) { |
---|
334 | + int line = var.selected_object->line; |
---|
335 | + |
---|
336 | + /* Move the display to the function line. */ |
---|
337 | + if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) { |
---|
338 | + edit_move_display (edit, line - WIDGET (edit)->lines / 2 - 1); |
---|
339 | + edit_move_to_line (edit, line - 1); |
---|
340 | + edit->force |= REDRAW_COMPLETELY; |
---|
341 | + } else { |
---|
342 | + char *fullpath = var.selected_object->fullpath; |
---|
343 | + gboolean do_moveto = FALSE; |
---|
344 | + if (!edit->modified) |
---|
345 | + do_moveto = TRUE; |
---|
346 | + else if (!edit_query_dialog2 |
---|
347 | + (_("Warning"), |
---|
348 | + _("Current text was modified without a file save.\n" |
---|
349 | + "Continue discards these changes."), _("C&ontinue"), _("&Cancel"))) |
---|
350 | + { |
---|
351 | + edit->force |= REDRAW_COMPLETELY; |
---|
352 | + do_moveto = TRUE; |
---|
353 | + } |
---|
354 | + |
---|
355 | + if (do_moveto) { |
---|
356 | + /* Replace the file in current editor (no new file is opened). */ |
---|
357 | + vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); |
---|
358 | + |
---|
359 | + if (edit->dir_vpath != NULL) |
---|
360 | + edit_history_moveto[edit_stack_iterator].filename_vpath = |
---|
361 | + vfs_path_append_vpath_new (edit->dir_vpath, edit->filename_vpath, NULL); |
---|
362 | + else |
---|
363 | + edit_history_moveto[edit_stack_iterator].filename_vpath = |
---|
364 | + vfs_path_clone (edit->filename_vpath); |
---|
365 | + |
---|
366 | + edit_history_moveto[edit_stack_iterator].line = edit->start_line + edit->curs_row + 1; |
---|
367 | + edit_stack_iterator++; |
---|
368 | + vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); |
---|
369 | + edit_history_moveto[edit_stack_iterator].filename_vpath = |
---|
370 | + vfs_path_from_str ((char *) fullpath); |
---|
371 | + edit_history_moveto[edit_stack_iterator].line = line; |
---|
372 | + edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath, |
---|
373 | + edit_history_moveto[edit_stack_iterator].line); |
---|
374 | + } |
---|
375 | + } |
---|
376 | } |
---|
377 | - g_free (path); |
---|
378 | +exit_jump_tag_obj: |
---|
379 | + /* Clear results hash */ |
---|
380 | + for (i = 0; i < num_obj; i++) |
---|
381 | + g_free (var.found_func[i].filename); |
---|
382 | |
---|
383 | - max_len = MAX_WIDTH_DEF_DIALOG; |
---|
384 | - word_len = 0; |
---|
385 | - if (num_def > 0) |
---|
386 | - editcmd_dialog_select_definition_show (edit, match_expr->str, max_len, word_len, |
---|
387 | - (etags_hash_t *) & def_hash, num_def); |
---|
388 | - g_string_free (match_expr, TRUE); |
---|
389 | + /* Release other variables. */ |
---|
390 | + g_free(var.fname); |
---|
391 | + g_free(var.tagfile); |
---|
392 | + g_free(var.path); |
---|
393 | + |
---|
394 | + if (var.match_expr) |
---|
395 | + g_string_free(var.match_expr, TRUE); |
---|
396 | } |
---|
397 | |
---|
398 | /* --------------------------------------------------------------------------------------------- */ |
---|
399 | diff --git a/src/editor/editcmd_dialogs.c b/src/editor/editcmd_dialogs.c |
---|
400 | index 8b3634f23..07f81b156 100644 |
---|
401 | --- a/src/editor/editcmd_dialogs.c |
---|
402 | +++ b/src/editor/editcmd_dialogs.c |
---|
403 | @@ -408,105 +408,83 @@ editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** comp |
---|
404 | } |
---|
405 | |
---|
406 | /* --------------------------------------------------------------------------------------------- */ |
---|
407 | -/* let the user select where function definition */ |
---|
408 | +/* function and data structure selection dialog */ |
---|
409 | |
---|
410 | -void |
---|
411 | -editcmd_dialog_select_definition_show (WEdit * edit, char *match_expr, int max_len, int word_len, |
---|
412 | - etags_hash_t * def_hash, int num_lines) |
---|
413 | +etags_hash_t * |
---|
414 | +editcmd_dialog_select_tags_object_show (WEdit * edit, char *match_expr, int max_len, |
---|
415 | + etags_hash_t * all_found, etags_jump_type_t type, |
---|
416 | + int num_lines) |
---|
417 | { |
---|
418 | - int start_x, start_y, offset, i; |
---|
419 | + int start_x, start_y, offset, i, selected_on_start = 0; |
---|
420 | + gboolean found_current = FALSE; |
---|
421 | char *curr = NULL; |
---|
422 | - WDialog *def_dlg; |
---|
423 | - WListbox *def_list; |
---|
424 | - int def_dlg_h; /* dialog height */ |
---|
425 | - int def_dlg_w; /* dialog width */ |
---|
426 | + WDialog *func_dlg; |
---|
427 | + WListbox *func_list; |
---|
428 | + int func_dlg_h; /* dialog height */ |
---|
429 | + int func_dlg_w; /* dialog width */ |
---|
430 | + etags_hash_t *selection_data = NULL; |
---|
431 | |
---|
432 | - (void) word_len; |
---|
433 | /* calculate the dialog metrics */ |
---|
434 | - def_dlg_h = num_lines + 2; |
---|
435 | - def_dlg_w = max_len + 4; |
---|
436 | - start_x = edit->curs_col + edit->start_col - (def_dlg_w / 2) + |
---|
437 | + func_dlg_h = num_lines + 2; |
---|
438 | + func_dlg_w = max_len >= MAX_WIDTH_DEF_DIALOG/2 ? max_len + 4 : MAX_WIDTH_DEF_DIALOG/2 + 4; |
---|
439 | + start_x = edit->curs_col + edit->start_col - (func_dlg_w / 2) + |
---|
440 | EDIT_TEXT_HORIZONTAL_OFFSET + (edit->fullscreen ? 0 : 1) + option_line_state_width; |
---|
441 | start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1; |
---|
442 | |
---|
443 | if (start_x < 0) |
---|
444 | start_x = 0; |
---|
445 | - if (def_dlg_w > COLS) |
---|
446 | - def_dlg_w = COLS; |
---|
447 | - if (def_dlg_h > LINES - 2) |
---|
448 | - def_dlg_h = LINES - 2; |
---|
449 | + if (func_dlg_w > COLS) |
---|
450 | + func_dlg_w = COLS; |
---|
451 | + if (func_dlg_h > LINES - 2) |
---|
452 | + func_dlg_h = LINES - 2; |
---|
453 | |
---|
454 | - offset = start_x + def_dlg_w - COLS; |
---|
455 | + offset = start_x + func_dlg_w - COLS; |
---|
456 | if (offset > 0) |
---|
457 | start_x -= offset; |
---|
458 | - offset = start_y + def_dlg_h - LINES; |
---|
459 | + offset = start_y + func_dlg_h - LINES; |
---|
460 | if (offset > 0) |
---|
461 | start_y -= (offset + 1); |
---|
462 | |
---|
463 | - def_dlg = dlg_create (TRUE, start_y, start_x, def_dlg_h, def_dlg_w, WPOS_KEEP_DEFAULT, TRUE, |
---|
464 | + func_dlg = dlg_create (TRUE, start_y, start_x, func_dlg_h, func_dlg_w, WPOS_KEEP_DEFAULT, TRUE, |
---|
465 | dialog_colors, NULL, NULL, "[Definitions]", match_expr); |
---|
466 | - def_list = listbox_new (1, 1, def_dlg_h - 2, def_dlg_w - 2, FALSE, NULL); |
---|
467 | - group_add_widget (GROUP (def_dlg), def_list); |
---|
468 | + func_list = listbox_new (1, 1, func_dlg_h - 2, func_dlg_w - 2, FALSE, NULL); |
---|
469 | + group_add_widget (GROUP (func_dlg), func_list); |
---|
470 | |
---|
471 | /* fill the listbox with the completions */ |
---|
472 | for (i = 0; i < num_lines; i++) |
---|
473 | { |
---|
474 | - char *label_def; |
---|
475 | + char *label = NULL; |
---|
476 | |
---|
477 | - label_def = |
---|
478 | - g_strdup_printf ("%s -> %s:%ld", def_hash[i].short_define, def_hash[i].filename, |
---|
479 | - def_hash[i].line); |
---|
480 | - listbox_add_item (def_list, LISTBOX_APPEND_AT_END, 0, label_def, &def_hash[i], FALSE); |
---|
481 | - g_free (label_def); |
---|
482 | + if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) |
---|
483 | + label = all_found[i].short_define; |
---|
484 | + else if (type == TAG_JUMP_KIND_MATCH_WORD) |
---|
485 | + label = |
---|
486 | + g_strdup_printf ("%s -> %s:%ld", all_found[i].short_define, all_found[i].filename, |
---|
487 | + all_found[i].line); |
---|
488 | + else |
---|
489 | + label = g_strdup("error"); |
---|
490 | + listbox_add_item (func_list, LISTBOX_APPEND_AT_END, 0, label, &all_found[i], FALSE); |
---|
491 | + g_free (label); |
---|
492 | + |
---|
493 | + /* Detect currently active code segment. */ |
---|
494 | + if ((all_found[i].line - 1) <= edit->buffer.curs_line) { |
---|
495 | + found_current = TRUE; |
---|
496 | + selected_on_start = i; |
---|
497 | + } |
---|
498 | } |
---|
499 | + if (found_current) |
---|
500 | + listbox_select_entry(func_list, selected_on_start); |
---|
501 | |
---|
502 | /* pop up the dialog and apply the chosen completion */ |
---|
503 | - if (dlg_run (def_dlg) == B_ENTER) |
---|
504 | - { |
---|
505 | - etags_hash_t *curr_def = NULL; |
---|
506 | - gboolean do_moveto = FALSE; |
---|
507 | - |
---|
508 | - listbox_get_current (def_list, &curr, (void **) &curr_def); |
---|
509 | - |
---|
510 | - if (!edit->modified) |
---|
511 | - do_moveto = TRUE; |
---|
512 | - else if (!edit_query_dialog2 |
---|
513 | - (_("Warning"), |
---|
514 | - _("Current text was modified without a file save.\n" |
---|
515 | - "Continue discards these changes."), _("C&ontinue"), _("&Cancel"))) |
---|
516 | - { |
---|
517 | - edit->force |= REDRAW_COMPLETELY; |
---|
518 | - do_moveto = TRUE; |
---|
519 | - } |
---|
520 | - |
---|
521 | - if (curr != NULL && do_moveto && edit_stack_iterator + 1 < MAX_HISTORY_MOVETO) |
---|
522 | - { |
---|
523 | - vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); |
---|
524 | - |
---|
525 | - if (edit->dir_vpath != NULL) |
---|
526 | - edit_history_moveto[edit_stack_iterator].filename_vpath = |
---|
527 | - vfs_path_append_vpath_new (edit->dir_vpath, edit->filename_vpath, NULL); |
---|
528 | - else |
---|
529 | - edit_history_moveto[edit_stack_iterator].filename_vpath = |
---|
530 | - vfs_path_clone (edit->filename_vpath); |
---|
531 | - |
---|
532 | - edit_history_moveto[edit_stack_iterator].line = edit->start_line + edit->curs_row + 1; |
---|
533 | - edit_stack_iterator++; |
---|
534 | - vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); |
---|
535 | - edit_history_moveto[edit_stack_iterator].filename_vpath = |
---|
536 | - vfs_path_from_str ((char *) curr_def->fullpath); |
---|
537 | - edit_history_moveto[edit_stack_iterator].line = curr_def->line; |
---|
538 | - edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath, |
---|
539 | - edit_history_moveto[edit_stack_iterator].line); |
---|
540 | - } |
---|
541 | - } |
---|
542 | - |
---|
543 | - /* clear definition hash */ |
---|
544 | - for (i = 0; i < MAX_DEFINITIONS; i++) |
---|
545 | - g_free (def_hash[i].filename); |
---|
546 | + if (dlg_run (func_dlg) == B_ENTER) |
---|
547 | + listbox_get_current (func_list, &curr, (void **) &selection_data); |
---|
548 | |
---|
549 | /* destroy dialog before return */ |
---|
550 | - dlg_destroy (def_dlg); |
---|
551 | + dlg_destroy (func_dlg); |
---|
552 | + |
---|
553 | + return selection_data; |
---|
554 | } |
---|
555 | |
---|
556 | /* --------------------------------------------------------------------------------------------- */ |
---|
557 | diff --git a/src/editor/editcmd_dialogs.h b/src/editor/editcmd_dialogs.h |
---|
558 | index f691c857e..8d6a7933a 100644 |
---|
559 | --- a/src/editor/editcmd_dialogs.h |
---|
560 | +++ b/src/editor/editcmd_dialogs.h |
---|
561 | @@ -5,7 +5,7 @@ |
---|
562 | |
---|
563 | /*** typedefs(not structures) and defined constants **********************************************/ |
---|
564 | |
---|
565 | -struct etags_hash_struct; |
---|
566 | +typedef struct etags_hash_struct etags_hash_t; |
---|
567 | |
---|
568 | #define B_REPLACE_ALL (B_USER+1) |
---|
569 | #define B_REPLACE_ONE (B_USER+2) |
---|
570 | @@ -28,8 +28,8 @@ int editcmd_dialog_raw_key_query (const char *heading, const char *query, gboole |
---|
571 | char *editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** compl, |
---|
572 | int num_compl); |
---|
573 | |
---|
574 | -void editcmd_dialog_select_definition_show (WEdit *, char *, int, int, struct etags_hash_struct *, |
---|
575 | - int); |
---|
576 | +etags_hash_t *editcmd_dialog_select_tags_object_show (WEdit *, char *, int, etags_hash_t *, |
---|
577 | + etags_jump_type_t, int); |
---|
578 | |
---|
579 | int editcmd_dialog_replace_prompt_show (WEdit *, char *, char *, int, int); |
---|
580 | /*** inline functions ****************************************************************************/ |
---|
581 | diff --git a/src/editor/etags.c b/src/editor/etags.c |
---|
582 | index 35c7a2f04..952df9b99 100644 |
---|
583 | --- a/src/editor/etags.c |
---|
584 | +++ b/src/editor/etags.c |
---|
585 | @@ -39,6 +39,8 @@ |
---|
586 | |
---|
587 | #include "lib/global.h" |
---|
588 | #include "lib/util.h" /* canonicalize_pathname() */ |
---|
589 | +#include "lib/fileloc.h" |
---|
590 | +#include "lib/strutil.h" |
---|
591 | |
---|
592 | #include "etags.h" |
---|
593 | |
---|
594 | @@ -53,6 +55,32 @@ |
---|
595 | /*** file scope functions ************************************************************************/ |
---|
596 | /* --------------------------------------------------------------------------------------------- */ |
---|
597 | |
---|
598 | +int |
---|
599 | +etags_locate_tags_file(char **tagfile_return, char **path_return) { |
---|
600 | + char *tagfile = *tagfile_return, *path = *path_return, *ptr = NULL; |
---|
601 | + int search_result = 0; |
---|
602 | + |
---|
603 | + /* Recursive search file 'TAGS' in parent dirs */ |
---|
604 | + do |
---|
605 | + { |
---|
606 | + ptr = g_path_get_dirname (path); |
---|
607 | + g_free (path); |
---|
608 | + path = ptr; |
---|
609 | + g_free (tagfile); |
---|
610 | + tagfile = mc_build_filename (path, TAGS_NAME, (char *) NULL); |
---|
611 | + if (exist_file (tagfile)) { |
---|
612 | + search_result = 1; |
---|
613 | + break; |
---|
614 | + } |
---|
615 | + } |
---|
616 | + while (strcmp (path, PATH_SEP_STR) != 0); |
---|
617 | + |
---|
618 | + *tagfile_return = tagfile; |
---|
619 | + *path_return = path; |
---|
620 | + |
---|
621 | + return search_result; |
---|
622 | +} |
---|
623 | + |
---|
624 | static gboolean |
---|
625 | parse_define (const char *buf, char **long_name, char **short_name, long *line) |
---|
626 | { |
---|
627 | @@ -169,6 +197,175 @@ parse_define (const char *buf, char **long_name, char **short_name, long *line) |
---|
628 | /*** public functions ****************************************************************************/ |
---|
629 | /* --------------------------------------------------------------------------------------------- */ |
---|
630 | |
---|
631 | +/* Fills the etags info array with ·all· objects of given ·type· (functions, etc.) */ |
---|
632 | +int etags_get_objects_for_file (etags_rank_t type, const char *tagfile, |
---|
633 | + const char *start_path, const char *match_filename, |
---|
634 | + etags_hash_t * functions_hash, |
---|
635 | + int *max_len_return, int size_limit) |
---|
636 | +{ |
---|
637 | + /* *INDENT-OFF* */ |
---|
638 | + enum |
---|
639 | + { |
---|
640 | + start, |
---|
641 | + in_filename, |
---|
642 | + in_define |
---|
643 | + } state = start; |
---|
644 | + /* *INDENT-ON* */ |
---|
645 | + |
---|
646 | + FILE *f; |
---|
647 | + char buf[BUF_LARGE]; |
---|
648 | + |
---|
649 | + int num = 0; /* returned value */ |
---|
650 | + char *filename = NULL; |
---|
651 | + |
---|
652 | + if (!match_filename || !tagfile) |
---|
653 | + return 0; |
---|
654 | + |
---|
655 | + *max_len_return = 0; |
---|
656 | + |
---|
657 | + /* open file with positions */ |
---|
658 | + f = fopen (tagfile, "r"); |
---|
659 | + if (f == NULL) |
---|
660 | + return 0; |
---|
661 | + |
---|
662 | + while (fgets (buf, sizeof (buf), f)) |
---|
663 | + { |
---|
664 | + switch (state) |
---|
665 | + { |
---|
666 | + case start: |
---|
667 | + if (buf[0] == 0x0C) |
---|
668 | + { |
---|
669 | + state = in_filename; |
---|
670 | + } |
---|
671 | + break; |
---|
672 | + case in_filename: |
---|
673 | + { |
---|
674 | + size_t pos; |
---|
675 | + |
---|
676 | + pos = strcspn (buf, ","); |
---|
677 | + g_free (filename); |
---|
678 | + filename = g_strndup (buf, pos); |
---|
679 | + state = in_define; |
---|
680 | + break; |
---|
681 | + } |
---|
682 | + case in_define: |
---|
683 | + if (buf[0] == 0x0C) |
---|
684 | + { |
---|
685 | + state = in_filename; |
---|
686 | + break; |
---|
687 | + } |
---|
688 | + /* check if the filename matches the requested one */ |
---|
689 | + if (strcmp (filename, match_filename) == 0) |
---|
690 | + { |
---|
691 | + char *longname = NULL; |
---|
692 | + char *shortname = NULL; |
---|
693 | + long line = 0; |
---|
694 | + |
---|
695 | + parse_define (buf, &longname, &shortname, &line); |
---|
696 | + if (num < size_limit - 1) |
---|
697 | + { |
---|
698 | + gboolean can_be_func, can_be_var, can_be_type, is_other; |
---|
699 | + |
---|
700 | + /* Prepare the work variable. */ |
---|
701 | + char *longname_wr; |
---|
702 | + longname_wr = g_strdup(longname); |
---|
703 | + |
---|
704 | + /* Function – if there's '(' in the declaration. */ |
---|
705 | + can_be_func = strstr(longname,"(") != NULL; |
---|
706 | + /* Variable – if there's no parens and no # in the declaration. */ |
---|
707 | + can_be_var = strstr(g_strdelimit(longname_wr,"}{()#",''),"") == NULL; |
---|
708 | + /* Type – if there's a 'struct', 'typedef', 'enum' or '}' in the declaration. */ |
---|
709 | + can_be_type=(strstr(longname,"struct ") || |
---|
710 | + strstr(longname,"typedef ") || |
---|
711 | + strstr(longname,"enum ")) || |
---|
712 | + (strstr(longname, "}") && |
---|
713 | + (g_str_has_suffix(shortname,"_t") || |
---|
714 | + g_str_has_suffix(shortname,"_type"))); |
---|
715 | + /* Other kind – nor any of the above. */ |
---|
716 | + is_other = !can_be_func && !can_be_var && !can_be_type; |
---|
717 | + |
---|
718 | + /* Renew the work variable. */ |
---|
719 | + g_free(longname_wr); |
---|
720 | + longname_wr = g_strdup(longname); |
---|
721 | + |
---|
722 | + /* A closer examination of type tags. */ |
---|
723 | + if (type == TAG_RANK_TYPES && can_be_type && !can_be_func) { |
---|
724 | + /* |
---|
725 | + * Verify if it's not a struct variable or an enum. |
---|
726 | + * It filters out occurrences such as: |
---|
727 | + * – struct type SHORTNAME … – i.e.: the shortname at 3rd position, because |
---|
728 | + * this means that a struct variable, not a struct type is being defined. |
---|
729 | + */ |
---|
730 | + gchar **words = g_strsplit(str_collapse_whitespace(longname_wr, ' ')," ", -1); |
---|
731 | + if (words[2] && strcmp(words[2], shortname) == 0) |
---|
732 | + can_be_type = FALSE; |
---|
733 | + g_strfreev(words); |
---|
734 | + } |
---|
735 | + |
---|
736 | + /* A closer examination of variable tags. */ |
---|
737 | + if (type == TAG_RANK_VARIABLES && can_be_var) { |
---|
738 | + /* Verify if it's not a struct typedef or an enum. */ |
---|
739 | + gchar **words = g_strsplit(str_collapse_whitespace(longname_wr, ' ')," ", -1); |
---|
740 | + if (strcmp(words[0], "typedef") == 0 || !words[0] || !words[1]) |
---|
741 | + can_be_var = FALSE; |
---|
742 | + /* Most probably an enum ENUM = 0|1|… assignment. */ |
---|
743 | + if (!words[0] || strstr(words[0], "=") || (words[1] && words[1][0] == '=')) |
---|
744 | + can_be_var = FALSE; |
---|
745 | + g_strfreev(words); |
---|
746 | + } |
---|
747 | + |
---|
748 | + /* Free the work variable. */ |
---|
749 | + g_free(longname_wr); |
---|
750 | + |
---|
751 | + /* Is the object of the requested type? */ |
---|
752 | + if (type == TAG_RANK_ANY || |
---|
753 | + ((type == TAG_RANK_FUNCTIONS && can_be_func) || |
---|
754 | + (type == TAG_RANK_VARIABLES && can_be_var) || |
---|
755 | + (type == TAG_RANK_TYPES && can_be_type) || |
---|
756 | + (type == TAG_RANK_OTHER && is_other))) |
---|
757 | + { |
---|
758 | + /* Update the max. length return variable */ |
---|
759 | + int max_len_candidate; |
---|
760 | + max_len_candidate = strlen(shortname); |
---|
761 | + if (*max_len_return < max_len_candidate) |
---|
762 | + *max_len_return = max_len_candidate; |
---|
763 | + |
---|
764 | + /* Save the filename. */ |
---|
765 | + functions_hash[num].filename = g_strdup (filename); |
---|
766 | + functions_hash[num].filename_len = strlen (filename); |
---|
767 | + |
---|
768 | + /* Save and canonicalize the path to the file. */ |
---|
769 | + functions_hash[num].fullpath = |
---|
770 | + mc_build_filename (start_path, filename, (char *) NULL); |
---|
771 | + canonicalize_pathname (functions_hash[num].fullpath); |
---|
772 | + |
---|
773 | + /* Save the short define. */ |
---|
774 | + if (shortname) |
---|
775 | + functions_hash[num].short_define = g_strdup (shortname); |
---|
776 | + else |
---|
777 | + functions_hash[num].short_define = g_strdup (longname); |
---|
778 | + |
---|
779 | + /* Save the line number. */ |
---|
780 | + functions_hash[num].line = line; |
---|
781 | + |
---|
782 | + /* Increase the count of the matched objects. */ |
---|
783 | + num++; |
---|
784 | + } |
---|
785 | + } |
---|
786 | + } |
---|
787 | + break; |
---|
788 | + default: |
---|
789 | + break; |
---|
790 | + } |
---|
791 | + } |
---|
792 | + |
---|
793 | + g_free (filename); |
---|
794 | + fclose (f); |
---|
795 | + return num; |
---|
796 | +} |
---|
797 | + |
---|
798 | +/* --------------------------------------------------------------------------------------------- */ |
---|
799 | + |
---|
800 | int |
---|
801 | etags_set_definition_hash (const char *tagfile, const char *start_path, |
---|
802 | const char *match_func, etags_hash_t * def_hash) |
---|
803 | diff --git a/src/editor/etags.h b/src/editor/etags.h |
---|
804 | index be71b3a27..a0eb77710 100644 |
---|
805 | --- a/src/editor/etags.h |
---|
806 | +++ b/src/editor/etags.h |
---|
807 | @@ -6,10 +6,10 @@ |
---|
808 | |
---|
809 | /*** typedefs(not structures) and defined constants **********************************************/ |
---|
810 | |
---|
811 | -#define MAX_WIDTH_DEF_DIALOG 60 /* max width def dialog */ |
---|
812 | -#define MAX_DEFINITIONS 60 /* count found entries show */ |
---|
813 | -#define SHORT_DEF_LEN 30 |
---|
814 | -#define LONG_DEF_LEN 40 |
---|
815 | +#define MAX_WIDTH_DEF_DIALOG 60 /* max width of the dialog */ |
---|
816 | +#define MAX_TAG_OBJECTS 350 |
---|
817 | +#define SHORT_DEF_LEN 70 |
---|
818 | +#define LONG_DEF_LEN 70 |
---|
819 | #define LINE_DEF_LEN 16 |
---|
820 | |
---|
821 | /*** enums ***************************************************************************************/ |
---|
822 | @@ -25,6 +25,27 @@ typedef struct etags_hash_struct |
---|
823 | long line; |
---|
824 | } etags_hash_t; |
---|
825 | |
---|
826 | + |
---|
827 | +typedef enum |
---|
828 | +{ |
---|
829 | + TAG_JUMP_KIND_FUNCTION_LIST, /* List of functions in current file. */ |
---|
830 | + TAG_JUMP_KIND_TYPE_LIST, /* List of type definitions in current file. */ |
---|
831 | + TAG_JUMP_KIND_VAR_LIST, /* List of variables in current file. */ |
---|
832 | + TAG_JUMP_KIND_OTHER_LIST, /* List of other tag object types for the current file. */ |
---|
833 | + TAG_JUMP_KIND_ANY_LIST, /* List of all tags for current file. */ |
---|
834 | + TAG_JUMP_KIND_MATCH_WORD, /* A list of tag objects matching left word. */ |
---|
835 | + TAG_JUMP_KIND_QUICK_WHOLE_WORD /* Future – instantly jump to the id under cursor, same file */ |
---|
836 | +} etags_jump_type_t; |
---|
837 | + |
---|
838 | +typedef enum |
---|
839 | +{ |
---|
840 | + TAG_RANK_FUNCTIONS, /* Function definitions */ |
---|
841 | + TAG_RANK_TYPES, /* Types (structs, typedefs, etc.) */ |
---|
842 | + TAG_RANK_VARIABLES, /* Variables */ |
---|
843 | + TAG_RANK_OTHER, /* Other kind (not of the above) */ |
---|
844 | + TAG_RANK_ANY /* All kinds */ |
---|
845 | +} etags_rank_t; |
---|
846 | + |
---|
847 | /*** global variables defined in .c file *********************************************************/ |
---|
848 | |
---|
849 | /*** declarations of public functions ************************************************************/ |
---|
850 | @@ -33,5 +54,12 @@ typedef struct etags_hash_struct |
---|
851 | int etags_set_definition_hash (const char *tagfile, const char *start_path, |
---|
852 | const char *match_func, etags_hash_t * def_hash); |
---|
853 | |
---|
854 | +int etags_get_objects_for_file (etags_rank_t type, const char *tagfile, |
---|
855 | + const char *start_path, const char *match_filename, |
---|
856 | + etags_hash_t * functions_hash, |
---|
857 | + int *max_len_return, int size_limit); |
---|
858 | + |
---|
859 | +int etags_locate_tags_file(char **tagfile_return, char **path_return); |
---|
860 | + |
---|
861 | /*** inline functions ****************************************************************************/ |
---|
862 | #endif /* MC__EDIT_ETAGS_H */ |
---|
863 | diff --git a/src/keybind-defaults.c b/src/keybind-defaults.c |
---|
864 | index c423e6be4..e16df0ea5 100644 |
---|
865 | --- a/src/keybind-defaults.c |
---|
866 | +++ b/src/keybind-defaults.c |
---|
867 | @@ -465,6 +465,11 @@ static const global_keymap_ini_t default_editor_keymap[] = { |
---|
868 | {"ShowNumbers", "alt-n"}, |
---|
869 | {"ShowTabTws", "alt-underline"}, |
---|
870 | {"SyntaxOnOff", "ctrl-s"}, |
---|
871 | + {"SelectFunction","alt-shift-f"}, |
---|
872 | + {"SelectVariable","alt-shift-v"}, |
---|
873 | + {"SelectType","alt-shift-t"}, |
---|
874 | + {"SelectOther","alt-shift-o"}, |
---|
875 | + {"SelectAllKinds","alt-shift-a"}, |
---|
876 | {"Find", "alt-enter"}, |
---|
877 | {"FilePrev", "alt-minus"}, |
---|
878 | {"FileNext", "alt-plus"}, |
---|
879 | -- |
---|
880 | 2.28.0 |
---|
881 | |
---|