Thread: [Vimprobable-users] view the HTML source with an external editor?
Vimprobable is a lean web browser optimised for full keyboard control
Brought to you by:
hanness
From: Marcos C. <vim...@pr...> - 2014-04-20 16:33:07
|
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 |
From: Matthew C. <je...@gm...> - 2014-05-02 18:27:42
Attachments:
esource.patch
|
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 > Vim...@li... > https://lists.sourceforge.net/lists/listinfo/vimprobable-users -- Matthew Carter je...@gm... |
From: Matthew C. <je...@gm...> - 2014-05-02 18:31:44
|
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 > > Vim...@li... > > https://lists.sourceforge.net/lists/listinfo/vimprobable-users > > -- > Matthew Carter > je...@gm... > 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 je...@gm... |
From: Marcos C. <vim...@pr...> - 2014-05-09 19:02:41
|
En/Je/On 2014-05-02 14:31, Matthew Carter escribió / skribis / wrote : > this could probably be updated to actually copy the full page source That would be nice. Then the whole page could be saved without the need to add <html> and </html> manually. But it's not a big problem. > but still excludes the doctype :( No top level that includes the whole? Not a big problem anyway. -- Marcos Cruz http://programandala.net |
From: Hannes S. <ha...@yl...> - 2014-05-03 07:36:07
|
That is amazing, thank you, Matt! I will definitely merge this after some testing. Hannes |
From: Matthew C. <je...@gm...> - 2014-05-03 15:39:31
|
Hi Hannes, Thanks, it works on most sites, sites that rely very heavily on javascript (such as the homepage of duckduckgo and google) both seem to fail if editing the source (when the page resumes it locks up) - if just viewin the source and not modifying it, it seems to resume alright. Reddit.com, slashdot.org and my site, ahungry.com have no issues with modifying the source and updating the page on the fly from what I've seen so far. -Matt On Sat, May 03, 2014 at 09:08:13AM +0200, Hannes Schüller wrote: > That is amazing, thank you, Matt! I will definitely merge this after > some testing. > > Hannes > > ------------------------------------------------------------------------------ > "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 > Vim...@li... > https://lists.sourceforge.net/lists/listinfo/vimprobable-users -- Matthew Carter je...@gm... |
From: Marcos C. <vim...@pr...> - 2014-05-09 14:51:39
|
En/Je/On 2014-05-03 11:39, Matthew Carter escribió / skribis / wrote : > sites that rely very heavily on javascript (such as the homepage of > duckduckgo and google) By the way, just in case anybody is interested, there's a HTML version of the DuckDuckGo homepage. From my <.vimprobablerc>: : DuckDuckGo: : HTML version shortcut dd https://duckduckgo.com/html/?q=%s&t=vimprobable : Javascript version shortcut ddj https://duckduckgo.com/?q=%s&t=vimprobable -- Marcos Cruz http://programandala.net |
From: Marcos C. <vim...@pr...> - 2014-05-09 15:10:19
|
En/Je/On 2014-05-02 14:27, Matthew Carter escribió / skribis / wrote : > Attached is a patch to do what Marcos described, Thank you Matthew. I'll try it ASAP. Sorry for the delay. Ten days ago my SSD suddenly died. I've lost no data, because I do several backups every day, but it has been long to find a proper replacement and to install and configure everything back. Still finishing. > 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. Great! You've read my mind :) I was going to suggest that feature too, as a second step. -- Marcos Cruz http://programandala.net |
From: Marcos C. <vim...@pr...> - 2014-05-09 19:29:10
|
I patched 1.4.2. It works great, Matthew. And Vim starts much faster than the internal viewer. It's a very useful feature. But after editing the HTML and quitting, the browser doesn't show the changes. Am I missing something? Also, with the patched version I get an error in the config file, but no line is specified. After commenting out blocks of lines, I've discovered the line that causes the error (no matter its position in the file): map _=pgzo But this one causes no error: map *=pgzi Does it happen to anyone else? Finally, I have a little suggestion: Is it possible to add the ".html" extension to the temporary file name? This way the syntax highlighting would work out of the box. Thank you. -- Marcos Cruz http://programandala.net |
From: Hannes S. <ha...@yl...> - 2014-05-11 22:14:13
|
On Fri, 9 May 2014 16:51:16 +0200, Marcos Cruz <vim...@pr...> wrote: > En/Je/On 2014-05-03 11:39, Matthew Carter escribió / skribis / wrote : > > sites that rely very heavily on javascript (such as the homepage of > > duckduckgo and google) > > By the way, just in case anybody is interested, there's a HTML version > of the DuckDuckGo homepage. From my <.vimprobablerc>: > > : DuckDuckGo: > : HTML version > shortcut dd https://duckduckgo.com/html/?q=%s&t=vimprobable > : Javascript version > shortcut ddj https://duckduckgo.com/?q=%s&t=vimprobable Both of these are in the default configuration (as d and dd) as well :) Hannes |
From: Marcos C. <vim...@pr...> - 2014-05-12 13:13:30
|
En/Je/On 2014-05-12 00:13, Hannes Schüller escribió / skribis / wrote : > > shortcut dd https://duckduckgo.com/html/?q=%s&t=vimprobable > > shortcut ddj https://duckduckgo.com/?q=%s&t=vimprobable > Both of these are in the default configuration (as d and dd) as well :) Oops :D -- Marcos Cruz http://programandala.net |
From: Matthew C. <je...@gm...> - 2014-05-30 19:19:40
Attachments:
esource-and-quickmark.patch
|
Hi all, Too lazy to split my patches, but the updated esource-and-quickmark.patch file includes the external source editor patch as well as a small update I added for my own use, to allow key binds like: Q1 To open quickmark #1 in a new tab/window (I often found myself pressing gH to get a new tab open, and then q1 immediately after to go to the quickmark I wanted). Also, please excuse the patched lines which are just whitespace removal at the end of said line (new emacs config option I'm using prunes extraneous white space at the end of lines :) ) Thanks, -Matt On Mon, May 12, 2014 at 02:46:32PM +0200, Marcos Cruz wrote: > En/Je/On 2014-05-12 00:13, Hannes Schüller escribió / skribis / wrote : > > > > shortcut dd https://duckduckgo.com/html/?q=%s&t=vimprobable > > > shortcut ddj https://duckduckgo.com/?q=%s&t=vimprobable > > > Both of these are in the default configuration (as d and dd) as well :) > > Oops :D > > -- > Marcos Cruz > http://programandala.net > > ------------------------------------------------------------------------------ > "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 > Vim...@li... > https://lists.sourceforge.net/lists/listinfo/vimprobable-users -- Matthew Carter je...@gm... |
From: Hannes S. <ha...@yl...> - 2014-05-31 08:47:27
|
Hi Matt, thanks for this patch! It may not look like it to you, but I do care about keeping the code history at least a little bit tidy. So please excuse that I will split this large patch into three again before applying them. Hannes |