diff options
Diffstat (limited to 'src/nvim/file_search.c')
-rw-r--r-- | src/nvim/file_search.c | 159 |
1 files changed, 83 insertions, 76 deletions
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 3a9acbd61c..15f1d3d065 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -57,7 +57,6 @@ #include "nvim/globals.h" #include "nvim/memory.h" #include "nvim/message.h" -#include "nvim/misc1.h" #include "nvim/option.h" #include "nvim/os/fs_defs.h" #include "nvim/os/input.h" @@ -484,8 +483,14 @@ void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int le int len = 0; if (p > search_ctx->ffsc_fix_path) { + // do not add '..' to the path and start upwards searching len = (int)(p - search_ctx->ffsc_fix_path) - 1; - STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len); + if ((len >= 2 && STRNCMP(search_ctx->ffsc_fix_path, "..", 2) == 0) + && (len == 2 || search_ctx->ffsc_fix_path[2] == PATHSEP)) { + xfree(buf); + goto error_return; + } + STRLCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, eb_len + (size_t)len + 1); add_pathsep((char *)ff_expand_buffer); } else { len = (int)STRLEN(search_ctx->ffsc_fix_path); @@ -524,9 +529,7 @@ error_return: return NULL; } -/* - * Get the stopdir string. Check that ';' is not escaped. - */ +/// @return the stopdir string. Check that ';' is not escaped. char_u *vim_findfile_stopdir(char_u *buf) { char_u *r_ptr = buf; @@ -549,9 +552,7 @@ char_u *vim_findfile_stopdir(char_u *buf) return r_ptr; } -/* - * Clean up the given search context. Can handle a NULL pointer. - */ +/// Clean up the given search context. Can handle a NULL pointer. void vim_findfile_cleanup(void *ctx) { if (ctx == NULL) { @@ -563,18 +564,19 @@ void vim_findfile_cleanup(void *ctx) xfree(ctx); } -/* - * Find a file in a search context. - * The search context was created with vim_findfile_init() above. - * Return a pointer to an allocated file name or NULL if nothing found. - * To get all matching files call this function until you get NULL. - * - * If the passed search_context is NULL, NULL is returned. - * - * The search algorithm is depth first. To change this replace the - * stack with a list (don't forget to leave partly searched directories on the - * top of the list). - */ +/// Find a file in a search context. +/// The search context was created with vim_findfile_init() above. +/// +/// To get all matching files call this function until you get NULL. +/// +/// If the passed search_context is NULL, NULL is returned. +/// +/// The search algorithm is depth first. To change this replace the +/// stack with a list (don't forget to leave partly searched directories on the +/// top of the list). +/// +/// @return a pointer to an allocated file name or, +/// NULL if nothing found. char_u *vim_findfile(void *search_ctx_arg) { char_u *file_path; @@ -608,7 +610,7 @@ char_u *vim_findfile(void *search_ctx_arg) for (;;) { // downward search loop for (;;) { - // check if user user wants to stop the search + // check if user wants to stop the search os_breakcheck(); if (got_int) { break; @@ -994,10 +996,8 @@ fail: return NULL; } -/* - * Free the list of lists of visited files and directories - * Can handle it if the passed search_context is NULL; - */ +/// Free the list of lists of visited files and directories +/// Can handle it if the passed search_context is NULL; void vim_findfile_free_visited(void *search_ctx_arg) { ff_search_ctx_T *search_ctx; @@ -1039,10 +1039,8 @@ static void ff_free_visited_list(ff_visited_T *vl) vl = NULL; } -/* - * Returns the already visited list for the given filename. If none is found it - * allocates a new one. - */ +/// @return the already visited list for the given filename. If none is found it +/// allocates a new one. static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, ff_visited_list_hdr_T **list_headp) { @@ -1089,13 +1087,13 @@ static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, return retptr; } -// Check if two wildcard paths are equal. -// They are equal if: -// - both paths are NULL -// - they have the same length -// - char by char comparison is OK -// - the only differences are in the counters behind a '**', so -// '**\20' is equal to '**\24' +/// Check if two wildcard paths are equal. +/// They are equal if: +/// - both paths are NULL +/// - they have the same length +/// - char by char comparison is OK +/// - the only differences are in the counters behind a '**', so +/// '**\20' is equal to '**\24' static bool ff_wc_equal(char_u *s1, char_u *s2) { int i, j; @@ -1129,18 +1127,17 @@ static bool ff_wc_equal(char_u *s1, char_u *s2) return s1[i] == s2[j]; } -/* - * maintains the list of already visited files and dirs - * returns FAIL if the given file/dir is already in the list - * returns OK if it is newly added - */ +/// maintains the list of already visited files and dirs +/// +/// @return FAIL if the given file/dir is already in the list or, +/// OK if it is newly added static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path) { ff_visited_T *vp; bool url = false; FileID file_id; - // For an URL we only compare the name, otherwise we compare the + // For a URL we only compare the name, otherwise we compare the // device/inode. if (path_with_url((char *)fname)) { STRLCPY(ff_expand_buffer, fname, MAXPATHL); @@ -1191,9 +1188,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u * return OK; } -/* - * create stack element from given path pieces - */ +/// create stack element from given path pieces static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, int level, int star_star_empty) { @@ -1221,9 +1216,7 @@ static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, in return new; } -/* - * Push a dir on the directory stack. - */ +/// Push a dir on the directory stack. static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr) { /* check for NULL pointer, not to return an error to the user, but @@ -1234,10 +1227,9 @@ static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr) } } -/* - * Pop a dir from the directory stack. - * Returns NULL if stack is empty. - */ +/// Pop a dir from the directory stack. +/// +/// @return NULL if stack is empty. static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx) { ff_stack_T *sptr; @@ -1250,9 +1242,7 @@ static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx) return sptr; } -/* - * free the given stack element - */ +/// free the given stack element static void ff_free_stack_element(ff_stack_T *const stack_ptr) { if (stack_ptr == NULL) { @@ -1270,9 +1260,7 @@ static void ff_free_stack_element(ff_stack_T *const stack_ptr) xfree(stack_ptr); } -/* - * Clear the search context, but NOT the visited list. - */ +/// Clear the search context, but NOT the visited list. static void ff_clear(ff_search_ctx_T *search_ctx) { ff_stack_T *sptr; @@ -1306,10 +1294,9 @@ static void ff_clear(ff_search_ctx_T *search_ctx) search_ctx->ffsc_level = 0; } -/* - * check if the given path is in the stopdirs - * returns TRUE if yes else FALSE - */ +/// check if the given path is in the stopdirs +/// +/// @return TRUE if yes else FALSE static int ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v) { int i = 0; @@ -1434,7 +1421,11 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first rel_fname = NULL; } - if (first == TRUE) { + if (first == true) { + if (len == 0) { + return NULL; + } + // copy file name into NameBuff, expanding environment variables save_char = ptr[len]; ptr[len] = NUL; @@ -1591,11 +1582,13 @@ theend: return file_name; } -void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause) +void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause, bool pre) { static bool recursive = false; - if (recursive || !has_event(EVENT_DIRCHANGED)) { + event_T event = pre ? EVENT_DIRCHANGEDPRE : EVENT_DIRCHANGED; + + if (recursive || !has_event(event)) { // No autocommand was defined or we changed // the directory from this autocommand. return; @@ -1603,7 +1596,8 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause) recursive = true; - dict_T *dict = get_vim_var_dict(VV_EVENT); + save_v_event_T save_v_event; + dict_T *dict = get_v_event(&save_v_event); char buf[8]; switch (scope) { @@ -1628,8 +1622,12 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause) new_dir = new_dir_buf; #endif + if (pre) { + tv_dict_add_str(dict, S_LEN("directory"), new_dir); + } else { + tv_dict_add_str(dict, S_LEN("cwd"), new_dir); + } tv_dict_add_str(dict, S_LEN("scope"), buf); // -V614 - tv_dict_add_str(dict, S_LEN("cwd"), new_dir); tv_dict_add_bool(dict, S_LEN("changed_window"), cause == kCdCauseWindow); tv_dict_set_keys_readonly(dict); @@ -1645,17 +1643,17 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause) abort(); } - apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false, - curbuf); + apply_autocmds(event, (char_u *)buf, (char_u *)new_dir, false, curbuf); - tv_dict_clear(dict); + restore_v_event(dict, &save_v_event); recursive = false; } /// Change to a file's directory. /// Caller must call shorten_fnames()! -/// @return OK or FAIL +/// +/// @return OK or FAIL int vim_chdirfile(char_u *fname, CdCause cause) { char dir[MAXPATHL]; @@ -1667,14 +1665,23 @@ int vim_chdirfile(char_u *fname, CdCause cause) NameBuff[0] = NUL; } - if (os_chdir(dir) == 0) { - if (cause != kCdCauseOther && pathcmp(dir, (char *)NameBuff, -1) != 0) { - do_autocmd_dirchanged(dir, kCdScopeWindow, cause); - } - } else { + if (pathcmp(dir, (char *)NameBuff, -1) == 0) { + // nothing to do + return OK; + } + + if (cause != kCdCauseOther) { + do_autocmd_dirchanged(dir, kCdScopeWindow, cause, true); + } + + if (os_chdir(dir) != 0) { return FAIL; } + if (cause != kCdCauseOther) { + do_autocmd_dirchanged(dir, kCdScopeWindow, cause, false); + } + return OK; } |