external scripting



Hi Pavel (at al)!

There are some very similar function in mc internal editor cmd menu. e.g.:
  - menu_date_cmd,
  - menu_format_paragraph
  - menu_ispell_cmd
  - menu_sort_cmd
  - menu_ext_cmd
  - menu_c_form_cmd
  - menu_mail_cmd

Every menu entry executes an external command/script with or without the
highlited area, and next insert back the script/command output or replace
the highlited area with the output of the script/command.

May be better if we provide an "all in one" menu entry. Through this
panel we reach the "old" script(s) as "basic" script(s) identified by
their names (e.g. indent or edit.indent.rc), and other commands
with new pipe fashion. The basic scripts laying in mc_home directory or
in the user specific mcedit dir: home_dir/EDIT_DIR ([off] why mcedit copies,
the system wide edit.indent.rc script to the user dir?[/off]) . The output of
the external commands may be inserted, replace the highlited area, or
discarded.
If no highliting, the whole file saved into the block file if user want it.

The pipe is a pipe :-) the stdin of the "command line" feed by the highlited
area/whole file (or nothing). The last (hidden) part of the command line is
" | cat >BLOCK_FILE", so the output of the pipe saved into the block file.


+---------------------------------------------------+
|   Script:       Name/commmand line                |
| ( ) Basic: _______________________________[^]     |
| ( ) Pipe:  _______________________________[^]     |
|                                                   |
| [ ] Whole file if no highliting                   |
| [ ] Pad if column highliting                      |
|                                                   |
| Output:                                           |
|  ( ) replace                                      |
|  ( ) insert                                       |
|  ( ) discard                                      |
|                                                   |

What change in the source?
A new edit_ext_cmd routine (edit_ext_script_cmd) with some new input
(basic/pipe, padding, whole file), and a new dialog. Split the original
edit_insert_column_of_text into two part, an edit_insert_column and an
edit_insert_column_of_text. Adding an edit_insert_column_from_file routine,
which use the edit_insert_column.

I think, this is a better solution of using external programs or scripts in
the editor, instead we make a menu entry for every particular thing.

Good things: :-)
    - uniform access
    - user can use their "old" scripts
    - user can make "anything" (e.g.: print, postscriptify whole file or just a
        highlited area, feed it through a complicated pipe or, so on)
    - quite easy to "emulate" the "old" things, e.g. insert current date,
        sort file or a part of the file, insert the output of a command
    - everything work with highlited blocks (rectangular areas!!!)
    - mcedit pad the column highlited area if there are short lines,
        when user need it

