Merge branch '267_code_navigation_via_etags'

This commit is contained in:
Ilia Maslakov 2009-03-11 18:25:45 +00:00
commit dc80d6821f
10 changed files with 512 additions and 5 deletions

View File

@ -10,6 +10,6 @@ libedit_a_SOURCES = \
bookmark.c edit.c editcmd.c editwidget.c editdraw.c editkeys.c \ bookmark.c edit.c editcmd.c editwidget.c editdraw.c editkeys.c \
editmenu.c editoptions.c editcmddef.h edit.h edit-widget.h \ editmenu.c editoptions.c editcmddef.h edit.h edit-widget.h \
editlock.c editlock.h syntax.c usermap.h usermap.c wordproc.c \ editlock.c editlock.h syntax.c usermap.h usermap.c wordproc.c \
choosesyntax.c choosesyntax.c etags.c etags.h
EXTRA_DIST = ChangeLog EXTRA_DIST = ChangeLog

View File

@ -646,6 +646,31 @@ edit_reload (WEdit *edit, const char *filename)
return 1; return 1;
} }
/*
* Load a new file into the editor and set line. If it fails, preserve the old file.
* To do it, allocate a new widget, initialize it and, if the new file
* was loaded, copy the data to the old widget.
* Return 1 on success, 0 on failure.
*/
int
edit_reload_line (WEdit *edit, const char *filename, long line)
{
WEdit *e;
int lines = edit->num_widget_lines;
int columns = edit->num_widget_columns;
e = g_malloc0 (sizeof (WEdit));
e->widget = edit->widget;
if (!edit_init (e, lines, columns, filename, line)) {
g_free (e);
return 0;
}
edit_clean (edit);
memcpy (edit, e, sizeof (WEdit));
g_free (e);
return 1;
}
/* /*
Recording stack for undo: Recording stack for undo:
@ -2480,6 +2505,13 @@ edit_execute_cmd (WEdit *edit, int command, int char_for_insertion)
edit_insert_file_cmd (edit); edit_insert_file_cmd (edit);
break; break;
case CK_Load_Prev_File:
edit_load_back_cmd (edit);
break;
case CK_Load_Next_File:
edit_load_forward_cmd (edit);
break;
case CK_Toggle_Syntax: case CK_Toggle_Syntax:
if ((option_syntax_highlighting ^= 1) == 1) if ((option_syntax_highlighting ^= 1) == 1)
edit_load_syntax (edit, NULL, option_syntax_type); edit_load_syntax (edit, NULL, option_syntax_type);
@ -2501,6 +2533,9 @@ edit_execute_cmd (WEdit *edit, int command, int char_for_insertion)
case CK_Complete_Word: case CK_Complete_Word:
edit_complete_word_cmd (edit); edit_complete_word_cmd (edit);
break; break;
case CK_Find_Definition:
edit_get_match_keyword_cmd (edit);
break;
case CK_Exit: case CK_Exit:
dlg_stop (edit->widget.parent); dlg_stop (edit->widget.parent);

View File

@ -103,6 +103,14 @@
#define TAB_SIZE option_tab_spacing #define TAB_SIZE option_tab_spacing
#define HALF_TAB_SIZE ((int) option_tab_spacing / 2) #define HALF_TAB_SIZE ((int) option_tab_spacing / 2)
/* max count stack files */
#define MAX_HISTORY_MOVETO 50
typedef struct edit_stack_type {
long line;
char *filename;
}edit_stack_type;
struct macro { struct macro {
short command; short command;
short ch; short ch;
@ -175,6 +183,8 @@ int edit_save_block (WEdit * edit, const char *filename, long start, long finish
int edit_save_block_cmd (WEdit * edit); int edit_save_block_cmd (WEdit * edit);
int edit_insert_file_cmd (WEdit * edit); int edit_insert_file_cmd (WEdit * edit);
int edit_insert_file (WEdit * edit, const char *filename); int edit_insert_file (WEdit * edit, const char *filename);
int edit_load_back_cmd (WEdit * edit);
int edit_load_forward_cmd (WEdit * edit);
void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block); void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block);
void freestrs (void); void freestrs (void);
void edit_refresh_cmd (WEdit * edit); void edit_refresh_cmd (WEdit * edit);

View File

@ -1,4 +1,4 @@
/* editor high level editing commands. /* editor high level editing commands
Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006, Copyright (C) 1996, 1997, 1998, 2001, 2002, 2003, 2004, 2005, 2006,
2007 Free Software Foundation, Inc. 2007 Free Software Foundation, Inc.
@ -45,6 +45,8 @@
#include "editlock.h" #include "editlock.h"
#include "editcmddef.h" #include "editcmddef.h"
#include "edit-widget.h" #include "edit-widget.h"
#include "../edit/etags.h"
#include "../src/panel.h"
#include "../src/color.h" /* dialog_colors */ #include "../src/color.h" /* dialog_colors */
#include "../src/tty.h" /* LINES */ #include "../src/tty.h" /* LINES */
@ -2795,6 +2797,7 @@ static void
edit_completion_dialog (WEdit * edit, int max_len, int word_len, edit_completion_dialog (WEdit * edit, int max_len, int word_len,
struct selection *compl, int num_compl) struct selection *compl, int num_compl)
{ {
int start_x, start_y, offset, i; int start_x, start_y, offset, i;
char *curr = NULL; char *curr = NULL;
Dlg_head *compl_dlg; Dlg_head *compl_dlg;
@ -2883,8 +2886,8 @@ edit_complete_word_cmd (WEdit *edit)
/* prepare match expression */ /* prepare match expression */
bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE] bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
[word_start & M_EDIT_BUF_SIZE]; [word_start & M_EDIT_BUF_SIZE];
match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos);
/* init search: backward, regexp, whole word, case sensitive */ /* init search: backward, regexp, whole word, case sensitive */
edit_set_search_parameters (0, 1, 1, 1, 1); edit_set_search_parameters (0, 1, 1, 1, 1);
@ -2969,3 +2972,220 @@ edit_begin_end_macro_cmd(WEdit *edit)
edit_execute_key_command (edit, command, -1); edit_execute_key_command (edit, command, -1);
} }
} }
int
edit_load_forward_cmd (WEdit *edit)
{
if (edit->modified) {
if (edit_query_dialog2
(_("Warning"),
_(" Current text was modified without a file save. \n"
" Continue discards these changes. "), _("C&ontinue"),
_("&Cancel"))) {
edit->force |= REDRAW_COMPLETELY;
return 0;
}
}
if ( edit_stack_iterator + 1 < MAX_HISTORY_MOVETO ) {
if ( edit_history_moveto[edit_stack_iterator + 1].line < 1 ) {
return 1;
}
edit_stack_iterator++;
if ( edit_history_moveto[edit_stack_iterator].filename ) {
edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
edit_history_moveto[edit_stack_iterator].line);
return 0;
} else {
return 1;
}
} else {
return 1;
}
}
int
edit_load_back_cmd (WEdit *edit)
{
if (edit->modified) {
if (edit_query_dialog2
(_("Warning"),
_(" Current text was modified without a file save. \n"
" Continue discards these changes. "), _("C&ontinue"),
_("&Cancel"))) {
edit->force |= REDRAW_COMPLETELY;
return 0;
}
}
if ( edit_stack_iterator > 0 ) {
edit_stack_iterator--;
if ( edit_history_moveto[edit_stack_iterator].filename ) {
edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
edit_history_moveto[edit_stack_iterator].line);
return 0;
} else {
return 1;
}
} else {
return 1;
}
}
/* let the user select where function definition */
static void
edit_select_definition_dialog (WEdit * edit, char *match_expr, int max_len, int word_len,
etags_hash_t *def_hash, int num_lines)
{
int start_x, start_y, offset, i;
char *curr = NULL;
etags_hash_t *curr_def;
Dlg_head *def_dlg;
WListbox *def_list;
int def_dlg_h; /* dialog height */
int def_dlg_w; /* dialog width */
/* calculate the dialog metrics */
def_dlg_h = num_lines + 2;
def_dlg_w = max_len + 4;
start_x = edit->curs_col + edit->start_col - (def_dlg_w / 2);
start_y = edit->curs_row + EDIT_TEXT_VERTICAL_OFFSET + 1;
if (start_x < 0)
start_x = 0;
if (def_dlg_w > COLS)
def_dlg_w = COLS;
if (def_dlg_h > LINES - 2)
def_dlg_h = LINES - 2;
offset = start_x + def_dlg_w - COLS;
if (offset > 0)
start_x -= offset;
offset = start_y + def_dlg_h - LINES;
if (offset > 0)
start_y -= (offset + 1);
/* create the dialog */
def_dlg = create_dlg (start_y, start_x, def_dlg_h, def_dlg_w,
dialog_colors, NULL, "[Definitions]", match_expr,
DLG_COMPACT);
/* create the listbox */
def_list = listbox_new (1, 1, def_dlg_w - 2, def_dlg_h - 2, NULL);
/* add the dialog */
add_widget (def_dlg, def_list);
char *label_def = NULL;
/* fill the listbox with the completions */
for (i = 0; i < num_lines; i++) {
label_def = g_strdup_printf ("%s -> %s:%ld", def_hash[i].short_define, def_hash[i].filename, def_hash[i].line);
listbox_add_item (def_list, LISTBOX_APPEND_AT_END, 0, label_def, &def_hash[i]);
g_free(label_def);
}
/* pop up the dialog */
run_dlg (def_dlg);
/* apply the choosen completion */
if ( def_dlg->ret_value == B_ENTER ) {
listbox_get_current (def_list, &curr, (etags_hash_t *) &curr_def);
int do_moveto = 0;
if ( edit->modified ) {
if ( !edit_query_dialog2
(_("Warning"),
_(" Current text was modified without a file save. \n"
" Continue discards these changes. "), _("C&ontinue"),
_("&Cancel"))) {
edit->force |= REDRAW_COMPLETELY;
do_moveto = 1;
}
} else {
do_moveto = 1;
}
if ( curr && do_moveto) {
if ( edit_stack_iterator+1 < MAX_HISTORY_MOVETO ) {
g_free (edit_history_moveto[edit_stack_iterator].filename);
if ( edit->dir ) {
edit_history_moveto[edit_stack_iterator].filename = g_strdup_printf ("%s/%s", edit->dir, edit->filename);
} else {
edit_history_moveto[edit_stack_iterator].filename = g_strdup (edit->filename);
}
edit_history_moveto[edit_stack_iterator].line = edit->start_line +
edit->curs_row + 1;
edit_stack_iterator++;
g_free( edit_history_moveto[edit_stack_iterator].filename );
edit_history_moveto[edit_stack_iterator].filename = g_strdup(curr_def->fullpath);
edit_history_moveto[edit_stack_iterator].line = curr_def->line;
edit_reload_line (edit, edit_history_moveto[edit_stack_iterator].filename,
edit_history_moveto[edit_stack_iterator].line);
}
}
}
/* clear definition hash */
for ( int i = 0; i < MAX_DEFINITIONS; i++) {
g_free(def_hash[i].filename);
}
/* destroy dialog before return */
destroy_dlg (def_dlg);
}
void
edit_get_match_keyword_cmd (WEdit *edit)
{
int word_len = 0;
int num_def = 0;
int max_len = 0;
long word_start = 0;
unsigned char *bufpos;
char *match_expr;
char *path = NULL;
char *ptr = NULL;
char *tagfile = NULL;
etags_hash_t def_hash[MAX_DEFINITIONS];
for ( int i = 0; i < MAX_DEFINITIONS; i++) {
def_hash[i].filename = NULL;
}
/* search start of word to be completed */
if (!edit_find_word_start (edit, &word_start, &word_len))
return;
/* prepare match expression */
bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE]
[word_start & M_EDIT_BUF_SIZE];
match_expr = g_strdup_printf ("%.*s", word_len, bufpos);
ptr = g_get_current_dir ();
path = g_strconcat (ptr, G_DIR_SEPARATOR_S, (char *) NULL);
g_free (ptr);
/* Recursive search file 'TAGS' in parent dirs */
do {
ptr = g_path_get_dirname (path);
g_free(path); path = ptr;
g_free (tagfile);
tagfile = g_build_filename (path, TAGS_NAME, (char *) NULL);
if ( exist_file (tagfile) )
break;
} while (strcmp( path, G_DIR_SEPARATOR_S) != 0);
if (tagfile){
num_def = etags_set_definition_hash(tagfile, path, match_expr, (etags_hash_t *) &def_hash);
g_free (tagfile);
}
g_free (path);
max_len = MAX_WIDTH_DEF_DIALOG;
word_len = 0;
if ( num_def > 0 ) {
edit_select_definition_dialog (edit, match_expr, max_len, word_len,
(etags_hash_t *) &def_hash,
num_def);
}
g_free (match_expr);
}

