Add command_spawn_editor() and implement normal_view_source()
authorLeonardo Taccari <iamleot@gmail.com>
Fri, 19 Oct 2018 11:04:41 +0000 (13:04 +0200)
committerLeonardo Taccari <iamleot@gmail.com>
Wed, 24 Oct 2018 22:09:42 +0000 (00:09 +0200)
- Add a command_spawn_editor() to asynchronously spawn editor
- Adjust input_editor_formfiller() to use command_spawn_editor()
- Add support to view the source of the current page via the editor (`gf'
  command).

src/command.c
src/command.h
src/input.c
src/normal.c

index 118881f..344a06d 100644 (file)
 #endif
 #include "command.h"
 #include "history.h"
+#include "util.h"
 #include "main.h"
 
+typedef struct {
+    Client   *c;
+    char     *file;
+    gpointer *data;
+    PostEditFunc func;
+} EditorData;
+
+static void resume_editor(GPid pid, int status, gpointer edata);
+
 /**
  * Start/perform/stop searching in webview.
  *
@@ -260,3 +270,96 @@ gboolean command_queue(Client *c, const Arg *arg)
     return res;
 }
 #endif
+
+/**
+ * Asynchronously spawn editor.
+ *
+ * @posteditfunc: If not NULL posteditfunc is called and the following arguments
+ *                are passed:
+ *                 - const char *text: text contents of the temporary file (or
+ *                                     NULL)
+ *                 - Client *c: current client passed to command_spawn_editor()
+ *                 - gpointer data: pointer that can be used for any local
+ *                                  purposes
+ * @data:         Generic pointer used to pass data to posteditfunc
+ */
+gboolean command_spawn_editor(Client *c, const Arg *arg,
+    PostEditFunc posteditfunc, gpointer data)
+{
+    char **argv = NULL, *file_path = NULL;
+    char *command = NULL;
+    int argc;
+    GPid pid;
+    gboolean success;
+    char *editor_command;
+    GError *error = NULL;
+
+    /* get the editor command */
+    editor_command = GET_CHAR(c, "editor-command");
+    if (!editor_command || !*editor_command) {
+        vb_echo(c, MSG_ERROR, TRUE, "No editor-command configured");
+        return FALSE;
+    }
+
+    /* create a temp file to pass text in/to editor */
+    if (!util_create_tmp_file(arg->s, &file_path)) {
+        goto error;
+    }
+
+    /* spawn editor */
+    command = g_strdup_printf(editor_command, file_path);
+    if (!g_shell_parse_argv(command, &argc, &argv, NULL)) {
+        g_critical("Could not parse editor-command '%s'", command);
+        goto error;
+    }
+
+    success = g_spawn_async(
+        NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+        NULL, NULL, &pid, &error
+    );
+
+    if (!success) {
+        g_warning("Could not spawn editor-command: %s", error->message);
+        g_error_free(error);
+        goto error;
+    }
+    g_strfreev(argv);
+
+    EditorData *ed = g_slice_new0(EditorData);
+    ed->file = file_path;
+    ed->c    = c;
+    ed->data = data;
+    ed->func = posteditfunc;
+
+    g_child_watch_add(pid, resume_editor, ed);
+
+    return TRUE;
+
+error:
+    unlink(file_path);
+    g_free(file_path);
+    g_strfreev(argv);
+    return FALSE;
+}
+
+static void resume_editor(GPid pid, int status, gpointer edata)
+{
+    char *text = NULL;
+    EditorData *ed = edata;
+
+    g_assert(pid);
+    g_assert(ed);
+    g_assert(ed->c);
+    g_assert(ed->file);
+
+    if (ed->func != NULL) {
+        text = util_get_file_contents(ed->file, NULL);
+        ed->func(text, ed->c, ed->data);
+        g_free(text);
+    }
+
+    unlink(ed->file);
+    g_free(ed->file);
+    g_slice_free(EditorData, ed);
+    g_spawn_close_pid(pid);
+}
index c3f8b68..3a49a63 100644 (file)
@@ -43,11 +43,14 @@ enum {
 };
 #endif
 
+typedef void (*PostEditFunc)(const char *, Client *, gpointer);
+
 gboolean command_search(Client *c, const Arg *arg, bool commit);
 gboolean command_yank(Client *c, const Arg *arg, char buf);
 gboolean command_save(Client *c, const Arg *arg);
 #ifdef FEATURE_QUEUE
 gboolean command_queue(Client *c, const Arg *arg);
 #endif
+gboolean command_spawn_editor(Client *c, const Arg *arg, PostEditFunc posteditfunc, gpointer data);
 
 #endif /* end of include guard: _COMMAND_H */
index ac6db07..56e2676 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 
 #include "ascii.h"
+#include "command.h"
 #include "config.h"
 #include "input.h"
 #include "main.h"
 #include "ext-proxy.h"
 
 typedef struct {
-    Client *c;
-    char   *file;
     char   *element_id;
     unsigned long element_map_key;
-} EditorData;
+} ElementEditorData;
 
-static void resume_editor(GPid pid, int status, EditorData *data);
+static void input_editor_formfiller(const char *text, Client *c, gpointer data);
 
 /**
  * Function called when vimb enters the input mode.
@@ -111,25 +110,15 @@ VbResult input_keypress(Client *c, int key)
 VbResult input_open_editor(Client *c)
 {
     static unsigned long element_map_key = 0;
-    char *element_id = NULL, *command = NULL;
-    char **argv = NULL, *file_path = NULL;
-    const char *text = NULL, *id = NULL, *editor_command;
-    int argc;
-    GPid pid;
+    char *element_id = NULL;
+    char *text = NULL, *id = NULL;
     gboolean success;
     GVariant *jsreturn;
     GVariant *idreturn;
-    GError *error = NULL;
+    ElementEditorData *data = NULL;
 
     g_assert(c);
 
-    /* get the editor command */
-    editor_command = GET_CHAR(c, "editor-command");
-    if (!editor_command || !*editor_command) {
-        vb_echo(c, MSG_ERROR, TRUE, "No editor-command configured");
-        return RESULT_ERROR;
-    }
-
     /* get the selected input element */
     jsreturn = ext_proxy_eval_script_sync(c, "vimb_input_mode_element.value");
     g_variant_get(jsreturn, "(bs)", &success, &text);
@@ -150,96 +139,54 @@ VbResult input_open_editor(Client *c)
         element_id = g_strdup(id);
     }
 
-    /* create a temp file to pass text to and from editor */
-    if (!util_create_tmp_file(text, &file_path)) {
-        goto error;
-    }
-
-    /* spawn editor */
-    command = g_strdup_printf(editor_command, file_path);
-    if (!g_shell_parse_argv(command, &argc, &argv, NULL)) {
-        g_critical("Could not parse editor-command '%s'", command);
-        goto error;
-    }
+    data                    = g_slice_new0(ElementEditorData);
+    data->element_id        = element_id;
+    data->element_map_key   = element_map_key;
 
-    success = g_spawn_async(
-        NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
-        NULL, NULL, &pid, &error
-    );
+    if (command_spawn_editor(c, &((Arg){0, text}), input_editor_formfiller, data)) {
+        /* disable the active element */
+        ext_proxy_lock_input(c, element_id);
 
-    if (!success) {
-        g_warning("Could not spawn editor-command: %s", error->message);
-        g_error_free(error);
-        goto error;
+        return RESULT_COMPLETE;
     }
-    g_strfreev(argv);
-
-    /* disable the active element */
-    ext_proxy_lock_input(c, element_id);
-
-    /* watch the editor process */
-    EditorData *data = g_slice_new0(EditorData);
-    data->file            = file_path;
-    data->c               = c;
-    data->element_id      = element_id;
-    data->element_map_key = element_map_key;
 
-    g_child_watch_add(pid, (GChildWatchFunc)resume_editor, data);
-
-    return RESULT_COMPLETE;
-
-error:
-    unlink(file_path);
-    g_free(file_path);
-    g_strfreev(argv);
     g_free(element_id);
+    g_slice_free(ElementEditorData, data);
     return RESULT_ERROR;
 }
 
-static void resume_editor(GPid pid, int status, EditorData *data)
+static void input_editor_formfiller(const char *text, Client *c, gpointer data)
 {
-    char *text, *escaped;
+    char *escaped;
     char *jscode;
     char *jscode_enable;
+    ElementEditorData *eed = (ElementEditorData *)data;
 
-    g_assert(pid);
-    g_assert(data);
-    g_assert(data->c);
-    g_assert(data->file);
-
-    if (status == 0) {
-        /* get the text the editor stored */
-        text = util_get_file_contents(data->file, NULL);
-
-        if (text) {
-            escaped = util_strescape(text, NULL);
+    if (text) {
+        escaped = util_strescape(text, NULL);
 
-            /* put the text back into the element */
-            if (data->element_id && strlen(data->element_id) > 0) {
-                jscode = g_strdup_printf("document.getElementById(\"%s\").value=\"%s\"", data->element_id, escaped);
-            } else {
-                jscode = g_strdup_printf("vimb_editor_map.get(\"%lu\").value=\"%s\"", data->element_map_key, escaped);
-            }
+        /* put the text back into the element */
+        if (eed->element_id && strlen(eed->element_id) > 0) {
+            jscode = g_strdup_printf("document.getElementById(\"%s\").value=\"%s\"", eed->element_id, escaped);
+        } else {
+            jscode = g_strdup_printf("vimb_editor_map.get(\"%lu\").value=\"%s\"", eed->element_map_key, escaped);
+        }
 
-            ext_proxy_eval_script(data->c, jscode, NULL);
+        ext_proxy_eval_script(c, jscode, NULL);
 
-            g_free(jscode);
-            g_free(escaped);
-            g_free(text);
-        }
+        g_free(jscode);
+        g_free(escaped);
     }
 
-    if (data->element_id && strlen(data->element_id) > 0) {
-        ext_proxy_unlock_input(data->c, data->element_id);
+    if (eed->element_id && strlen(eed->element_id) > 0) {
+        ext_proxy_unlock_input(c, eed->element_id);
     } else {
         jscode_enable = g_strdup_printf(JS_FOCUS_EDITOR_MAP_ELEMENT,
-                data->element_map_key, data->element_map_key);
-        ext_proxy_eval_script(data->c, jscode_enable, NULL);
+                eed->element_map_key, eed->element_map_key);
+        ext_proxy_eval_script(c, jscode_enable, NULL);
         g_free(jscode_enable);
     }
-    g_unlink(data->file);
-    g_free(data->file);
-    g_free(data->element_id);
-    g_slice_free(EditorData, data);
-    g_spawn_close_pid(pid);
+
+    g_free(eed->element_id);
+    g_slice_free(ElementEditorData, eed);
 }
index 02ba27b..689bf1b 100644 (file)
@@ -74,6 +74,7 @@ static VbResult normal_search(Client *c, const NormalCmdInfo *info);
 static VbResult normal_search_selection(Client *c, const NormalCmdInfo *info);
 static VbResult normal_view_inspector(Client *c, const NormalCmdInfo *info);
 static VbResult normal_view_source(Client *c, const NormalCmdInfo *info);
+static void normal_view_source_loaded(WebKitWebResource *resource, GAsyncResult *res, Client *c);
 static VbResult normal_yank(Client *c, const NormalCmdInfo *info);
 static VbResult normal_zoom(Client *c, const NormalCmdInfo *info);
 
@@ -446,7 +447,7 @@ static VbResult normal_g_cmd(Client *c, const NormalCmdInfo *info)
             return normal_view_inspector(c, info);
 
         case 'f':
-            normal_view_source(c, info);
+            return normal_view_source(c, info);
 
         case 'g':
             return normal_scroll(c, info);
@@ -743,10 +744,29 @@ static VbResult normal_view_inspector(Client *c, const NormalCmdInfo *info)
 
 static VbResult normal_view_source(Client *c, const NormalCmdInfo *info)
 {
-    /* TODO the source mode isn't supported anymore use external editor for this */
+    WebKitWebResource *resource;
+
+    if ((resource = webkit_web_view_get_main_resource(c->webview)) == NULL) {
+        return RESULT_ERROR;
+    }
+
+    webkit_web_resource_get_data(resource, NULL,
+       (GAsyncReadyCallback)normal_view_source_loaded, c);
+
     return RESULT_COMPLETE;
 }
 
+static void normal_view_source_loaded(WebKitWebResource *resource,
+    GAsyncResult *res, Client *c)
+{
+    gsize length;
+    guchar *text = NULL;
+
+    text = webkit_web_resource_get_data_finish(resource, res, &length, NULL);
+    command_spawn_editor(c, &((Arg){0, (char *)text}), NULL, NULL);
+    g_free(text);
+}
+
 static VbResult normal_yank(Client *c, const NormalCmdInfo *info)
 {
     Arg a = {info->key == 'Y' ? COMMAND_YANK_SELECTION : COMMAND_YANK_URI};