# HG changeset patch # User Bram Moolenaar # Date 1345032305 -7200 # Node ID 99f076ca8d846d553aefd7e626ca938bcf93f259 # Parent 8bfe7f121b55bbb416429dfdf6caef06cb0bae67 updated for version 7.3.631 Problem: Cannot complete user names. Solution: Add user name completion. (Dominique Pelle) diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt --- 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 --- 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 \ diff --git a/src/config.h.in b/src/config.h.in --- 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 --- 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 --- 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 will be replaced by user's home + * directory i.e. something like ~user -> /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 --- 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; diff --git a/src/misc1.c b/src/misc1.c --- 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 /* diff --git a/src/misc2.c b/src/misc2.c --- 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 --- 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)); diff --git a/src/version.c b/src/version.c --- 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 --- 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