Hi all,

Forgot to add, you can invoke it on a page with ":esource".

If there was a demand for it, this could probably be updated to actually
copy the full page source instead of relying on the jsapi_eval call to
pull the innerHTML (outerHTML is closer but still excludes the doctype)
and resave without the jsapi as well.

-Matt

On Fri, May 02, 2014 at 02:27:29PM -0400, Matthew Carter wrote:
> 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);
>       }
>  


-- 
Matthew Carter
[email protected]

------------------------------------------------------------------------------
"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