summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/command.c87
-rw-r--r--src/command.h1
-rw-r--r--src/config.h2
-rw-r--r--src/dom.c33
-rw-r--r--src/dom.h16
-rw-r--r--src/main.h1
-rw-r--r--src/searchengine.c20
-rw-r--r--src/setting.c18
-rw-r--r--src/util.c55
-rw-r--r--src/util.h2
10 files changed, 212 insertions, 23 deletions
diff --git a/src/command.c b/src/command.c
index cdfb389..48cf36c 100644
--- a/src/command.c
+++ b/src/command.c
@@ -29,6 +29,13 @@
#include "bookmark.h"
#include "dom.h"
+typedef struct {
+ char *file;
+ Element *element;
+} OpenEditorData;
+
+static void editor_resume(GPid pid, int status, OpenEditorData *data);
+
extern VbCore vb;
extern const unsigned int INPUT_LENGTH;
@@ -102,6 +109,7 @@ static CommandInfo cmd_list[] = {
{"run", command_run_multi, {0}},
{"bookmark-add", command_bookmark, {1}},
{"eval", command_eval, {0}},
+ {"editor", command_editor, {0}},
};
@@ -628,3 +636,82 @@ gboolean command_eval(const Arg *arg)
return success;
}
+
+gboolean command_editor(const Arg *arg)
+{
+ char *file_path = NULL;
+ const char *text;
+ char **argv;
+ int argc;
+ GPid pid;
+ gboolean success;
+
+ if (!vb.config.editor_command) {
+ vb_echo(VB_MSG_ERROR, true, "No editor-command configured");
+ return false;
+ }
+ Element* active = dom_get_active_element(vb.gui.webview);
+
+ /* check if element is suitable for editing */
+ if (!active || !dom_is_editable(active)) {
+ return false;
+ }
+
+ text = dom_editable_element_get_value(active);
+ if (!text) {
+ return false;
+ }
+
+ if (!util_create_tmp_file(text, &file_path)) {
+ return false;
+ }
+
+ /* spawn editor */
+ char* command = g_strdup_printf(vb.config.editor_command, file_path);
+ if (!g_shell_parse_argv(command, &argc, &argv, NULL)) {
+ fprintf(stderr, "Could not parse editor-command");
+ g_free(command);
+ return false;
+ }
+ g_free(command);
+
+ success = g_spawn_async(
+ NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, &pid, NULL
+ );
+ g_strfreev(argv);
+
+ if (!success) {
+ unlink(file_path);
+ g_free(file_path);
+ return false;
+ }
+
+ /* disable the active element */
+ dom_editable_element_set_disable(active, true);
+
+ OpenEditorData *data = g_new0(OpenEditorData, 1);
+ data->file = file_path;
+ data->element = active;
+
+ g_child_watch_add(pid, (GChildWatchFunc)editor_resume, data);
+
+ return true;
+}
+
+static void editor_resume(GPid pid, int status, OpenEditorData *data)
+{
+ char *text;
+ if (status == 0) {
+ text = util_get_file_contents(data->file, NULL);
+ if (text) {
+ dom_editable_element_set_value(data->element, text);
+ }
+ g_free(text);
+ }
+ dom_editable_element_set_disable(data->element, false);
+
+ g_free(data->file);
+ g_free(data);
+ g_spawn_close_pid(pid);
+}
diff --git a/src/command.h b/src/command.h
index 8b81d17..a526e03 100644
--- a/src/command.h
+++ b/src/command.h
@@ -75,5 +75,6 @@ gboolean command_zoom(const Arg *arg);
gboolean command_history(const Arg *arg);
gboolean command_bookmark(const Arg *arg);
gboolean command_eval(const Arg *arg);
+gboolean command_editor(const Arg *arg);
#endif /* end of include guard: _COMMAND_H */
diff --git a/src/config.h b/src/config.h
index d6e0e16..325cf2c 100644
--- a/src/config.h
+++ b/src/config.h
@@ -92,6 +92,7 @@ const char *default_config[] = {
"cmap <down>=hist-next",
"hmap <tab>=hint-focus-next",
"hmap <shift-tab>=hint-focus-prev",
+ "imap <ctrl-t>=editor",
"searchengine-add dl=https://duckduckgo.com/lite/?q=%s",
"searchengine-add dd=https://duckduckgo.com/?q=%s",
"searchengine-default dl",
@@ -148,6 +149,7 @@ const char *default_config[] = {
"set home-page=https://github.com/fanglingsu/vimb",
"set download-path=/tmp/vimb",
"set history-max-items=2000",
+ "set editor-command=x-terminal-emulator -e vi %s",
NULL
};
diff --git a/src/dom.c b/src/dom.c
index 9ded553..3c49b30 100644
--- a/src/dom.c
+++ b/src/dom.c
@@ -93,6 +93,39 @@ Element *dom_get_active_element(WebKitWebView *view)
return get_active_element(webkit_web_view_get_dom_document(view));
}
+const char *dom_editable_element_get_value(Element *element)
+{
+ const char *value = NULL;
+
+ if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT((HtmlInputElement*)element)) {
+ value = webkit_dom_html_input_element_get_value((HtmlInputElement*)element);
+ } else {
+ /* we should check WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT, but this
+ * seems to return alway false */
+ value = webkit_dom_html_text_area_element_get_value((HtmlTextareaElement*)element);
+ }
+
+ return value;
+}
+
+void dom_editable_element_set_value(Element *element, const char *value)
+{
+ if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(element)) {
+ webkit_dom_html_input_element_set_value((HtmlInputElement*)element, value);
+ } else {
+ webkit_dom_html_text_area_element_set_value((HtmlTextareaElement*)element, value);
+ }
+}
+
+void dom_editable_element_set_disable(Element *element, gboolean value)
+{
+ if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(element)) {
+ webkit_dom_html_input_element_set_disabled((HtmlInputElement*)element, value);
+ } else {
+ webkit_dom_html_text_area_element_set_disabled((HtmlTextareaElement*)element, value);
+ }
+}
+
static gboolean auto_insert(Element *element)
{
if (dom_is_editable(element)) {
diff --git a/src/dom.h b/src/dom.h
index 18f9388..0c99b45 100644
--- a/src/dom.h
+++ b/src/dom.h
@@ -23,11 +23,14 @@
#include <webkit/webkit.h>
// Types
-#define Document WebKitDOMDocument
-#define HtmlElement WebKitDOMHTMLElement
-#define Element WebKitDOMElement
-#define Event WebKitDOMEvent
-#define EventTarget WebKitDOMEventTarget
+#define Document WebKitDOMDocument
+#define HtmlElement WebKitDOMHTMLElement
+#define Element WebKitDOMElement
+#define Node WebKitDOMNode
+#define Event WebKitDOMEvent
+#define EventTarget WebKitDOMEventTarget
+#define HtmlInputElement WebKitDOMHTMLInputElement
+#define HtmlTextareaElement WebKitDOMHTMLTextAreaElement
// style
#define style_compare_property(style, name, value) (!strcmp(webkit_dom_css_style_declaration_get_property_value(style, name), value))
@@ -43,5 +46,8 @@ void dom_check_auto_insert(WebKitWebView *view);
void dom_clear_focus(WebKitWebView *view);
gboolean dom_is_editable(Element *element);
Element *dom_get_active_element(WebKitWebView *view);
+const char *dom_editable_element_get_value(Element *element);
+void dom_editable_element_set_value(Element *element, const char *value);
+void dom_editable_element_set_disable(Element *element, gboolean value);
#endif /* end of include guard: _DOM_H */
diff --git a/src/main.h b/src/main.h
index 97f400e..7a644f1 100644
--- a/src/main.h
+++ b/src/main.h
@@ -257,6 +257,7 @@ typedef struct {
char *home_page;
char *download_dir;
guint history_max;
+ char *editor_command;
} Config;
typedef struct {
diff --git a/src/searchengine.c b/src/searchengine.c
index e693df6..0724dd6 100644
--- a/src/searchengine.c
+++ b/src/searchengine.c
@@ -19,6 +19,7 @@
#include "main.h"
#include "searchengine.h"
+#include "util.h"
extern VbCore vb;
@@ -31,7 +32,6 @@ static GSList *searchengines;
static char *default_handle = NULL;
static GSList *find(const char *handle);
-static gboolean is_valid_uri(const char *uri);
static void free_searchengine(Searchengine *se);
@@ -45,7 +45,7 @@ void searchengine_cleanup(void)
gboolean searchengine_add(const char *handle, const char *uri)
{
/* validate if the uri contains only one %s sequence */
- if (!is_valid_uri(uri)) {
+ if (!util_valid_format_string(uri, 's', 1)) {
return false;
}
Searchengine *s = g_new0(Searchengine, 1);
@@ -128,22 +128,6 @@ static GSList *find(const char *handle)
return NULL;
}
-static gboolean is_valid_uri(const char *uri)
-{
- int count = 0;
-
- for (; *uri; uri++) {
- if (*uri == '%') {
- uri++;
- if (*uri == 's') {
- count++;
- }
- }
- }
-
- return count == 1;
-}
-
static void free_searchengine(Searchengine *se)
{
g_free(se->uri);
diff --git a/src/setting.c b/src/setting.c
index 8ed1886..671470d 100644
--- a/src/setting.c
+++ b/src/setting.c
@@ -42,6 +42,7 @@ static gboolean download_path(const Setting *s, const SettingType type);
static gboolean proxy(const Setting *s, const SettingType type);
static gboolean user_style(const Setting *s, const SettingType type);
static gboolean history_max_items(const Setting *s, const SettingType type);
+static gboolean editor_command(const Setting *s, const SettingType type);
static Setting default_settings[] = {
/* webkit settings */
@@ -103,6 +104,7 @@ static Setting default_settings[] = {
{NULL, "home-page", TYPE_CHAR, home_page, {0}},
{NULL, "download-path", TYPE_CHAR, download_path, {0}},
{NULL, "history-max-items", TYPE_INTEGER, history_max_items, {0}},
+ {NULL, "editor-command", TYPE_CHAR, editor_command, {0}},
};
void setting_init(void)
@@ -691,3 +693,19 @@ static gboolean history_max_items(const Setting *s, const SettingType type)
return true;
}
+
+static gboolean editor_command(const Setting *s, const SettingType type)
+{
+ if (type == SETTING_GET) {
+ print_value(s, vb.config.editor_command);
+
+ return true;
+ }
+
+ if (!util_valid_format_string(s->arg.s, 's', 1)) {
+ return false;
+ }
+ OVERWRITE_STRING(vb.config.editor_command, s->arg.s);
+
+ return true;
+}
diff --git a/src/util.c b/src/util.c
index ca09c9a..ba5af22 100644
--- a/src/util.c
+++ b/src/util.c
@@ -119,3 +119,58 @@ next:
}
return NULL;
}
+
+/**
+ * Checks if given printf style format string is valid. That means that it
+ * contains only one defined placeholder given as char.
+ */
+gboolean util_valid_format_string(const char *format, char type, unsigned int count)
+{
+ unsigned int c;
+ for (c = 0; *format; format++) {
+ if (*format == '%') {
+ format++;
+ if (*format == type) {
+ c++;
+ }
+ }
+ }
+
+ return c == count;
+}
+
+/**
+ * Creates a temporary file with given content.
+ *
+ * Upon success, and if file is non-NULL, the actual file path used is
+ * returned in file. This string should be freed with g_free() when not
+ * needed any longer.
+ */
+gboolean util_create_tmp_file(const char *content, char **file)
+{
+ int fp;
+ ssize_t bytes, len;
+
+ fp = g_file_open_tmp(PROJECT "-XXXXXX", file, NULL);
+ if (fp == -1) {
+ fprintf(stderr, "Could not create temporary file %s", *file);
+ g_free(*file);
+ return false;
+ }
+
+ len = strlen(content);
+
+ /* write content into temporary file */
+ bytes = write(fp, content, len);
+ if (bytes < len) {
+ close(fp);
+ unlink(*file);
+ fprintf(stderr, "Could not write temporary file %s", *file);
+ g_free(*file);
+
+ return false;
+ }
+ close(fp);
+
+ return true;
+}
diff --git a/src/util.h b/src/util.h
index 5a52031..8255b30 100644
--- a/src/util.h
+++ b/src/util.h
@@ -30,5 +30,7 @@ void util_create_file_if_not_exists(const char* filename);
char* util_get_file_contents(const char* filename, gsize* length);
char** util_get_lines(const char* filename);
char* util_strcasestr(const char* haystack, const char* needle);
+gboolean util_valid_format_string(const char *format, char type, unsigned int count);
+gboolean util_create_tmp_file(const char *content, char **file);
#endif /* end of include guard: _UTIL_H */