From: Leonardo Taccari Date: Fri, 19 Oct 2018 11:04:41 +0000 (+0200) Subject: Add command_spawn_editor() and implement normal_view_source() X-Git-Url: https://git.owens.tech///git?a=commitdiff_plain;h=51949de98cba926ff9ae0d08d95ef795612472ec;p=vimb.git Add command_spawn_editor() and implement normal_view_source() - 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). --- diff --git a/src/command.c b/src/command.c index 118881f..344a06d 100644 --- a/src/command.c +++ b/src/command.c @@ -30,8 +30,18 @@ #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); +} diff --git a/src/command.h b/src/command.h index c3f8b68..3a49a63 100644 --- a/src/command.h +++ b/src/command.h @@ -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 */ diff --git a/src/input.c b/src/input.c index ac6db07..56e2676 100644 --- a/src/input.c +++ b/src/input.c @@ -22,6 +22,7 @@ #include #include "ascii.h" +#include "command.h" #include "config.h" #include "input.h" #include "main.h" @@ -31,13 +32,11 @@ #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); } diff --git a/src/normal.c b/src/normal.c index 02ba27b..689bf1b 100644 --- a/src/normal.c +++ b/src/normal.c @@ -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};