Ticket #4193: OtherFileConceptUpstr.patch

File OtherFileConceptUpstr.patch, 15.0 KB (added by psprint, 4 years ago)
  • lib/keybind.c

    From 36f78be1f6af51f834036210f3c49e2d3847a40d Mon Sep 17 00:00:00 2001
    From: Sebastian Gniazdowski <sgniazdowski@gmail.com>
    Date: Tue, 2 Feb 2021 12:50:19 -0600
    Subject: Other File concept: jumping between headers and sources.
    
    ---
     lib/keybind.c           |   1 +
     lib/keybind.h           |   1 +
     lib/vfs/path.c          |  19 +++++
     lib/vfs/path.h          |   1 +
     misc/mc.default.keymap  |   1 +
     misc/mc.emacs.keymap    |   1 +
     src/editor/edit-impl.h  |  13 +++-
     src/editor/edit.c       |  27 +++++++
     src/editor/edit.h       |   2 +
     src/editor/editcmd.c    |   7 +-
     src/editor/editwidget.c | 165 +++++++++++++++++++++++++++++++++++++++-
     src/editor/editwidget.h |   1 +
     src/keybind-defaults.c  |   1 +
     13 files changed, 236 insertions(+), 4 deletions(-)
    
    diff --git a/lib/keybind.c b/lib/keybind.c
    index abd44d3e2..2ec715bfa 100644
    a b static name_keymap_t command_names[] = { 
    277277    ADD_KEYMAP_NAME (ParagraphUp), 
    278278    ADD_KEYMAP_NAME (ParagraphDown), 
    279279    ADD_KEYMAP_NAME (EditFile), 
     280    ADD_KEYMAP_NAME (OtherFile), 
    280281    ADD_KEYMAP_NAME (MarkWord), 
    281282    ADD_KEYMAP_NAME (MarkLine), 
    282283    ADD_KEYMAP_NAME (MarkAll), 
  • lib/keybind.h

    diff --git a/lib/keybind.h b/lib/keybind.h
    index af019df09..cd7192d06 100644
    a b enum 
    246246    CK_ParagraphDown, 
    247247    /* file commands */ 
    248248    CK_EditFile, 
     249    CK_OtherFile, 
    249250    CK_InsertFile, 
    250251    CK_EditSyntaxFile, 
    251252    CK_Close, 
  • lib/vfs/path.c

    diff --git a/lib/vfs/path.c b/lib/vfs/path.c
    index 49553198f..46a694d08 100644
    a b vfs_path_strip_home (const char *dir) 
    593593/*** public functions ****************************************************************************/ 
    594594/* --------------------------------------------------------------------------------------------- */ 
    595595 
     596/** 
     597 * Returns TRUE if path has one of the given extensions (in a NULL terminated array). 
     598 * The extension strings should include the dot. 
     599 */ 
     600gboolean 
     601vfs_path_has_extension (const vfs_path_t * fs_path, const char *exts[]) 
     602{ 
     603    const char *path, **cur_ext; 
     604    path = vfs_path_as_str (fs_path); 
     605    for (cur_ext = exts; cur_ext != NULL && *cur_ext != NULL; cur_ext++) 
     606    { 
     607        if (g_str_has_suffix (path, *cur_ext)) 
     608            return TRUE; 
     609    } 
     610    return FALSE; 
     611} 
     612 
     613/* --------------------------------------------------------------------------------------------- */ 
     614 
    596615#define vfs_append_from_path(appendfrom, is_relative) \ 
    597616{ \ 
    598617    if ((flags & VPF_STRIP_HOME) && element_index == 0 && \ 
  • lib/vfs/path.h

    diff --git a/lib/vfs/path.h b/lib/vfs/path.h
    index c5dc4f5a4..f1a24e49e 100644
    a b char *vfs_path_to_str_elements_count (const vfs_path_t * path, int elements_coun 
    6767char *vfs_path_to_str_flags (const vfs_path_t * vpath, int elements_count, vfs_path_flag_t flags); 
    6868vfs_path_t *vfs_path_from_str (const char *path_str); 
    6969vfs_path_t *vfs_path_from_str_flags (const char *path_str, vfs_path_flag_t flags); 
     70gboolean vfs_path_has_extension (const vfs_path_t * fs_path, const char *exts[]); 
    7071vfs_path_t *vfs_path_build_filename (const char *first_element, ...); 
    7172vfs_path_t *vfs_path_append_new (const vfs_path_t * vpath, const char *first_element, ...); 
    7273vfs_path_t *vfs_path_append_vpath_new (const vfs_path_t * first_vpath, ...); 
  • misc/mc.default.keymap

    diff --git a/misc/mc.default.keymap b/misc/mc.default.keymap
    index 2931ddd0a..075c8e4ce 100644
    a b DeleteToEnd = ctrl-k 
    291291Save = f2 
    292292# EditFile = 
    293293EditNew = ctrl-n 
     294OtherFile = alt-a 
    294295SaveAs = f12; ctrl-f2 
    295296# Close = 
    296297History = alt-shift-e 
  • misc/mc.emacs.keymap

    diff --git a/misc/mc.emacs.keymap b/misc/mc.emacs.keymap
    index 7cc305db7..bff42b0a0 100644
    a b DeleteToEnd = ctrl-k 
    290290# ParagraphDown = 
    291291Save = f2 
    292292# EditFile = 
     293OtherFile = alt-a 
    293294SaveAs = f12; ctrl-f2 
    294295# Close = 
    295296History = alt-shift-e 
  • src/editor/edit-impl.h

    diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h
    index 3ad04dbea..90dc5dedb 100644
    a b typedef enum 
    9494    EDIT_DO_BACKUP 
    9595} edit_save_mode_t; 
    9696 
     97 
     98/* Describes how well a file suits for editing. Symlinks and empty files get average grade. */ 
     99typedef enum 
     100{ 
     101    FILE_RANK_INVALID = -1, 
     102    FILE_RANK_NOT_SUITABLE = 0, 
     103    FILE_RANK_AVERAGE_SUITABLE, 
     104    FILE_RANK_SUITABLE 
     105} file_suitable_rank_t; 
     106 
    97107/*** structures declarations (and typedefs of structures)*****************************************/ 
    98108 
    99109/* search/replace options */ 
    WEdit *edit_init (WEdit * edit, int y, int x, int lines, int cols, 
    185195                  const vfs_path_t * filename_vpath, long line); 
    186196gboolean edit_clean (WEdit * edit); 
    187197gboolean edit_ok_to_exit (WEdit * edit); 
    188 gboolean edit_load_cmd (WDialog * h); 
     198file_suitable_rank_t edit_check_file_suitable (const vfs_path_t * fs_path); 
     199gboolean edit_load_cmd (WDialog * h, const void *data); 
    189200gboolean edit_load_file_from_history (WDialog * h); 
    190201gboolean edit_load_syntax_file (WDialog * h); 
    191202gboolean edit_load_menu_file (WDialog * h); 
  • src/editor/edit.c

    diff --git a/src/editor/edit.c b/src/editor/edit.c
    index edda1f832..befaed434 100644
    a b edit_insert_stream (WEdit * edit, FILE * f) 
    277277    return i; 
    278278} 
    279279 
     280/* --------------------------------------------------------------------------------------------- */ 
     281/** 
     282 * Gives a 3-level evaluation of how well given file is looking as a suitable input to the editor. 
     283 */ 
     284file_suitable_rank_t 
     285edit_check_file_suitable (const vfs_path_t * fs_path) 
     286{ 
     287    struct stat lst, st; 
     288 
     289    if (fs_path == NULL) 
     290        return FILE_RANK_INVALID; 
     291 
     292    if (exist_file (vfs_path_as_str (fs_path))) 
     293    { 
     294        if (mc_lstat (fs_path, &lst) == 0 && mc_stat (fs_path, &st) == 0) 
     295        { 
     296            if (st.st_size != 0 && S_ISREG (st.st_mode) && !S_ISLNK (lst.st_mode)) 
     297                return FILE_RANK_SUITABLE; 
     298            else 
     299                return FILE_RANK_AVERAGE_SUITABLE; 
     300        } 
     301    } 
     302    return FILE_RANK_NOT_SUITABLE; 
     303} 
     304 
    280305/* --------------------------------------------------------------------------------------------- */ 
    281306/** 
    282307  * Open file and create it if necessary. 
    edit_init (WEdit * edit, int y, int x, int lines, int cols, const vfs_path_t * f 
    21082133        w->options |= WOP_SELECTABLE | WOP_TOP_SELECT | WOP_WANT_CURSOR; 
    21092134        w->keymap = editor_map; 
    21102135        w->ext_keymap = editor_x_map; 
     2136        edit->otherfile_vpath = NULL; 
    21112137        edit->fullscreen = TRUE; 
    21122138        edit_save_size (edit); 
    21132139    } 
    edit_clean (WEdit * edit) 
    22042230    g_free (edit->redo_stack); 
    22052231    vfs_path_free (edit->filename_vpath); 
    22062232    vfs_path_free (edit->dir_vpath); 
     2233    vfs_path_free (edit->otherfile_vpath); 
    22072234    mc_search_free (edit->search); 
    22082235    g_free (edit->last_search_string); 
    22092236 
  • src/editor/edit.h

    diff --git a/src/editor/edit.h b/src/editor/edit.h
    index 6c519e9d3..74c38d1b3 100644
    a b extern gboolean show_right_margin; 
    6666void edit_stack_init (void); 
    6767void edit_stack_free (void); 
    6868 
     69/* If file is open, switch to it, otherwise it is loaded */ 
     70gboolean edit_switch_to_file (WDialog * h, const vfs_path_t * file); 
    6971gboolean edit_file (const vfs_path_t * file_vpath, long line); 
    7072gboolean edit_files (const GList * files); 
    7173 
  • src/editor/editcmd.c

    diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c
    index 0d2caa923..3609d7adf 100644
    a b edit_save_confirm_cmd (WEdit * edit) 
    20632063  */ 
    20642064 
    20652065gboolean 
    2066 edit_load_cmd (WDialog * h) 
     2066edit_load_cmd (WDialog * h, const void *data) 
    20672067{ 
    20682068    char *exp; 
    20692069    gboolean ret = TRUE;        /* possible cancel */ 
    20702070 
    2071     exp = input_expand_dialog (_("Load"), _("Enter file name:"), 
     2071    if (data != NULL) 
     2072        exp = (char *) data; 
     2073    else 
     2074        exp = input_expand_dialog (_("Load"), _("Enter file name:"), 
    20722075                               MC_HISTORY_EDIT_LOAD, INPUT_LAST_TEXT, 
    20732076                               INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD); 
    20742077 
  • src/editor/editwidget.c

    diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c
    index 18ac00e66..721933d2f 100644
    a b static unsigned int edit_dlg_init_refcounter = 0; 
    8888static cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, 
    8989                                      void *data); 
    9090 
     91/* --------------------------------------------------------------------------------------------- */ 
     92 
     93static char * 
     94replace_suffix_with (const char *src_str, const char *old_suffix, const char *new_suffix) 
     95{ 
     96    char *new_str, *sufx_ptr; 
     97    new_str = g_strndup (src_str, strlen (src_str) + strlen (new_suffix)); 
     98    sufx_ptr = g_strrstr (new_str, old_suffix); 
     99    if (sufx_ptr != NULL) 
     100    { 
     101        g_stpcpy (sufx_ptr, new_suffix); 
     102        return new_str; 
     103    } 
     104    else 
     105    { 
     106        g_free (new_str); 
     107        return NULL; 
     108    } 
     109} 
     110 
     111/* --------------------------------------------------------------------------------------------- */ 
     112/** 
     113 * Fills otherfile_vpath field with a detected and verified alternate (also called `other`) 
     114 * file path. In short, the other file is a header main.h when editing main.c and vice versa. 
     115 */ 
     116static gboolean 
     117edit_compute_other_file_vfs_path (WEdit * edit) 
     118{ 
     119    const char *headers[] = { ".h", ".hpp", NULL }; 
     120    const char *sources[] = { ".c", ".cpp", NULL }; 
     121    const char **exts[] = { headers, sources }; 
     122    vfs_path_t *fs_path, *avg_path; 
     123    int idx, oth_type = -1, ext_index; 
     124    file_suitable_rank_t existing_rank; 
     125 
     126    /* Try the already computed one if it exists in otherfile_vpath field */ 
     127    fs_path = edit->otherfile_vpath; 
     128    avg_path = fs_path; 
     129    edit->otherfile_vpath = NULL; 
     130 
     131    /* Is it only an average match or no match? If yes, try to find a better one */ 
     132    existing_rank = edit_check_file_suitable (fs_path); 
     133    if (existing_rank <= FILE_RANK_AVERAGE_SUITABLE && edit->filename_vpath != NULL) 
     134    { 
     135        for (idx = 0; idx <= 1; idx++) 
     136        { 
     137            if (vfs_path_has_extension (edit->filename_vpath, exts[idx])) 
     138            { 
     139                oth_type = 1 - idx; 
     140                break; 
     141            } 
     142        } 
     143        if (oth_type >= 0) 
     144            fs_path = edit->filename_vpath; 
     145    } 
     146    /* No extension matched, or using the previously, highly suited file */ 
     147    if (oth_type == -1) 
     148    { 
     149        edit->otherfile_vpath = avg_path; 
     150        return (existing_rank >= FILE_RANK_AVERAGE_SUITABLE); 
     151    } 
     152 
     153    for (ext_index = 0; exts[oth_type][ext_index] != NULL; ext_index++) 
     154    { 
     155        char *try_path; 
     156        vfs_path_t *cand_fs_path = NULL; 
     157        file_suitable_rank_t rank; 
     158 
     159        try_path = replace_suffix_with (vfs_path_as_str (fs_path), ".", exts[oth_type][ext_index]); 
     160 
     161        if (try_path == NULL) 
     162            continue; 
     163 
     164        cand_fs_path = vfs_path_from_str (try_path); 
     165        g_free (try_path); 
     166 
     167        if (cand_fs_path == NULL) 
     168            continue; 
     169 
     170        rank = edit_check_file_suitable (cand_fs_path); 
     171        if (rank < FILE_RANK_AVERAGE_SUITABLE) 
     172        { 
     173            vfs_path_free (cand_fs_path); 
     174            cand_fs_path = NULL; 
     175            continue; 
     176        } 
     177        else if (rank == FILE_RANK_AVERAGE_SUITABLE) 
     178        { 
     179            if (existing_rank < rank) 
     180            { 
     181                existing_rank = rank; 
     182                if (avg_path != NULL) 
     183                    vfs_path_free (avg_path); 
     184                avg_path = cand_fs_path; 
     185                cand_fs_path = NULL; 
     186            } 
     187            else 
     188            { 
     189                vfs_path_free (cand_fs_path); 
     190                cand_fs_path = NULL; 
     191            } 
     192        } 
     193        else if (rank >= FILE_RANK_SUITABLE) 
     194        { 
     195            if (avg_path != NULL) 
     196                vfs_path_free (avg_path); 
     197            edit->otherfile_vpath = cand_fs_path; 
     198            return TRUE; 
     199        } 
     200    } 
     201 
     202    /* Any side-saved average candidate? */ 
     203    if (avg_path != NULL) 
     204    { 
     205        edit->otherfile_vpath = avg_path; 
     206        return (existing_rank >= FILE_RANK_AVERAGE_SUITABLE); 
     207    } 
     208    return FALSE; 
     209} 
     210 
    91211/* --------------------------------------------------------------------------------------------- */ 
    92212/** 
    93213 * Init the 'edit' subsystem 
    edit_dialog_command_execute (WDialog * h, long command) 
    391511        edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0); 
    392512        break; 
    393513    case CK_EditFile: 
    394         edit_load_cmd (h); 
     514        edit_load_cmd (h, NULL); 
     515        break; 
     516    case CK_OtherFile: 
     517        { 
     518            WEdit *e = (WEdit *) g->current->data; 
     519            gboolean retval = FALSE; 
     520 
     521            if (e != NULL) 
     522            { 
     523                retval = edit_compute_other_file_vfs_path (e); 
     524                if (retval) 
     525                    retval = edit_switch_to_file (h, e->otherfile_vpath); 
     526            } 
     527            if (!retval) 
     528                ret = MSG_NOT_HANDLED; 
     529        } 
    395530        break; 
    396531    case CK_History: 
    397532        edit_load_file_from_history (h); 
    edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 
    11781313/* --------------------------------------------------------------------------------------------- */ 
    11791314/*** public functions ****************************************************************************/ 
    11801315/* --------------------------------------------------------------------------------------------- */ 
     1316 
     1317gboolean 
     1318edit_switch_to_file (WDialog * h, const vfs_path_t * file) 
     1319{ 
     1320    const WGroup *g = CONST_GROUP (h); 
     1321    GList *el; 
     1322    gboolean ret = FALSE; 
     1323 
     1324    for (el = g->widgets; el != NULL; el = g_list_next (el)) 
     1325    { 
     1326        if (edit_widget_is_editor (CONST_WIDGET (el->data))) 
     1327        { 
     1328            WEdit *e = (WEdit *) el->data; 
     1329            if (g_strcmp0 (edit_get_file_name (e), vfs_path_as_str (file)) == 0) 
     1330            { 
     1331                widget_select (WIDGET (e)); 
     1332                ret = TRUE; 
     1333                break; 
     1334            } 
     1335        } 
     1336    } 
     1337    if (!ret) 
     1338        ret = edit_load_cmd (h, vfs_path_as_str (file)); 
     1339    return ret; 
     1340} 
     1341 
     1342/* --------------------------------------------------------------------------------------------- */ 
     1343 
    11811344/** 
    11821345 * Edit one file. 
    11831346 * 
  • src/editor/editwidget.h

    diff --git a/src/editor/editwidget.h b/src/editor/editwidget.h
    index 446ef07ac..b4b10692e 100644
    a b struct WEdit 
    7272 
    7373    vfs_path_t *filename_vpath; /* Name of the file */ 
    7474    vfs_path_t *dir_vpath;      /* NULL if filename is absolute */ 
     75    vfs_path_t *otherfile_vpath;        /* Name of the `other` file (e.g.: header, with .h extension) */ 
    7576 
    7677    /* dynamic buffers and cursor position for editor: */ 
    7778    edit_buffer_t buffer; 
  • src/keybind-defaults.c

    diff --git a/src/keybind-defaults.c b/src/keybind-defaults.c
    index 7b87c2f5a..aa4eb5ec0 100644
    a b static const global_keymap_ini_t default_editor_keymap[] = { 
    393393    {"InsertOverwrite", "insert"}, 
    394394    {"Help", "f1"}, 
    395395    {"Save", "f2"}, 
     396    {"OtherFile", "alt-a"}, 
    396397    {"Mark", "f3"}, 
    397398    {"Replace", "f4"}, 
    398399    {"Copy", "f5"},