Hi,

I've taken Hannes' patch for the external editor and changed it to
emply the handler mechanism.  Basically, you say

handler vimprobableedit vim -gf %s

in your vimprobablerc, and when hitting ^t in a text field, you'll
get a gvim window.

This also fixes a bug in which the ":" protocol separator did not get
stripped from the argument in open_handler (but frankly, that code is
extremely spooky -- does anyone actually understand what all the temp
magic is supposed to do?).

One "architectural" question: I'm potentially emitting quit a bit of
diagnostics -- is give_feedback the right function for this?  Should
I do something else yet?

If people are happy with the way this works, I'd go ahead and
document it (plus probable bug fixing); I guess the vim -gf shold be
a builtin default, shouldn't it?


While I'm here:  I'd like to add a toggle syntax for boolean flags,
probably along the lines of vim{perator}'s set inv{option}; this is
to support stuff like

map <C-S> set invscripts

or so.  Would anyone consider this feature bloat?


Even more featurecreepy would be to have indicators of script and
proxy in the status line (little S and P chars at the very right, I'd
guess).  Are their any strong feelings about that?

Cheers,

         Markus
diff --git a/Makefile b/Makefile
index 772a30c..fe39667 100644
--- a/Makefile
+++ b/Makefile
@@ -15,9 +15,9 @@ MANINSTALL = $(addprefix $(MANDIR)/man1/,$(MAN1)) \
 INSTALL = $(BINDIR)/$(TARGET) $(MANINSTALL)
 
 # DEBUG build?  Off by default
-V_DEBUG = 0
+V_DEBUG = 1
 
-CFLAGS += `pkg-config --cflags $(LIBS)`
+CFLAGS += `pkg-config --cflags $(LIBS)` -D_XOPEN_SOURCE=500
 LDFLAGS += `pkg-config --libs $(LIBS)` -lX11 -lXext
 
 # TA:  This is a pretty stringent list of warnings to bail on!
