Skip to content

Instantly share code, notes, and snippets.

@h-east
Last active August 29, 2015 14:22
Show Gist options
  • Save h-east/9842e6691559a1103f12 to your computer and use it in GitHub Desktop.
Save h-east/9842e6691559a1103f12 to your computer and use it in GitHub Desktop.
find select ex command (WIP. 100% implement done)
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -564,6 +564,9 @@
EX(CMD_for, "for", ex_while,
EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
ADDR_LINES),
+EX(CMD_fselect, "fselect", ex_fselect,
+ BANG|WORD1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
EX(CMD_function, "function", ex_function,
EXTRA|BANG|CMDWIN,
ADDR_LINES),
@@ -1236,6 +1239,9 @@
EX(CMD_sfirst, "sfirst", ex_rewind,
EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
ADDR_LINES),
+EX(CMD_sfselect, "sfselect", ex_fselect,
+ BANG|WORD1|EDITCMD|ARGOPT|TRLBAR,
+ ADDR_LINES),
EX(CMD_shell, "shell", ex_shell,
TRLBAR|CMDWIN,
ADDR_LINES),
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -495,6 +495,9 @@
#ifndef FEAT_PROFILE
# define ex_profile ex_ni
#endif
+#ifndef FEAT_SEARCHPATH
+# define ex_fselect ex_ni
+#endif
/*
* Declare cmdnames[].
@@ -3818,6 +3821,11 @@
if (xp->xp_context == EXPAND_FILES)
xp->xp_context = EXPAND_FILES_IN_PATH;
break;
+ case CMD_fselect:
+ case CMD_sfselect:
+ xp->xp_context = EXPAND_DIRECTORIES;
+ xp->xp_pattern = arg;
+ break;
case CMD_cd:
case CMD_chdir:
case CMD_lcd:
diff --git a/src/ex_getln.c b/src/ex_getln.c
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -4569,6 +4569,8 @@
flags |= EW_SILENT;
if (options & WILD_ALLLINKS)
flags |= EW_ALLLINKS;
+ if (options & WILD_FILE_WITHOUT_DIR)
+ flags &= ~EW_DIR;
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
@@ -5941,6 +5943,88 @@
}
#endif
+#if defined(FEAT_SEARCHPATH) || defined(PROTO)
+/*
+ * ":fselect [+command] <file>" command.
+ */
+ void
+ex_fselect(eap)
+ exarg_T *eap;
+{
+ expand_T xpc;
+ char_u *pat_str;
+ int i;
+ garray_T ga;
+ int flags = WILD_FILE_WITHOUT_DIR;
+ char_u *file_pat, *dir_pat;
+ char_u *path_opt;
+
+ ga_init2(&ga, (int)sizeof(char_u *), 10);
+ ExpandInit(&xpc);
+ xpc.xp_context = EXPAND_FILES;
+ dir_pat = vim_strsave(eap->arg);
+
+ file_pat = gettail(dir_pat);
+ if (STRCMP(dir_pat, "**") == 0)
+ {
+ path_opt = dir_pat;
+ file_pat = "";
+ }
+ else if (dir_pat == file_pat)
+ path_opt = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
+ else
+ {
+ path_opt = dir_pat;
+ file_pat[-1] = NUL;
+ }
+
+ pat_str = addstar(file_pat, (int)STRLEN(file_pat), xpc.xp_context);
+
+ globpath(path_opt, pat_str, &ga, flags);
+ if (ga.ga_len > 0)
+ {
+ int num_files = ga.ga_len;
+ char_u **files = (char_u **)ga.ga_data;
+
+ msg_start();
+ MSG_PUTS_TITLE(" # file");
+ msg_clr_eos();
+ msg_putchar('\n');
+
+ for (i=0; i < num_files && !got_int; i++)
+ {
+ sprintf((char *)IObuff, " %3d %s\n", i + 1, files[i]);
+ msg_puts(IObuff);
+ ui_breakcheck();
+ }
+ if (got_int)
+ got_int = FALSE; /* only stop the listing */
+ i = prompt_for_number(NULL);
+ msg_putchar('\n');
+ need_wait_return = FALSE;
+ if (i > 0 && i <= num_files && !got_int)
+ {
+ /* split window or create new tab page first */
+ if (*eap->cmd == 's' || cmdmod.tab != 0)
+ {
+ if (win_split(0, 0) == FAIL)
+ goto end;
+ RESET_BINDING(curwin);
+ }
+ eap->arg = files[i - 1];
+ do_exedit(eap, NULL);
+ }
+ }
+ else
+ EMSG2(_("E345: Can't find file \"%s\" in path"), eap->arg);
+
+end:
+ vim_free(pat_str);
+ vim_free(dir_pat);
+ ga_clear_strings(&ga);
+}
+#endif
+
#if defined(FEAT_CMDHIST) || defined(PROTO)
/*
* :history command - print a history
diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro
--- a/src/proto/ex_getln.pro
+++ b/src/proto/ex_getln.pro
@@ -47,6 +47,7 @@
int del_history_idx __ARGS((int histype, int idx));
void remove_key_from_history __ARGS((void));
int get_list_range __ARGS((char_u **str, int *num1, int *num2));
+void ex_fselect __ARGS((exarg_T *eap));
void ex_history __ARGS((exarg_T *eap));
void prepare_viminfo_history __ARGS((int asklen, int writing));
int read_viminfo_history __ARGS((vir_T *virp, int writing));
diff --git a/src/vim.h b/src/vim.h
--- a/src/vim.h
+++ b/src/vim.h
@@ -824,6 +824,7 @@
#define WILD_ESCAPE 0x80
#define WILD_ICASE 0x100
#define WILD_ALLLINKS 0x200
+#define WILD_FILE_WITHOUT_DIR 0x400
/* Flags for expand_wildcards() */
#define EW_DIR 0x01 /* include directory names */
@h-east
Copy link
Author

h-east commented Jun 14, 2015

TODO:

  • Implement :fselect
  • Debug :fselect
  • Implement :sfselect and :tabfselect. (:tab fselect can do this)
  • Add test code.
  • Add document.
  • Send patch to vim_dev.

@h-east
Copy link
Author

h-east commented Jun 14, 2015

Known Bug

  • File name sometimes duplicated. Depending on the contents of 'path' option. This is Vim's specification.
  • Unexpected reference to the 'path' option, when specify an absolute or relative(start from '.') path to the ex command argument. (2015-06-15 9:40 JST) fixed.

Unimplemented feature

  • Command line directory completion (, ) Done.
  • It does not include the directory to list. Done.

@h-east
Copy link
Author

h-east commented Jun 20, 2015

Overview

This patch to add :fselect command for Vim.
fselect is "find select". fselect is a select version of the :find command.

How to use

:fselect [file]
When file equals **, list files an entire current directory tree.
When file does not contain the path-separator, search matches files name from path option's directories.
And you select a number, open the selected file.

:sfselect [file]
Same :fselect, but splits the window.

:tab sfselect [file]
Same :fselect, but open the tabpage.

NOTE: In all results, List the file only. Directory does not list.

Sample

  • :fs is similar to :echo globpath(&path, "*")'s result. (However, directory does not list.)
  • :fs file is similar to :echo globpath(&path, "file*")'s result. (However, directory does not list.)
  • :fs **/file is similar to :echo globpath("**", "file*")'s result. (However, directory does not list.)
  • :fs foo/bar/file is similar to :echo globpath("foo/bar", "file*")'s result. (However, directory does not list.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment