New input type for shell commands: 'Document copy'

This commit is contained in:
Yevgen Muntyan 2011-01-10 02:13:44 -08:00
parent 59702458b9
commit 157c7cc277
8 changed files with 165 additions and 332 deletions

View File

@ -242,7 +242,8 @@ text field using default user shell on Unix systems or <command>cmd.exe</command
Its input and output are specified by the following controls:
<itemizedlist>
<listitem>
<parameter><guilabel>Input</guilabel></parameter> entry specifies what text from the document should be passed to the command via its standard input:
<parameter><guilabel>Input</guilabel></parameter> entry specifies what text from the document should be passed to the command.
The text is passed via command's standard input, except for <parameter>Document copy</parameter> case.
<variablelist>
<?dbhtml list-presentation="table"?>
<varlistentry>
@ -263,6 +264,12 @@ Its input and output are specified by the following controls:
<term><parameter>Whole document</parameter></term>
<listitem>whole document contents.</listitem>
</varlistentry>
<varlistentry>
<term><parameter>Document copy</parameter></term>
<listitem>document contents will be saved to a temporary file and the file path will be stored
in <envar>INPUT_FILE</envar> environment variable. No text will be passed to the command via standard
input.</listitem>
</varlistentry>
</variablelist>
</listitem>
@ -336,6 +343,10 @@ following environment variables are set when scripts are executed:
<filename>/home/user/file.c</filename>). Basename is always
<filename><envar>$DOC_BASE</envar><envar>$DOC_EXT</envar></filename>.</listitem>
</varlistentry>
<varlistentry>
<term><envar>DOC_PATH</envar></term>
<listitem>full document path.</listitem>
</varlistentry>
<varlistentry>
<term><envar>LINE</envar></term>
<listitem><constant>1</constant>-based number of the line containing cursor.
@ -352,6 +363,11 @@ following environment variables are set when scripts are executed:
<term><envar>DATA_DIR</envar></term>
<listitem>user data directory (&medit-user-data-dir-unix; on Unix systems).</listitem>
</varlistentry>
<varlistentry>
<term><envar>INPUT_FILE</envar></term>
<listitem>if <parameter>input</parameter> was set to "Document copy" then this is set to
full path of the temporary file containing document text.</listitem>
</varlistentry>
</variablelist>
</para>
<para>

View File