diff --git a/keymap.h b/keymap.h
index 7ba5d0b..86aea55 100644
--- a/keymap.h
+++ b/keymap.h
@@ -114,6 +114,9 @@ Key keys[] = {
     { 0,                    GDK_semicolon,  GDK_T,          input,      {.s = ";T"} },
     { 0,                    GDK_semicolon,  GDK_W,          input,      {.s = ";W"} },
 
+    /* this needs to be a binding using CTRL for obvious reasons */
+    { GDK_CONTROL_MASK,     0,              GDK_t,          open_editor,{} },
+
     { 0,                    GDK_VoidSymbol, GDK_Escape,     set,        {ModeNormal} },
     { GDK_CONTROL_MASK,     GDK_VoidSymbol, GDK_bracketleft,set,        {ModeNormal} },
     { GDK_CONTROL_MASK,     0,              GDK_z,          set,        {ModePassThrough} },
diff --git a/main.c b/main.c
index b3407ba..a35e638 100644
--- a/main.c
+++ b/main.c
@@ -11,7 +11,10 @@
 */
 
 #include <X11/Xlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <errno.h>
+#include <stdlib.h>
 #include "includes.h"
 #include "vimprobable.h"
 #include "utilities.h"
@@ -61,6 +64,7 @@ static gboolean complete(const Arg *arg);
 static gboolean descend(const Arg *arg);
 gboolean echo(const Arg *arg);
 static gboolean focus_input(const Arg *arg);
+static gboolean open_editor(const Arg *arg);
 static gboolean input(const Arg *arg);
 static gboolean navigate(const Arg *arg);
 static gboolean number(const Arg *arg);
@@ -432,6 +436,9 @@ webview_keypress_cb(WebKitWebView *webview, GdkEventKey *event) {
             g_free(a.s);
             a.i = ModeNormal;
             return set(&a);
+        } else if (CLEAN(event->state) & GDK_CONTROL_MASK) {
+            /* keybindings of non-printable characters */
+            if (process_keypress(event) == TRUE) return TRUE;
         }
     case ModePassThrough:
         if (IS_ESCAPE(event)) {
@@ -1821,6 +1828,136 @@ view_source(const Arg * arg) {
     return TRUE;
 }
 
+/* open an external editor defined by the protocol handler for
+vimprobableedit on a text box or similar */
+static gboolean
+open_editor(const Arg *arg) {
+    FILE *fp;
+    char *text = NULL, s[255] = "";
+    gboolean success;
+    GString *new_text = g_string_new("");
+    GPid child_pid;
+    int child_status;
+    gchar *value = NULL, *message = NULL, *tag = NULL, *edit_url = NULL;
+    gchar temp_file_name[] = "/tmp/vimprobableeditXXXXXX";
+    int temp_file_handle = -1;
+
+    /* check if active element is suitable for text editing */
+    jsapi_evaluate_script("document.activeElement.tagName", &value, &message);
+    if (value == NULL)
+        return FALSE;
+    tag = g_strdup(value);
+    if (strcmp(tag, "INPUT") == 0) {
+        /* extra check: type == text */
+        jsapi_evaluate_script("document.activeElement.type", &value, &message);
+        if (strcmp(value, "text") != 0) {
+            g_free(value);
+            g_free(message);
+            return FALSE;
+        }
+    } else if (strcmp(tag, "TEXTAREA") != 0) {
+        g_free(value);
+        g_free(message);
+        return FALSE;
+    }
+    jsapi_evaluate_script("document.activeElement.value", &value, &message);
+    text = g_strdup(value);
+    if (text == NULL) {
+        g_free(value);
+        g_free(message);
+        return FALSE;
+    }
+
+    /* write text into temporary file */
+    temp_file_handle = mkstemp(temp_file_name);
+    if (temp_file_handle == -1) {
+        message = g_strdup_printf("Could not create temporary file: %s",
+            strerror(errno));
+        give_feedback(message);
+        g_free(value);
+        g_free(message);
+        g_free(text);
+        return FALSE;
+    }
+    if (write(temp_file_handle, text, strlen(text)) != strlen(text)) {
+        message = g_strdup_printf("Short write to temporary file: %s",
+            strerror(errno));
+        give_feedback(message);
+        g_free(value);
+        g_free(message);
+        g_free(text);
+        return FALSE;
+	}
+	close(temp_file_handle);
+    g_free(text);
+
+    /* spawn editor */
+    edit_url = g_strdup_printf("vimprobableedit:%s", temp_file_name);
+    success = open_handler_pid(edit_url, &child_pid);
+    g_free(edit_url);
+    if (!success) {
+        give_feedback("External editor open failed (no handler for"
+            " vimprobableedit protocol?)");
+        unlink(temp_file_name);
+        g_free(value);
+        g_free(message);
+        return FALSE;
+    }
+    
+    /* Wait for the child to exit */
+    /* TODO: use g_child_watch_add and make the rest a callback */
+    while (waitpid(child_pid, &child_status, 0)) {
+        if (errno!=EINTR) {
+            break;
+        }
+    }
+    g_spawn_close_pid (child_pid);
+
+    if (child_status) {
+        give_feedback("External editor returned with non-zero status,"
+            " discarding edits.");
+        unlink(temp_file_name);
+        g_free(value);
+        g_free(message);
+        return FALSE;
+    }
+
+    /* re-read the new contents of the file and put it into the HTML element */
+    if (!access(temp_file_name, R_OK) == 0) {
+        g_free(value);
+        g_free(message);
+        return FALSE;
+    }
+    fp = fopen(temp_file_name, "r");
+    if (fp == NULL) {
+        g_free(value);
+        g_free(message);
+        return FALSE;
+    }
+    jsapi_evaluate_script("document.activeElement.value = '';", &value, &message);
+    new_text = g_string_append(new_text, "\"");
+    while (fgets(s, 254, fp)) {
+        if (s[strlen(s)-1] == '\n') {
+            /* encode line breaks into the string as Javascript does not like actual line breaks */
+            new_text = g_string_append_len(new_text, s, strlen(s) - 1);
+            new_text = g_string_append(new_text, "\\n");
+        } else {
+            new_text = g_string_append(new_text, s);
+        }
+    }
+    new_text = g_string_append(new_text, "\"");
+    fclose(fp);
+    jsapi_evaluate_script(g_strconcat("document.activeElement.value = ", new_text->str, ";", NULL), &value, &message);
+
+    /* done */
+    g_string_free(new_text, TRUE);
+    g_free(value);
+    g_free(message);
+    g_free(tag);
+    unlink(temp_file_name);
+    return TRUE;
+}
+
 static gboolean
 focus_input(const Arg *arg) {
     static Arg a;
diff --git a/utilities.c b/utilities.c
index 6ee63d1..fcef30b 100644
--- a/utilities.c
+++ b/utilities.c
@@ -795,13 +795,22 @@ void make_uri_handlers_list(URIHandler *uri_handlers, int length)
     }
 }
 
+
+/* spawn a child process handling a protocol encoded in URI.
+
+On success, pid will contain the pid of the spawned child.
+If you pass NULL as child_pid, glib will reap the child. */
 gboolean
-open_handler(char *uri) {
+open_handler_pid(char *uri, GPid *child_pid) {
     char *argv[64];
     char *p = NULL, *arg, arg_temp[MAX_SETTING_SIZE], *temp, temp2[MAX_SETTING_SIZE] = "", *temp3;
     int j;
     GList *l;
+    GSpawnFlags flags = G_SPAWN_SEARCH_PATH; 
 
+    if (child_pid) {
+        flags |= G_SPAWN_DO_NOT_REAP_CHILD;
+    }
     p = strchr(uri, ':');
     if (p) {
     	if (dynamic_uri_handlers != NULL) {
@@ -821,7 +830,7 @@ open_handler(char *uri) {
                                 	strncat(arg_temp, temp3, 1);
                                 	temp3++;
                             	}
-                            	strcat(arg_temp, arg);
+                            	strcat(arg_temp, arg+1);
                             	temp3++;
                             	temp3++;
                             	strcat(arg_temp, temp3);
@@ -833,7 +842,8 @@ open_handler(char *uri) {
                         	j++;
                     	}
                     	argv[j] =  NULL;
-                    	g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
+                    	g_spawn_async(NULL, argv, NULL, flags,
+                    	    NULL, NULL, child_pid, NULL);
                 	}
                 	return TRUE;
             	}
@@ -843,3 +853,8 @@ open_handler(char *uri) {
     return FALSE;
 }
 
+
+gboolean
+open_handler(char *uri) {
+	return open_handler_pid(uri, NULL);
+}
diff --git a/utilities.h b/utilities.h
index f9ac1ba..3b532d2 100644
--- a/utilities.h
+++ b/utilities.h
@@ -35,4 +35,4 @@ char *find_uri_for_searchengine(const char *handle);
 void make_searchengines_list(Searchengine *searchengines, int length);
 void make_uri_handlers_list(URIHandler *uri_handlers, int length);
 gboolean open_handler(char *uri);
-
+gboolean open_handler_pid(char *uri, GPid *child_pid);
diff --git a/vimprobable.h b/vimprobable.h
index 5a6c2df..e2c647e 100644
--- a/vimprobable.h
+++ b/vimprobable.h
@@ -181,6 +181,9 @@ enum ConfigFileError {
 #define             HISTORY_STORAGE_FILENAME    "%s/vimprobable/history", config_base
 #define             CLOSED_URL_FILENAME         "%s/vimprobable/closed", config_base
 
+/* external editor - temporary file */
+#define             TEMPFILE                    "/tmp/vimprobable_edit"
+
 /* Command size */
 #define	            COMMANDSIZE	                1024
 
------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://ad.doubleclick.net/clk;258768047;13503038;j?
http://info.appdynamics.com/FreeJavaPerformanceDownload.html
_______________________________________________
Vimprobable-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/vimprobable-users

Reply via email to