Ticket #4169: 0001-Selectable-listing-of-various-object-types-from-TAGS.patch

File 0001-Selectable-listing-of-various-object-types-from-TAGS.patch, 33.9 KB (added by psprint, 3 years ago)
  • lib/keybind.c

    From 41b925152221c864d37f425b7a73ea354cbe197e Mon Sep 17 00:00:00 2001
    From: Sebastian Gniazdowski <sgniazdowski@gmail.com>
    Date: Sun, 10 Jan 2021 10:41:55 -0600
    Subject: [PATCH] Selectable listing of various object types from TAGS file.
    
    ---
     lib/keybind.c                |   5 +
     lib/keybind.h                |   5 +
     lib/strutil.h                |   2 +
     lib/strutil/strutil.c        |  32 ++++++
     misc/mc.default.keymap       |   5 +
     src/editor/edit-impl.h       |   3 +-
     src/editor/edit.c            |  17 ++-
     src/editor/editcmd.c         | 183 ++++++++++++++++++++++++--------
     src/editor/editcmd_dialogs.c | 122 +++++++++-------------
     src/editor/editcmd_dialogs.h |   6 +-
     src/editor/etags.c           | 197 +++++++++++++++++++++++++++++++++++
     src/editor/etags.h           |  36 ++++++-
     src/keybind-defaults.c       |   5 +
     13 files changed, 491 insertions(+), 127 deletions(-)
    
    diff --git a/lib/keybind.c b/lib/keybind.c
    index abd44d3e2..41a39579b 100644
    a b static name_keymap_t command_names[] = { 
    152152    ADD_KEYMAP_NAME (ViewRaw), 
    153153    ADD_KEYMAP_NAME (ViewFile), 
    154154    ADD_KEYMAP_NAME (ViewFiltered), 
     155    ADD_KEYMAP_NAME (SelectFunction), 
     156    ADD_KEYMAP_NAME (SelectVariable), 
     157    ADD_KEYMAP_NAME (SelectType), 
     158    ADD_KEYMAP_NAME (SelectOther), 
     159    ADD_KEYMAP_NAME (SelectAllKinds), 
    155160    ADD_KEYMAP_NAME (Find), 
    156161    ADD_KEYMAP_NAME (DirSize), 
    157162    ADD_KEYMAP_NAME (CompareDirs), 
  • lib/keybind.h

    diff --git a/lib/keybind.h b/lib/keybind.h
    index 9638bd651..92f496479 100644
    a b enum 
    139139    CK_ViewRaw, 
    140140    CK_ViewFile, 
    141141    CK_ViewFiltered, 
     142    CK_SelectFunction, 
     143    CK_SelectVariable, 
     144    CK_SelectType, 
     145    CK_SelectOther, 
     146    CK_SelectAllKinds, 
    142147    CK_Find, 
    143148    CK_DirSize, 
    144149    CK_HotListAdd, 
  • lib/strutil.h

    diff --git a/lib/strutil.h b/lib/strutil.h
    index a091c25aa..abfe4014d 100644
    a b strtol_error_t xstrtoumax (const char *s, char **ptr, int base, uintmax_t * val, 
    582582                           const char *valid_suffixes); 
    583583uintmax_t parse_integer (const char *str, gboolean * invalid); 
    584584 
     585char *str_collapse_whitespace(char *s, char overwrite_char); 
     586 
    585587/* --------------------------------------------------------------------------------------------- */ 
    586588/*** inline functions ****************************************************************************/ 
    587589/* --------------------------------------------------------------------------------------------- */ 
  • lib/strutil/strutil.c

    diff --git a/lib/strutil/strutil.c b/lib/strutil/strutil.c
    index cf11d00d8..adc29c406 100644
    a b  
    2929#include <langinfo.h> 
    3030#include <string.h> 
    3131#include <errno.h> 
     32#include <ctype.h> 
    3233 
    3334#include "lib/global.h" 
    3435#include "lib/util.h"           /* MC_PTR_FREE */ 
    parse_integer (const char *str, gboolean * invalid) 
    10211022} 
    10221023 
    10231024/* --------------------------------------------------------------------------------------------- */ 
     1025 
     1026char *str_collapse_whitespace(char *s, char overwrite_char) 
     1027{ 
     1028    int i, wi=0, size, span=0; 
     1029    size=strlen(s); 
     1030 
     1031    /* Skip leading whitespace. */ 
     1032    for (i=0; i<size; i++) { 
     1033        if (!isspace(s[i])) 
     1034            break; 
     1035    } 
     1036 
     1037    /* Collapse remaining whitespace. */ 
     1038    for (; i<size; i++) { 
     1039        if (isspace(s[i])) // == ' ') 
     1040            span=1; 
     1041        else { 
     1042            if(span) 
     1043                s[wi++] = overwrite_space; 
     1044 
     1045            s[wi++] = s[i]; 
     1046            span = 0; 
     1047        } 
     1048    } 
     1049 
     1050    s[wi]='\0'; 
     1051 
     1052    return s; 
     1053} 
     1054 
     1055/* --------------------------------------------------------------------------------------------- */ 
  • misc/mc.default.keymap

    diff --git a/misc/mc.default.keymap b/misc/mc.default.keymap
    index 1bf68b2df..721e85022 100644
    a b SpellCheckCurrentWord = ctrl-p 
    387387# WindowNext = 
    388388# WindowPrev = 
    389389# ExtendedKeyMap = 
     390SelectFunction = alt-shift-f 
     391SelectVariable = alt-shift-v 
     392SelectType = alt-shift-t 
     393SelectOther = alt-shift-o 
     394SelectAllKinds = alt-shift-a 
    390395 
    391396[viewer] 
    392397Help = f1 
  • src/editor/edit-impl.h

    diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h
    index 3ad04dbea..dd996face 100644
    a b  
    1818#include "lib/vfs/vfs.h"        /* vfs_path_t */ 
    1919 
    2020#include "edit.h" 
     21#include "etags.h" 
    2122 
    2223/*** typedefs(not structures) and defined constants **********************************************/ 
    2324 
    mc_search_cbret_t edit_search_cmd_callback (const void *user_data, gsize char_of 
    202203mc_search_cbret_t edit_search_update_callback (const void *user_data, gsize char_offset); 
    203204 
    204205void edit_complete_word_cmd (WEdit * edit); 
    205 void edit_get_match_keyword_cmd (WEdit * edit); 
     206void edit_select_object_from_tags(WEdit * edit, etags_jump_type_t type); 
    206207 
    207208#ifdef HAVE_ASPELL 
    208209int edit_suggest_current_word (WEdit * edit); 
  • src/editor/edit.c

    diff --git a/src/editor/edit.c b/src/editor/edit.c
    index e13be389a..0e7e75867 100644
    a b edit_execute_cmd (WEdit * edit, long command, int char_for_insertion) 
    38603860        else 
    38613861            edit_complete_word_cmd (edit); 
    38623862        break; 
     3863    case CK_SelectFunction: 
     3864        edit_select_object_from_tags(edit, TAG_JUMP_KIND_FUNCTION_LIST); 
     3865        break; 
     3866    case CK_SelectVariable: 
     3867        edit_select_object_from_tags(edit, TAG_JUMP_KIND_VAR_LIST); 
     3868        break; 
     3869    case CK_SelectType: 
     3870        edit_select_object_from_tags(edit, TAG_JUMP_KIND_TYPE_LIST); 
     3871        break; 
     3872    case CK_SelectOther: 
     3873        edit_select_object_from_tags(edit, TAG_JUMP_KIND_OTHER_LIST); 
     3874        break; 
     3875    case CK_SelectAllKinds: 
     3876        edit_select_object_from_tags(edit, TAG_JUMP_KIND_ANY_LIST); 
     3877        break; 
    38633878    case CK_Find: 
    3864         edit_get_match_keyword_cmd (edit); 
     3879        edit_select_object_from_tags(edit, TAG_JUMP_KIND_MATCH_WORD); 
    38653880        break; 
    38663881 
    38673882#ifdef HAVE_ASPELL 
  • src/editor/editcmd.c

    diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c
    index e2b904604..4265cd8fc 100644
    a b edit_find_word_start (const edit_buffer_t * buf, off_t * word_start, gsize * wor 
    11401140        return FALSE; 
    11411141 
    11421142    c = edit_buffer_get_previous_byte (buf); 
    1143     /* return if not at end or in word */ 
     1143    /* return if the word is empty */ 
    11441144    if (is_break_char (c)) 
    11451145        return FALSE; 
    11461146 
    edit_find_word_start (const edit_buffer_t * buf, off_t * word_start, gsize * wor 
    11691169    return TRUE; 
    11701170} 
    11711171 
     1172/* Gets the word on the left of the cursor. 
     1173 * 
     1174 * @param buf The edit buffer. 
     1175 * @param initial Initial contents of the result. 
     1176 * @param release_on_empty Should the initial g_string be released when returning NULL. 
     1177 * @return g_string with the word or NULL if the word is empty. 
     1178*/ 
     1179static GString * 
     1180edit_get_left_whole_word(const edit_buffer_t * buf, GString *initial, gboolean release_on_empty) 
     1181{ 
     1182    GString *ret = initial; 
     1183    gsize i, word_len = 0; 
     1184    off_t word_start = 0; 
     1185 
     1186    /* Search start of word left of cursor. */ 
     1187    if (!edit_find_word_start (buf, &word_start, &word_len)) { 
     1188        if (initial && release_on_empty) 
     1189            g_string_free(initial, TRUE); 
     1190        return NULL; 
     1191    } 
     1192 
     1193    /* ret = g_strdup_printf ("\\b%.*s[a-zA-Z_0-9]+", word_len, bufpos); */ 
     1194    if (!ret) 
     1195        ret = g_string_sized_new (SHORT_DEF_LEN); 
     1196 
     1197    for (i = 0; i < word_len; i++) 
     1198        g_string_append_c (ret, edit_buffer_get_byte (buf, word_start + i)); 
     1199 
     1200    return ret; 
     1201} 
     1202 
    11721203/* --------------------------------------------------------------------------------------------- */ 
    11731204/** 
    11741205 * Get current word under cursor 
    edit_load_back_cmd (WEdit * edit) 
    35013532/* --------------------------------------------------------------------------------------------- */ 
    35023533 
    35033534void 
    3504 edit_get_match_keyword_cmd (WEdit * edit) 
     3535edit_select_object_from_tags(WEdit * edit, etags_jump_type_t type) 
    35053536{ 
    3506     gsize word_len = 0, max_len = 0; 
    3507     int num_def = 0; 
    3508     gsize i; 
    3509     off_t word_start = 0; 
    3510     GString *match_expr; 
    3511     char *path = NULL; 
    3512     char *ptr = NULL; 
    3513     char *tagfile = NULL; 
     3537    int i, num_obj, max_len; 
    35143538 
    3515     etags_hash_t def_hash[MAX_DEFINITIONS]; 
     3539    /* Group 0-initialized pointers into a struct for easy initialization. */ 
     3540    struct { 
     3541        const char *fname0; char *fname, *tagfile, *path, *ptr; 
     3542        GString *match_expr; 
     3543        etags_hash_t found_func[MAX_TAG_OBJECTS], *selected_object; 
     3544    } var = {0}; 
    35163545 
    3517     for (i = 0; i < MAX_DEFINITIONS; i++) 
    3518         def_hash[i].filename = NULL; 
    3519  
    3520     /* search start of word to be completed */ 
    3521     if (!edit_find_word_start (&edit->buffer, &word_start, &word_len)) 
     3546    /* No file means no entries in tags file → exit. */ 
     3547    if (edit->filename_vpath == NULL) 
    35223548        return; 
    35233549 
    3524     /* prepare match expression */ 
    3525     match_expr = g_string_sized_new (word_len); 
    3526     for (i = 0; i < word_len; i++) 
    3527         g_string_append_c (match_expr, edit_buffer_get_byte (&edit->buffer, word_start + i)); 
     3550    /* Set up current directory variable. */ 
     3551    var.ptr = g_get_current_dir (); 
     3552    var.path = g_strconcat (var.ptr, PATH_SEP_STR, (char *) NULL); 
     3553    g_free (var.ptr); 
    35283554 
    3529     ptr = g_get_current_dir (); 
    3530     path = g_strconcat (ptr, PATH_SEP_STR, (char *) NULL); 
    3531     g_free (ptr); 
     3555    /* Locate the tags file and its directory.  */ 
     3556    etags_locate_tags_file(&var.tagfile, &var.path); 
    35323557 
    3533     /* Recursive search file 'TAGS' in parent dirs */ 
    3534     do 
    3535     { 
    3536         ptr = g_path_get_dirname (path); 
    3537         g_free (path); 
    3538         path = ptr; 
    3539         g_free (tagfile); 
    3540         tagfile = mc_build_filename (path, TAGS_NAME, (char *) NULL); 
    3541         if (exist_file (tagfile)) 
    3542             break; 
     3558    if (!var.tagfile) 
     3559        goto exit_jump_tag_obj; 
     3560 
     3561    if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) { 
     3562        /* Establish the base relative filename of current buffer. */ 
     3563        var.fname0 = vfs_path_as_str (edit->filename_vpath); 
     3564        if (g_str_has_prefix(var.fname0, var.path)) { 
     3565            var.fname0 = var.fname0 + strlen(var.path) + 1; 
     3566            var.fname = g_strdup(var.fname0); 
     3567        } else 
     3568            /* A fallback that shouldn't be needed and is unreliable. */ 
     3569            var.fname = g_path_get_basename(var.fname0); 
     3570        var.match_expr = g_string_new(var.fname); 
     3571    } else if (type == TAG_JUMP_KIND_MATCH_WORD) { 
     3572        // The function releases the string on empty word result. 
     3573        var.match_expr = edit_get_left_whole_word(&edit->buffer, NULL, FALSE); 
     3574 
     3575        if(!var.match_expr) 
     3576            goto exit_jump_tag_obj; 
     3577 
     3578    } else 
     3579        goto exit_jump_tag_obj; 
     3580 
     3581    if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) { 
     3582        num_obj = etags_get_objects_for_file(type, var.tagfile, var.path, var.fname, (etags_hash_t *) 
     3583                        &var.found_func, &max_len, MAX_TAG_OBJECTS); 
     3584    } else { 
     3585        max_len = MAX_WIDTH_DEF_DIALOG; 
     3586        num_obj = etags_set_definition_hash (var.tagfile, var.path, var.match_expr->str, (etags_hash_t *)  
     3587&var.found_func); 
    35433588    } 
    3544     while (strcmp (path, PATH_SEP_STR) != 0); 
    35453589 
    3546     if (tagfile != NULL) 
    3547     { 
    3548         num_def = 
    3549             etags_set_definition_hash (tagfile, path, match_expr->str, (etags_hash_t *) & def_hash); 
    3550         g_free (tagfile); 
     3590    /* Show the list. */ 
     3591    if (num_obj > 0) 
     3592        var.selected_object = editcmd_dialog_select_tags_object_show (edit, var.fname, max_len, 
     3593                                               (etags_hash_t *) & var.found_func, type, num_obj); 
     3594 
     3595    if (var.selected_object) { 
     3596        int line = var.selected_object->line; 
     3597 
     3598        /* Move the display to the function line. */ 
     3599        if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) { 
     3600            edit_move_display (edit, line - WIDGET (edit)->lines / 2 - 1); 
     3601            edit_move_to_line (edit, line - 1); 
     3602            edit->force |= REDRAW_COMPLETELY; 
     3603        } else { 
     3604            char *fullpath = var.selected_object->fullpath; 
     3605            gboolean do_moveto = FALSE; 
     3606            if (!edit->modified) 
     3607                do_moveto = TRUE; 
     3608            else if (!edit_query_dialog2 
     3609                     (_("Warning"), 
     3610                      _("Current text was modified without a file save.\n" 
     3611                        "Continue discards these changes."), _("C&ontinue"), _("&Cancel"))) 
     3612            { 
     3613                edit->force |= REDRAW_COMPLETELY; 
     3614                do_moveto = TRUE; 
     3615            } 
     3616 
     3617            if (do_moveto) { 
     3618                /* Replace the file in current editor (no new file is opened). */ 
     3619                vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); 
     3620 
     3621                if (edit->dir_vpath != NULL) 
     3622                    edit_history_moveto[edit_stack_iterator].filename_vpath = 
     3623                        vfs_path_append_vpath_new (edit->dir_vpath, edit->filename_vpath, NULL); 
     3624                else 
     3625                    edit_history_moveto[edit_stack_iterator].filename_vpath = 
     3626                        vfs_path_clone (edit->filename_vpath); 
     3627 
     3628                edit_history_moveto[edit_stack_iterator].line = edit->start_line + edit->curs_row + 1; 
     3629                edit_stack_iterator++; 
     3630                vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); 
     3631                edit_history_moveto[edit_stack_iterator].filename_vpath = 
     3632                    vfs_path_from_str ((char *) fullpath); 
     3633                edit_history_moveto[edit_stack_iterator].line = line; 
     3634                edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath, 
     3635                                edit_history_moveto[edit_stack_iterator].line); 
     3636            } 
     3637        } 
    35513638    } 
    3552     g_free (path); 
     3639exit_jump_tag_obj: 
     3640    /* Clear results hash */ 
     3641    for (i = 0; i < num_obj; i++) 
     3642        g_free (var.found_func[i].filename); 
    35533643 
    3554     max_len = MAX_WIDTH_DEF_DIALOG; 
    3555     word_len = 0; 
    3556     if (num_def > 0) 
    3557         editcmd_dialog_select_definition_show (edit, match_expr->str, max_len, word_len, 
    3558                                                (etags_hash_t *) & def_hash, num_def); 
    3559     g_string_free (match_expr, TRUE); 
     3644    /* Release other variables. */ 
     3645    g_free(var.fname); 
     3646    g_free(var.tagfile); 
     3647    g_free(var.path); 
     3648 
     3649    if (var.match_expr) 
     3650        g_string_free(var.match_expr, TRUE); 
    35603651} 
    35613652 
    35623653/* --------------------------------------------------------------------------------------------- */ 
  • src/editor/editcmd_dialogs.c

    diff --git a/src/editor/editcmd_dialogs.c b/src/editor/editcmd_dialogs.c
    index 8b3634f23..07f81b156 100644
    a b editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** comp 
    408408} 
    409409 
    410410/* --------------------------------------------------------------------------------------------- */ 
    411 /* let the user select where function definition */ 
     411/* function and data structure selection dialog */ 
    412412 
    413 void 
    414 editcmd_dialog_select_definition_show (WEdit * edit, char *match_expr, int max_len, int word_len, 
    415                                        etags_hash_t * def_hash, int num_lines) 
     413etags_hash_t * 
     414editcmd_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) 
    416417{ 
    417     int start_x, start_y, offset, i; 
     418    int start_x, start_y, offset, i, selected_on_start = 0; 
     419    gboolean found_current = FALSE; 
    418420    char *curr = NULL; 
    419     WDialog *def_dlg; 
    420     WListbox *def_list; 
    421     int def_dlg_h;              /* dialog height */ 
    422     int def_dlg_w;              /* dialog width */ 
     421    WDialog *func_dlg; 
     422    WListbox *func_list; 
     423    int func_dlg_h;              /* dialog height */ 
     424    int func_dlg_w;              /* dialog width */ 
     425    etags_hash_t *selection_data = NULL; 
    423426 
    424     (void) word_len; 
    425427    /* calculate the dialog metrics */ 
    426     def_dlg_h = num_lines + 2; 
    427     def_dlg_w = max_len + 4; 
    428     start_x = edit->curs_col + edit->start_col - (def_dlg_w / 2) + 
     428    func_dlg_h = num_lines + 2; 
     429    func_dlg_w = max_len >= MAX_WIDTH_DEF_DIALOG/2 ? max_len + 4 : MAX_WIDTH_DEF_DIALOG/2 + 4; 
     430    start_x = edit->curs_col + edit->start_col - (func_dlg_w / 2) + 
    429431        EDIT_TEXT_HORIZONTAL_OFFSET + (edit->fullscreen ? 0 : 1) + option_line_state_width; 
    430432    start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + (edit->fullscreen ? 0 : 1) + 1; 
    431433 
    432434    if (start_x < 0) 
    433435        start_x = 0; 
    434     if (def_dlg_w > COLS) 
    435         def_dlg_w = COLS; 
    436     if (def_dlg_h > LINES - 2) 
    437         def_dlg_h = LINES - 2; 
     436    if (func_dlg_w > COLS) 
     437        func_dlg_w = COLS; 
     438    if (func_dlg_h > LINES - 2) 
     439        func_dlg_h = LINES - 2; 
    438440 
    439     offset = start_x + def_dlg_w - COLS; 
     441    offset = start_x + func_dlg_w - COLS; 
    440442    if (offset > 0) 
    441443        start_x -= offset; 
    442     offset = start_y + def_dlg_h - LINES; 
     444    offset = start_y + func_dlg_h - LINES; 
    443445    if (offset > 0) 
    444446        start_y -= (offset + 1); 
    445447 
    446     def_dlg = dlg_create (TRUE, start_y, start_x, def_dlg_h, def_dlg_w, WPOS_KEEP_DEFAULT, TRUE, 
     448    func_dlg = dlg_create (TRUE, start_y, start_x, func_dlg_h, func_dlg_w, WPOS_KEEP_DEFAULT, TRUE, 
    447449                          dialog_colors, NULL, NULL, "[Definitions]", match_expr); 
    448     def_list = listbox_new (1, 1, def_dlg_h - 2, def_dlg_w - 2, FALSE, NULL); 
    449     group_add_widget (GROUP (def_dlg), def_list); 
     450    func_list = listbox_new (1, 1, func_dlg_h - 2, func_dlg_w - 2, FALSE, NULL); 
     451    group_add_widget (GROUP (func_dlg), func_list); 
    450452 
    451453    /* fill the listbox with the completions */ 
    452454    for (i = 0; i < num_lines; i++) 
    453455    { 
    454         char *label_def; 
     456        char *label = NULL; 
    455457 
    456         label_def = 
    457             g_strdup_printf ("%s -> %s:%ld", def_hash[i].short_define, def_hash[i].filename, 
    458                              def_hash[i].line); 
    459         listbox_add_item (def_list, LISTBOX_APPEND_AT_END, 0, label_def, &def_hash[i], FALSE); 
    460         g_free (label_def); 
     458        if (type >= TAG_JUMP_KIND_FUNCTION_LIST && type <= TAG_JUMP_KIND_ANY_LIST) 
     459            label = all_found[i].short_define; 
     460        else if (type == TAG_JUMP_KIND_MATCH_WORD) 
     461            label = 
     462                g_strdup_printf ("%s -> %s:%ld", all_found[i].short_define, all_found[i].filename, 
     463                             all_found[i].line); 
     464        else 
     465            label = g_strdup("error"); 
     466        listbox_add_item (func_list, LISTBOX_APPEND_AT_END, 0, label, &all_found[i], FALSE); 
     467        g_free (label); 
     468 
     469        /* Detect currently active code segment. */ 
     470        if ((all_found[i].line - 1) <= edit->buffer.curs_line) { 
     471            found_current = TRUE; 
     472            selected_on_start = i; 
     473        } 
    461474    } 
     475    if (found_current) 
     476        listbox_select_entry(func_list, selected_on_start); 
     477    /* Option to enable Multi Search from the start. */ 
     478    listbox_conditionally_enable_multi_search(func_list); 
    462479 
    463480    /* pop up the dialog and apply the chosen completion */ 
    464     if (dlg_run (def_dlg) == B_ENTER) 
    465     { 
    466         etags_hash_t *curr_def = NULL; 
    467         gboolean do_moveto = FALSE; 
    468  
    469         listbox_get_current (def_list, &curr, (void **) &curr_def); 
    470  
    471         if (!edit->modified) 
    472             do_moveto = TRUE; 
    473         else if (!edit_query_dialog2 
    474                  (_("Warning"), 
    475                   _("Current text was modified without a file save.\n" 
    476                     "Continue discards these changes."), _("C&ontinue"), _("&Cancel"))) 
    477         { 
    478             edit->force |= REDRAW_COMPLETELY; 
    479             do_moveto = TRUE; 
    480         } 
    481  
    482         if (curr != NULL && do_moveto && edit_stack_iterator + 1 < MAX_HISTORY_MOVETO) 
    483         { 
    484             vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); 
    485  
    486             if (edit->dir_vpath != NULL) 
    487                 edit_history_moveto[edit_stack_iterator].filename_vpath = 
    488                     vfs_path_append_vpath_new (edit->dir_vpath, edit->filename_vpath, NULL); 
    489             else 
    490                 edit_history_moveto[edit_stack_iterator].filename_vpath = 
    491                     vfs_path_clone (edit->filename_vpath); 
    492  
    493             edit_history_moveto[edit_stack_iterator].line = edit->start_line + edit->curs_row + 1; 
    494             edit_stack_iterator++; 
    495             vfs_path_free (edit_history_moveto[edit_stack_iterator].filename_vpath); 
    496             edit_history_moveto[edit_stack_iterator].filename_vpath = 
    497                 vfs_path_from_str ((char *) curr_def->fullpath); 
    498             edit_history_moveto[edit_stack_iterator].line = curr_def->line; 
    499             edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename_vpath, 
    500                               edit_history_moveto[edit_stack_iterator].line); 
    501         } 
    502     } 
    503  
    504     /* clear definition hash */ 
    505     for (i = 0; i < MAX_DEFINITIONS; i++) 
    506         g_free (def_hash[i].filename); 
     481    if (dlg_run (func_dlg) == B_ENTER) 
     482        listbox_get_current (func_list, &curr, (void **) &selection_data); 
    507483 
    508484    /* destroy dialog before return */ 
    509     dlg_destroy (def_dlg); 
     485    dlg_destroy (func_dlg); 
     486 
     487    return selection_data; 
    510488} 
    511489 
    512490/* --------------------------------------------------------------------------------------------- */ 
  • src/editor/editcmd_dialogs.h

    diff --git a/src/editor/editcmd_dialogs.h b/src/editor/editcmd_dialogs.h
    index f691c857e..8d6a7933a 100644
    a b  
    55 
    66/*** typedefs(not structures) and defined constants **********************************************/ 
    77 
    8 struct etags_hash_struct; 
     8typedef struct etags_hash_struct etags_hash_t; 
    99 
    1010#define B_REPLACE_ALL (B_USER+1) 
    1111#define B_REPLACE_ONE (B_USER+2) 
    int editcmd_dialog_raw_key_query (const char *heading, const char *query, gboole 
    2828char *editcmd_dialog_completion_show (const WEdit * edit, int max_len, GString ** compl, 
    2929                                      int num_compl); 
    3030 
    31 void editcmd_dialog_select_definition_show (WEdit *, char *, int, int, struct etags_hash_struct *, 
    32                                             int); 
     31etags_hash_t *editcmd_dialog_select_tags_object_show (WEdit *, char *, int, etags_hash_t *, 
     32                                                        etags_jump_type_t, int); 
    3333 
    3434int editcmd_dialog_replace_prompt_show (WEdit *, char *, char *, int, int); 
    3535/*** inline functions ****************************************************************************/ 
  • src/editor/etags.c

    diff --git a/src/editor/etags.c b/src/editor/etags.c
    index 35c7a2f04..952df9b99 100644
    a b  
    3939 
    4040#include "lib/global.h" 
    4141#include "lib/util.h"           /* canonicalize_pathname() */ 
     42#include "lib/fileloc.h" 
     43#include "lib/strutil.h" 
    4244 
    4345#include "etags.h" 
    4446 
     
    5355/*** file scope functions ************************************************************************/ 
    5456/* --------------------------------------------------------------------------------------------- */ 
    5557 
     58int 
     59etags_locate_tags_file(char **tagfile_return, char **path_return) { 
     60    char *tagfile = *tagfile_return, *path = *path_return, *ptr = NULL; 
     61    int search_result = 0; 
     62 
     63    /* Recursive search file 'TAGS' in parent dirs */ 
     64    do 
     65    { 
     66        ptr = g_path_get_dirname (path); 
     67        g_free (path); 
     68        path = ptr; 
     69        g_free (tagfile); 
     70        tagfile = mc_build_filename (path, TAGS_NAME, (char *) NULL); 
     71        if (exist_file (tagfile)) { 
     72            search_result = 1; 
     73            break; 
     74        } 
     75    } 
     76    while (strcmp (path, PATH_SEP_STR) != 0); 
     77 
     78    *tagfile_return = tagfile; 
     79    *path_return = path; 
     80 
     81    return search_result; 
     82} 
     83 
    5684static gboolean 
    5785parse_define (const char *buf, char **long_name, char **short_name, long *line) 
    5886{ 
    parse_define (const char *buf, char **long_name, char **short_name, long *line) 
    169197/*** public functions ****************************************************************************/ 
    170198/* --------------------------------------------------------------------------------------------- */ 
    171199 
     200/* Fills the etags info array with ·all· objects of given ·type· (functions, etc.) */ 
     201int etags_get_objects_for_file (etags_rank_t type, const char *tagfile, 
     202                            const char *start_path, const char *match_filename, 
     203                            etags_hash_t * functions_hash, 
     204                            int *max_len_return, int size_limit) 
     205{ 
     206    /* *INDENT-OFF* */ 
     207    enum 
     208    { 
     209        start, 
     210        in_filename, 
     211        in_define 
     212    } state = start; 
     213    /* *INDENT-ON* */ 
     214 
     215    FILE *f; 
     216    char buf[BUF_LARGE]; 
     217 
     218    int num = 0;                /* returned value */ 
     219    char *filename = NULL; 
     220 
     221    if (!match_filename || !tagfile) 
     222        return 0; 
     223 
     224    *max_len_return = 0; 
     225 
     226    /* open file with positions */ 
     227    f = fopen (tagfile, "r"); 
     228    if (f == NULL) 
     229        return 0; 
     230 
     231    while (fgets (buf, sizeof (buf), f)) 
     232    { 
     233        switch (state) 
     234        { 
     235        case start: 
     236            if (buf[0] == 0x0C) 
     237            { 
     238                state = in_filename; 
     239            } 
     240            break; 
     241        case in_filename: 
     242            { 
     243                size_t pos; 
     244 
     245                pos = strcspn (buf, ","); 
     246                g_free (filename); 
     247                filename = g_strndup (buf, pos); 
     248                state = in_define; 
     249                break; 
     250            } 
     251        case in_define: 
     252            if (buf[0] == 0x0C) 
     253            { 
     254                state = in_filename; 
     255                break; 
     256            } 
     257            /* check if the filename matches the requested one */ 
     258            if (strcmp (filename, match_filename) == 0) 
     259            { 
     260                char *longname = NULL; 
     261                char *shortname = NULL; 
     262                long line = 0; 
     263 
     264                parse_define (buf, &longname, &shortname, &line); 
     265                if (num < size_limit - 1) 
     266                { 
     267                    gboolean can_be_func, can_be_var, can_be_type, is_other; 
     268 
     269                    /* Prepare the work variable. */ 
     270                    char *longname_wr; 
     271                    longname_wr = g_strdup(longname); 
     272 
     273                    /* Function – if there's '(' in the declaration. */ 
     274                    can_be_func = strstr(longname,"(") != NULL; 
     275                    /* Variable – if there's no parens and no # in the declaration. */ 
     276                    can_be_var = strstr(g_strdelimit(longname_wr,"}{()#",''),"") == NULL; 
     277                    /* Type – if there's a 'struct', 'typedef', 'enum' or '}' in the declaration. */ 
     278                    can_be_type=(strstr(longname,"struct ") ||  
     279                                            strstr(longname,"typedef ") || 
     280                                            strstr(longname,"enum ")) || 
     281                                (strstr(longname, "}") && 
     282                                    (g_str_has_suffix(shortname,"_t") ||  
     283                                        g_str_has_suffix(shortname,"_type"))); 
     284                    /* Other kind – nor any of the above. */ 
     285                    is_other = !can_be_func && !can_be_var && !can_be_type; 
     286 
     287                    /* Renew the work variable. */ 
     288                    g_free(longname_wr); 
     289                    longname_wr = g_strdup(longname); 
     290 
     291                    /* A closer examination of type tags. */ 
     292                    if (type == TAG_RANK_TYPES && can_be_type && !can_be_func) { 
     293                        /* 
     294                         * Verify if it's not a struct variable or an enum. 
     295                         * It filters out occurrences such as: 
     296                         * – struct type SHORTNAME … – i.e.: the shortname at 3rd position, because 
     297                         *   this means that a struct variable, not a struct type is being defined. 
     298                         */ 
     299                        gchar **words = g_strsplit(str_collapse_whitespace(longname_wr, ' ')," ", -1); 
     300                        if (words[2] && strcmp(words[2], shortname) == 0) 
     301                            can_be_type = FALSE; 
     302                        g_strfreev(words); 
     303                    } 
     304 
     305                    /* A closer examination of variable tags. */ 
     306                    if (type == TAG_RANK_VARIABLES && can_be_var) { 
     307                        /* Verify if it's not a struct typedef or an enum. */ 
     308                        gchar **words = g_strsplit(str_collapse_whitespace(longname_wr, ' ')," ", -1); 
     309                        if (strcmp(words[0], "typedef") == 0 || !words[0] || !words[1]) 
     310                            can_be_var = FALSE; 
     311                        /* Most probably an enum ENUM = 0|1|… assignment. */ 
     312                        if (!words[0] || strstr(words[0], "=") || (words[1] && words[1][0] == '=')) 
     313                            can_be_var = FALSE; 
     314                        g_strfreev(words); 
     315                    } 
     316 
     317                    /* Free the work variable. */ 
     318                    g_free(longname_wr); 
     319 
     320                    /* Is the object of the requested type? */ 
     321                    if (type == TAG_RANK_ANY || 
     322                        ((type == TAG_RANK_FUNCTIONS && can_be_func) || 
     323                            (type == TAG_RANK_VARIABLES && can_be_var) || 
     324                            (type == TAG_RANK_TYPES && can_be_type) || 
     325                            (type == TAG_RANK_OTHER && is_other))) 
     326                    { 
     327                        /* Update the max. length return variable */ 
     328                        int max_len_candidate; 
     329                        max_len_candidate = strlen(shortname); 
     330                        if (*max_len_return < max_len_candidate) 
     331                            *max_len_return = max_len_candidate; 
     332 
     333                        /* Save the filename. */ 
     334                        functions_hash[num].filename = g_strdup (filename); 
     335                        functions_hash[num].filename_len = strlen (filename); 
     336 
     337                        /* Save and canonicalize the path to the file. */ 
     338                        functions_hash[num].fullpath = 
     339                            mc_build_filename (start_path, filename, (char *) NULL); 
     340                        canonicalize_pathname (functions_hash[num].fullpath); 
     341 
     342                        /* Save the short define. */ 
     343                        if (shortname) 
     344                            functions_hash[num].short_define = g_strdup (shortname); 
     345                        else 
     346                            functions_hash[num].short_define = g_strdup (longname); 
     347 
     348                        /* Save the line number. */ 
     349                        functions_hash[num].line = line; 
     350 
     351                        /* Increase the count of the matched objects. */ 
     352                        num++; 
     353                    } 
     354                } 
     355            } 
     356            break; 
     357        default: 
     358            break; 
     359        } 
     360    } 
     361 
     362    g_free (filename); 
     363    fclose (f); 
     364    return num; 
     365} 
     366 
     367/* --------------------------------------------------------------------------------------------- */ 
     368 
    172369int 
    173370etags_set_definition_hash (const char *tagfile, const char *start_path, 
    174371                           const char *match_func, etags_hash_t * def_hash) 
  • src/editor/etags.h

    diff --git a/src/editor/etags.h b/src/editor/etags.h
    index be71b3a27..a0eb77710 100644
    a b  
    66 
    77/*** typedefs(not structures) and defined constants **********************************************/ 
    88 
    9 #define MAX_WIDTH_DEF_DIALOG 60 /* max width def dialog */ 
    10 #define MAX_DEFINITIONS 60      /* count found entries show */ 
    11 #define SHORT_DEF_LEN   30 
    12 #define LONG_DEF_LEN    40 
     9#define MAX_WIDTH_DEF_DIALOG 60 /* max width of the dialog */ 
     10#define MAX_TAG_OBJECTS   350 
     11#define SHORT_DEF_LEN   70 
     12#define LONG_DEF_LEN    70 
    1313#define LINE_DEF_LEN    16 
    1414 
    1515/*** enums ***************************************************************************************/ 
    typedef struct etags_hash_struct 
    2525    long line; 
    2626} etags_hash_t; 
    2727 
     28 
     29typedef enum 
     30{ 
     31    TAG_JUMP_KIND_FUNCTION_LIST,   /* List of functions in current file. */ 
     32    TAG_JUMP_KIND_TYPE_LIST,       /* List of type definitions in current file. */ 
     33    TAG_JUMP_KIND_VAR_LIST,        /* List of variables in current file. */ 
     34    TAG_JUMP_KIND_OTHER_LIST,      /* List of other tag object types for the current file. */ 
     35    TAG_JUMP_KIND_ANY_LIST,        /* List of all tags for current file. */ 
     36    TAG_JUMP_KIND_MATCH_WORD,      /* A list of tag objects matching left word. */ 
     37    TAG_JUMP_KIND_QUICK_WHOLE_WORD /* Future – instantly jump to the id under cursor, same file */ 
     38} etags_jump_type_t; 
     39 
     40typedef enum 
     41{ 
     42    TAG_RANK_FUNCTIONS,     /* Function definitions */ 
     43    TAG_RANK_TYPES,         /* Types (structs, typedefs, etc.)  */ 
     44    TAG_RANK_VARIABLES,     /* Variables */ 
     45    TAG_RANK_OTHER,         /* Other kind (not of the above) */ 
     46    TAG_RANK_ANY            /* All kinds */ 
     47} etags_rank_t; 
     48 
    2849/*** global variables defined in .c file *********************************************************/ 
    2950 
    3051/*** declarations of public functions ************************************************************/ 
    typedef struct etags_hash_struct 
    3354int etags_set_definition_hash (const char *tagfile, const char *start_path, 
    3455                               const char *match_func, etags_hash_t * def_hash); 
    3556 
     57int etags_get_objects_for_file (etags_rank_t type, const char *tagfile, 
     58                            const char *start_path, const char *match_filename, 
     59                            etags_hash_t * functions_hash, 
     60                            int *max_len_return, int size_limit); 
     61 
     62int etags_locate_tags_file(char **tagfile_return, char **path_return); 
     63 
    3664/*** inline functions ****************************************************************************/ 
    3765#endif /* MC__EDIT_ETAGS_H */ 
  • src/keybind-defaults.c

    diff --git a/src/keybind-defaults.c b/src/keybind-defaults.c
    index c423e6be4..e16df0ea5 100644
    a b static const global_keymap_ini_t default_editor_keymap[] = { 
    465465    {"ShowNumbers", "alt-n"}, 
    466466    {"ShowTabTws", "alt-underline"}, 
    467467    {"SyntaxOnOff", "ctrl-s"}, 
     468    {"SelectFunction","alt-shift-f"}, 
     469    {"SelectVariable","alt-shift-v"}, 
     470    {"SelectType","alt-shift-t"}, 
     471    {"SelectOther","alt-shift-o"}, 
     472    {"SelectAllKinds","alt-shift-a"}, 
    468473    {"Find", "alt-enter"}, 
    469474    {"FilePrev", "alt-minus"}, 
    470475    {"FileNext", "alt-plus"},