@ -102,6 +102,13 @@ moo_edit_open_info_dup (MooEditOpenInfo *info)
return copy;
}
void
moo_edit_open_info_free (MooEditOpenInfo *info)
{
if (info)
g_object_unref (info);
}
static void
moo_edit_open_info_finalize (GObject *object)
{
@ -202,6 +209,13 @@ moo_edit_save_info_dup (MooEditSaveInfo *info)
return copy;
}
void
moo_edit_save_info_free (MooEditSaveInfo *info)
{
if (info)
g_object_unref (info);
}
static void
moo_edit_save_info_finalize (GObject *object)
{
@ -263,6 +277,13 @@ moo_edit_reload_info_dup (MooEditReloadInfo *info)
return copy;
}
void
moo_edit_reload_info_free (MooEditReloadInfo *info)
{
if (info)
g_object_unref (info);
}
static void
moo_edit_reload_info_finalize (GObject *object)
{

View File

@ -103,9 +103,11 @@ MooEditOpenInfo *moo_edit_open_info_new_path (const char *path,
MooEditOpenInfo *moo_edit_open_info_new_uri (const char *uri,
const char *encoding);
MooEditOpenInfo *moo_edit_open_info_dup (MooEditOpenInfo *info);
void moo_edit_open_info_free (MooEditOpenInfo *info);
MooEditReloadInfo *moo_edit_reload_info_new (const char *encoding);
MooEditReloadInfo *moo_edit_reload_info_dup (MooEditReloadInfo *info);
void moo_edit_reload_info_free (MooEditReloadInfo *info);
MooEditSaveInfo *moo_edit_save_info_new (GFile *file,
const char *encoding);
@ -114,6 +116,7 @@ MooEditSaveInfo *moo_edit_save_info_new_path (const char *path,
MooEditSaveInfo *moo_edit_save_info_new_uri (const char *uri,
const char *encoding);
MooEditSaveInfo *moo_edit_save_info_dup (MooEditSaveInfo *info);
void moo_edit_save_info_free (MooEditSaveInfo *info);
G_END_DECLS

View File

@ -43,6 +43,16 @@ end
table.sort(lines)
doc.replace_selected_lines(lines)
]]></lua:code>
</command>
<command id="DiffToDisk"><!-- ###unix### -->
<name>Diff to Disk</name>
<options>need-file</options>
<type>exe</type>
<exe:input>doc-copy</exe:input>
<exe:code><![CDATA[
diff -pu $DOC_PATH $INPUT_FILE > $TEMP_DIR/m.diff
medit -r $TEMP_DIR/m.diff
]]></exe:code>
</command>
<command id="Yacc"><!-- ###unix### -->
<name>Bison</name>

View File

@ -23,6 +23,7 @@
#include "mooutils/mooi18n.h"
#include "mooutils/mooutils-fs.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooutils-script.h"
#include "mooutils/mooutils-debug.h"
#include "mooutils/moospawn.h"
#include "mooutils/mootype-macros.h"
@ -45,7 +46,7 @@
#define SCRIPT_EXTENSION ".bat"
#endif
#define MOO_COMMAND_EXE_MAX_INPUT (MOO_COMMAND_EXE_INPUT_DOC + 1)
#define MOO_COMMAND_EXE_MAX_INPUT (MOO_COMMAND_EXE_INPUT_DOC_COPY + 1)
#define MOO_COMMAND_EXE_MAX_OUTPUT (MOO_COMMAND_EXE_OUTPUT_NEW_DOC + 1)
#define MOO_COMMAND_EXE_INPUT_DEFAULT MOO_COMMAND_EXE_INPUT_NONE
#define MOO_COMMAND_EXE_OUTPUT_DEFAULT MOO_COMMAND_EXE_OUTPUT_NONE
@ -55,7 +56,8 @@ typedef enum
MOO_COMMAND_EXE_INPUT_NONE,
MOO_COMMAND_EXE_INPUT_LINES,
MOO_COMMAND_EXE_INPUT_SELECTION,
MOO_COMMAND_EXE_INPUT_DOC
MOO_COMMAND_EXE_INPUT_DOC,
MOO_COMMAND_EXE_INPUT_DOC_COPY,
} MooCommandExeInput;
typedef enum
@ -116,7 +118,6 @@ struct _MooCommandExePrivate {
char *filter;
};
G_DEFINE_TYPE (MooCommandExe, _moo_command_exe, MOO_TYPE_COMMAND)
typedef MooCommandFactory MooCommandFactoryExe;
@ -167,9 +168,30 @@ get_lines (MooEdit *doc,
}
static char *
get_input (MooCommandExe *cmd,
MooCommandContext *ctx,
gboolean select_it)
save_input_file (MooEdit *doc)
{
MooEditSaveInfo *info;
GError *error = NULL;
char *file;
file = moo_tempnam (NULL);
info = moo_edit_save_info_new_path (file, moo_edit_get_encoding (doc));
if (!moo_edit_save_copy (doc, info, &error))
{
g_error_free (error);
g_free (file);
file = NULL;
}
moo_edit_save_info_free (info);
return file;
}
static char *
get_input (MooCommandExe *cmd,
MooCommandContext *ctx,
gboolean select_it)
{
MooEdit *doc = moo_command_context_get_doc (ctx);
MooEditView *view = doc ? moo_edit_get_view (doc) : NULL;
@ -179,6 +201,7 @@ get_input (MooCommandExe *cmd,
switch (cmd->priv->input)
{
case MOO_COMMAND_EXE_INPUT_NONE:
case MOO_COMMAND_EXE_INPUT_DOC_COPY:
return NULL;
case MOO_COMMAND_EXE_INPUT_LINES:
return get_lines (doc, select_it);
@ -188,7 +211,7 @@ get_input (MooCommandExe *cmd,
return moo_text_view_get_text (GTK_TEXT_VIEW (view));
}
g_return_val_if_reached (NULL);
moo_return_val_if_reached (NULL);
}
@ -196,20 +219,10 @@ static char *
save_temp (const char *data,
gssize length)
{
int fd;
GError *error = NULL;
char *filename;
fd = g_file_open_tmp ("medit-tmp-XXXXXX", &filename, &error);
if (fd < 0)
{
g_critical ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
return NULL;
}
close (fd);
filename = moo_tempnam (NULL);
/* XXX */
if (!_moo_save_file_utf8 (filename, data, length, &error))
@ -232,7 +245,7 @@ make_cmd (const char *base_cmd_line,
input_len = input ? strlen (input) : 0;
if (!input || !input_len)
if (!input_len)
return g_strdup (base_cmd_line);
if (input_len < 2048)
@ -432,79 +445,93 @@ insert_text (MooEdit *doc,
static void
set_variable (const char *name,
const GValue *gval,
gpointer array)
get_extension (const char *string,
char **base,
char **ext)
{
char *freeme = NULL;
const char *value = NULL;
char *dot;
switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (gval)))
g_return_if_fail (string != NULL);
dot = strrchr (string, '.');
if (dot)
{
case G_TYPE_CHAR:
freeme = g_strdup_printf ("%c", g_value_get_char (gval));
break;
case G_TYPE_UCHAR:
freeme = g_strdup_printf ("%c", g_value_get_uchar (gval));
break;
case G_TYPE_INT:
freeme = g_strdup_printf ("%d", g_value_get_int (gval));
break;
case G_TYPE_UINT:
freeme = g_strdup_printf ("%u", g_value_get_uint (gval));
break;
case G_TYPE_LONG:
freeme = g_strdup_printf ("%ld", g_value_get_long (gval));
break;
case G_TYPE_ULONG:
freeme = g_strdup_printf ("%lu", g_value_get_ulong (gval));
break;
case G_TYPE_INT64:
freeme = g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (gval));
break;
case G_TYPE_UINT64:
freeme = g_strdup_printf ("%" G_GUINT64_FORMAT, g_value_get_uint64 (gval));
break;
case G_TYPE_STRING:
value = g_value_get_string (gval);
break;
default:
g_message ("ignoring value of type %s", g_type_name (G_VALUE_TYPE (gval)));
*base = g_strndup (string, dot - string);
*ext = g_strdup (dot);
}
else
{
*base = g_strdup (string);
*ext = g_strdup ("");
}
if (freeme)
value = freeme;
if (value)
g_ptr_array_add (array, g_strdup_printf ("%s=%s", name, value));
g_free (freeme);
}
static void
create_environment (MooCommandContext *ctx,
create_environment (MooCommandExe *cmd,
MooCommandContext *ctx,
char **working_dir,
char ***envp)
{
GPtrArray *array;
MooEdit *doc;
MooEdit *doc = moo_command_context_get_doc (ctx);
array = g_ptr_array_new ();
moo_command_context_foreach (ctx, set_variable, array);
if (array->len)
if (doc && !moo_edit_is_untitled (doc))
{
g_ptr_array_add (array, NULL);
*envp = (char**) g_ptr_array_free (array, FALSE);
}
else
{
g_ptr_array_free (array, TRUE);
*envp = NULL;
char *filename, *basename;
char *dirname, *base = NULL, *extension = NULL;
filename = moo_edit_get_filename (doc);
basename = filename ? g_path_get_basename (filename) : NULL;
dirname = g_path_get_dirname (filename);
get_extension (basename, &base, &extension);
g_ptr_array_add (array, g_strdup_printf ("DOC=%s", basename));
g_ptr_array_add (array, g_strdup_printf ("DOC_DIR=%s", dirname));
g_ptr_array_add (array, g_strdup_printf ("DOC_BASE=%s", base));
g_ptr_array_add (array, g_strdup_printf ("DOC_EXT=%s", extension));
g_ptr_array_add (array, g_strdup_printf ("DOC_PATH=%s", filename));
g_free (basename);
g_free (dirname);
g_free (base);
g_free (extension);
g_free (filename);
}
if (doc)
{
MooEditView *view = moo_edit_get_view (doc);
int line = moo_text_view_get_cursor_line (GTK_TEXT_VIEW (view));
g_ptr_array_add (array, g_strdup_printf ("LINE0=%d", line));
g_ptr_array_add (array, g_strdup_printf ("LINE=%d", line + 1));
}
{
char *data_dir = moo_get_user_data_dir ();
char *temp_dir = moo_tempdir ();
g_ptr_array_add (array, g_strdup_printf ("DATA_DIR=%s", data_dir));
g_ptr_array_add (array, g_strdup_printf ("TEMP_DIR=%s", temp_dir));
g_free (data_dir);
g_free (temp_dir);
}
g_ptr_array_add (array, g_strdup_printf ("APP_PID=%s", _moo_get_pid_string ()));
g_ptr_array_add (array, g_strdup_printf ("MEDIT_PID=%s", _moo_get_pid_string ()));
if (cmd->priv->input == MOO_COMMAND_EXE_INPUT_DOC_COPY)
{
char *input_file = save_input_file (doc);
if (input_file)
g_ptr_array_add (array, g_strdup_printf ("INPUT_FILE=%s", input_file));
g_free (input_file);
}
g_ptr_array_add (array, NULL);
*envp = (char**) g_ptr_array_free (array, FALSE);
*working_dir = NULL;
doc = moo_command_context_get_doc (ctx);
if (doc && !moo_edit_is_untitled (doc))
{
@ -695,7 +722,7 @@ moo_command_exe_run (MooCommand *cmd_base,
char *output = NULL;
char *working_dir;
create_environment (ctx, &working_dir, &envp);
create_environment (cmd, ctx, &working_dir, &envp);
switch (cmd->priv->output)
{
@ -758,6 +785,7 @@ moo_command_exe_check_sensitive (MooCommand *cmd_base,
case MOO_COMMAND_EXE_INPUT_LINES:
case MOO_COMMAND_EXE_INPUT_SELECTION:
case MOO_COMMAND_EXE_INPUT_DOC:
case MOO_COMMAND_EXE_INPUT_DOC_COPY:
options |= MOO_COMMAND_NEED_DOC;
break;
}
@ -849,6 +877,8 @@ parse_input (const char *string,
*input = MOO_COMMAND_EXE_INPUT_SELECTION;
else if (!strcmp (string, "doc"))
*input = MOO_COMMAND_EXE_INPUT_DOC;
else if (!strcmp (string, "doc-copy"))
*input = MOO_COMMAND_EXE_INPUT_DOC_COPY;
else
{
g_warning ("unknown input type %s", string);
@ -1036,7 +1066,13 @@ unx_factory_create_widget (G_GNUC_UNUSED MooCommandFactory *factory)
ExePageXml *xml;
/* Translators: these are kinds of input for a shell command, do not translate the part before | */
const char *input_names[] = {N_("Input|None"), N_("Input|Selected lines"), N_("Input|Selection"), N_("Input|Whole document")};
const char *input_names[] = {
N_("Input|None"),
N_("Input|Selected lines"),
N_("Input|Selection"),
N_("Input|Whole document"),
N_("Input|Document copy")
};
xml = exe_page_xml_new ();
@ -1095,7 +1131,7 @@ unx_factory_save_data (G_GNUC_UNUSED MooCommandFactory *factory,
char *new_cmd_line;
gboolean changed = FALSE;
int index, old_index;
const char *input_strings[4] = {"none", "lines", "selection", "doc"};
const char *input_strings[5] = { "none", "lines", "selection", "doc", "doc-copy" };
xml = exe_page_xml_get (page);
g_return_val_if_fail (xml != NULL, FALSE);

View File

@ -53,7 +53,6 @@ typedef struct {
} Variable;
struct _MooCommandContextPrivate {
GHashTable *vars;
MooEditWindow *window;
MooEdit *doc;
};
@ -78,8 +77,6 @@ static GHashTable *registered_factories;
static GHashTable *registered_filters;
static Variable *variable_new (const GValue *value);
static void variable_free (Variable *var);
static void moo_command_data_take_code (MooCommandData *data,
char *code);
@ -566,118 +563,6 @@ out:
}
static Variable *
variable_new (const GValue *value)
{
Variable *var;
g_return_val_if_fail (G_IS_VALUE (value), NULL);
var = g_new0 (Variable, 1);
g_value_init (&var->value, G_VALUE_TYPE (value));
g_value_copy (value, &var->value);
return var;
}
static void
variable_free (Variable *var)
{
if (var)
{
g_value_unset (&var->value);
g_free (var);
}
}
void
moo_command_context_set (MooCommandContext *ctx,
const char *name,
const GValue *value)
{
Variable *var;
g_return_if_fail (MOO_IS_COMMAND_CONTEXT (ctx));
g_return_if_fail (name != NULL);
g_return_if_fail (G_IS_VALUE (value));
var = variable_new (value);
g_hash_table_insert (ctx->priv->vars, g_strdup (name), var);
}
void
moo_command_context_set_string (MooCommandContext *ctx,
const char *name,
const char *value)
{
if (value)
{
GValue gval;
gval.g_type = 0;
g_value_init (&gval, G_TYPE_STRING);
g_value_set_static_string (&gval, value);
moo_command_context_set (ctx, name, &gval);
g_value_unset (&gval);
}
else
{
moo_command_context_unset (ctx, name);
}
}
gboolean
moo_command_context_get (MooCommandContext *ctx,
const char *name,
GValue *value)
{
Variable *var;
g_return_val_if_fail (MOO_IS_COMMAND_CONTEXT (ctx), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
g_return_val_if_fail (G_VALUE_TYPE (value) == 0, FALSE);
var = g_hash_table_lookup (ctx->priv->vars, name);
if (!var)
return FALSE;
g_value_init (value, G_VALUE_TYPE (&var->value));
g_value_copy (&var->value, value);
return TRUE;
}
const char *
moo_command_context_get_string (MooCommandContext *ctx,
const char *name)
{
Variable *var;
g_return_val_if_fail (MOO_IS_COMMAND_CONTEXT (ctx), NULL);
g_return_val_if_fail (name != NULL, NULL);
var = g_hash_table_lookup (ctx->priv->vars, name);
if (!var)
return NULL;
g_return_val_if_fail (G_VALUE_TYPE (&var->value) == G_TYPE_STRING, NULL);
return g_value_get_string (&var->value);
}
void
moo_command_context_unset (MooCommandContext *ctx,
const char *name)
{
g_return_if_fail (MOO_IS_COMMAND_CONTEXT (ctx));
g_return_if_fail (name != NULL);
g_hash_table_remove (ctx->priv->vars, name);
}
static void
moo_command_context_dispose (GObject *object)
{
@ -685,7 +570,6 @@ moo_command_context_dispose (GObject *object)
if (ctx->priv)
{
g_hash_table_destroy (ctx->priv->vars);
if (ctx->priv->window)
g_object_unref (ctx->priv->window);
if (ctx->priv->doc)
@ -767,42 +651,6 @@ static void
moo_command_context_init (MooCommandContext *ctx)
{
ctx->priv = G_TYPE_INSTANCE_GET_PRIVATE (ctx, MOO_TYPE_COMMAND_CONTEXT, MooCommandContextPrivate);
ctx->priv->vars = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify) variable_free);
}
static void
ctx_foreach_func (const char *name,
Variable *var,
gpointer user_data)
{
struct {
MooCommandContextForeachFunc func;
gpointer data;
} *data = user_data;
data->func (name, &var->value, data->data);
}
void
moo_command_context_foreach (MooCommandContext *ctx,
MooCommandContextForeachFunc func,
gpointer func_data)
{
struct {
MooCommandContextForeachFunc func;
gpointer data;
} data;
g_return_if_fail (MOO_IS_COMMAND_CONTEXT (ctx));
g_return_if_fail (func != NULL);
data.func = func;
data.data = func_data;
g_hash_table_foreach (ctx->priv->vars, (GHFunc) ctx_foreach_func, &data);
}

View File

@ -162,28 +162,6 @@ void moo_command_context_set_window (MooCommandContext *ctx,
MooEdit *moo_command_context_get_doc (MooCommandContext *ctx);
MooEditWindow *moo_command_context_get_window (MooCommandContext *ctx);
void moo_command_context_set (MooCommandContext *ctx,
const char *name,
const GValue *value);
gboolean moo_command_context_get (MooCommandContext *ctx,
const char *name,
GValue *value);
void moo_command_context_unset (MooCommandContext *ctx,
const char *name);
void moo_command_context_set_string (MooCommandContext *ctx,
const char *name,
const char *value);
const char *moo_command_context_get_string (MooCommandContext *ctx,
const char *name);
typedef void (*MooCommandContextForeachFunc) (const char *name,
const GValue *value,
gpointer data);
void moo_command_context_foreach (MooCommandContext *ctx,
MooCommandContextForeachFunc func,
gpointer data);
typedef MooOutputFilter *(*MooCommandFilterFactory) (const char *id,
gpointer data);

View File

@ -76,8 +76,6 @@ typedef struct {
typedef MooEditActionClass MooToolActionClass;
static MooCommandContext *create_command_context (MooEditWindow *window,
MooEdit *doc);
static MooUserToolInfo *_moo_user_tool_info_ref (MooUserToolInfo *info);
static void add_info (MooUserToolInfo *info,
GSList **list,
@ -1299,7 +1297,7 @@ moo_tool_action_activate (GtkAction *gtkaction)
doc = moo_edit_window_get_active_doc (window);
}
ctx = create_command_context (window, doc);
ctx = moo_command_context_new (doc, window);
moo_command_run (action->cmd, ctx);
@ -1354,83 +1352,6 @@ _moo_tool_action_class_init (MooToolActionClass *klass)
}
static void
get_extension (const char *string,
char **base,
char **ext)
{
char *dot;
g_return_if_fail (string != NULL);
dot = strrchr (string, '.');
if (dot)
{
*base = g_strndup (string, dot - string);
*ext = g_strdup (dot);
}
else
{
*base = g_strdup (string);
*ext = g_strdup ("");
}
}
static MooCommandContext *
create_command_context (MooEditWindow *window,
MooEdit *doc)
{
MooCommandContext *ctx;
char *user_dir;
ctx = moo_command_context_new (doc, window);
if (doc && !moo_edit_is_untitled (doc))
{
char *filename, *basename;
char *dirname, *base = NULL, *extension = NULL;
filename = moo_edit_get_filename (doc);
basename = filename ? g_path_get_basename (filename) : NULL;
dirname = g_path_get_dirname (filename);
get_extension (basename, &base, &extension);
moo_command_context_set_string (ctx, "DOC", basename);
moo_command_context_set_string (ctx, "DOC_DIR", dirname);
moo_command_context_set_string (ctx, "DOC_BASE", base);
moo_command_context_set_string (ctx, "DOC_EXT", extension);
g_free (dirname);
g_free (base);
g_free (extension);
g_free (basename);
g_free (filename);
}
if (doc)
{
GValue val = { 0 };
MooEditView *view = moo_edit_get_view (doc);
g_value_init (&val, G_TYPE_INT);
g_value_set_int (&val, moo_text_view_get_cursor_line (GTK_TEXT_VIEW (view)));
moo_command_context_set (ctx, "LINE0", &val);
g_value_set_int (&val, moo_text_view_get_cursor_line (GTK_TEXT_VIEW (view)) + 1);
moo_command_context_set (ctx, "LINE", &val);
g_value_unset (&val);
}
user_dir = moo_get_user_data_dir ();
moo_command_context_set_string (ctx, "DATA_DIR", user_dir);
moo_command_context_set_string (ctx, "APP_PID", _moo_get_pid_string ());
/* XXX */
moo_command_context_set_string (ctx, "MEDIT_PID", _moo_get_pid_string ());
g_free (user_dir);
return ctx;
}
static GtkWidget *
user_tools_plugin_prefs_page (G_GNUC_UNUSED MooPlugin *plugin)
{