Bad things: :-(
    - no one-key-combination shortcut for every old menu entry
    - users sometimes have to make upto five selection for a command

Some other note:
  May instead of a simple pipe command line, we may implement a combo box,
  with the sortcut of some common comand e.g.:
    indent
    sort
    fmt
    mail
    lpr
    enscript
    trueprint
    a2ps
    pipe
 the input string will be the last part of the command line, and the
 pipe/command entry represent a totally free command line.

 May add some shortcut for particular "old" commands which call this
 interface...

Gergely

p.s.: here is a patch. It only add a new menu entry to command menu (External
scripting) and NOT remove any existing entry or routine...

p.s.2: OK, there is a bug in the edit_block_copy_cmd, we don't want the 

   if (column_highlighting)
 	if ((x >= edit->column1 && x < edit->column2)
 	    || (x > edit->column2 && x <= edit->column1))
 	    return;

  part because the edit_get_buf copy the whole block, and copying it not make
  any interference with the original block... This patch comment out this
  section, so you can copy a rectangular block to everywhere now.

diff -u edit.orig/edit.c ./edit.c
--- edit.orig/edit.c	2004-02-04 23:27:58.000000000 +0100
+++ ./edit.c	2004-06-22 12:37:19.000000000 +0200
@@ -2555,6 +2555,9 @@
     case CK_Mail:
 	edit_mail_dialog (edit);
 	break;
+    case CK_Escript:
+	edit_escript_dialog (edit);
+	break;
     case CK_Shell:
 	view_other_cmd ();
 	break;
diff -u edit.orig/edit.h ./edit.h
--- edit.orig/edit.h	2004-02-04 23:27:58.000000000 +0100
+++ ./edit.h	2004-06-18 15:00:43.000000000 +0200
@@ -253,6 +253,7 @@
 void edit_insert_indent (WEdit *edit, int indent);
 void edit_options_dialog (void);
 void edit_mail_dialog (WEdit *edit);
+void edit_escript_dialog (WEdit *edit);
 void format_paragraph (WEdit *edit, int force);
 
 /* either command or char_for_insertion must be passed as -1 */
diff -u edit.orig/editcmd.c ./editcmd.c
--- edit.orig/editcmd.c	2003-11-27 11:23:50.000000000 +0100
+++ ./editcmd.c	2004-06-22 16:38:20.000000000 +0200
@@ -885,6 +885,43 @@
 #define space_width 1
 
 static void
+edit_insert_column (WEdit * edit, unsigned char data, int col, int width)
+{
+    if (data == '\n') {	/* fill in and move to next line */
+	int l;
+	long p;
+
+	if (edit_get_byte (edit, edit->curs1) != '\n') {
+	    l = width - (edit_get_col (edit) - col);
+	    while (l > 0) {
+		edit_insert (edit, ' ');
+		l -= space_width;
+	    }
+	}
+	for (p = edit->curs1;; p++) {
+	    if (p == edit->last_byte) {
+		edit_cursor_move (edit, edit->last_byte - edit->curs1);
+		edit_insert_ahead (edit, '\n');
+		p++;
+		break;
+	    }
+	    if (edit_get_byte (edit, p) == '\n') {
+		p++;
+		break;
+	    }
+	}
+	edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
+	l = col - edit_get_col (edit);
+	while (l >= space_width) {
+	    edit_insert (edit, ' ');
+	    l -= space_width;
+	}
+	return;
+    }
+    edit_insert (edit, data);
+}
+
+static void
 edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
 {
     long cursor;
@@ -892,41 +929,31 @@
     cursor = edit->curs1;
     col = edit_get_col (edit);
     for (i = 0; i < size; i++) {
-	if (data[i] == '\n') {	/* fill in and move to next line */
-	    int l;
-	    long p;
-	    if (edit_get_byte (edit, edit->curs1) != '\n') {
-		l = width - (edit_get_col (edit) - col);
-		while (l > 0) {
-		    edit_insert (edit, ' ');
-		    l -= space_width;
-		}
-	    }
-	    for (p = edit->curs1;; p++) {
-		if (p == edit->last_byte) {
-		    edit_cursor_move (edit, edit->last_byte - edit->curs1);
-		    edit_insert_ahead (edit, '\n');
-		    p++;
-		    break;
-		}
-		if (edit_get_byte (edit, p) == '\n') {
-		    p++;
-		    break;
-		}
-	    }
-	    edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
-	    l = col - edit_get_col (edit);
-	    while (l >= space_width) {
-		edit_insert (edit, ' ');
-		l -= space_width;
-	    }
-	    continue;
-	}
-	edit_insert (edit, data[i]);
+	edit_insert_column (edit, data[i], col, width);
     }
     edit_cursor_move (edit, cursor - edit->curs1);
 }
 
+static void
+edit_insert_column_from_file (WEdit * edit, char *filename, int width)
+{
+    int file;
+
+    long cursor;
+    int i, col;
+    unsigned char data;
+    cursor = edit->curs1;
+    col = edit_get_col (edit);
+
+    if ((file = open (filename, O_RDONLY | O_BINARY)) == -1)
+	    return;
+    while ((i = read (file, &data, 1)) > 0) {
+	edit_insert_column (edit, data, col, width);
+    }
+
+    edit_cursor_move (edit, cursor - edit->curs1);
+}
+
 
 void
 edit_block_copy_cmd (WEdit *edit)
@@ -939,11 +966,11 @@
     x = edit->curs_col;
     if (eval_marks (edit, &start_mark, &end_mark))
 	return;
-    if (column_highlighting)
+/*   if (column_highlighting)
 	if ((x >= edit->column1 && x < edit->column2)
 	    || (x > edit->column2 && x <= edit->column1))
 	    return;
-
+*/
     copy_buf = edit_get_block (edit, start_mark, end_mark, &size);
 
     /* all that gets pushed are deletes hence little space is used on the stack */
@@ -1484,7 +1511,7 @@
 	    }
 	} else {	/* regexp matching */
 	    long offset = 0;
-	    int found_start, match_bol, move_win = 0; 
+	    int found_start, match_bol, move_win = 0;
 
 	    while (start + offset < last_byte) {
 		match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
@@ -2138,6 +2165,49 @@
     return r;
 }
 
+typedef void (*edit_iter_block_cb_t) (WEdit *edit, long start, long idx,
+		long finish, int pad, int ch, void *data);
+
+/* return next character of highlited block... */
+static void
+edit_iter_block (WEdit *edit, long start, long finish, int pad,
+			     edit_iter_block_cb_t cb, void *data)
+{
+    long idx = start;
+
+    if (column_highlighting) {
+	int col1, col2;
+	
+	col1 = min (edit->column1, edit->column2);
+	col2 = max (edit->column1, edit->column2);
+	
+	if (edit_move_forward3 (edit, edit_bol (edit, idx), 0, idx) == col2)
+	    idx++;
+	/* copy from buffer, excluding chars that are out of the column 'margins' */
+	while (idx < finish) {
+	    long i;
+	    int c, x;
+	    c = edit_get_byte (edit, idx);
+	    x = edit_move_forward3 (edit, edit_bol (edit, idx), 0, idx);
+	    if (x >= col1 && x < col2) {
+		if (c == '\n' && pad)
+		    for (i = edit_move_forward3 (edit, edit_bol (edit, idx),
+				0, idx); i < col2; i++)
+			cb (edit, start, idx, finish, pad, ' ', data);
+		cb (edit, start, idx, finish, pad, c, data);
+	    }
+	    else if (x == col2)
+		cb (edit, start, idx, finish, pad, '\n', data);
+	    idx++;
+	}
+    } else {
+	while (idx < finish) {
+	    cb (edit, start, idx, finish, pad, edit_get_byte (edit, idx), data);
+	    idx++;
+	}
+    }
+}
+
 /* save block, returns 1 on success */
 int
 edit_save_block (WEdit * edit, const char *filename, long start,
@@ -2343,7 +2413,7 @@
 
     exp = old ? old : "";
 
-    exp = input_dialog (_(" Run Sort "), 
+    exp = input_dialog (_(" Run Sort "),
     _(" Enter sort options (see manpage) separated by whitespace: "), exp);
 
     if (!exp)
@@ -2355,12 +2425,12 @@
     e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ",
home_dir, TEMP_FILE, 0));
     if (e) {
 	if (e == -1 || e == 127) {
-	    edit_error_dialog (_(" Sort "), 
+	    edit_error_dialog (_(" Sort "),
 	    get_sys_error (_(" Cannot execute sort command ")));
 	} else {
 	    char q[8];
 	    sprintf (q, "%d ", e);
-	    edit_error_dialog (_(" Sort "), 
+	    edit_error_dialog (_(" Sort "),
 	    catstrs (_(" Sort returned non-zero: "), q, 0));
 	}
 	return -1;
@@ -2608,6 +2678,192 @@
 }
 
 
+#define EXT_SCRIPT_BASIC  0
+#define EXT_SCRIPT_FILTER 1
+
+#define EXT_SCRIPT_REPLACE 0
+#define EXT_SCRIPT_INSERT  1
+#define EXT_SCRIPT_DISCARD 2
+
+void edit_ext_script_cb (WEdit *edit, long start, long idx,
+		long finish, int pad, int ch, void *data)
+{
+    FILE *p = data;
+    putc (ch, p);
+}
+
+void
+edit_ext_script_cmd (WEdit *edit, const char *scr, int type,
+			     int sout, int ifnhi, int pad)
+{
+    long start_mark, end_mark;
+    FILE *script_home = NULL;
+    FILE *p = NULL;	/* pipe */
+    char *s = NULL;	/* script */
+    char *b = NULL;	/* block file */
+    char *q = NULL;	/* quoted name */
+
+    if (eval_marks (edit, &start_mark, &end_mark)) {	/* no highlite */
+	if (ifnhi) {
+	    edit_push_markers (edit);
+	    edit_set_markers (edit, 0, edit->last_byte, 0, 0);
+	    eval_marks (edit, &start_mark, &end_mark);
+	} else
+	    sout = EXT_SCRIPT_DISCARD;
+    }
+
+    b  = catstrs (home_dir, BLOCK_FILE, 0);	/* block file */
+    q = name_quote (edit->filename, 0);
+    open_error_pipe ();
+    if (type == EXT_SCRIPT_BASIC) {
+
+	s = catstrs (home_dir, EDIT_DIR "/", scr, 0);	/* user script */
+	if (!(script_home = fopen (s, "r"))) {
+	    s = catstrs (home_dir, EDIT_DIR "/edit.", scr, ".rc", 0); /* user script
short name */
+	    if (!(script_home = fopen (s, "r"))) {
+		s = catstrs (mc_home, scr, 0);	/* system wide script */
+		if (!(script_home = fopen (s, "r"))) {
+		    s = catstrs (mc_home, "edit.", scr, ".rc", 0);	/* system wide script */
+		}
+	    }
+	}
+	if (script_home)
+	    fclose (script_home);
+	    
+	edit_save_block (edit, b, start_mark, end_mark);
+	/*
+	 * Run script.
+	 * Initial space is to avoid polluting bash history.
+	 * Arguments:
+	 *   $1 - name of the edited file (to check its extension etc).
+	 *   $2 - file containing the current block.
+	 *   $3 - file where error messages should be put
+	 *        (for compatibility with old scripts).
+	 *                    $0      $1      $2   $3                   */
+	system (catstrs (" ", s, " ", q, " ", b, " /dev/null", NULL));
+
+    } else if (type == EXT_SCRIPT_FILTER) {
+	s = catstrs (" ", scr, "| cat >", b, 0);
+	if (*(s+1) == '|')	/* oops, empty scr !!!*/
+	    *(s+1) = ' ';	/* :-) */
+			/* ok save stdout to BLOCK_FILE :-) */
+	p = popen (s, "w");
+	if (p) {
+	    edit_iter_block (edit, start_mark, end_mark, pad,
+					    edit_ext_script_cb, p);
+	    pclose (p);
+	}
+    }
+
+    g_free (q);
+    if (close_error_pipe (0, 0))
+	return;
+
+    edit_refresh_cmd (edit);
+    edit->force |= REDRAW_COMPLETELY;
+
+    /* insert result block */
+
+    switch (sout) {
+    case EXT_SCRIPT_REPLACE:
+	if (edit_block_delete_cmd (edit))
+	    return;
+	if (column_highlighting) 	/* Hmm.. Column selected */
+	    edit_cursor_move (edit, start_mark - edit->curs1);
+    case EXT_SCRIPT_INSERT:
+	if (column_highlighting) 	/* Hmm.. Column selected */
+	    edit_insert_column_from_file (edit, b,
+				max (edit->column2 - edit->column1,
+					edit->column1 - edit->column2));
+	else
+	    edit_insert_file (edit, b);
+	break;
+    case EXT_SCRIPT_DISCARD:
+	break;
+    }
+
+/*    if ((block_file = fopen (b, "w")))
+        fclose (block_file);	*/
+
+    return;
+}
+
+#define EXT_SCRIPT_H 17
+#define EXT_SCRIPT_W 51
+
+void edit_escript_dialog (WEdit * edit)
+{
+    static char *type_str[] =	/* no translate :-( */
+	{N_("Basic"), N_("Pipe"), NULL};
+    static char *sout_str[] =	/* no translate :-( */
+	{N_("Replace"), N_("Insert"), N_("Discard"), NULL};
+
+    static char *script = 0, *filter = 0;
+    static int  type = 0, sout = 0, ifnhi = 0, pad = 1;
+
+    char *script_temp = script, *filter_temp = filter;
+    int type_temp = type, sout_temp = sout, ifnhi_temp = ifnhi, pad_temp = pad;
+
+    QuickDialog Quick_input =
+    {EXT_SCRIPT_W, EXT_SCRIPT_H, -1, 0, N_(" External scripting "),
+     "[Input Line Keys]", 0};
+
+    QuickWidget quick_widgets[] =
+    {
+/* 0*/	{quick_button, 6, 10, 15, EXT_SCRIPT_H, N_("&Cancel"), 0, B_CANCEL, 0,
+	 0, NULL},
+/* 1*/	{quick_button, 2, 10, 15, EXT_SCRIPT_H, N_("&OK"), 0, B_ENTER, 0,
+	 0, NULL},
+/* 2*/	{quick_radio, 4, EXT_SCRIPT_W, 11, EXT_SCRIPT_H, "", 3, sout, &sout,
+         sout_str, "extscript-dlg-stdout"},
+/* 3*/	{quick_label, 3, EXT_SCRIPT_W, 10, EXT_SCRIPT_H, N_("Output:"), 0, 0, 0,
+         0, NULL},
+/* 4*/	{quick_checkbox, 3, EXT_SCRIPT_W, 8, EXT_SCRIPT_H, N_("Pad if column
highliting"), 0, 0, 0,
+	 0, NULL},
+/* 5*/	{quick_checkbox, 3, EXT_SCRIPT_W, 7, EXT_SCRIPT_H, N_("Whole file if no
highlited block"), 0, 0, 0,
+	 0, NULL},
+/* 6*/	{quick_input, 14, EXT_SCRIPT_W, 5, EXT_SCRIPT_H, "", EXT_SCRIPT_W - 17,
0, 0,
+	 0, "extscript-dlg-pipe"},
+/* 7*/	{quick_input, 14, EXT_SCRIPT_W, 4, EXT_SCRIPT_H, "", EXT_SCRIPT_W - 17,
0, 0,
+	 0, "extscript-dlg-script"},
+/* 8*/	{quick_radio, 4, EXT_SCRIPT_W, 4, EXT_SCRIPT_H, "", 2, type, &type,
+         type_str, "extscript-dlg-type"},
+/* 9*/	{quick_label, 3, EXT_SCRIPT_W, 3, EXT_SCRIPT_H, N_("Script:"), 0, 0, 0,
+         0, NULL},
+/*10*/	{quick_label, 14, EXT_SCRIPT_W, 3, EXT_SCRIPT_H, N_("Name/command
line"), 0, 0, 0,
+	 0, 0},
+	{0}};
+
+    quick_widgets[2].result = &sout_temp;
+    quick_widgets[4].result = &pad_temp;
+    quick_widgets[5].result = &ifnhi_temp;
+
+    quick_widgets[6].str_result = &filter_temp;
+    quick_widgets[6].text = filter_temp ? filter_temp : "";
+
+    quick_widgets[7].str_result = &script_temp;
+    quick_widgets[7].text = script_temp ? script_temp : "";
+
+    quick_widgets[8].result = &type_temp;
+
+    Quick_input.widgets = quick_widgets;
+
+    if (quick_dialog (&Quick_input) != B_CANCEL) {
+	if (script)
+	    g_free (script);
+	if (filter)
+	    g_free (filter);
+	type = type_temp;
+	sout = sout_temp;
+	ifnhi = ifnhi_temp;
+	pad = pad_temp;
+	script = script_temp;
+	filter = filter_temp;
+	edit_ext_script_cmd (edit, (type == EXT_SCRIPT_BASIC ? script : filter),
+				 type, sout, ifnhi, pad);
+    }
+}
+
 /*******************/
 /* Word Completion */
 /*******************/
@@ -2617,7 +2873,7 @@
 static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len)
 {
     int i, c, last;
-    
+
 /* return if at begin of file */
     if (edit->curs1 <= 0)
 	return 0;
@@ -2625,14 +2881,14 @@
     c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1);
 /* return if not at end or in word */
     if (isspace (c) || !(isalnum (c) || c == '_'))
-	return 0; 
+	return 0;
 
 /* search start of word to be completed */
     for (i = 2;; i++) {
 /* return if at begin of file */
-	if (edit->curs1 - i < 0) 
+	if (edit->curs1 - i < 0)
 	    return 0;
-	    
+	
 	last = c;
 	c = (unsigned char) edit_get_byte (edit, edit->curs1 - i);
 
diff -u edit.orig/editcmddef.h ./editcmddef.h
--- edit.orig/editcmddef.h	2004-02-05 00:09:22.000000000 +0100
+++ ./editcmddef.h	2004-06-18 14:59:26.000000000 +0200
@@ -98,6 +98,7 @@
 #define CK_ExtCmd		424
 
 #define CK_User_Menu		425
+#define CK_Escript		427
 /* application control */
 #define CK_Save_Desktop		451
 #define CK_New_Window		452
diff -u edit.orig/editkeys.c ./editkeys.c
--- edit.orig/editkeys.c	2004-02-05 00:09:22.000000000 +0100
+++ ./editkeys.c	2004-06-18 14:59:26.000000000 +0200
@@ -36,6 +36,7 @@
 static const long cooledit_key_map[] = {
     ALT ('b'), CK_Match_Bracket,
     ALT ('m'), CK_Mail,
+    ALT ('x'), CK_Escript,
     XCTRL ('f'), CK_Save_Block,
     XCTRL ('n'), CK_New,
     XCTRL ('p'), CK_Pipe_Block (1),	/* spell check */
diff -u edit.orig/editmenu.c ./editmenu.c
--- edit.orig/editmenu.c	2003-10-29 09:54:48.000000000 +0100
+++ ./editmenu.c	2004-06-18 14:59:26.000000000 +0200
@@ -272,12 +272,19 @@
 {
     edit_options_dialog ();
 }
+
 static void
 menu_user_menu_cmd (void)
 {
     menu_key (KEY_F (11));
 }
 
+static void
+menu_escript_cmd (void)
+{
+    menu_cmd (CK_Escript);
+}
+
 static menu_entry FileMenu[] =
 {
     {' ', N_("&Open file..."),         'O', menu_load_cmd},
@@ -363,6 +370,7 @@
     {' ', N_("Sor&t...                 M-t"), 'T', menu_sort_cmd},
     {' ', N_("Paste o&utput of...      M-u"), 'U', menu_ext_cmd},
     {' ', N_("E&xternal Formatter      F19"), 'C', menu_c_form_cmd},
+    {' ', N_("Exte&rnal Scripting      M-x"), 'X', menu_escript_cmd},
     {' ', N_("&Mail...                    "), 'M', menu_mail_cmd}
 };
 
@@ -387,6 +395,7 @@
     {' ', N_("Sor&t...                 M-t"), 'T', menu_sort_cmd},
     {' ', N_("Paste o&utput of...      M-u"), 'U', menu_ext_cmd},
     {' ', N_("E&xternal Formatter      F19"), 'C', menu_c_form_cmd},
+    {' ', N_("Exte&rnal Scripting      M-x"), 'X', menu_escript_cmd},
     {' ', N_("&Mail...                    "), 'M', menu_mail_cmd}
 };
 







[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]