Open several files in mc editor from command line.

Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
This commit is contained in:
Andrew Borodin 2012-01-07 13:35:01 +03:00
parent 109f07465e
commit 84aa04fa6e
7 changed files with 239 additions and 113 deletions

View File

@ -1,11 +1,12 @@
/* /*
Handle command line arguments. Handle command line arguments.
Copyright (C) 2009, 2011 Copyright (C) 2009, 2010, 2011, 2012
The Free Software Foundation, Inc. The Free Software Foundation, Inc.
Written by: Written by:
Slava Zanko <slavazanko@gmail.com>, 2009. Slava Zanko <slavazanko@gmail.com>, 2009.
Andrew Borodin <aborodin@vmail.ru>, 2011, 2012.
This file is part of the Midnight Commander. This file is part of the Midnight Commander.
@ -60,9 +61,6 @@ gboolean mc_args__force_colors = FALSE;
/* Don't load keymap form file and use default one */ /* Don't load keymap form file and use default one */
gboolean mc_args__nokeymap = FALSE; gboolean mc_args__nokeymap = FALSE;
/* Line to start the editor on */
int mc_args__edit_start_line = 0;
char *mc_args__last_wd_file = NULL; char *mc_args__last_wd_file = NULL;
/* when enabled NETCODE, use folowing file as logfile */ /* when enabled NETCODE, use folowing file as logfile */
@ -179,10 +177,10 @@ static const GOptionEntry argument_main_table[] = {
}, },
{ {
"edit", 'e', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, "edit", 'e', G_OPTION_FLAG_IN_MAIN | G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
parse_mc_e_argument, parse_mc_e_argument,
N_("Edits one file"), N_("Edit files"),
"<file>"}, "<file> ..." },
{ {
NULL, '\0', 0, 0, NULL, NULL, NULL /* Complete struct initialization */ NULL, '\0', 0, 0, NULL, NULL, NULL /* Complete struct initialization */
@ -443,11 +441,11 @@ static gboolean
parse_mc_e_argument (const gchar * option_name, const gchar * value, gpointer data, GError ** error) parse_mc_e_argument (const gchar * option_name, const gchar * value, gpointer data, GError ** error)
{ {
(void) option_name; (void) option_name;
(void) value;
(void) data; (void) data;
(void) error; (void) error;
mc_global.mc_run_mode = MC_RUN_EDITOR; mc_global.mc_run_mode = MC_RUN_EDITOR;
mc_run_param0 = g_strdup (value);
return TRUE; return TRUE;
} }
@ -467,6 +465,113 @@ parse_mc_v_argument (const gchar * option_name, const gchar * value, gpointer da
return TRUE; return TRUE;
} }
/* --------------------------------------------------------------------------------------------- */
/**
* Get list of filenames (and line numbers) from command line, when mc called as editor
*
* @param argc count of all arguments
* @param argv array of strings, contains arguments
* @return list of mcedit_arg_t objects
*/
static GList *
parse_mcedit_arguments (int argc, char **argv)
{
GList *flist = NULL;
int i;
int first_line_number = -1;
for (i = 0; i < argc; i++)
{
char *tmp;
char *end, *p;
mcedit_arg_t *arg;
tmp = argv[i];
/*
* First, try to get line number as +lineno.
*/
if (*tmp == '+')
{
long lineno;
char *error;
lineno = strtol (tmp + 1, &error, 10);
if (*error == '\0')
{
/* this is line number */
first_line_number = (int) lineno;
continue;
}
/* this is file name */
}
/*
* Check for filename:lineno, followed by an optional colon.
* This format is used by many programs (especially compilers)
* in error messages and warnings. It is supported so that
* users can quickly copy and paste file locations.
*/
end = tmp + strlen (tmp);
p = end;
if (p > tmp && p[-1] == ':')
p--;
while (p > tmp && g_ascii_isdigit ((gchar) p[-1]))
p--;
if (tmp < p && p < end && p[-1] == ':')
{
char *fname;
vfs_path_t *tmp_vpath, *fname_vpath;
struct stat st;
fname = g_strndup (tmp, p - 1 - tmp);
tmp_vpath = vfs_path_from_str (tmp);
fname_vpath = vfs_path_from_str (fname);
/*
* Check that the file before the colon actually exists.
* If it doesn't exist, create new file.
*/
if (mc_stat (tmp_vpath, &st) == -1 && mc_stat (fname_vpath, &st) != -1)
{
arg = mcedit_arg_vpath_new (fname_vpath, atoi (p));
vfs_path_free (tmp_vpath);
}
else
{
arg = mcedit_arg_vpath_new (tmp_vpath, 1);
vfs_path_free (fname_vpath);
}
g_free (fname);
}
else
arg = mcedit_arg_new (tmp, 1);
flist = g_list_prepend (flist, arg);
}
if (flist == NULL)
flist = g_list_prepend (flist, mcedit_arg_new (NULL, 1));
else if (first_line_number != -1)
{
/* overwrite line number for first file */
GList *l;
if (first_line_number == 0)
first_line_number = 1;
l = g_list_last (flist);
((mcedit_arg_t *) l->data)->line_number = first_line_number;
}
return flist;
}
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/ /*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */
@ -633,84 +738,7 @@ mc_setup_by_args (int argc, char **argv, GError ** error)
{ {
/* mce* or vi is link to mc */ /* mce* or vi is link to mc */
mc_run_param0 = g_strdup (""); mc_run_param0 = parse_mcedit_arguments (argc - 1, &argv[1]);
if (tmp != NULL)
{
/*
* Check for filename:lineno, followed by an optional colon.
* This format is used by many programs (especially compilers)
* in error messages and warnings. It is supported so that
* users can quickly copy and paste file locations.
*/
char *end, *p;
end = tmp + strlen (tmp);
p = end;
if (p > tmp && p[-1] == ':')
p--;
while (p > tmp && g_ascii_isdigit ((gchar) p[-1]))
p--;
if (tmp < p && p < end && p[-1] == ':')
{
char *fname;
struct stat st;
vfs_path_t *tmp_vpath, *fname_vpath;
gboolean ok;
fname = g_strndup (tmp, p - 1 - tmp);
tmp_vpath = vfs_path_from_str (tmp);
fname_vpath = vfs_path_from_str (fname);
/*
* Check that the file before the colon actually exists.
* If it doesn't exist, revert to the old behavior.
*/
ok = mc_stat (tmp_vpath, &st) == -1 && mc_stat (fname_vpath, &st) != -1;
vfs_path_free (tmp_vpath);
vfs_path_free (fname_vpath);
if (ok)
{
mc_run_param0 = fname;
mc_args__edit_start_line = atoi (p);
}
else
{
g_free (fname);
goto try_plus_filename;
}
}
else
{
try_plus_filename:
if (*tmp == '+' && g_ascii_isdigit ((gchar) tmp[1]))
{
int start_line;
start_line = atoi (tmp);
/*
* If start_line is zero, position the cursor at the
* beginning of the file as other editors (vi, nano)
*/
if (start_line == 0)
start_line++;
if (start_line > 0)
{
char *file;
file = (argc > 1) ? argv[2] : NULL;
if (file != NULL)
{
tmp = file;
mc_args__edit_start_line = start_line;
}
}
}
mc_run_param0 = g_strdup (tmp);
}
}
mc_global.mc_run_mode = MC_RUN_EDITOR; mc_global.mc_run_mode = MC_RUN_EDITOR;
} }
else if (strncmp (base, "mcv", 3) == 0 || strcmp (base, "view") == 0) else if (strncmp (base, "mcv", 3) == 0 || strcmp (base, "view") == 0)
@ -755,8 +783,11 @@ mc_setup_by_args (int argc, char **argv, GError ** error)
switch (mc_global.mc_run_mode) switch (mc_global.mc_run_mode)
{ {
case MC_RUN_EDITOR: case MC_RUN_EDITOR:
mc_run_param0 = parse_mcedit_arguments (argc - 1, &argv[1]);
break;
case MC_RUN_VIEWER: case MC_RUN_VIEWER:
/* mc_run_param0 is set up in parse_mc_e_argument() and parse_mc_v_argument() */ /* mc_run_param0 is set up in parse_mc_v_argument() */
break; break;
case MC_RUN_DIFFVIEWER: case MC_RUN_DIFFVIEWER:
@ -782,3 +813,55 @@ mc_setup_by_args (int argc, char **argv, GError ** error)
} }
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */
/**
* Create mcedit_arg_t object from file name and the line number.
*
* @param file_name file name
* @param line_number line number
* @return mcedit_arg_t object
*/
mcedit_arg_t *
mcedit_arg_new (const char *file_name, int line_number)
{
return mcedit_arg_vpath_new (vfs_path_from_str (file_name), line_number);
}
/* --------------------------------------------------------------------------------------------- */
/**
* Create mcedit_arg_t object from vfs_path_t object and the line number.
*
* @param file_vpath file path object
* @param line_number line number
* @return mcedit_arg_t object
*/
mcedit_arg_t *
mcedit_arg_vpath_new (vfs_path_t * file_vpath, int line_number)
{
mcedit_arg_t *arg;
arg = g_new (mcedit_arg_t, 1);
arg->file_vpath = file_vpath;
if (line_number == 0)
line_number = 1;
arg->line_number = line_number;
return arg;
}
/* --------------------------------------------------------------------------------------------- */
/**
* Free the mcedit_arg_t object.
*
* @param arg mcedit_arg_t object
*/
void
mcedit_arg_free (mcedit_arg_t * arg)
{
vfs_path_free (arg->file_vpath);
g_free (arg);
}
/* --------------------------------------------------------------------------------------------- */

View File

@ -2,6 +2,7 @@
#define MC__ARGS_H #define MC__ARGS_H
#include "lib/global.h" /* gboolean */ #include "lib/global.h" /* gboolean */
#include "lib/vfs/vfs.h" /* vfs_path_t */
/*** typedefs(not structures) and defined constants **********************************************/ /*** typedefs(not structures) and defined constants **********************************************/
@ -9,13 +10,18 @@
/*** structures declarations (and typedefs of structures)*****************************************/ /*** structures declarations (and typedefs of structures)*****************************************/
typedef struct
{
vfs_path_t *file_vpath;
int line_number;
} mcedit_arg_t;
/*** global variables defined in .c file *********************************************************/ /*** global variables defined in .c file *********************************************************/
extern gboolean mc_args__force_xterm; extern gboolean mc_args__force_xterm;
extern gboolean mc_args__nomouse; extern gboolean mc_args__nomouse;
extern gboolean mc_args__force_colors; extern gboolean mc_args__force_colors;
extern gboolean mc_args__nokeymap; extern gboolean mc_args__nokeymap;
extern int mc_args__edit_start_line;
extern char *mc_args__last_wd_file; extern char *mc_args__last_wd_file;
extern char *mc_args__netfs_logfile; extern char *mc_args__netfs_logfile;
extern char *mc_args__keymap_file; extern char *mc_args__keymap_file;
@ -27,5 +33,10 @@ gboolean mc_args_parse (int *argc, char ***argv, const char *translation_domain,
gboolean mc_args_show_info (void); gboolean mc_args_show_info (void);
gboolean mc_setup_by_args (int argc, char **argv, GError ** error); gboolean mc_setup_by_args (int argc, char **argv, GError ** error);
mcedit_arg_t *mcedit_arg_new (const char *file_name, int line_number);
mcedit_arg_t *mcedit_arg_vpath_new (vfs_path_t * file_vpath, int line_number);
void mcedit_arg_free (mcedit_arg_t * arg);
/*** inline functions ****************************************************************************/ /*** inline functions ****************************************************************************/
#endif /* MC__ARGS_H */ #endif /* MC__ARGS_H */

View File

@ -61,7 +61,8 @@ extern int show_right_margin;
void edit_stack_init (void); void edit_stack_init (void);
void edit_stack_free (void); void edit_stack_free (void);
gboolean edit_file (const vfs_path_t * _file_vpath, int line); gboolean edit_file (const vfs_path_t * file_vpath, int line);
gboolean edit_files (const GList * files);
char *edit_get_file_name (const WEdit * edit); char *edit_get_file_name (const WEdit * edit);
int edit_get_curs_col (const WEdit * edit); int edit_get_curs_col (const WEdit * edit);

View File

@ -59,6 +59,7 @@
#include "src/main.h" /* home_dir */ #include "src/main.h" /* home_dir */
#include "src/filemanager/cmd.h" /* view_other_cmd(), save_setup_cmd() */ #include "src/filemanager/cmd.h" /* view_other_cmd(), save_setup_cmd() */
#include "src/learn.h" /* learn_keys() */ #include "src/learn.h" /* learn_keys() */
#include "src/args.h" /* mcedit_arg_t */
#include "edit-impl.h" #include "edit-impl.h"
#include "editwidget.h" #include "editwidget.h"
@ -1013,14 +1014,37 @@ edit_callback (Widget * w, widget_msg_t msg, int parm)
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */
/*** public functions ****************************************************************************/ /*** public functions ****************************************************************************/
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */
/**
* Edit one file.
*
* @param file_vpath file object
* @param line line number
* @return TRUE if no errors was occured, FALSE otherwise
*/
gboolean gboolean
edit_file (const vfs_path_t * _file_vpath, int line) edit_file (const vfs_path_t * file_vpath, int line)
{
mcedit_arg_t arg = { (vfs_path_t *) file_vpath, line };
GList *files;
gboolean ok;
files = g_list_prepend (NULL, &arg);
ok = edit_files (files);
g_list_free (files);
return ok;
}
/* --------------------------------------------------------------------------------------------- */
gboolean
edit_files (const GList *files)
{ {
static gboolean made_directory = FALSE; static gboolean made_directory = FALSE;
Dlg_head *edit_dlg; Dlg_head *edit_dlg;
WMenuBar *menubar; WMenuBar *menubar;
gboolean ok; const GList *file;
gboolean ok = FALSE;
if (!made_directory) if (!made_directory)
{ {
@ -1053,8 +1077,17 @@ edit_file (const vfs_path_t * _file_vpath, int line)
add_widget (edit_dlg, buttonbar_new (TRUE)); add_widget (edit_dlg, buttonbar_new (TRUE));
ok = edit_add_window (edit_dlg, edit_dlg->y + 1, edit_dlg->x, for (file = files; file != NULL; file = g_list_next (file))
edit_dlg->lines - 2, edit_dlg->cols, _file_vpath, line); {
mcedit_arg_t *f = (mcedit_arg_t *) file->data;
gboolean f_ok;
f_ok = edit_add_window (edit_dlg, edit_dlg->y + 1, edit_dlg->x,
edit_dlg->lines - 2, edit_dlg->cols,
f->file_vpath, f->line_number);
/* at least one file has been opened succefully */
ok = ok || f_ok;
}
if (ok) if (ok)
run_dlg (edit_dlg); run_dlg (edit_dlg);

View File

@ -580,7 +580,7 @@ create_panels (void)
current_mode = startup_left_mode; current_mode = startup_left_mode;
other_mode = startup_right_mode; other_mode = startup_right_mode;
/* if mc_run_param0 is NULL, working directory will be used for the left panel */ /* if mc_run_param0 is NULL, working directory will be used for the left panel */
current_dir = mc_run_param0; current_dir = (char *) mc_run_param0;
/* mc_run_param1 is never NULL. It is setup from command line or from panels.ini /* mc_run_param1 is never NULL. It is setup from command line or from panels.ini
* (value of other_dir). mc_run_param1 will be used for the right panel */ * (value of other_dir). mc_run_param1 will be used for the right panel */
other_dir = mc_run_param1; other_dir = mc_run_param1;
@ -600,7 +600,7 @@ create_panels (void)
if (mc_run_param0 != NULL) if (mc_run_param0 != NULL)
{ {
current_dir = NULL; current_dir = NULL;
other_dir = mc_run_param0; other_dir = (char *) mc_run_param0;
} }
else else
{ {
@ -973,29 +973,21 @@ prepend_cwd_on_local (const char *filename)
static gboolean static gboolean
mc_maybe_editor_or_viewer (void) mc_maybe_editor_or_viewer (void)
{ {
int ret; gboolean ret;
switch (mc_global.mc_run_mode) switch (mc_global.mc_run_mode)
{ {
#ifdef USE_INTERNAL_EDIT #ifdef USE_INTERNAL_EDIT
case MC_RUN_EDITOR: case MC_RUN_EDITOR:
{ ret = edit_files ((GList *) mc_run_param0);
vfs_path_t *vpath = NULL;
if (mc_run_param0 != NULL && *mc_run_param0 != '\0')
vpath = vfs_path_from_str (mc_run_param0);
ret = edit_file (vpath, mc_args__edit_start_line);
vfs_path_free (vpath);
}
break; break;
#endif /* USE_INTERNAL_EDIT */ #endif /* USE_INTERNAL_EDIT */
case MC_RUN_VIEWER: case MC_RUN_VIEWER:
{ {
vfs_path_t *vpath = NULL; vfs_path_t *vpath = NULL;
if (mc_run_param0 != NULL && *mc_run_param0 != '\0') if (mc_run_param0 != NULL && *(char *) mc_run_param0 != '\0')
vpath = prepend_cwd_on_local (mc_run_param0); vpath = prepend_cwd_on_local ((char *) mc_run_param0);
ret = view_file (vpath, 0, 1); ret = view_file (vpath, 0, 1);
vfs_path_free (vpath); vfs_path_free (vpath);
@ -1007,10 +999,10 @@ mc_maybe_editor_or_viewer (void)
break; break;
#endif /* USE_DIFF_VIEW */ #endif /* USE_DIFF_VIEW */
default: default:
ret = 0; ret = FALSE;
} }
return (ret != 0); return ret;
} }
/* --------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------- */

View File

@ -96,7 +96,7 @@ int use_internal_view = 1;
/* If set, use the builtin editor */ /* If set, use the builtin editor */
int use_internal_edit = 1; int use_internal_edit = 1;
char *mc_run_param0 = NULL; void *mc_run_param0 = NULL;
char *mc_run_param1 = NULL; char *mc_run_param1 = NULL;
/* The user's shell */ /* The user's shell */
@ -630,7 +630,13 @@ main (int argc, char *argv[])
str_uninit_strings (); str_uninit_strings ();
g_free (mc_run_param0); if (mc_global.mc_run_mode != MC_RUN_EDITOR)
g_free (mc_run_param0);
else
{
g_list_foreach ((GList *) mc_run_param0, (GFunc) mcedit_arg_free, NULL);
g_list_free ((GList *) mc_run_param0);
}
g_free (mc_run_param1); g_free (mc_run_param1);
mc_config_deinit_config_paths (); mc_config_deinit_config_paths ();

View File

@ -42,11 +42,11 @@ struct mc_fhl_struct;
/* /*
* MC_RUN_FULL: dir for left panel * MC_RUN_FULL: dir for left panel
* MC_RUN_EDITOR: file to edit * MC_RUN_EDITOR: list of files to edit
* MC_RUN_VIEWER: file to view * MC_RUN_VIEWER: file to view
* MC_RUN_DIFFVIEWER: first file to compare * MC_RUN_DIFFVIEWER: first file to compare
*/ */
extern char *mc_run_param0; extern void *mc_run_param0;
/* /*
* MC_RUN_FULL: dir for right panel * MC_RUN_FULL: dir for right panel
* MC_RUN_EDITOR: unused * MC_RUN_EDITOR: unused