Updated patch attach which adds support for skipping strings and
characters that include the identifier. With the patch applied, pressing
gd in the example below would end up on line 4 as opposed of line 3:
int func(void)
{
char *s = "x"; // line #3
int x = 1; // line #4
return x;
^
|
cursor
}
While at it, I added a few more tests to cover this new behavior.
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/src/normal.c b/src/normal.c
index 8302ffb..9a27d3c 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -4240,6 +4240,52 @@ nv_gd(
}
/*
+ * Return TRUE if line[offset] is not inside a C-style comment or string, FALSE
+ * otherwise.
+ */
+static int
+is_ident(char_u *line, int offset)
+{
+ int i;
+ int incomment = FALSE;
+ int instring = FALSE;
+ int prev;
+ int strdel; /* string delimiter character */
+
+ for (i = prev = 0; i < offset && line[i] != NUL; i++)
+ {
+ if (incomment)
+ {
+ if (prev == '*' && line[i] == '/')
+ incomment = FALSE;
+ }
+ else if (prev == '/' && line[i] == '*')
+ {
+ incomment = TRUE;
+ }
+ else if (prev == '/' && line[i] == '/')
+ {
+ return FALSE;
+ }
+
+ if (instring)
+ {
+ if (prev != '\\' && line[i] == strdel)
+ instring = FALSE;
+ }
+ else if (prev != '\\' && (line[i] == '"' || line[i] == '\''))
+ {
+ instring = TRUE;
+ strdel = line[i];
+ }
+
+ prev = line[i];
+ }
+
+ return incomment == FALSE && instring == FALSE;
+}
+
+/*
* Search for variable declaration of "ptr[len]".
* When "locally" is TRUE in the current function ("gd"), otherwise in the
* current file ("gD").
@@ -4264,6 +4310,7 @@ find_decl(
int retval = OK;
int incll;
int searchflags = flags_arg;
+ int valid;
if ((pat = alloc(len + 7)) == NULL)
return FAIL;
@@ -4301,6 +4348,7 @@ find_decl(
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)
@@ -4337,9 +4385,20 @@ find_decl(
continue;
}
#endif
- if (!locally) /* global search: use first match found */
+
+ /* If the current position is not a valid identifier and a previous
+ * match is present, favor that one instead. */
+ if ((valid = is_ident(ml_get_curline(), curwin->w_cursor.col)) == FALSE
+ && found_pos.lnum != 0)
+ {
+ curwin->w_cursor = found_pos;
break;
- if (curwin->w_cursor.lnum >= par_pos.lnum)
+ }
+
+ /* Global search: use first valid 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)
@@ -4347,11 +4406,20 @@ find_decl(
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)
+ {
+ /* Braces needed due to macro expansion of clearpos. */
+ 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/testdir/test_goto.vim b/src/testdir/test_goto.vim
index 2afd96b..7ea5169 100644
--- a/src/testdir/test_goto.vim
+++ b/src/testdir/test_goto.vim
@@ -1,20 +1,237 @@
" 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 key. The cursor should now be
positioned
+" at the given line and col.
+func XTest_goto_decl(key, 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:key
+ 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_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_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