---
config.def.h | 1 +
main.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vis.c | 6 +++-
vis.h | 1 +
4 files changed, 121 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 8699136..9e52102 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -319,6 +319,7 @@ static const KeyBinding bindings_insert[] = {
{ "<C-d>", ALIAS("<Escape><<i") },
{ "<C-i>", ALIAS("<Tab>") },
{ "<C-j>", ALIAS("<Enter>") },
+ { "<C-n>", ACTION(FILE_TEXT_AUTOCOMPLETE) },
{ "<C-m>", ALIAS("<Enter>") },
{ "<C-o>", ACTION(MODE_OPERATOR_PENDING) },
{ "<C-r>", ACTION(INSERT_REGISTER) },
diff --git a/main.c b/main.c
index d0c0c73..9e224d1 100644
--- a/main.c
+++ b/main.c
_AT_@ -125,6 +125,12 @@ static const char *percent(Vis*, const char *keys, const Arg *arg);
static const char *number_increment_decrement(Vis*, const char *keys, const Arg *arg);
/* open a filename under cursor in same (!arg->b) or new (arg->b) window */
static const char *open_file_under_cursor(Vis*, const char *keys, const Arg *arg);
+/* Insert text chosen in external file dialog at cursor position(s) */
+static void insert_dialog_selection(Vis*, const char *cmdline, ...);
+/* Get output of external command */
+static char *get_output_of_external_command(Vis*, const char *argv[]);
+/* Autocomplete input text at cursor based on the words in the current file */
+static const char *autocomplete_file_text(Vis*, const char *keys, const Arg *arg);
enum {
VIS_ACTION_EDITOR_SUSPEND,
_AT_@ -307,6 +313,7 @@ enum {
VIS_ACTION_NUMBER_DECREMENT,
VIS_ACTION_OPEN_FILE_UNDER_CURSOR,
VIS_ACTION_OPEN_FILE_UNDER_CURSOR_NEW_WINDOW,
+ VIS_ACTION_FILE_TEXT_AUTOCOMPLETE,
VIS_ACTION_NOP,
};
_AT_@ -1211,6 +1218,11 @@ static const KeyAction vis_action[] = {
"Open file under the cursor in a new window",
open_file_under_cursor, { .b = true }
},
+ [VIS_ACTION_FILE_TEXT_AUTOCOMPLETE] = {
+ "autocomplete-file-text",
+ "Autocomplete text in file",
+ autocomplete_file_text,
+ },
[VIS_ACTION_NOP] = {
"nop",
"Ignore key, do nothing",
_AT_@ -2093,6 +2105,108 @@ static const char *open_file_under_cursor(Vis *vis, const char *keys, const Arg
return keys;
}
+ssize_t read_buffer(void *context, char *data, size_t len) {
+ buffer_append(context, data, len);
+ return len;
+}
+
+static char *get_output_of_external_command(Vis *vis, const char *argv[]) {
+ char *out = NULL;
+ Buffer bufout, buferr;
+ buffer_init(&bufout);
+ buffer_init(&buferr);
+
+ Filerange empty = text_range_empty();
+ int status = vis_pipe(vis, &empty, argv, &bufout, read_buffer,
+ &buferr, read_buffer);
+
+ if (status != 0) {
+ vis_info_show(vis, "Command failed %s", buffer_content0(&buferr));
+ } else {
+ out = malloc(bufout.len);
+ strncpy(out, buffer_content0(&bufout), buffer_length0(&bufout));
+ out[buffer_length0(&bufout)] = '\0';
+ }
+
+ buffer_release(&bufout);
+ buffer_release(&buferr);
+ return out;
+}
+
+// Caller has to free the allocated memory for the prefix
+static char *get_prefix_for_autocomplete(Vis *vis) {
+ View *view = vis_view(vis);
+ Cursor *c = view_cursors(view);
+ Text *txt = vis_text(vis);
+
+ Filerange r = text_object_word(txt, view_cursors_pos(c)-1);
+ if (!text_range_valid(&r))
+ return NULL;
+
+ char *prefix = text_bytes_alloc0(txt, r.start, text_range_size(&r));
+ char *check;
+ for (check = prefix; *check; check++) {
+ if (!isspace(*check))
+ break;
+ }
+ if (*check == '\0') {
+ vis_info_show(vis, "Autocompletion without prefix input is not valid.");
+ free(prefix);
+ return NULL;
+ }
+
+ return prefix;
+}
+
+static const char *autocomplete_file_text(Vis *vis, const char *keys, const Arg *arg) {
+ Win *win = vis_window(vis);
+ const char *fn = vis_window_filename(win);
+
+ char *prefix = get_prefix_for_autocomplete(vis);
+ if (!prefix)
+ return keys;
+
+ // TODO: get menu/dialog program to use from config?
+ insert_dialog_selection(vis, "cat '%s' | tr \" ;:$<>#?{}()[],.'\" '\n' | grep \"^%s\" | sort | uniq | dmenu | tr -d '\n' | sed \"s/%s//\"", fn, prefix, prefix);
+
+ free(prefix);
+ return keys;
+}
+
+static void insert_dialog_selection(Vis *vis, const char *cmdline, ...) {
+ View *view = vis_view(vis);
+ Cursor *c = view_cursors(view);
+
+ va_list ap;
+ va_start(ap, cmdline);
+
+ char* cmd = malloc(4096);
+ size_t ret = vsnprintf(cmd, 4096, cmdline, ap);
+ if (ret == 4096) {
+ vis_info_show(vis, "Command line too long.");
+ return;
+ }
+ va_end(ap);
+
+ char *outtext = get_output_of_external_command(vis, (const char*[]){cmd, NULL});
+ if (outtext == NULL) {
+ vis_info_show(vis, "Autocompletion command failed. Command was %s", cmd);
+ free(cmd);
+ return;
+ }
+ size_t len = strlen(outtext);
+
+ for (; c; c = view_cursors_next(c)) {
+ size_t pos = view_cursors_pos(c);
+ vis_insert(vis, pos, outtext, len);
+ view_cursors_scroll_to(c, pos + len);
+ }
+
+ free(outtext);
+ free(cmd);
+ return;
+}
+
static Vis *vis;
static void signal_handler(int signum, siginfo_t *siginfo, void *context) {
diff --git a/vis.c b/vis.c
index 3f04c87..09f854f 100644
--- a/vis.c
+++ b/vis.c
_AT_@ -1360,4 +1360,8 @@ Win *vis_window(Vis *vis) {
bool vis_get_autoindent(const Vis *vis) {
return vis->autoindent;
-}
\ No newline at end of file
+}
+
+const char *vis_window_filename(Win *win) {
+ return win->file->name;
+}
diff --git a/vis.h b/vis.h
index ab7eade..2878f09 100644
--- a/vis.h
+++ b/vis.h
_AT_@ -447,6 +447,7 @@ Regex *vis_regex(Vis*, const char *pattern);
Text *vis_text(Vis*);
View *vis_view(Vis*);
Win *vis_window(Vis*);
+const char *vis_window_filename(Win*);
bool vis_theme_load(Vis*, const char *name);
--
2.8.2
Received on Mon May 16 2016 - 13:00:58 CEST
This archive was generated by hypermail 2.3.0 : Mon May 16 2016 - 13:12:16 CEST