aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2024-08-07 09:12:33 +0800
committerGitHub <noreply@github.com>2024-08-07 01:12:33 +0000
commit11a6f3c9301b3deb71f7e5886fce3718420355be (patch)
tree2291e586d0bc8de3411d0e9db402adc994582d77
parent0c99ce0e89515de218f2b4e5f270885045868e93 (diff)
downloadrneovim-11a6f3c9301b3deb71f7e5886fce3718420355be.tar.gz
rneovim-11a6f3c9301b3deb71f7e5886fce3718420355be.tar.bz2
rneovim-11a6f3c9301b3deb71f7e5886fce3718420355be.zip
vim-patch:partial:8.1.0914: code related to findfile() is spread out (#30000)
Problem: Code related to findfile() is spread out. Solution: Put findfile() related code into a new source file. (Yegappan Lakshmanan, closes vim/vim#3934) https://github.com/vim/vim/commit/5fd0f5052f9a312bb4cfe7b4176b1211d45127ee Keep functions related to wildcard expansion in path.c, as in Vim they are now spread out among multiple files, which isn't really ideal.
-rw-r--r--src/nvim/file_search.c224
-rw-r--r--src/nvim/file_search.h12
-rw-r--r--src/nvim/normal.c1
-rw-r--r--src/nvim/ops.c1
-rw-r--r--src/nvim/path.c88
-rw-r--r--src/nvim/search.c1
-rw-r--r--src/nvim/window.c136
-rw-r--r--src/nvim/window.h11
8 files changed, 238 insertions, 236 deletions
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 5760fc864a..cdfd281718 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -52,7 +52,9 @@
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/autocmd_defs.h"
-#include "nvim/buffer_defs.h"
+#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -63,6 +65,7 @@
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/normal.h"
#include "nvim/option.h"
#include "nvim/option_vars.h"
#include "nvim/os/fs.h"
@@ -1503,6 +1506,225 @@ theend:
return file_name;
}
+/// Get the file name at the cursor.
+/// If Visual mode is active, use the selected text if it's in one line.
+/// Returns the name in allocated memory, NULL for failure.
+char *grab_file_name(int count, linenr_T *file_lnum)
+{
+ int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC;
+ if (VIsual_active) {
+ size_t len;
+ char *ptr;
+ if (get_visual_text(NULL, &ptr, &len) == FAIL) {
+ return NULL;
+ }
+ // Only recognize ":123" here
+ if (file_lnum != NULL && ptr[len] == ':' && isdigit((uint8_t)ptr[len + 1])) {
+ char *p = ptr + len + 1;
+
+ *file_lnum = getdigits_int32(&p, false, 0);
+ }
+ return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname);
+ }
+ return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
+}
+
+/// Return the file name under or after the cursor.
+///
+/// The 'path' option is searched if the file name is not absolute.
+/// The string returned has been alloc'ed and should be freed by the caller.
+/// NULL is returned if the file name or file is not found.
+///
+/// options:
+/// FNAME_MESS give error messages
+/// FNAME_EXP expand to path
+/// FNAME_HYP check for hypertext link
+/// FNAME_INCL apply "includeexpr"
+char *file_name_at_cursor(int options, int count, linenr_T *file_lnum)
+{
+ return file_name_in_line(get_cursor_line_ptr(),
+ curwin->w_cursor.col, options, count, curbuf->b_ffname,
+ file_lnum);
+}
+
+/// @param rel_fname file we are searching relative to
+/// @param file_lnum line number after the file name
+///
+/// @return the name of the file under or after ptr[col].
+///
+/// Otherwise like file_name_at_cursor().
+char *file_name_in_line(char *line, int col, int options, int count, char *rel_fname,
+ linenr_T *file_lnum)
+{
+ // search forward for what could be the start of a file name
+ char *ptr = line + col;
+ while (*ptr != NUL && !vim_isfilec((uint8_t)(*ptr))) {
+ MB_PTR_ADV(ptr);
+ }
+ if (*ptr == NUL) { // nothing found
+ if (options & FNAME_MESS) {
+ emsg(_("E446: No file name under cursor"));
+ }
+ return NULL;
+ }
+
+ size_t len;
+ bool in_type = true;
+ bool is_url = false;
+
+ // Search backward for first char of the file name.
+ // Go one char back to ":" before "//", or to the drive letter before ":\" (even if ":"
+ // is not in 'isfname').
+ while (ptr > line) {
+ if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) {
+ ptr -= len + 1;
+ } else if (vim_isfilec((uint8_t)ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) {
+ ptr--;
+ } else {
+ break;
+ }
+ }
+
+ // Search forward for the last char of the file name.
+ // Also allow ":/" when ':' is not in 'isfname'.
+ len = path_has_drive_letter(ptr) ? 2 : 0;
+ while (vim_isfilec((uint8_t)ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
+ || ((options & FNAME_HYP) && path_is_url(ptr + len))
+ || (is_url && vim_strchr(":?&=", (uint8_t)ptr[len]) != NULL)) {
+ // After type:// we also include :, ?, & and = as valid characters, so that
+ // http://google.com:8080?q=this&that=ok works.
+ if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z')) {
+ if (in_type && path_is_url(ptr + len + 1)) {
+ is_url = true;
+ }
+ } else {
+ in_type = false;
+ }
+
+ if (ptr[len] == '\\' && ptr[len + 1] == ' ') {
+ // Skip over the "\" in "\ ".
+ len++;
+ }
+ len += (size_t)(utfc_ptr2len(ptr + len));
+ }
+
+ // If there is trailing punctuation, remove it.
+ // But don't remove "..", could be a directory name.
+ if (len > 2 && vim_strchr(".,:;!", (uint8_t)ptr[len - 1]) != NULL
+ && ptr[len - 2] != '.') {
+ len--;
+ }
+
+ if (file_lnum != NULL) {
+ const char *line_english = " line ";
+ const char *line_transl = _(line_msg);
+
+ // Get the number after the file name and a separator character.
+ // Also accept " line 999" with and without the same translation as
+ // used in last_set_msg().
+ char *p = ptr + len;
+ if (strncmp(p, line_english, strlen(line_english)) == 0) {
+ p += strlen(line_english);
+ } else if (strncmp(p, line_transl, strlen(line_transl)) == 0) {
+ p += strlen(line_transl);
+ } else {
+ p = skipwhite(p);
+ }
+ if (*p != NUL) {
+ if (!isdigit((uint8_t)(*p))) {
+ p++; // skip the separator
+ }
+ p = skipwhite(p);
+ if (isdigit((uint8_t)(*p))) {
+ *file_lnum = (linenr_T)getdigits_long(&p, false, 0);
+ }
+ }
+ }
+
+ return find_file_name_in_path(ptr, len, options, count, rel_fname);
+}
+
+static char *eval_includeexpr(const char *const ptr, const size_t len)
+{
+ const sctx_T save_sctx = current_sctx;
+ set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
+ current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx;
+
+ char *res = eval_to_string_safe(curbuf->b_p_inex,
+ was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL),
+ true);
+
+ set_vim_var_string(VV_FNAME, NULL, 0);
+ current_sctx = save_sctx;
+ return res;
+}
+
+/// Return the name of the file ptr[len] in 'path'.
+/// Otherwise like file_name_at_cursor().
+///
+/// @param rel_fname file we are searching relative to
+char *find_file_name_in_path(char *ptr, size_t len, int options, long count, char *rel_fname)
+{
+ char *file_name;
+ char *tofree = NULL;
+
+ if (len == 0) {
+ return NULL;
+ }
+
+ if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
+ tofree = eval_includeexpr(ptr, len);
+ if (tofree != NULL) {
+ ptr = tofree;
+ len = strlen(ptr);
+ }
+ }
+
+ if (options & FNAME_EXP) {
+ char *file_to_find = NULL;
+ char *search_ctx = NULL;
+
+ file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
+ true, rel_fname, &file_to_find, &search_ctx);
+
+ // If the file could not be found in a normal way, try applying
+ // 'includeexpr' (unless done already).
+ if (file_name == NULL
+ && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
+ tofree = eval_includeexpr(ptr, len);
+ if (tofree != NULL) {
+ ptr = tofree;
+ len = strlen(ptr);
+ file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
+ true, rel_fname, &file_to_find, &search_ctx);
+ }
+ }
+ if (file_name == NULL && (options & FNAME_MESS)) {
+ char c = ptr[len];
+ ptr[len] = NUL;
+ semsg(_("E447: Can't find file \"%s\" in path"), ptr);
+ ptr[len] = c;
+ }
+
+ // Repeat finding the file "count" times. This matters when it
+ // appears several times in the path.
+ while (file_name != NULL && --count > 0) {
+ xfree(file_name);
+ file_name = find_file_in_path(ptr, len, options, false, rel_fname,
+ &file_to_find, &search_ctx);
+ }
+
+ xfree(file_to_find);
+ vim_findfile_cleanup(search_ctx);
+ } else {
+ file_name = xstrnsave(ptr, len);
+ }
+
+ xfree(tofree);
+
+ return file_name;
+}
+
void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause, bool pre)
{
static bool recursive = false;
diff --git a/src/nvim/file_search.h b/src/nvim/file_search.h
index 2450472681..f21d2b8468 100644
--- a/src/nvim/file_search.h
+++ b/src/nvim/file_search.h
@@ -2,6 +2,7 @@
#include <stddef.h> // IWYU pragma: keep
+#include "nvim/pos_defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h" // IWYU pragma: keep
#include "nvim/vim_defs.h" // IWYU pragma: keep
@@ -12,6 +13,17 @@ enum {
FINDFILE_BOTH = 2, ///< files and directories
};
+/// Values for file_name_in_line()
+enum {
+ FNAME_MESS = 1, ///< give error message
+ FNAME_EXP = 2, ///< expand to path
+ FNAME_HYP = 4, ///< check for hypertext link
+ FNAME_INCL = 8, ///< apply 'includeexpr'
+ FNAME_REL = 16, ///< ".." and "./" are relative to the (current)
+ ///< file instead of the current directory
+ FNAME_UNESC = 32, ///< remove backslashes used for escaping
+};
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "file_search.h.generated.h"
#endif
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 3931ae3ee9..9e17fe234d 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -35,6 +35,7 @@
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 05b9db474e..4b3f69a378 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -31,6 +31,7 @@
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_getln.h"
#include "nvim/extmark.h"
+#include "nvim/file_search.h"
#include "nvim/fold.h"
#include "nvim/garray.h"
#include "nvim/garray_defs.h"
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 67acc6e51b..c9bfd5228c 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -8,23 +8,17 @@
#include "auto/config.h"
#include "nvim/ascii_defs.h"
-#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cmdexpand.h"
#include "nvim/eval.h"
-#include "nvim/eval/typval_defs.h"
#include "nvim/ex_docmd.h"
-#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/garray.h"
-#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/macros_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
-#include "nvim/message.h"
#include "nvim/option.h"
-#include "nvim/option_defs.h"
#include "nvim/option_vars.h"
#include "nvim/os/fs.h"
#include "nvim/os/fs_defs.h"
@@ -37,7 +31,6 @@
#include "nvim/regexp_defs.h"
#include "nvim/strings.h"
#include "nvim/vim_defs.h"
-#include "nvim/window.h"
enum {
URL_SLASH = 1, // path_is_url() has found ":/"
@@ -1687,87 +1680,6 @@ void simplify_filename(char *filename)
} while (*p != NUL);
}
-static char *eval_includeexpr(const char *const ptr, const size_t len)
-{
- const sctx_T save_sctx = current_sctx;
- set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
- current_sctx = curbuf->b_p_script_ctx[BV_INEX].script_ctx;
-
- char *res = eval_to_string_safe(curbuf->b_p_inex,
- was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL),
- true);
-
- set_vim_var_string(VV_FNAME, NULL, 0);
- current_sctx = save_sctx;
- return res;
-}
-
-/// Return the name of the file ptr[len] in 'path'.
-/// Otherwise like file_name_at_cursor().
-///
-/// @param rel_fname file we are searching relative to
-char *find_file_name_in_path(char *ptr, size_t len, int options, long count, char *rel_fname)
-{
- char *file_name;
- char *tofree = NULL;
-
- if (len == 0) {
- return NULL;
- }
-
- if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
- tofree = eval_includeexpr(ptr, len);
- if (tofree != NULL) {
- ptr = tofree;
- len = strlen(ptr);
- }
- }
-
- if (options & FNAME_EXP) {
- char *file_to_find = NULL;
- char *search_ctx = NULL;
-
- file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
- true, rel_fname, &file_to_find, &search_ctx);
-
- // If the file could not be found in a normal way, try applying
- // 'includeexpr' (unless done already).
- if (file_name == NULL
- && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
- tofree = eval_includeexpr(ptr, len);
- if (tofree != NULL) {
- ptr = tofree;
- len = strlen(ptr);
- file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
- true, rel_fname, &file_to_find, &search_ctx);
- }
- }
- if (file_name == NULL && (options & FNAME_MESS)) {
- char c = ptr[len];
- ptr[len] = NUL;
- semsg(_("E447: Can't find file \"%s\" in path"), ptr);
- ptr[len] = c;
- }
-
- // Repeat finding the file "count" times. This matters when it
- // appears several times in the path.
- while (file_name != NULL && --count > 0) {
- xfree(file_name);
- file_name = find_file_in_path(ptr, len, options, false, rel_fname,
- &file_to_find, &search_ctx);
- }
-
- xfree(file_to_find);
- vim_findfile_cleanup(search_ctx);
- } else {
- file_name = xstrnsave(ptr, len);
- }
-
- xfree(tofree);
-
- return file_name;
-}
-
/// Checks for a Windows drive letter ("C:/") at the start of the path.
///
/// @see https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
diff --git a/src/nvim/search.c b/src/nvim/search.c
index d1cb336905..9e00664d86 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -26,6 +26,7 @@
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/garray.h"
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 4fde200a01..d959c5377f 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6837,142 +6837,6 @@ static void frame_add_height(frame_T *frp, int n)
}
}
-// Get the file name at the cursor.
-// If Visual mode is active, use the selected text if it's in one line.
-// Returns the name in allocated memory, NULL for failure.
-char *grab_file_name(int count, linenr_T *file_lnum)
-{
- int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC;
- if (VIsual_active) {
- size_t len;
- char *ptr;
- if (get_visual_text(NULL, &ptr, &len) == FAIL) {
- return NULL;
- }
- // Only recognize ":123" here
- if (file_lnum != NULL && ptr[len] == ':' && isdigit((uint8_t)ptr[len + 1])) {
- char *p = ptr + len + 1;
-
- *file_lnum = getdigits_int32(&p, false, 0);
- }
- return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname);
- }
- return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
-}
-
-// Return the file name under or after the cursor.
-//
-// The 'path' option is searched if the file name is not absolute.
-// The string returned has been alloc'ed and should be freed by the caller.
-// NULL is returned if the file name or file is not found.
-//
-// options:
-// FNAME_MESS give error messages
-// FNAME_EXP expand to path
-// FNAME_HYP check for hypertext link
-// FNAME_INCL apply "includeexpr"
-char *file_name_at_cursor(int options, int count, linenr_T *file_lnum)
-{
- return file_name_in_line(get_cursor_line_ptr(),
- curwin->w_cursor.col, options, count, curbuf->b_ffname,
- file_lnum);
-}
-
-/// @param rel_fname file we are searching relative to
-/// @param file_lnum line number after the file name
-///
-/// @return the name of the file under or after ptr[col]. Otherwise like file_name_at_cursor().
-char *file_name_in_line(char *line, int col, int options, int count, char *rel_fname,
- linenr_T *file_lnum)
-{
- // search forward for what could be the start of a file name
- char *ptr = line + col;
- while (*ptr != NUL && !vim_isfilec((uint8_t)(*ptr))) {
- MB_PTR_ADV(ptr);
- }
- if (*ptr == NUL) { // nothing found
- if (options & FNAME_MESS) {
- emsg(_("E446: No file name under cursor"));
- }
- return NULL;
- }
-
- size_t len;
- bool in_type = true;
- bool is_url = false;
-
- // Search backward for first char of the file name.
- // Go one char back to ":" before "//", or to the drive letter before ":\" (even if ":"
- // is not in 'isfname').
- while (ptr > line) {
- if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) {
- ptr -= len + 1;
- } else if (vim_isfilec((uint8_t)ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) {
- ptr--;
- } else {
- break;
- }
- }
-
- // Search forward for the last char of the file name.
- // Also allow ":/" when ':' is not in 'isfname'.
- len = path_has_drive_letter(ptr) ? 2 : 0;
- while (vim_isfilec((uint8_t)ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
- || ((options & FNAME_HYP) && path_is_url(ptr + len))
- || (is_url && vim_strchr(":?&=", (uint8_t)ptr[len]) != NULL)) {
- // After type:// we also include :, ?, & and = as valid characters, so that
- // http://google.com:8080?q=this&that=ok works.
- if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z')) {
- if (in_type && path_is_url(ptr + len + 1)) {
- is_url = true;
- }
- } else {
- in_type = false;
- }
-
- if (ptr[len] == '\\' && ptr[len + 1] == ' ') {
- // Skip over the "\" in "\ ".
- len++;
- }
- len += (size_t)(utfc_ptr2len(ptr + len));
- }
-
- // If there is trailing punctuation, remove it.
- // But don't remove "..", could be a directory name.
- if (len > 2 && vim_strchr(".,:;!", (uint8_t)ptr[len - 1]) != NULL
- && ptr[len - 2] != '.') {
- len--;
- }
-
- if (file_lnum != NULL) {
- const char *line_english = " line ";
- const char *line_transl = _(line_msg);
-
- // Get the number after the file name and a separator character.
- // Also accept " line 999" with and without the same translation as
- // used in last_set_msg().
- char *p = ptr + len;
- if (strncmp(p, line_english, strlen(line_english)) == 0) {
- p += strlen(line_english);
- } else if (strncmp(p, line_transl, strlen(line_transl)) == 0) {
- p += strlen(line_transl);
- } else {
- p = skipwhite(p);
- }
- if (*p != NUL) {
- if (!isdigit((uint8_t)(*p))) {
- p++; // skip the separator
- }
- p = skipwhite(p);
- if (isdigit((uint8_t)(*p))) {
- *file_lnum = (linenr_T)getdigits_long(&p, false, 0);
- }
- }
- }
-
- return find_file_name_in_path(ptr, len, options, count, rel_fname);
-}
-
/// Add or remove a status line from window(s), according to the
/// value of 'laststatus'.
///
diff --git a/src/nvim/window.h b/src/nvim/window.h
index d20b799e20..9618ff1c2a 100644
--- a/src/nvim/window.h
+++ b/src/nvim/window.h
@@ -8,17 +8,6 @@
#include "nvim/option_defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h" // IWYU pragma: keep
-/// Values for file_name_in_line()
-enum {
- FNAME_MESS = 1, ///< give error message
- FNAME_EXP = 2, ///< expand to path
- FNAME_HYP = 4, ///< check for hypertext link
- FNAME_INCL = 8, ///< apply 'includeexpr'
- FNAME_REL = 16, ///< ".." and "./" are relative to the (current)
- ///< file instead of the current directory
- FNAME_UNESC = 32, ///< remove backslashes used for escaping
-};
-
/// arguments for win_split()
enum {
WSP_ROOM = 0x01, ///< require enough room