Re: [Vimprobable-users] Editor patch evolution
Vimprobable is a lean web browser optimised for full keyboard control
Brought to you by:
hanness
|
From: Serge E. H. <se...@ha...> - 2012-10-05 14:46:59
|
Quoting Markus Demleitner (msd...@ar...):
> Hi,
>
> During a longish train ride today, I polished up the editor patch a
> bit. For one, the editor now runs asynchronously, so vimprobable
> doesn't just sit there as long as the editor runs. To keep people
> from futzing around in the original text field, it is now grayed out
> while the editor is active.
>
> I've also fixed the editing behaviour in the presence of " characters
> in the content. I'm not quite happy with this, though -- javascript
> escaping must be more complex than this. Can anyone point to a
> comprehensive and authoritative answer as to how javascript expects
> its string liteals?
>
> Attached are two patches; one should apply on top of the patch
> yesterday, the other should apply on a clean 1.1.1 release.
>
> Any feedback is welcome. Is there anyone I should my git
> format-patch to assuming people like this?
Hi,
Very nice, thanks!
Do you mind making the directory for the tempfiles configurable? I'm
currently hardcoding it to getenv("HOME")/Downloads rather than using /tmp,
because that is the only directory to which I allow vimprobable and its
children write access. It'd be nice if it could simply be set in
vimprobablerc.
> Cheers,
>
> Markus
> diff --git a/Makefile b/Makefile
> index 7493657..772a30c 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -17,7 +17,7 @@ INSTALL = $(BINDIR)/$(TARGET) $(MANINSTALL)
> # DEBUG build? Off by default
> V_DEBUG = 0
>
> -CFLAGS += `pkg-config --cflags $(LIBS)` -D_XOPEN_SOURCE=500
> +CFLAGS += `pkg-config --cflags $(LIBS)`
> 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 86aea55..7ba5d0b 100644
> --- a/keymap.h
> +++ b/keymap.h
> @@ -114,9 +114,6 @@ 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 36e0edb..b3407ba 100644
> --- a/main.c
> +++ b/main.c
> @@ -11,10 +11,7 @@
> */
>
> #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"
> @@ -64,8 +61,6 @@ 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);
> -void _resume_from_editor(GPid child_pid, int status, gpointer data);
> static gboolean input(const Arg *arg);
> static gboolean navigate(const Arg *arg);
> static gboolean number(const Arg *arg);
> @@ -437,9 +432,6 @@ 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)) {
> @@ -1829,182 +1821,6 @@ 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) {
> - char *text = NULL;
> - gboolean success;
> - GPid child_pid;
> - gchar *value = NULL, *message = NULL, *tag = NULL, *edit_url = NULL;
> - gchar *temp_file_name = g_strdup("/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;
> - }
> -
> - /* mark the active text box as "under processing" */
> - jsapi_evaluate_script(
> - "document.activeElement.disabled = true;"
> - "document.activeElement.originalBackground = "
> - " document.activeElement.style.background;"
> - "document.activeElement.style.background = '#aaaaaa';"
> - ,&value, &message);
> -
> - g_child_watch_add(child_pid, _resume_from_editor, 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.
> -
> -The data argument points to allocated memory containing the temporary file
> -name. */
> -void
> -_resume_from_editor(GPid child_pid, int child_status, gpointer data) {
> - FILE *fp;
> - GString *set_value_js = g_string_new(
> - "document.activeElement.value = \"");
> - 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;
> -
> - jsapi_evaluate_script(
> - "document.activeElement.disabled = true;"
> - "document.activeElement.style.background = '#aaaaaa';"
> - ,&value, &message);
> -
> - if (child_status) {
> - give_feedback("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.activeElement.value = '';",
> - &value, &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);
> -
> - /* Fall through, error and normal exit are identical */
> -error_exit:
> - jsapi_evaluate_script(
> - "document.activeElement.disabled = false;"
> - "document.activeElement.style.background ="
> - " document.activeElement.originalBackground;"
> - ,&value, &message);
> -
> - 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;
> diff --git a/utilities.c b/utilities.c
> index fcef30b..6ee63d1 100644
> --- a/utilities.c
> +++ b/utilities.c
> @@ -795,22 +795,13 @@ 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_pid(char *uri, GPid *child_pid) {
> +open_handler(char *uri) {
> 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) {
> @@ -830,7 +821,7 @@ open_handler_pid(char *uri, GPid *child_pid) {
> strncat(arg_temp, temp3, 1);
> temp3++;
> }
> - strcat(arg_temp, arg+1);
> + strcat(arg_temp, arg);
> temp3++;
> temp3++;
> strcat(arg_temp, temp3);
> @@ -842,8 +833,7 @@ open_handler_pid(char *uri, GPid *child_pid) {
> j++;
> }
> argv[j] = NULL;
> - g_spawn_async(NULL, argv, NULL, flags,
> - NULL, NULL, child_pid, NULL);
> + g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
> }
> return TRUE;
> }
> @@ -853,8 +843,3 @@ open_handler_pid(char *uri, GPid *child_pid) {
> return FALSE;
> }
>
> -
> -gboolean
> -open_handler(char *uri) {
> - return open_handler_pid(uri, NULL);
> -}
> diff --git a/utilities.h b/utilities.h
> index 3b532d2..f9ac1ba 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 f5d3e64..5a6c2df 100644
> --- a/vimprobable.h
> +++ b/vimprobable.h
> @@ -181,9 +181,6 @@ 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
>
> @@ -194,6 +191,3 @@ enum ConfigFileError {
>
> /* completion list size */
> #define MAX_LIST_SIZE 40
> -
> -/* Size of (some) I/O buffers */
> -#define BUF_SIZE 1024
> diff --git a/Makefile b/Makefile
> index fe39667..7493657 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -15,7 +15,7 @@ MANINSTALL = $(addprefix $(MANDIR)/man1/,$(MAN1)) \
> INSTALL = $(BINDIR)/$(TARGET) $(MANINSTALL)
>
> # DEBUG build? Off by default
> -V_DEBUG = 1
> +V_DEBUG = 0
>
> CFLAGS += `pkg-config --cflags $(LIBS)` -D_XOPEN_SOURCE=500
> LDFLAGS += `pkg-config --libs $(LIBS)` -lX11 -lXext
> diff --git a/main.c b/main.c
> index a35e638..5acf509 100644
> --- a/main.c
> +++ b/main.c
> @@ -65,6 +65,7 @@ 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);
> +void _resume_from_editor(GPid child_pid, int status, gpointer data);
> static gboolean input(const Arg *arg);
> static gboolean navigate(const Arg *arg);
> static gboolean number(const Arg *arg);
> @@ -1832,14 +1833,11 @@ view_source(const Arg * arg) {
> vimprobableedit on a text box or similar */
> static gboolean
> open_editor(const Arg *arg) {
> - FILE *fp;
> - char *text = NULL, s[255] = "";
> + char *text = NULL;
> 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";
> + gchar *temp_file_name = g_strdup("/tmp/vimprobableeditXXXXXX");
> int temp_file_handle = -1;
>
> /* check if active element is suitable for text editing */
> @@ -1888,7 +1886,7 @@ open_editor(const Arg *arg) {
> g_free(text);
> return FALSE;
> }
> - close(temp_file_handle);
> + close(temp_file_handle);
> g_free(text);
>
> /* spawn editor */
> @@ -1903,59 +1901,97 @@ open_editor(const Arg *arg) {
> 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);
> +
> + /* mark the active text box as "under processing" */
> + jsapi_evaluate_script(
> + "document.activeElement.disabled = true;"
> + "document.activeElement.originalBackground = "
> + " document.activeElement.style.background;"
> + "document.activeElement.style.background = '#aaaaaa';"
> + ,&value, &message);
> +
> + g_child_watch_add(child_pid, _resume_from_editor, 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.
> +
> +The data argument points to allocated memory containing the temporary file
> +name. */
> +void
> +_resume_from_editor(GPid child_pid, int child_status, gpointer data) {
> + FILE *fp;
> + GString *new_text = g_string_new("");
> + g_spawn_close_pid(child_pid);
> + gchar *value = NULL, *message = NULL;
> + gchar *temp_file_name = data;
> + gchar buffer[255] = "";
> +
> + jsapi_evaluate_script(
> + "document.activeElement.disabled = true;"
> + "document.activeElement.style.background = '#aaaaaa';"
> + ,&value, &message);
>
> 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;
> + 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) {
> - g_free(value);
> - g_free(message);
> - return FALSE;
> + message = g_strdup_printf("Could not access temporary file: %s",
> + strerror(errno));
> + goto error_exit;
> }
> fp = fopen(temp_file_name, "r");
> if (fp == NULL) {
> - g_free(value);
> - g_free(message);
> - return FALSE;
> + /* this would be too weird to even emit an error message */
> + goto error_exit;
> }
> - jsapi_evaluate_script("document.activeElement.value = '';", &value, &message);
> + 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') {
> + while (fgets(buffer, 254, fp)) {
> + if (buffer[strlen(buffer)-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_len(
> + new_text, buffer, strlen(buffer) - 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, buffer);
> }
> }
> new_text = g_string_append(new_text, "\"");
> fclose(fp);
> - jsapi_evaluate_script(g_strconcat("document.activeElement.value = ", new_text->str, ";", NULL), &value, &message);
> + /* FIXME: Is the memory returned by g_strconcat actually freed? */
> + jsapi_evaluate_script(g_strconcat("document.activeElement.value = ",
> + new_text->str, ";", NULL), &value, &message);
> +
> + /* Fall through, error and normal exit are identical */
> +error_exit:
> + if (new_text) {
> + g_string_free(new_text, TRUE);
> + }
>
> - /* done */
> - g_string_free(new_text, TRUE);
> + jsapi_evaluate_script(
> + "document.activeElement.disabled = false;"
> + "document.activeElement.style.background ="
> + " document.activeElement.originalBackground;"
> + ,&value, &message);
> +
> + unlink(temp_file_name);
> + g_free(temp_file_name);
> g_free(value);
> g_free(message);
> - g_free(tag);
> - unlink(temp_file_name);
> - return TRUE;
> }
>
> static gboolean
> ------------------------------------------------------------------------------
> Got visibility?
> Most devs has no idea what their production app looks like.
> Find out how fast your code is with AppDynamics Lite.
> http://ad.doubleclick.net/clk;262219671;13503038;y?
> http://info.appdynamics.com/FreeJavaPerformanceDownload.html
> _______________________________________________
> Vimprobable-users mailing list
> Vim...@li...
> https://lists.sourceforge.net/lists/listinfo/vimprobable-users
|