aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJurica Bradaric <jbradaric@gmail.com>2017-07-16 20:49:07 +0200
committerJurica Bradaric <jbradaric@gmail.com>2017-07-16 21:43:06 +0200
commit9ffa22b7efefebf49a42364de21bb895adabd2de (patch)
treea448f224ed4f0a830d1fd9a5fdd17122f19deea4
parenta76da96e86cc338dd5d8ff2f6014cff68e055ce9 (diff)
downloadrneovim-9ffa22b7efefebf49a42364de21bb895adabd2de.tar.gz
rneovim-9ffa22b7efefebf49a42364de21bb895adabd2de.tar.bz2
rneovim-9ffa22b7efefebf49a42364de21bb895adabd2de.zip
vim-patch:8.0.0023
Problem: "gd" and "gD" may find a match in a comment or string. Solution: Ignore matches in comments and strings. (Anton Lindqvist) https://github.com/vim/vim/commit/226630a030c0d41145e1109f09633360fc9c999d
-rw-r--r--src/nvim/normal.c68
-rw-r--r--src/nvim/testdir/test_goto.vim281
-rw-r--r--src/nvim/version.c2
3 files changed, 328 insertions, 23 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index d891c74fd2..c1676780d8 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -3657,6 +3657,39 @@ nv_gd (
}
}
+// Return true if line[offset] is not inside a C-style comment or string, false
+// otherwise.
+static bool is_ident(char_u *line, int offset)
+{
+ bool incomment = false;
+ int instring = 0;
+ int prev = 0;
+
+ for (int i = 0; i < offset && line[i] != NUL; i++) {
+ if (instring != 0) {
+ if (prev != '\\' && line[i] == instring) {
+ instring = 0;
+ }
+ } else if ((line[i] == '"' || line[i] == '\'') && !incomment) {
+ instring = line[i];
+ } else {
+ if (incomment) {
+ if (prev == '*' && line[i] == '/') {
+ incomment = false;
+ }
+ } else if (prev == '/' && line[i] == '*') {
+ incomment = true;
+ } else if (prev == '/' && line[i] == '/') {
+ return false;
+ }
+ }
+
+ prev = line[i];
+ }
+
+ return incomment == false && instring == 0;
+}
+
/*
* Search for variable declaration of "ptr[len]".
* When "locally" is true in the current function ("gd"), otherwise in the
@@ -3683,6 +3716,7 @@ find_decl (
bool retval = true;
bool incll;
int searchflags = flags_arg;
+ bool valid;
pat = xmalloc(len + 7);
@@ -3717,6 +3751,7 @@ find_decl (
/* Search forward for the identifier, ignore comment lines. */
clearpos(&found_pos);
for (;; ) {
+ valid = false;
t = searchit(curwin, curbuf, &curwin->w_cursor, FORWARD,
pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL);
if (curwin->w_cursor.lnum >= old_pos.lnum)
@@ -3747,20 +3782,35 @@ find_decl (
curwin->w_cursor.col = 0;
continue;
}
- if (!locally) /* global search: use first match found */
+ valid = is_ident(get_cursor_line_ptr(), curwin->w_cursor.col);
+
+ // If the current position is not a valid identifier and a previous match is
+ // present, favor that one instead.
+ if (!valid && found_pos.lnum != 0) {
+ curwin->w_cursor = found_pos;
break;
- if (curwin->w_cursor.lnum >= par_pos.lnum) {
- /* If we previously found a valid position, use it. */
- if (found_pos.lnum != 0)
+ }
+ // global search: use first match found
+ if (valid && !locally) {
+ break;
+ }
+ if (valid && curwin->w_cursor.lnum >= par_pos.lnum) {
+ // If we previously found a valid position, use it.
+ if (found_pos.lnum != 0) {
curwin->w_cursor = found_pos;
+ }
break;
}
- // For finding a local variable and the match is before the "{" search
- // to find a later match. For K&R style function declarations this
- // skips the function header without types. Remove SEARCH_START from
- // flags to avoid getting stuck at one position.
- found_pos = curwin->w_cursor;
+ // For finding a local variable and the match is before the "{" or
+ // inside a comment, continue searching. For K&R style function
+ // declarations this skips the function header without types.
+ if (!valid) {
+ clearpos(&found_pos);
+ } else {
+ found_pos = curwin->w_cursor;
+ }
+ // Remove SEARCH_START from flags to avoid getting stuck at one position.
searchflags &= ~SEARCH_START;
}
diff --git a/src/nvim/testdir/test_goto.vim b/src/nvim/testdir/test_goto.vim
index b6ac5720c3..909e29e27e 100644
--- a/src/nvim/testdir/test_goto.vim
+++ b/src/nvim/testdir/test_goto.vim
@@ -1,22 +1,277 @@
" Test commands that jump somewhere.
-func Test_geeDEE()
+" Create a new buffer using "lines" and place the cursor on the word after the
+" first occurrence of return and invoke "cmd". The cursor should now be
+" positioned at the given line and col.
+func XTest_goto_decl(cmd, lines, line, col)
new
- call setline(1, ["Filename x;", "", "int Filename", "int func() {", "Filename y;"])
- /y;/
- normal gD
- call assert_equal(1, line('.'))
+ call setline(1, a:lines)
+ /return/
+ normal! W
+ execute 'norm! ' . a:cmd
+ call assert_equal(a:line, line('.'))
+ call assert_equal(a:col, col('.'))
quit!
endfunc
-func Test_gee_dee()
- new
- call setline(1, ["int x;", "", "int func(int x)", "{", " return x;", "}"])
- /return/
- normal $hgd
- call assert_equal(3, line('.'))
- call assert_equal(14, col('.'))
- quit!
+func Test_gD()
+ let lines = [
+ \ 'int x;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 1, 5)
+endfunc
+
+func Test_gD_too()
+ let lines = [
+ \ 'Filename x;',
+ \ '',
+ \ 'int Filename',
+ \ 'int func() {',
+ \ ' Filename x;',
+ \ ' return x;',
+ \ ]
+ call XTest_goto_decl('gD', lines, 1, 10)
+endfunc
+
+func Test_gD_comment()
+ let lines = [
+ \ '/* int x; */',
+ \ 'int x;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gD_inline_comment()
+ let lines = [
+ \ 'int y /* , x */;',
+ \ 'int x;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gD_string()
+ let lines = [
+ \ 'char *s[] = "x";',
+ \ 'int x = 1;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gD_string_same_line()
+ let lines = [
+ \ 'char *s[] = "x", int x = 1;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 1, 22)
+endfunc
+
+func Test_gD_char()
+ let lines = [
+ \ "char c = 'x';",
+ \ 'int x = 1;',
+ \ '',
+ \ 'int func(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gD', lines, 2, 5)
+endfunc
+
+func Test_gd()
+ let lines = [
+ \ 'int x;',
+ \ '',
+ \ 'int func(int x)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 3, 14)
+endfunc
+
+func Test_gd_not_local()
+ let lines = [
+ \ 'int func1(void)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ '',
+ \ 'int func2(int x)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 3, 10)
+endfunc
+
+func Test_gd_kr_style()
+ let lines = [
+ \ 'int func(x)',
+ \ ' int x;',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 2, 7)
+endfunc
+
+func Test_gd_missing_braces()
+ let lines = [
+ \ 'def func1(a)',
+ \ ' a + 1',
+ \ 'end',
+ \ '',
+ \ 'a = 1',
+ \ '',
+ \ 'def func2()',
+ \ ' return a',
+ \ 'end',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 11)
+endfunc
+
+func Test_gd_comment()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' /* int x; */',
+ \ ' int x;',
+ \ ' return x;',
+ \ '}',
+ \]
+ call XTest_goto_decl('gd', lines, 4, 7)
+endfunc
+
+func Test_gd_comment_in_string()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' char *s ="//"; int x;',
+ \ ' int x;',
+ \ ' return x;',
+ \ '}',
+ \]
+ call XTest_goto_decl('gd', lines, 3, 22)
+endfunc
+
+func Test_gd_string_in_comment()
+ set comments=
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' /* " */ int x;',
+ \ ' int x;',
+ \ ' return x;',
+ \ '}',
+ \]
+ call XTest_goto_decl('gd', lines, 3, 15)
+ set comments&
+endfunc
+
+func Test_gd_inline_comment()
+ let lines = [
+ \ 'int func(/* x is an int */ int x)',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 32)
+endfunc
+
+func Test_gd_inline_comment_only()
+ let lines = [
+ \ 'int func(void) /* one lonely x */',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 3, 10)
+endfunc
+
+func Test_gd_inline_comment_body()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' int y /* , x */;',
+ \ '',
+ \ ' for (/* int x = 0 */; y < 2; y++);',
+ \ '',
+ \ ' int x = 0;',
+ \ '',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 7, 7)
+endfunc
+
+func Test_gd_trailing_multiline_comment()
+ let lines = [
+ \ 'int func(int x) /* x is an int */',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 14)
+endfunc
+
+func Test_gd_trailing_comment()
+ let lines = [
+ \ 'int func(int x) // x is an int',
+ \ '{',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 1, 14)
+endfunc
+
+func Test_gd_string()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' char *s = "x";',
+ \ ' int x = 1;',
+ \ '',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 4, 7)
+endfunc
+
+func Test_gd_string_only()
+ let lines = [
+ \ 'int func(void)',
+ \ '{',
+ \ ' char *s = "x";',
+ \ '',
+ \ ' return x;',
+ \ '}',
+ \ ]
+ call XTest_goto_decl('gd', lines, 5, 10)
endfunc
" Check that setting 'cursorline' does not change curswant
diff --git a/src/nvim/version.c b/src/nvim/version.c
index c7b8220776..0bc1655a74 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -706,7 +706,7 @@ static const int included_patches[] = {
// 26,
// 25,
// 24 NA
- // 23,
+ 23,
// 22 NA
// 21,
// 20,