View File

@ -42,6 +42,8 @@
#define CK_Load 102 #define CK_Load 102
#define CK_New 103 #define CK_New 103
#define CK_Save_As 104 #define CK_Save_As 104
#define CK_Load_Prev_File 111
#define CK_Load_Next_File 112
/* block commands */ /* block commands */
#define CK_Mark 201 #define CK_Mark 201
@ -96,8 +98,9 @@
#define CK_Terminal 422 #define CK_Terminal 422
#define CK_Terminal_App 423 #define CK_Terminal_App 423
#define CK_ExtCmd 424 #define CK_ExtCmd 424
#define CK_User_Menu 425 #define CK_User_Menu 425
#define CK_Find_Definition 426
/* application control */ /* application control */
#define CK_Save_Desktop 451 #define CK_Save_Desktop 451
#define CK_New_Window 452 #define CK_New_Window 452

View File

@ -99,7 +99,7 @@ static const edit_key_map_type common_key_map[] = {
{ KEY_RIGHT, CK_Right }, { KEY_RIGHT, CK_Right },
{ KEY_UP, CK_Up }, { KEY_UP, CK_Up },
{ ALT ('\n'), CK_Return }, { ALT ('\n'), CK_Find_Definition },
{ ALT ('\t'), CK_Complete_Word }, { ALT ('\t'), CK_Complete_Word },
{ ALT ('l'), CK_Goto }, { ALT ('l'), CK_Goto },
{ ALT ('L'), CK_Goto }, { ALT ('L'), CK_Goto },
@ -108,6 +108,8 @@ static const edit_key_map_type common_key_map[] = {
{ ALT ('u'), CK_ExtCmd }, { ALT ('u'), CK_ExtCmd },
{ ALT ('<'), CK_Beginning_Of_Text }, { ALT ('<'), CK_Beginning_Of_Text },
{ ALT ('>'), CK_End_Of_Text }, { ALT ('>'), CK_End_Of_Text },
{ ALT ('-'), CK_Load_Prev_File },
{ ALT ('='), CK_Load_Next_File },
{ ALT (KEY_BACKSPACE), CK_Delete_Word_Left }, { ALT (KEY_BACKSPACE), CK_Delete_Word_Left },
{ XCTRL ('k'), CK_Delete_To_Line_End }, { XCTRL ('k'), CK_Delete_To_Line_End },

185
edit/etags.c Normal file
View File

@ -0,0 +1,185 @@
/* editor C-code navigation via tags.
make TAGS file via command:
$ find . -type f -name "*.[ch]" | etags -l c --declarations -
or, if etags utility not installed:
$ find . -type f -name "*.[ch]" | ctags --c-kinds=+p --fields=+iaS --extra=+q -e -L-
Copyright (C) 2009 Free Software Foundation, Inc.
Authors:
Ilia Maslakov <il.smind@gmail.com>, 2009
Slava Zanko <slavazanko@gmail.com>, 2009
This file is part of the Midnight Commander.
The Midnight Commander is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The Midnight Commander is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <ctype.h>
#include "../src/global.h"
#include "../src/util.h" /* canonicalize_pathname() */
#include "../edit/etags.h"
/*** file scope functions **********************************************/
static gboolean parse_define(char *buf, char **long_name, char **short_name, long *line)
{
enum {in_longname, in_shortname, in_line, finish} def_state = in_longname;
static char longdef[LONG_DEF_LEN];
static char shortdef[SHORT_DEF_LEN];
static char linedef[LINE_DEF_LEN];
int nlong = 0;
int nshort = 0;
int nline = 0;
char c = *buf;
while ( !(c =='\0' || c =='\n') ) {
switch ( def_state ) {
case in_longname:
if ( c == 0x01 ) {
def_state = in_line;
} else if ( c == 0x7F ) {
def_state = in_shortname;
} else {
if ( nlong < LONG_DEF_LEN - 1 ) {
longdef[nlong++] = c;
}
}
break;
case in_shortname:
if ( isdigit(c) ) {
nshort = 0;
buf--;
def_state = in_line;
} else if ( c == 0x01 ) {
def_state = in_line;
} else {
if ( nshort < SHORT_DEF_LEN - 1 ) {
shortdef[nshort++] = c;
}
}
break;
case in_line:
if ( c == ',' ) {
def_state = finish;
} else if ( isdigit(c) ) {
if ( nline < LINE_DEF_LEN - 1 ) {
linedef[nline++] = c;
}
}
break;
case finish:
longdef[nlong] = '\0';
shortdef[nshort] = '\0';
linedef[nline] = '\0';
*long_name = g_strdup (longdef);
*short_name = g_strdup (shortdef);
*line = atol (linedef);
return TRUE;
break;
}
buf++;
c = *buf;
}
*long_name = NULL;
*short_name = NULL;
*line = 0;
return FALSE;
}
/*** public functions **************************************************/
int etags_set_definition_hash(const char *tagfile, const char *start_path,
const char *match_func,
etags_hash_t *def_hash)
{
FILE *f;
static char buf[BUF_LARGE];
char *longname = NULL;
char *shortname = NULL;
long line;
char *chekedstr = NULL;
int num = 0; /* returned value */
/* open file with positions */
f = fopen (tagfile, "r");
if (!f)
return 0;
int pos;
char *filename = NULL;
enum {start, in_filename, in_define} state = start;
while (fgets (buf, sizeof (buf), f)) {
switch ( state ) {
case start:
if ( buf[0] == 0x0C ) {
state = in_filename;
}
break;
case in_filename:
pos = strcspn(buf, ",");
g_free(filename);
filename = g_malloc (pos + 2);
g_strlcpy(filename, (char *)buf, pos + 1);
state = in_define;
break;
case in_define:
if ( buf[0] == 0x0C ) {
state = in_filename;
break;
}
/* check if the filename matches the define pos */
chekedstr = strstr (buf, match_func);
if ( chekedstr ) {
parse_define (chekedstr, &longname, &shortname, &line);
if ( num < MAX_DEFINITIONS - 1 ) {
def_hash[num].filename_len = strlen (filename);
def_hash[num].fullpath = g_build_filename (start_path, filename, (char *) NULL);
canonicalize_pathname (def_hash[num].fullpath);
def_hash[num].filename = g_strdup (filename);
if ( shortname ) {
def_hash[num].short_define = g_strdup (shortname);
} else {
def_hash[num].short_define = g_strdup (longname);
}
def_hash[num].line = line;
g_free(shortname);
g_free(longname);
num++;
}
}
break;
}
}
g_free(filename);
return num;
}

25
edit/etags.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef MC_EDIT_ETAGS_H
#define MC_EDIT_ETAGS_H 1
#include <sys/types.h> /* size_t */
#include "../src/global.h" /* include <glib.h> */
#define MAX_WIDTH_DEF_DIALOG 60 /* max width def dialog */
#define MAX_DEFINITIONS 60 /* count found entries show */
#define SHORT_DEF_LEN 30
#define LONG_DEF_LEN 40
#define LINE_DEF_LEN 16
#define TAGS_NAME "TAGS"
typedef struct etags_hash_struct {
size_t filename_len;
unsigned char *fullpath;
unsigned char *filename;
unsigned char *short_define;
long line;
} etags_hash_t;
int etags_set_definition_hash (const char *tagfile, const char *start_path,
const char *match_func, etags_hash_t *def_hash);
#endif /* MC_EDIT_ETAGS_H */

View File

@ -279,6 +279,11 @@ char *mc_home = NULL;
char cmd_buf[512]; char cmd_buf[512];
#ifdef USE_INTERNAL_EDIT
int edit_stack_iterator = 0;
struct edit_stack_type edit_history_moveto[MAX_HISTORY_MOVETO];
#endif
static void static void
reload_panelized (WPanel *panel) reload_panelized (WPanel *panel)
{ {
@ -2135,6 +2140,13 @@ main (int argc, char *argv[])
vfs_init (); vfs_init ();
#ifdef USE_INTERNAL_EDIT
for ( int i = 0; i < MAX_HISTORY_MOVETO; i++ ) {
edit_history_moveto[i].filename = NULL;
edit_history_moveto[i].line = -1;
}
#endif
#ifdef HAVE_SLANG #ifdef HAVE_SLANG
SLtt_Ignore_Beep = 1; SLtt_Ignore_Beep = 1;
#endif #endif
@ -2255,5 +2267,11 @@ main (int argc, char *argv[])
g_free (this_dir); g_free (this_dir);
g_free (other_dir); g_free (other_dir);
#ifdef USE_INTERNAL_EDIT
for ( int i = 0; i < MAX_HISTORY_MOVETO; i++ ) {
g_free(edit_history_moveto[i].filename);
}
#endif
return 0; return 0;
} }

View File

@ -5,6 +5,10 @@
#include "panel.h" #include "panel.h"
#include "widget.h" #include "widget.h"
#ifdef USE_INTERNAL_EDIT
#include "../edit/edit.h"
#endif
/* Toggling functions */ /* Toggling functions */
void toggle_fast_reload (void); void toggle_fast_reload (void);
void toggle_mix_all_files (void); void toggle_mix_all_files (void);
@ -38,6 +42,11 @@ extern int mou_auto_repeat;
extern char *other_dir; extern char *other_dir;
extern int mouse_move_pages; extern int mouse_move_pages;
#ifdef USE_INTERNAL_EDIT
extern int edit_stack_iterator;
struct edit_stack_type edit_history_moveto[MAX_HISTORY_MOVETO];
#endif
#ifdef HAVE_CHARSET #ifdef HAVE_CHARSET
extern int source_codepage; extern int source_codepage;
extern int display_codepage; extern int display_codepage;