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