diff options
Diffstat (limited to 'src/nvim/file_search.c')
-rw-r--r-- | src/nvim/file_search.c | 189 |
1 files changed, 133 insertions, 56 deletions
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index beefc4238e..d733ba311a 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1,48 +1,44 @@ -/* TODO: make some #ifdef for this */ -/*--------[ file searching ]-------------------------------------------------*/ -/* - * File searching functions for 'path', 'tags' and 'cdpath' options. - * External visible functions: - * vim_findfile_init() creates/initialises the search context - * vim_findfile_free_visited() free list of visited files/dirs of search - * context - * vim_findfile() find a file in the search context - * vim_findfile_cleanup() cleanup/free search context created by - * vim_findfile_init() - * - * All static functions and variables start with 'ff_' - * - * In general it works like this: - * First you create yourself a search context by calling vim_findfile_init(). - * It is possible to give a search context from a previous call to - * vim_findfile_init(), so it can be reused. After this you call vim_findfile() - * until you are satisfied with the result or it returns NULL. On every call it - * returns the next file which matches the conditions given to - * vim_findfile_init(). If it doesn't find a next file it returns NULL. - * - * It is possible to call vim_findfile_init() again to reinitialise your search - * with some new parameters. Don't forget to pass your old search context to - * it, so it can reuse it and especially reuse the list of already visited - * directories. If you want to delete the list of already visited directories - * simply call vim_findfile_free_visited(). - * - * When you are done call vim_findfile_cleanup() to free the search context. - * - * The function vim_findfile_init() has a long comment, which describes the - * needed parameters. - * - * - * - * ATTENTION: - * ========== - * Also we use an allocated search context here, this functions are NOT - * thread-safe!!!!! - * - * To minimize parameter passing (or because I'm to lazy), only the - * external visible functions get a search context as a parameter. This is - * then assigned to a static global, which is used throughout the local - * functions. - */ +// File searching functions for 'path', 'tags' and 'cdpath' options. +// +// External visible functions: +// vim_findfile_init() creates/initialises the search context +// vim_findfile_free_visited() free list of visited files/dirs of search +// context +// vim_findfile() find a file in the search context +// vim_findfile_cleanup() cleanup/free search context created by +// vim_findfile_init() +// +// All static functions and variables start with 'ff_' +// +// In general it works like this: +// First you create yourself a search context by calling vim_findfile_init(). +// It is possible to give a search context from a previous call to +// vim_findfile_init(), so it can be reused. After this you call vim_findfile() +// until you are satisfied with the result or it returns NULL. On every call it +// returns the next file which matches the conditions given to +// vim_findfile_init(). If it doesn't find a next file it returns NULL. +// +// It is possible to call vim_findfile_init() again to reinitialise your search +// with some new parameters. Don't forget to pass your old search context to +// it, so it can reuse it and especially reuse the list of already visited +// directories. If you want to delete the list of already visited directories +// simply call vim_findfile_free_visited(). +// +// When you are done call vim_findfile_cleanup() to free the search context. +// +// The function vim_findfile_init() has a long comment, which describes the +// needed parameters. +// +// +// +// ATTENTION: +// ========== +// We use an allocated search context, these functions are NOT thread-safe!!!!! +// +// To minimize parameter passing (or because I'm too lazy), only the +// external visible functions get a search context as a parameter. This is +// then assigned to a static global, which is used throughout the local +// functions. #include <assert.h> #include <string.h> @@ -52,6 +48,7 @@ #include <limits.h> #include "nvim/vim.h" +#include "nvim/eval.h" #include "nvim/ascii.h" #include "nvim/file_search.h" #include "nvim/charset.h" @@ -59,7 +56,7 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/misc2.h" +#include "nvim/option.h" #include "nvim/os_unix.h" #include "nvim/path.h" #include "nvim/strings.h" @@ -196,7 +193,6 @@ typedef struct ff_search_ctx_T { static char_u e_pathtoolong[] = N_("E854: path too long for completion"); - /* * Initialization routine for vim_findfile(). * @@ -791,7 +787,7 @@ char_u *vim_findfile(void *search_ctx_arg) for (;; ) { /* if file exists and we didn't already find it */ if ((path_with_url((char *)file_path) - || (os_file_exists(file_path) + || (os_path_exists(file_path) && (search_ctx->ffsc_find_what == FINDFILE_BOTH || ((search_ctx->ffsc_find_what @@ -1153,7 +1149,7 @@ static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, in new->ffs_filearray_cur = 0; new->ffs_stage = 0; new->ffs_level = level; - new->ffs_star_star_empty = star_star_empty;; + new->ffs_star_star_empty = star_star_empty; /* the following saves NULL pointer checks in vim_findfile */ if (fix_part == NULL) @@ -1374,11 +1370,16 @@ find_file_in_path_option ( char_u *buf = NULL; int rel_to_curdir; + if (rel_fname != NULL && path_with_url((const char *)rel_fname)) { + // Do not attempt to search "relative" to a URL. #6009 + rel_fname = NULL; + } + if (first == TRUE) { /* copy file name into NameBuff, expanding environment variables */ save_char = ptr[len]; ptr[len] = NUL; - expand_env(ptr, NameBuff, MAXPATHL); + expand_env_esc(ptr, NameBuff, MAXPATHL, false, true, NULL); ptr[len] = save_char; xfree(ff_file_to_find); @@ -1442,12 +1443,12 @@ find_file_in_path_option ( buf = suffixes; for (;; ) { if ( - (os_file_exists(NameBuff) - && (find_what == FINDFILE_BOTH - || ((find_what == FINDFILE_DIR) - == os_isdir(NameBuff))))) { - file_name = vim_strsave(NameBuff); - goto theend; + (os_path_exists(NameBuff) + && (find_what == FINDFILE_BOTH + || ((find_what == FINDFILE_DIR) + == os_isdir(NameBuff))))) { + file_name = vim_strsave(NameBuff); + goto theend; } if (*buf == NUL) break; @@ -1526,3 +1527,79 @@ theend: return file_name; } +static void do_autocmd_dirchanged(char_u *new_dir, CdScope scope) +{ + static bool recursive = false; + + if (recursive || !has_event(EVENT_DIRCHANGED)) { + // No autocommand was defined or we changed + // the directory from this autocommand. + return; + } + + recursive = true; + + dict_T *dict = get_vim_var_dict(VV_EVENT); + char buf[8]; + + switch (scope) { + case kCdScopeGlobal: + snprintf(buf, sizeof(buf), "global"); + break; + case kCdScopeTab: + snprintf(buf, sizeof(buf), "tab"); + break; + case kCdScopeWindow: + snprintf(buf, sizeof(buf), "window"); + break; + case kCdScopeInvalid: + // Should never happen. + assert(false); + } + + dict_add_nr_str(dict, "scope", 0L, (char_u *)buf); + dict_add_nr_str(dict, "cwd", 0L, new_dir); + dict_set_keys_readonly(dict); + + apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, new_dir, false, NULL); + + dict_clear(dict); + + recursive = false; +} + +/// Change to a file's directory. +/// Caller must call shorten_fnames()! +/// @return OK or FAIL +int vim_chdirfile(char_u *fname) +{ + char_u dir[MAXPATHL]; + + STRLCPY(dir, fname, MAXPATHL); + *path_tail_with_sep(dir) = NUL; + if (os_chdir((char *)dir) != 0) { + return FAIL; + } + do_autocmd_dirchanged(dir, kCdScopeWindow); + + return OK; +} + +/// Change directory to "new_dir". Search 'cdpath' for relative directory names. +int vim_chdir(char_u *new_dir, CdScope scope) +{ + char_u *dir_name = find_directory_in_path(new_dir, STRLEN(new_dir), + FNAME_MESS, curbuf->b_ffname); + if (dir_name == NULL) { + return -1; + } + + int r = os_chdir((char *)dir_name); + if (r == 0) { + do_autocmd_dirchanged(dir_name, scope); + } + + xfree(dir_name); + return r; +} + |