summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/map.txt1
-rwxr-xr-xsrc/auto/configure2
-rw-r--r--src/config.h.in1
-rw-r--r--src/configure.in2
-rw-r--r--src/ex_docmd.c18
-rw-r--r--src/ex_getln.c2
-rw-r--r--src/misc1.c87
-rw-r--r--src/misc2.c3
-rw-r--r--src/proto/misc1.pro3
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
11 files changed, 120 insertions, 2 deletions
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index b4b77deaa..59c661d3f 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1244,6 +1244,7 @@ completion can be enabled:
-complete=syntax syntax file names |'syntax'|
-complete=tag tags
-complete=tag_listfiles tags, file names are shown when CTRL-D is hit
+ -complete=user user names
-complete=var user variables
-complete=custom,{func} custom completion, defined via {func}
-complete=customlist,{func} custom completion, defined via {func}
diff --git a/src/auto/configure b/src/auto/configure
index 68be9f327..bc4607439 100755
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -10631,7 +10631,7 @@ if test "x$vim_cv_getcwd_broken" = "xyes" ; then
fi
for ac_func in bcmp fchdir fchown fsync getcwd getpseudotty \
- getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \
+ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \
memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
sigvec strcasecmp strerror strftime stricmp strncasecmp \
diff --git a/src/config.h.in b/src/config.h.in
index d1adb3a3a..e15793938 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -161,6 +161,7 @@
#undef HAVE_FSYNC
#undef HAVE_GETCWD
#undef HAVE_GETPSEUDOTTY
+#undef HAVE_GETPWENT
#undef HAVE_GETPWNAM
#undef HAVE_GETPWUID
#undef HAVE_GETRLIMIT
diff --git a/src/configure.in b/src/configure.in
index fb6aed0d4..2ff0f90a1 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -2994,7 +2994,7 @@ fi
dnl Check for functions in one big call, to reduce the size of configure.
dnl Can only be used for functions that do not require any include.
AC_CHECK_FUNCS(bcmp fchdir fchown fsync getcwd getpseudotty \
- getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \
+ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \
memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \
sigvec strcasecmp strerror strftime stricmp strncasecmp \
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index c7e6316f0..ead520a22 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3515,6 +3515,23 @@ set_one_cmd_context(xp, buff)
#endif
}
}
+#if defined(FEAT_CMDL_COMPL)
+ /* Check for user names */
+ if (*xp->xp_pattern == '~')
+ {
+ for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p)
+ ;
+ /* Complete ~user only if it partially matches a user name.
+ * A full match ~user<Tab> will be replaced by user's home
+ * directory i.e. something like ~user<Tab> -> /home/user/ */
+ if (*p == NUL && p > xp->xp_pattern + 1
+ && match_user(xp->xp_pattern + 1) == 1)
+ {
+ xp->xp_context = EXPAND_USER;
+ ++xp->xp_pattern;
+ }
+ }
+#endif
}
/*
@@ -5396,6 +5413,7 @@ static struct
#endif
{EXPAND_TAGS, "tag"},
{EXPAND_TAGS_LISTFILES, "tag_listfiles"},
+ {EXPAND_USER, "user"},
{EXPAND_USER_VARS, "var"},
{0, NULL}
};
diff --git a/src/ex_getln.c b/src/ex_getln.c
index bc92488da..9cf1287a4 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -4336,6 +4336,7 @@ addstar(fname, len, context)
* EXPAND_EXPRESSION Complete internal or user defined function/variable
* names in expressions, eg :while s^I
* EXPAND_ENV_VARS Complete environment variable names
+ * EXPAND_USER Complete user names
*/
static void
set_expand_context(xp)
@@ -4681,6 +4682,7 @@ ExpandFromContext(xp, pat, num_file, file, options)
{EXPAND_LOCALES, get_locales, TRUE, FALSE},
#endif
{EXPAND_ENV_VARS, get_env_name, TRUE, TRUE},
+ {EXPAND_USER, get_users, TRUE, FALSE},
};
int i;
diff --git a/src/misc1.c b/src/misc1.c
index e11e10e0c..636fc4a07 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -18,6 +18,11 @@ static char_u *vim_version_dir __ARGS((char_u *vimdir));
static char_u *remove_tail __ARGS((char_u *p, char_u *pend, char_u *name));
static int copy_indent __ARGS((int size, char_u *src));
+/* All user names (for ~user completion as done by shell). */
+#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
+static garray_T ga_users;
+#endif
+
/*
* Count the size (in window cells) of the indent in the current line.
*/
@@ -3782,6 +3787,14 @@ free_homedir()
{
vim_free(homedir);
}
+
+# ifdef FEAT_CMDL_COMPL
+ void
+free_users()
+{
+ ga_clear_strings(&ga_users);
+}
+# endif
#endif
/*
@@ -4451,6 +4464,80 @@ get_env_name(xp, idx)
return name;
# endif
}
+
+/*
+ * Find all user names for user completion.
+ * Done only once and then cached.
+ */
+ static void
+init_users() {
+ static int lazy_init_done = FALSE;
+
+ if (lazy_init_done)
+ return;
+
+ lazy_init_done = TRUE;
+ ga_init2(&ga_users, sizeof(char_u *), 20);
+
+# if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
+ {
+ char_u* user;
+ struct passwd* pw;
+
+ setpwent();
+ while ((pw = getpwent()) != NULL)
+ /* pw->pw_name shouldn't be NULL but just in case... */
+ if (pw->pw_name != NULL)
+ {
+ if (ga_grow(&ga_users, 1) == FAIL)
+ break;
+ user = vim_strsave((char_u*)pw->pw_name);
+ if (user == NULL)
+ break;
+ ((char_u **)(ga_users.ga_data))[ga_users.ga_len++] = user;
+ }
+ endpwent();
+ }
+# endif
+}
+
+/*
+ * Function given to ExpandGeneric() to obtain an user names.
+ */
+ char_u*
+get_users(xp, idx)
+ expand_T *xp UNUSED;
+ int idx;
+{
+ init_users();
+ if (idx < ga_users.ga_len)
+ return ((char_u **)ga_users.ga_data)[idx];
+ return NULL;
+}
+
+/*
+ * Check whether name matches a user name. Return:
+ * 0 if name does not match any user name.
+ * 1 if name partially matches the beginning of a user name.
+ * 2 is name fully matches a user name.
+ */
+int match_user(name)
+ char_u* name;
+{
+ int i;
+ int n = (int)STRLEN(name);
+ int result = 0;
+
+ init_users();
+ for (i = 0; i < ga_users.ga_len; i++)
+ {
+ if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0)
+ return 2; /* full match */
+ if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0)
+ result = 1; /* partial match */
+ }
+ return result;
+}
#endif
/*
diff --git a/src/misc2.c b/src/misc2.c
index 5d60954be..43fec19bc 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1110,6 +1110,9 @@ free_all_mem()
free_all_marks();
alist_clear(&global_alist);
free_homedir();
+# if defined(FEAT_CMDL_COMPL)
+ free_users();
+# endif
free_search_patterns();
free_old_sub();
free_last_insert();
diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro
index f646a1cbb..e74cf9efd 100644
--- a/src/proto/misc1.pro
+++ b/src/proto/misc1.pro
@@ -50,6 +50,7 @@ void beep_flush __ARGS((void));
void vim_beep __ARGS((void));
void init_homedir __ARGS((void));
void free_homedir __ARGS((void));
+void free_users __ARGS((void));
char_u *expand_env_save __ARGS((char_u *src));
char_u *expand_env_save_opt __ARGS((char_u *src, int one));
void expand_env __ARGS((char_u *src, char_u *dst, int dstlen));
@@ -57,6 +58,8 @@ void expand_env_esc __ARGS((char_u *srcp, char_u *dst, int dstlen, int esc, int
char_u *vim_getenv __ARGS((char_u *name, int *mustfree));
void vim_setenv __ARGS((char_u *name, char_u *val));
char_u *get_env_name __ARGS((expand_T *xp, int idx));
+char_u *get_users __ARGS((expand_T *xp, int idx));
+int match_user __ARGS((char_u* name));
void home_replace __ARGS((buf_T *buf, char_u *src, char_u *dst, int dstlen, int one));
char_u *home_replace_save __ARGS((buf_T *buf, char_u *src));
int fullpathcmp __ARGS((char_u *s1, char_u *s2, int checkname));
diff --git a/src/version.c b/src/version.c
index fad108155..5e6dedc85 100644
--- a/src/version.c
+++ b/src/version.c
@@ -715,6 +715,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 631,
+/**/
630,
/**/
629,
diff --git a/src/vim.h b/src/vim.h
index 3ed981e53..35b23105b 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -782,6 +782,7 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
#define EXPAND_OWNSYNTAX 39
#define EXPAND_LOCALES 40
#define EXPAND_HISTORY 41
+#define EXPAND_USER 42
/* Values for exmode_active (0 is no exmode) */
#define EXMODE_NORMAL 1