Hi all,

Attached is a patch to do what Marcos described, it also lets you edit
the source and upon saving and quitting your editor, it updates the
page's source code to match what you changed.

Uses the same logic and URI handler as the special textarea editor
handling.

It does not include the surrounding <html> tags or the doctype as that
makes it difficult to refresh the browser with what was edited (so
essentially you're getting a view of the
document.documentElement.innerHTML, which you can then change/look
through in your editor of choice).

Thanks,
-Matt

On Sun, Apr 20, 2014 at 03:35:10PM +0200, Marcos Cruz wrote:
> Hi all,
> 
> Sometimes, when I need to examinate the source of a page, I prefer to do
> it with all the power of Vim instead of the internal viewer. So I get
> the page with wget or the Elinks browser and then launch Vim.
> 
> I think currently there's no way to choose an external editor as source
> viewer. Am I right? If so, I suggest this feature.  Would it be
> feasible? Do other Vimprobable users would find it useful?
> 
> -- 
> Marcos Cruz
> http://programandala.net
> 
> ------------------------------------------------------------------------------
> Learn Graph Databases - Download FREE O'Reilly Book
> "Graph Databases" is the definitive new guide to graph databases and their
> applications. Written by three acclaimed leaders in the field,
> this first edition is now available. Download your free book today!
> http://p.sf.net/sfu/NeoTech
> _______________________________________________
> Vimprobable-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/vimprobable-users

-- 
Matthew Carter
[email protected]
diff --git a/config.h b/config.h
index e9d6bba..9b6a7cc 100644
--- a/config.h
+++ b/config.h
@@ -154,6 +154,7 @@ Command commands[COMMANDSIZE] = {
     { "bma",                                           	bookmark,         {0} },
     { "bookmark",                                      	bookmark,         {0} },
     { "source",                                        	view_source,      {0} },
+    { "esource",                                       	edit_source,      {0} },
     { "openeditor",                                   	open_editor,      {0} },
     { "set",                                           	browser_settings, {0} },
     { "map",                                           	mappings,         {0} },
@@ -162,7 +163,7 @@ Command commands[COMMANDSIZE] = {
     { "jumpright",                                      scroll,           {ScrollJumpTo   | DirectionRight} },
     { "jumptop",                                        scroll,           {ScrollJumpTo   | DirectionTop} },
     { "jumpbottom",                                     scroll,           {ScrollJumpTo   | DirectionBottom} },
-    { "pageup",                                         scroll,           {ScrollMove     | DirectionTop      | UnitPage} },	
+    { "pageup",                                         scroll,           {ScrollMove     | DirectionTop      | UnitPage} },
     { "pagedown",                                       scroll,           {ScrollMove     | DirectionBottom   | UnitPage} },
     { "navigationback",   	                            navigate,         {NavigationBack} },
     { "navigationforward",	                            navigate,         {NavigationForward} },
diff --git a/main.c b/main.c
index d70f88a..0c1a4c6 100644
--- a/main.c
+++ b/main.c
@@ -69,7 +69,9 @@ 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 edit_source(const Arg *arg);
 void _resume_from_editor(GPid child_pid, int status, gpointer data);
+void _resume_from_edit_source(GPid child_pid, int status, gpointer data);
 static gboolean input(const Arg *arg);
 static gboolean open_inspector(const Arg * arg);
 static gboolean navigate(const Arg *arg);
@@ -1066,7 +1068,7 @@ static gboolean
 open_inspector(const Arg * arg) {
     gboolean inspect_enabled;
     WebKitWebSettings *settings;
-    State *state = &client.state;    
+    State *state = &client.state;
 
     settings = webkit_web_view_get_settings(client.gui.webview);
     g_object_get(G_OBJECT(settings), "enable-developer-extras", &inspect_enabled, NULL);
@@ -1239,7 +1241,7 @@ open_arg(const Arg *arg) {
         new = NULL;
         /* check for external handlers */
         if (open_handler(s))
-            return TRUE;        
+            return TRUE;
         /* check for search engines */
         p = strchr(s, ' ');
         if (!p) {
@@ -1414,7 +1416,7 @@ revive(const Arg *arg) {
     return FALSE;
 }
 
-static 
+static
 gboolean print_frame(const Arg *arg)
 {
     WebKitWebFrame *frame = webkit_web_view_get_main_frame(client.gui.webview);
@@ -1667,7 +1669,7 @@ zoom(const Arg *arg) {
     return TRUE;
 }
 
-gboolean 
+gboolean
 fake_key_event(const Arg *a) {
     if(!client.state.embed) {
         return FALSE;
@@ -1677,7 +1679,7 @@ fake_key_event(const Arg *a) {
         echo_message(Error, "Couldn't find the XDisplay.");
         return FALSE;
     }
-       
+
     XKeyEvent xk;
     xk.display = xdpy;
     xk.subwindow = None;
@@ -1697,12 +1699,12 @@ fake_key_event(const Arg *a) {
         echo_message(Error, "Couldn't translate %s to keysym", a->s );
         return FALSE;
     }
-    
+
     if( (xk.keycode = XKeysymToKeycode(xdpy, keysym)) == NoSymbol ) {
         echo_message(Error, "Couldn't translate keysym to keycode");
         return FALSE;
     }
-   
+
     xk.type = KeyPress;
     if( !XSendEvent(xdpy, client.state.embed, True, KeyPressMask, (XEvent *)&xk) ) {
         echo_message(Error, "XSendEvent failed");
@@ -1930,7 +1932,7 @@ open_editor(const Arg *arg) {
         g_free(message);
         return FALSE;
     }
-   
+
     /* mark the active text box as "under processing" */
     jsapi_evaluate_script(
         "document.activeElement.disabled = true;"
@@ -1948,14 +1950,79 @@ open_editor(const Arg *arg) {
     return TRUE;
 }
 
+/* open an external editor defined by the protocol handler for
+vimprobableedit on page source */
+static gboolean
+edit_source(const Arg *arg) {
+    char *text = NULL;
+    gboolean success;
+    GPid child_pid;
+    gchar *value = NULL, *message = NULL, *tag = NULL, *edit_url = NULL;
+    gchar *temp_file_name = g_strdup_printf("%s/vimprobableeditXXXXXX",
+      temp_dir);
+    int temp_file_handle = -1;
+
+    jsapi_evaluate_script("document.documentElement.innerHTML", &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));
+        echo_message(Error, 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));
+        echo_message(Error, 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) {
+        echo_message(Error, "External editor open failed (no handler for"
+            " vimprobableedit protocol?)");
+        unlink(temp_file_name);
+        g_free(value);
+        g_free(message);
+        return FALSE;
+    }
+
+    g_child_watch_add(child_pid, _resume_from_edit_source, temp_file_name);
+
+    /* temp_file_name is freed in _resume_from_editor */
+    g_free(value);
+    g_free(message);
+    g_free(tag);
+    return TRUE;
+}
+
 
 /* pick up from where open_editor left the work to the glib event loop.
 
-This is called when the external editor exits. 
+This is called when the external editor exits.
 
 The data argument points to allocated memory containing the temporary file
 name. */
-void 
+void
 _resume_from_editor(GPid child_pid, int child_status, gpointer data) {
     FILE *fp;
     GString *set_value_js = g_string_new(
@@ -1963,7 +2030,7 @@ _resume_from_editor(GPid child_pid, int child_status, gpointer data) {
     g_spawn_close_pid(child_pid);
     gchar *value = NULL, *message = NULL;
     gchar *temp_file_name = data;
-    gchar buffer[BUF_SIZE] = ""; 
+    gchar buffer[BUF_SIZE] = "";
     gchar *buf_ptr = buffer;
     int char_read;
 
@@ -1991,7 +2058,7 @@ _resume_from_editor(GPid child_pid, int child_status, gpointer data) {
         /* this would be too weird to even emit an error message */
         goto error_exit;
     }
-    jsapi_evaluate_script("document.activeElement.value = '';", 
+    jsapi_evaluate_script("document.activeElement.value = '';",
         &value, &message);
     g_free(value);
     g_free(message);
@@ -2038,6 +2105,82 @@ error_exit:
     g_free(message);
 }
 
+/* pick up from where edit_source left the work to the glib event loop.
+
+This is called when the external editor exits.
+
+The data argument points to allocated memory containing the temporary file
+name. */
+void
+_resume_from_edit_source(GPid child_pid, int child_status, gpointer data) {
+    FILE *fp;
+    GString *set_value_js = g_string_new(
+        "document.documentElement.innerHTML = \"");
+    g_spawn_close_pid(child_pid);
+    gchar *value = NULL, *message = NULL;
+    gchar *temp_file_name = data;
+    gchar buffer[BUF_SIZE] = "";
+    gchar *buf_ptr = buffer;
+    int char_read;
+
+    if (child_status) {
+        echo_message(Error, "External editor returned with non-zero status,"
+            " discarding edits.");
+        goto error_exit;
+    }
+
+    /* re-read the new contents of the file and put it into the HTML element */
+    if (!access(temp_file_name, R_OK) == 0) {
+        message = g_strdup_printf("Could not access temporary file: %s",
+            strerror(errno));
+        goto error_exit;
+    }
+    fp = fopen(temp_file_name, "r");
+    if (fp == NULL) {
+        /* this would be too weird to even emit an error message */
+        goto error_exit;
+    }
+    jsapi_evaluate_script("document.documentElement.innerHTML = '';",
+        &value, &message);
+    g_free(value);
+    g_free(message);
+
+    while (EOF != (char_read = fgetc(fp))) {
+        if (char_read == '\n') {
+            *buf_ptr++ = '\\';
+            *buf_ptr++ = 'n';
+        } else if (char_read == '"') {
+            *buf_ptr++ = '\\';
+            *buf_ptr++ = '"';
+        } else {
+            *buf_ptr++ = char_read;
+        }
+        /* ship out as the buffer when space gets tight.  This has
+        fuzz to save on thinking, plus we have enough space for the
+        trailing "; in any case. */
+        if (buf_ptr-buffer>=BUF_SIZE-10) {
+            *buf_ptr = 0;
+            g_string_append(set_value_js, buffer);
+            buf_ptr = buffer;
+        }
+    }
+    *buf_ptr++ = '"';
+    *buf_ptr++ = ';';
+    *buf_ptr = 0;
+    g_string_append(set_value_js, buffer);
+    fclose(fp);
+
+    jsapi_evaluate_script(set_value_js->str, &value, &message);
+
+error_exit:
+
+    g_string_free(set_value_js, TRUE);
+    unlink(temp_file_name);
+    g_free(temp_file_name);
+    g_free(value);
+    g_free(message);
+}
+
 static gboolean
 focus_input(const Arg *arg) {
     static Arg a;
@@ -2199,16 +2342,16 @@ process_set_line(char *line) {
             } else if (strlen(my_pair.what) == 7 && strncmp("cookies", my_pair.what, 7) == 0) {
                 /* cookie policy */
                 if (strncmp(my_pair.value, "on", 2) == 0 || strncmp(my_pair.value, "true", 4) == 0 ||
-                        strncmp(my_pair.value, "ON", 2) == 0 || strncmp(my_pair.value, "TRUE", 4) == 0 || 
+                        strncmp(my_pair.value, "ON", 2) == 0 || strncmp(my_pair.value, "TRUE", 4) == 0 ||
                         strncmp(my_pair.value, "all", 3) == 0 || strncmp(my_pair.value, "ALL", 3) == 0) {
                     CookiePolicy = SOUP_COOKIE_JAR_ACCEPT_ALWAYS;
-                } else if (strncmp(my_pair.value, "off", 3) == 0 || strncmp(my_pair.value, "false", 5) == 0 || 
-                        strncmp(my_pair.value, "OFF", 3) == 0 || strncmp(my_pair.value, "FALSE", 5) == 0 || 
-                        strncmp(my_pair.value, "never", 5) == 0 || strncmp(my_pair.value, "NEVER", 5) == 5 || 
+                } else if (strncmp(my_pair.value, "off", 3) == 0 || strncmp(my_pair.value, "false", 5) == 0 ||
+                        strncmp(my_pair.value, "OFF", 3) == 0 || strncmp(my_pair.value, "FALSE", 5) == 0 ||
+                        strncmp(my_pair.value, "never", 5) == 0 || strncmp(my_pair.value, "NEVER", 5) == 5 ||
                         strncmp(my_pair.value, "none", 4) == 0 || strncmp(my_pair.value, "NONE", 4) == 0) {
                     CookiePolicy = SOUP_COOKIE_JAR_ACCEPT_NEVER;
-                } else if (strncmp(my_pair.value, "origin", 6) == 0 || strncmp(my_pair.value, "ORIGIN", 6) == 0 || 
-                        strncmp(my_pair.value, "no_third", 8) == 0 || strncmp(my_pair.value, "NO_THIRD", 8) == 0 || 
+                } else if (strncmp(my_pair.value, "origin", 6) == 0 || strncmp(my_pair.value, "ORIGIN", 6) == 0 ||
+                        strncmp(my_pair.value, "no_third", 8) == 0 || strncmp(my_pair.value, "NO_THIRD", 8) == 0 ||
                         strncmp(my_pair.value, "no third", 8) == 0 || strncmp(my_pair.value, "NO THIRD", 8) == 0) {
                     CookiePolicy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
                 } else {
@@ -2334,7 +2477,7 @@ search_tag(const Arg * a) {
         t = strlen(s) - 1;
         while (isspace(s[t]))
             t--;
-        if (s[t] != ']') continue;      
+        if (s[t] != ']') continue;
         while (t > 0) {
             if (s[t] == ']') {
                 if (!intag)
@@ -2349,7 +2492,7 @@ search_tag(const Arg * a) {
                         while (k < intag)
                             foundtag[i++] = s[k++];
                         foundtag[i] = '\0';
-                        /* foundtag now contains the tag */	
+                        /* foundtag now contains the tag */
                         if (strlen(foundtag) < MAXTAGSIZE && strcmp(tag, foundtag) == 0) {
                             i = 0;
                             while (isspace(s[i])) i++;
@@ -2798,7 +2941,7 @@ setup_cookies()
  *      is limited to handling cookies.
  */
 void
-new_generic_request(SoupSession *session, SoupMessage *soup_msg, gpointer unused) 
+new_generic_request(SoupSession *session, SoupMessage *soup_msg, gpointer unused)
 {
     SoupMessageHeaders *soup_msg_h;
     SoupURI *uri;
@@ -2840,7 +2983,7 @@ handle_cookie_request(SoupMessage *soup_msg, gpointer unused)
 		{
 			SoupDate *soup_date;
 			cookie = soup_cookie_copy((SoupCookie *)resp_cookie->data);
-	
+
 			if (client.config.cookie_timeout && cookie->expires == NULL) {
 				soup_date = soup_date_new_from_time_t(time(NULL) + client.config.cookie_timeout * 10);
 				soup_cookie_set_expires(cookie, soup_date);
@@ -2856,7 +2999,7 @@ handle_cookie_request(SoupMessage *soup_msg, gpointer unused)
 				soup_cookie_jar_add_cookie(client.net.file_cookie_jar, cookie);
 			}
 		}
-	
+
 		soup_cookies_free(cookie_list);
 	}
 
------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.  Get 
unparalleled scalability from the best Selenium testing platform available.
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
Vimprobable-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/vimprobable-users

Reply via email to