changeset 3744:99f076ca8d84 v7.3.631

updated for version 7.3.631 Problem: Cannot complete user names. Solution: Add user name completion. (Dominique Pelle)
author Bram Moolenaar <bram@vim.org>
date Wed, 15 Aug 2012 14:05:05 +0200
parents 8bfe7f121b55
children c9291159f229
files runtime/doc/map.txt src/auto/configure src/config.h.in src/configure.in src/ex_docmd.c src/ex_getln.c src/misc1.c src/misc2.c src/proto/misc1.pro src/version.c src/vim.h
diffstat 11 files changed, 120 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- 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}
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -10631,7 +10631,7 @@ if test "x$vim_cv_getcwd_broken" = "xyes
 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 \
--- 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
--- 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 \
--- 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}
 };
--- 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, fil
 	    {EXPAND_LOCALES, get_locales, TRUE, FALSE},
 #endif
 	    {EXPAND_ENV_VARS, get_env_name, TRUE, TRUE},
+	    {EXPAND_USER, get_users, TRUE, FALSE},
 	};
 	int	i;
 
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -18,6 +18,11 @@ static char_u *vim_version_dir __ARGS((c
 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
 
 /*
--- 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();
--- 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 *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));
--- 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,
--- a/src/vim.h
+++ b/src/vim.h
@@ -782,6 +782,7 @@ extern char *(*dyn_libintl_textdomain)(c
 #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