Ticket #4193: OtherFileConceptUpstr_v2.patch
File OtherFileConceptUpstr_v2.patch, 15.0 KB (added by psprint, 4 years ago) |
---|
-
lib/keybind.c
From 4acc6835387a1c9e5477ec5fc7949eb6a40d1d1b 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[] = { 277 277 ADD_KEYMAP_NAME (ParagraphUp), 278 278 ADD_KEYMAP_NAME (ParagraphDown), 279 279 ADD_KEYMAP_NAME (EditFile), 280 ADD_KEYMAP_NAME (OtherFile), 280 281 ADD_KEYMAP_NAME (MarkWord), 281 282 ADD_KEYMAP_NAME (MarkLine), 282 283 ADD_KEYMAP_NAME (MarkAll), -
lib/keybind.h
diff --git a/lib/keybind.h b/lib/keybind.h index af019df09..cd7192d06 100644
a b enum 246 246 CK_ParagraphDown, 247 247 /* file commands */ 248 248 CK_EditFile, 249 CK_OtherFile, 249 250 CK_InsertFile, 250 251 CK_EditSyntaxFile, 251 252 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) 593 593 /*** public functions ****************************************************************************/ 594 594 /* --------------------------------------------------------------------------------------------- */ 595 595 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 */ 600 gboolean 601 vfs_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 596 615 #define vfs_append_from_path(appendfrom, is_relative) \ 597 616 { \ 598 617 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 67 67 char *vfs_path_to_str_flags (const vfs_path_t * vpath, int elements_count, vfs_path_flag_t flags); 68 68 vfs_path_t *vfs_path_from_str (const char *path_str); 69 69 vfs_path_t *vfs_path_from_str_flags (const char *path_str, vfs_path_flag_t flags); 70 gboolean vfs_path_has_extension (const vfs_path_t * fs_path, const char *exts[]); 70 71 vfs_path_t *vfs_path_build_filename (const char *first_element, ...); 71 72 vfs_path_t *vfs_path_append_new (const vfs_path_t * vpath, const char *first_element, ...); 72 73 vfs_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 291 291 Save = f2 292 292 # EditFile = 293 293 EditNew = ctrl-n 294 OtherFile = alt-a 294 295 SaveAs = f12; ctrl-f2 295 296 # Close = 296 297 History = 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 290 290 # ParagraphDown = 291 291 Save = f2 292 292 # EditFile = 293 OtherFile = alt-a 293 294 SaveAs = f12; ctrl-f2 294 295 # Close = 295 296 History = 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 94 94 EDIT_DO_BACKUP 95 95 } edit_save_mode_t; 96 96 97 98 /* Describes how well a file suits for editing. Symlinks and empty files get average grade. */ 99 typedef 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 97 107 /*** structures declarations (and typedefs of structures)*****************************************/ 98 108 99 109 /* search/replace options */ … … WEdit *edit_init (WEdit * edit, int y, int x, int lines, int cols, 185 195 const vfs_path_t * filename_vpath, long line); 186 196 gboolean edit_clean (WEdit * edit); 187 197 gboolean edit_ok_to_exit (WEdit * edit); 188 gboolean edit_load_cmd (WDialog * h); 198 file_suitable_rank_t edit_check_file_suitable (const vfs_path_t * fs_path); 199 gboolean edit_load_cmd (WDialog * h, const void *data); 189 200 gboolean edit_load_file_from_history (WDialog * h); 190 201 gboolean edit_load_syntax_file (WDialog * h); 191 202 gboolean 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) 277 277 return i; 278 278 } 279 279 280 /* --------------------------------------------------------------------------------------------- */ 281 /** 282 * Gives a 3-level evaluation of how well given file is looking as a suitable input to the editor. 283 */ 284 file_suitable_rank_t 285 edit_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 280 305 /* --------------------------------------------------------------------------------------------- */ 281 306 /** 282 307 * Open file and create it if necessary. … … edit_init (WEdit * edit, int y, int x, int lines, int cols, const vfs_path_t * f 2108 2133 w->options |= WOP_SELECTABLE | WOP_TOP_SELECT | WOP_WANT_CURSOR; 2109 2134 w->keymap = editor_map; 2110 2135 w->ext_keymap = editor_x_map; 2136 edit->otherfile_vpath = NULL; 2111 2137 edit->fullscreen = TRUE; 2112 2138 edit_save_size (edit); 2113 2139 } … … edit_clean (WEdit * edit) 2204 2230 g_free (edit->redo_stack); 2205 2231 vfs_path_free (edit->filename_vpath); 2206 2232 vfs_path_free (edit->dir_vpath); 2233 vfs_path_free (edit->otherfile_vpath); 2207 2234 mc_search_free (edit->search); 2208 2235 g_free (edit->last_search_string); 2209 2236 -
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; 66 66 void edit_stack_init (void); 67 67 void edit_stack_free (void); 68 68 69 /* If file is open, switch to it, otherwise it is loaded */ 70 gboolean edit_switch_to_file (WDialog * h, const vfs_path_t * file); 69 71 gboolean edit_file (const vfs_path_t * file_vpath, long line); 70 72 gboolean edit_files (const GList * files); 71 73 -
src/editor/editcmd.c
diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c index 0d2caa923..fbfd8a66a 100644
a b edit_save_confirm_cmd (WEdit * edit) 2063 2063 */ 2064 2064 2065 2065 gboolean 2066 edit_load_cmd (WDialog * h )2066 edit_load_cmd (WDialog * h, const void *data) 2067 2067 { 2068 2068 char *exp; 2069 2069 gboolean ret = TRUE; /* possible cancel */ 2070 2070 2071 exp = input_expand_dialog (_("Load"), _("Enter file name:"), 2071 if (data != NULL) 2072 exp = g_strdup((char *) data); 2073 else 2074 exp = input_expand_dialog (_("Load"), _("Enter file name:"), 2072 2075 MC_HISTORY_EDIT_LOAD, INPUT_LAST_TEXT, 2073 2076 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD); 2074 2077 -
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; 88 88 static cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, 89 89 void *data); 90 90 91 /* --------------------------------------------------------------------------------------------- */ 92 93 static char * 94 replace_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 */ 116 static gboolean 117 edit_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 91 211 /* --------------------------------------------------------------------------------------------- */ 92 212 /** 93 213 * Init the 'edit' subsystem … … edit_dialog_command_execute (WDialog * h, long command) 391 511 edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0); 392 512 break; 393 513 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 } 395 530 break; 396 531 case CK_History: 397 532 edit_load_file_from_history (h); … … edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 1178 1313 /* --------------------------------------------------------------------------------------------- */ 1179 1314 /*** public functions ****************************************************************************/ 1180 1315 /* --------------------------------------------------------------------------------------------- */ 1316 1317 gboolean 1318 edit_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 1181 1344 /** 1182 1345 * Edit one file. 1183 1346 * -
src/editor/editwidget.h
diff --git a/src/editor/editwidget.h b/src/editor/editwidget.h index 446ef07ac..b4b10692e 100644
a b struct WEdit 72 72 73 73 vfs_path_t *filename_vpath; /* Name of the file */ 74 74 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) */ 75 76 76 77 /* dynamic buffers and cursor position for editor: */ 77 78 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[] = { 393 393 {"InsertOverwrite", "insert"}, 394 394 {"Help", "f1"}, 395 395 {"Save", "f2"}, 396 {"OtherFile", "alt-a"}, 396 397 {"Mark", "f3"}, 397 398 {"Replace", "f4"}, 398 399 {"Copy", "f5"},