diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2015-07-10 17:56:28 +0200 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2015-07-10 18:03:24 +0200 |
| commit | a657e8499ab04bf8b9b4ffcb954acee574d239a1 (patch) | |
| tree | 7aa7af07677a5b24955230e9da2d708b8abb1ec3 | |
| parent | 29b718e1d2b94f95281911c80ec5460cbd7fc526 (diff) | |
| download | vis-a657e8499ab04bf8b9b4ffcb954acee574d239a1.tar.gz vis-a657e8499ab04bf8b9b4ffcb954acee574d239a1.tar.xz | |
vis: add a file open dialog
For this to work make sure you have vis-open and slmenu or dmenu
somewhere in $PATH.
For now the file dialog is shown for :open, :split and :vsplit
when the argument is either . (a dot) or looks like a file pattern.
For example
:open *.[ch]
will show a listing of all C source and header files in the current
directory. Use a fuzzy search to make your choice.
| -rw-r--r-- | Makefile | 2 | ||||
| -rwxr-xr-x | vis-open | 47 | ||||
| -rw-r--r-- | vis.c | 77 |
3 files changed, 107 insertions, 19 deletions
@@ -34,6 +34,8 @@ install: vis @mkdir -p ${DESTDIR}${PREFIX}/bin @cp -f vis ${DESTDIR}${PREFIX}/bin @chmod 755 ${DESTDIR}${PREFIX}/bin/vis + @cp -f vis-open ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/vis-open @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 @mkdir -p ${DESTDIR}${MANPREFIX}/man1 @sed "s/VERSION/${VERSION}/g" < vis.1 > ${DESTDIR}${MANPREFIX}/man1/vis.1 diff --git a/vis-open b/vis-open new file mode 100755 index 0000000..0bcdd5c --- /dev/null +++ b/vis-open @@ -0,0 +1,47 @@ +#!/bin/sh + +PATTERN="." +[ -z "$VIS_MENU" ] && VIS_MENU="slmenu" +[ -z "$VIS_MENU_ARGS" ] && VIS_MENU_ARGS="-b" + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + echo "usage: $0 [-h] [-p prompt] [file-pattern]" + exit 0; + ;; + -p) + VIS_MENU_ARGS="$VIS_MENU_ARGS -p $2" + shift + shift + ;; + *) + PATTERN=$* + break + ;; + esac +done + +if ! type "$VIS_MENU" >/dev/null 2>&1; then + if [ ! -z "$DISPLAY" ] && type "dmenu" >/dev/null 2>&1; then + VIS_MENU="dmenu" + else + echo "Neither slmenu nor dmenu found" + exit 1 + fi +fi + +DIR="" + +while true; do + SEL=$({ echo ..; ls -1 $PATTERN; } | $VIS_MENU $VIS_MENU_ARGS) + [ -z "$SEL" ] && exit 1 + [ ! -z "$DIR" ] && SEL="$DIR/$SEL" + if [ -d "$SEL" ]; then + DIR="$SEL" + PATTERN="$DIR" + else + echo "$SEL" + exit 0 + fi +done @@ -1502,13 +1502,58 @@ static bool cmd_set(Filerange *range, enum CmdOpt cmdopt, const char *argv[]) { return true; } -static bool cmd_open(Filerange *range, enum CmdOpt opt, const char *argv[]) { - if (!argv[1]) - return vis_window_new(NULL); - for (const char **file = &argv[1]; *file; file++) { - if (!vis_window_new(*file)) { - errno = 0; - editor_info_show(vis, "Can't open `%s' %s", *file, +static bool is_file_pattern(const char *pattern) { + return strcmp(pattern, ".") == 0 || strchr(pattern, '*') || + strchr(pattern, '[') || strchr(pattern, '{'); +} + +static const char *file_open_dialog(const char *pattern) { + if (!is_file_pattern(pattern)) + return pattern; + /* this is a bit of a hack, we temporarily replace the text/view of the active + * window such that we can use cmd_filter as is */ + char vis_open[512]; + static char filename[PATH_MAX]; + Filerange range = text_range_empty(); + Win *win = vis->win; + File *file = win->file; + Text *txt_orig = file->text; + View *view_orig = win->view; + Text *txt = text_load(NULL); + View *view = view_new(txt, NULL); + filename[0] = '\0'; + snprintf(vis_open, sizeof(filename)-1, "vis-open %s", pattern ? pattern : ""); + + if (!txt || !view) + goto out; + win->view = view; + file->text = txt; + + if (cmd_filter(&range, CMD_OPT_NONE, (const char *[]){ "open", vis_open, NULL })) { + size_t len = text_size(txt); + if (len >= sizeof(filename)) + len = 0; + if (len > 0) + text_bytes_get(txt, 0, len-1, filename); + filename[len] = '\0'; + } + +out: + view_free(view); + text_free(txt); + win->view = view_orig; + file->text = txt_orig; + return filename[0] ? filename : NULL; +} + +static bool openfiles(const char **files) { + for (; *files; files++) { + const char *file = file_open_dialog(*files); + if (!file) + continue; + errno = 0; + if (!vis_window_new(file)) { + editor_info_show(vis, "Could not open `%s' %s", file, errno ? strerror(errno) : ""); return false; } @@ -1516,6 +1561,12 @@ static bool cmd_open(Filerange *range, enum CmdOpt opt, const char *argv[]) { return true; } +static bool cmd_open(Filerange *range, enum CmdOpt opt, const char *argv[]) { + if (!argv[1]) + return vis_window_new(NULL); + return openfiles(&argv[1]); +} + static bool is_view_closeable(Win *win) { if (!text_modified(win->file->text)) return true; @@ -1620,18 +1671,6 @@ static bool cmd_substitute(Filerange *range, enum CmdOpt opt, const char *argv[] return cmd_filter(range, opt, (const char*[]){ argv[0], "sed", pattern, NULL}); } -static bool openfiles(const char **files) { - for (; *files; files++) { - errno = 0; - if (!vis_window_new(*files)) { - editor_info_show(vis, "Could not open `%s' %s", *files, - errno ? strerror(errno) : ""); - return false; - } - } - return true; -} - static bool cmd_split(Filerange *range, enum CmdOpt opt, const char *argv[]) { editor_windows_arrange(vis, UI_LAYOUT_HORIZONTAL); if (!argv[1]) |
