Vim Tips Wiki
mNo edit summary
 
No edit summary
(14 intermediate revisions by 5 users not shown)
Line 1: Line 1:
  +
{{Duplicate|945|1087|1267|1296}}
 
 
{{review}}
 
{{review}}
  +
{{TipImported
{{Tip
 
 
|id=1454
 
|id=1454
  +
|previous=1440
|title=Shows what function the cursor is in. (for C/C__PLUS____PLUS__)
 
  +
|next=1455
|created=January 1, 2007 2:46
 
  +
|created=January 1, 2007
 
|complexity=intermediate
 
|complexity=intermediate
|author=AOYAMA Shotaro
+
|author=Shotaro Aoyama
 
|version=n/a
 
|version=n/a
 
|rating=11/5
 
|rating=11/5
  +
|category1=C
|text=
 
  +
|category2=C++
This is a function to show what C/C++ function/struct/class
 
  +
}}
  +
This is a function to show what C/C++ function/struct/class the cursor is in. I think this method is fast enough for practical use, but it's not complete.
   
  +
<pre>
the cursor is in.
 
  +
function! GetProtoLine()
  +
let ret = ""
  +
let line_save = line(".")
  +
let col_save = col(".")
  +
let top = line_save - winline() + 1
  +
let so_save = &so
  +
let &so = 0
  +
let istypedef = 0
  +
" find closing brace
  +
let closing_lnum = search('^}','cW')
  +
if closing_lnum > 0
  +
if getline(line(".")) =~ '\w\s*;\s*$'
  +
let istypedef = 1
  +
let closingline = getline(".")
  +
endif
  +
" go to the opening brace
  +
normal! %
  +
" if the start position is between the two braces
  +
if line(".") <= line_save
  +
if istypedef
  +
let ret = matchstr(closingline, '\w\+\s*;')
  +
else
  +
" find a line contains function name
  +
let lnum = search('^\w','bcnW')
  +
if lnum > 0
  +
let ret = getline(lnum)
  +
endif
  +
endif
  +
endif
  +
endif
  +
" restore position and screen line
  +
exe "normal! " . top . "Gz\<CR>"
  +
call cursor(line_save, col_save)
  +
let &so = so_save
  +
return ret
  +
endfunction
   
  +
function! WhatFunction()
  +
if &ft != "c" && &ft != "cpp"
  +
return ""
  +
endif
  +
let proto = GetProtoLine()
  +
if proto == ""
  +
return "?"
  +
endif
  +
if stridx(proto, '(') > 0
  +
let ret = matchstr(proto, '\w\+(\@=')
  +
elseif proto =~# '\<struct\>'
  +
let ret = matchstr(proto, 'struct\s\+\w\+')
  +
elseif proto =~# '\<class\>'
  +
let ret = matchstr(proto, 'class\s\+\w\+')
  +
else
  +
let ret = strpart(proto, 0, 15) . "..."
  +
endif
  +
return ret
  +
endfunction
   
  +
" You may want to call WhatFunction in the statusline
  +
set statusline=%f:%{WhatFunction()}\ %m%=\ %l-%v\ %p%%\ %02B
  +
</pre>
   
  +
This function works well in the following testcase:
I think this method is fast enough for practical use,
 
  +
<pre>
  +
void draw()
  +
{
  +
// When cursor is here, WhatFunction() shows "draw"
  +
glClear(GL_COLOR_BUFFER_BIT {{|}} GL_DEPTH_BUFFER_BIT);
  +
}
   
  +
typedef struct {
but not complete.
 
  +
int ident; // { <- braces in comments are ignored thanks to %. Great!
  +
int version; // here it shows "} HEADER"
  +
} HEADER;
   
  +
# define EX(a, b, c, d) a
Any feedback is appreciated.
 
  +
enum CMD_index
  +
#endif
  +
{
  +
EX(CMD_append, "append", ex_append); // here "enum CMD_index..."
  +
};
   
  +
class Sys {
  +
public:
  +
load() {
  +
// NG: here, it shows "Sys" instead of "load"...
  +
}
  +
};
   
  +
class Camera : public Object
  +
{
  +
public:
  +
void init();
  +
};
   
  +
void Camera::init()
function! GetProtoLine()
 
  +
{
  +
// here WhatFunction shows "init"
  +
}
  +
</pre>
   
  +
==Comments==
let ret = ""
 
  +
I again had some problems with scrolling. This time, side-to-side scrolling in diff mode (specifically no line wrap). When the text was scrolled left, pressing 'h' or 'l' would act as if I'd pressed 'zh' or 'zl'.
   
  +
Similar to the previous issue, I solved the problem by storing the value returned from wincol() in a variable, at the beginning of GetProtoLine(). Then at the end of GetProtoLine(), if wincol() is different, I scroll appropriately.
let line_save = line(".")
 
   
  +
So:
let col_save = col(".")
 
  +
<pre>
  +
" restore position and screen line
  +
exe "normal! " . top . "Gz\<CR>"
  +
call cursor(line_save, col_save)
  +
let &so = so_save
  +
</pre>
   
  +
Became:
let top = line_save - winline() + 1
 
  +
<pre>
  +
" restore position and screen line
  +
exe "normal! " . top . "Gz\<CR>"
  +
call cursor(line_save, col_save)
  +
let line_diff = winline() - window_line
  +
if line_diff > 0
  +
exe 'normal ' . line_diff . '^E'
  +
elseif line_diff < 0
  +
exe 'normal ' . -line_diff . '^Y'
  +
endif
  +
let &so = so_save
  +
</pre>
  +
----
  +
But should be:
  +
<pre>
  +
" restore position and screen line
  +
exe "normal! " . top . "Gz\<CR>"
  +
call cursor(line_save, col_save)
  +
let line_diff = winline() - window_line
  +
" check if we are in diff mode
  +
if &diff
  +
if line_diff > 0
  +
exe 'normal ' . line_diff . '^E'
  +
elseif line_diff < 0
  +
exe 'normal ' . -line_diff . '^Y'
  +
endif
  +
endif
  +
let &so = so_save
  +
</pre>
  +
We need to check if we are in diff mode or it will fail otherwise
  +
----
  +
----
  +
Calling WhatFunction() in the status line breaks multi-line actions like "2yy" for me, just one line is copied instead of two. Any idea how to fix that?
   
  +
----
let so_save = &amp;so
 
  +
To use it, simply enter this (perhaps using a mapping) to show the function name:
  +
<pre>
  +
:echo WhatFunction()
  +
</pre>
   
  +
Or use it in the statusline as already mentioned.
let &amp;so = 0
 
   
  +
The method of finding opening brace can be replaced by the one of {{script|id=1628}}. That's better?
let istypedef = 0
 
   
  +
----
" find closing brace
 
  +
The regexp used to find the function name, assumes that the function name would not have underscores
   
  +
present code:
let closing_lnum = search('^}','cW')
 
  +
let ret = matchstr(proto, '\w\+(\@=')
  +
could be:
  +
let ret = matchstr(proto, '[[:alnum:]_ ]\+(\@=')
   
  +
----
if closing_lnum &gt; 0
 
  +
Don't forget that you'll have tildes in destructor names.
   
  +
So:
if getline(line(".")) =~ '\w\s*;\s*$'
 
  +
let ret = matchstr(proto, '[[:alnum:]_ ]\+(\@=')
  +
could be:
  +
let ret = matchstr(proto, '\~\?[[:alnum:]_ ]\+(\@=')
   
  +
----
let istypedef = 1
 
  +
I set this up to show the function name in my statusline. However, when I was diff-ing two different versions of the same file, and odd scrolling behavior occurred... With the cursor on the bottom line of the window, I pressed 'k', and vi acted as if I pressed 'Ctrl-y'.
   
  +
I solved the problem by storing the value returned from winline() in a variable, at the beginning of GetProtoLine(). Then at the end of GetProtoLine(), if winline() is different, I scroll appropriately.
let closingline = getline(".")
 
   
  +
----
endif
 
   
" go to the opening brace
 
   
  +
'''A shorter (but not perfect) method'''
normal! %
 
   
  +
type "[[" - jump to the previous '{' in the first column. Of course functions must look like this:
" if the start position is between the two braces
 
   
  +
type function_name( ... )
if line(".") &lt;= line_save
 
  +
{
  +
...
  +
}
   
  +
not
if istypedef
 
   
  +
type function_name( ... ) {
let ret = matchstr(closingline, '\w\+\s*;')
 
  +
...
  +
}
   
else
 
   
  +
jump back with "CTRL-O"
" find a line contains function name
 
   
let lnum = search('^\w','bcnW')
 
 
if lnum &gt; 0
 
 
let ret = getline(lnum)
 
 
endif
 
 
endif
 
 
endif
 
 
endif
 
 
" restore position and screen line
 
 
exe "normal! " . top . "Gz\&lt;CR&gt;"
 
 
call cursor(line_save, col_save)
 
 
let &amp;so = so_save
 
 
return ret
 
 
endfunction
 
 
 
 
function! WhatFunction()
 
 
if &amp;ft != "c" &amp;&amp; &amp;ft != "cpp"
 
 
return ""
 
 
endif
 
 
let proto = GetProtoLine()
 
 
if proto == ""
 
 
return "?"
 
 
endif
 
 
if stridx(proto, '(') &gt; 0
 
 
let ret = matchstr(proto, '\w\+(\@=')
 
 
elseif proto =~&#35; '\&lt;struct\&gt;'
 
 
let ret = matchstr(proto, 'struct\s\+\w\+')
 
 
elseif proto =~&#35; '\&lt;class\&gt;'
 
 
let ret = matchstr(proto, 'class\s\+\w\+')
 
 
else
 
 
let ret = strpart(proto, 0, 15) . "..."
 
 
endif
 
 
return ret
 
 
endfunction
 
 
 
 
" You may want to call WhatFunction in the statusline
 
 
set statusline=%f:%{WhatFunction()}\ %m%=\ %l-%v\ %p%%\ %02B
 
 
 
 
 
 
This function works well in the following testcase:
 
 
 
 
void draw()
 
 
{
 
 
// When cursor is here, WhatFunction() shows "draw"
 
 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 
}
 
 
 
 
typedef struct {
 
 
int ident; // { &lt;- braces in comments are ignored thanks to %. Great!
 
 
int version; // here it shows "} HEADER"
 
 
} HEADER;
 
 
 
 
&#35; define EX(a, b, c, d) a
 
 
enum CMD_index
 
 
&#35;endif
 
 
{
 
 
EX(CMD_append, "append", ex_append); // here "enum CMD_index..."
 
 
};
 
 
 
 
class Sys {
 
 
public:
 
 
load() {
 
 
// NG: here, it shows "Sys" instead of "load"...
 
 
}
 
 
};
 
 
 
 
class Camera : public Object
 
 
{
 
 
public:
 
 
void init();
 
 
};
 
 
 
 
void Camera::init()
 
 
{
 
 
// here WhatFunction shows "init"
 
 
}
 
 
 
 
 
}}
 
 
== Comments ==
 
I again had some problems with scrolling. This time, side-to-side scrolling in diff mode (specifically no line wrap). When the text was scrolled left, pressing 'h' or 'l' would act as if I'd pressed 'zh' or 'zl'.
 
 
Similar to the previous issue, I solved the problem by storing the value returned from wincol() in a variable, at the beginning of GetProtoLine(). Then at the end of GetProtoLine(), if wincol() is different, I scroll appropriately...
 
 
So:
 
" restore position and screen line
 
exe "normal! " . top . "Gz\&lt;CR&gt;"
 
call cursor(line_save, col_save)
 
let &amp;so = so_save
 
Became:
 
" restore position and screen line
 
exe "normal! " . top . "Gz\&lt;CR&gt;"
 
call cursor(line_save, col_save)
 
let line_diff = winline() - window_line
 
if line_diff &gt; 0
 
exe 'normal ' . line_diff . '^E'
 
elseif line_diff &lt; 0
 
exe 'normal ' . -line_diff . '^Y'
 
endif
 
let col_diff = wincol() - window_col
 
if col_diff &gt; 0
 
exe 'normal ' . col_diff . 'zl'
 
elseif col_diff &lt; 0
 
exe 'normal ' . -col_diff . 'zh'
 
endif
 
let &amp;so = so_save
 
 
 
'''Anonymous'''
 
, January 9, 2007 5:52
 
 
----
 
----
I again had some problems with scrolling. This time, side-to-side scrolling in diff mode (specifically no line wrap). When the text was scrolled left, pressing 'h' or 'l' would act as if I'd pressed 'zh' or 'zl'.
 
   
  +
''' Jumplist fix'''
Similar to the previous issue, I solved the problem by storing the value returned from wincol() in a variable, at the beginning of GetProtoLine(). Then at the end of GetProtoLine(), if wincol() is different, I scroll appropriately...
 
   
  +
The script modified the :jumplist, to fix this, change <tt>normal! %</tt> to <tt>keepjumps normal! %</tt> and <tt>exe "normal! " . top . "Gz\<CR>"</tt> to <tt>exe "keepjumps normal! " . top . "Gz\<CR>"</tt>.
So:
 
" restore position and screen line
 
exe "normal! " . top . "Gz\&lt;CR&gt;"
 
call cursor(line_save, col_save)
 
let &amp;so = so_save
 
Became:
 
" restore position and screen line
 
exe "normal! " . top . "Gz\&lt;CR&gt;"
 
call cursor(line_save, col_save)
 
let line_diff = winline() - window_line
 
if line_diff &gt; 0
 
exe 'normal ' . line_diff . '^E'
 
elseif line_diff &lt; 0
 
exe 'normal ' . -line_diff . '^Y'
 
endif
 
let col_diff = wincol() - window_col
 
if col_diff &gt; 0
 
exe 'normal ' . col_diff . 'zl'
 
elseif col_diff &lt; 0
 
exe 'normal ' . -col_diff . 'zh'
 
endif
 
let &amp;so = so_save
 
   
  +
(BTW, the original reg ex accepts "_", because it is in \w, why should a change be needed?)
   
'''Anonymous'''
 
, January 9, 2007 5:51
 
 
----
 
----
Calling WhatFunction() in the status line breaks multi-line actions like "2yy" for me, just one line is copied instead of two. Any idea how to fix that?
 
   
  +
I think it could be helpful to add a way to quickly disable it for a buffer:
andrel--AT--cybernoia.de
 
, January 15, 2007 0:46
 
----
 
It would have been better if you could also tell how to use it!!!
 
   
  +
<pre>
'''Anonymous'''
 
  +
" allow to quickly disable it (:let b:noWhatFunction=1)
, January 4, 2007 4:20
 
  +
if exists("b:noWhatFunction") && b:noWhatFunction
----
 
  +
return ""
To use it, simply
 
  +
endif
:echo WhatFunction()
 
  +
</pre>
shows the function name.
 
Or use it in the statusline as already mentioned.
 
   
The method of finding opening brace can be replaced by the on of vimscript &#35; 1628.
 
That's better?
 
 
'''Anonymous'''
 
, January 4, 2007 14:03
 
 
----
 
----
The regexp used to find the function name, assumes that the function name would not have underscores
 
   
  +
''' All-in-One-Version '''
present code:
 
let ret = matchstr(proto, '\w\+(\--AT--=')
 
could be:
 
let ret = matchstr(proto, '[[:alnum:]_ ]\+(\--AT--=')
 
   
  +
To simplify using all the improvements, here an update C&P-ready:
And yes, Thank you, AOYAMA Shotaro
 
   
  +
<pre>
  +
function! GetProtoLine()
  +
let ret = ""
  +
let line_save = line(".")
  +
let col_save = col(".")
  +
let window_line = winline()
  +
let top = line_save - winline() + 1
  +
let so_save = &so
  +
let &so = 0
  +
let istypedef = 0
  +
" find closing brace
  +
let closing_lnum = search('^}','cW')
  +
if closing_lnum > 0
  +
if getline(line(".")) =~ '\w\s*;\s*$'
  +
let istypedef = 1
  +
let closingline = getline(".")
  +
endif
  +
" go to the opening brace
  +
keepjumps normal! %
  +
" if the start position is between the two braces
  +
if line(".") <= line_save
  +
if istypedef
  +
let ret = matchstr(closingline, '\w\+\s*;')
  +
else
  +
" find a line contains function name
  +
let lnum = search('^\w','bcnW')
  +
if lnum > 0
  +
let ret = getline(lnum)
  +
endif
  +
endif
  +
let lines = closing_lnum - line(".")
  +
let line_rel = line_save - line(".")
  +
let ret = ret . ':' . line_rel . '/' . lines
  +
endif
  +
endif
  +
"exe "keepjumps normal! " . top . "Gz\<CR>"
  +
" restore position and screen line
  +
call cursor(line_save, col_save)
  +
" needed for diff mode (scroll fixing)
  +
let line_diff = winline() - window_line
  +
if line_diff > 0
  +
exe 'normal ' . line_diff . "\<c-e>"
  +
elseif line_diff < 0
  +
exe 'normal ' . -line_diff . "\<c-y>"
  +
endif
  +
" sometimes cursor position is wrong after scroll fix, why? Workaround:
  +
call cursor(line_save, col_save)
  +
let &so = so_save
  +
return ret
  +
endfunction
   
  +
function! WhatFunction()
nihars--AT--gmail.com
 
  +
" allow to quickly disable it (:let b:noWhatFunction=1)
, January 8, 2007 1:17
 
  +
if exists("b:noWhatFunction") && b:noWhatFunction
----
 
  +
return ""
Don't forget that you'll have tildas in destructor names.
 
  +
endif
 
  +
if &ft != "c" && &ft != "cpp"
So:
 
  +
return ""
let ret = matchstr(proto, '[[:alnum:]_ ]\+(\--AT--=')
 
  +
endif
could be:
 
  +
let proto = GetProtoLine()
let ret = matchstr(proto, '\~\?[[:alnum:]_ ]\+(\--AT--=')
 
  +
if proto == ""
 
  +
return "?"
 
  +
endif
'''Anonymous'''
 
  +
let line_info = matchstr(proto, ':\d\+\/\d\+')
, January 8, 2007 6:33
 
  +
if stridx(proto, '(') > 0
----
 
  +
let ret = matchstr(proto, '\~\?\w\+(\@=')
I set this up to show the function name in my statusline. However, when I was diff-ing two different versions of the same file, and odd scrolling behavior occured... With the cursor on the bottom line of the window, I pressed 'k', and vi acted as if I pressed 'Ctrl-y'.
 
  +
elseif proto =~# '\<struct\>'
 
  +
let ret = matchstr(proto, 'struct\s\+\w\+')
I solved the problem by storing the value returned from winline() in a variable, at the beginning of GetProtoLine(). Then at the end of GetProtoLine(), if winline() is different, I scroll appropriately...
 
  +
elseif proto =~# '\<class\>'
 
  +
let ret = matchstr(proto, 'class\s\+\w\+')
So:
 
  +
else
" restore position and screen line
 
  +
let ret = strpart(proto, 0, 15) . "..."
exe "normal! " . top . "Gz\&lt;CR&gt;"
 
  +
endif
call cursor(line_save, col_save)
 
let &amp;so = so_save
+
let ret .= line_info
  +
return ret
Became:
 
  +
endfunction
" restore position and screen line
 
  +
</pre>
exe "normal! " . top . "Gz\&lt;CR&gt;"
 
call cursor(line_save, col_save)
 
let line_diff = winline() - window_line
 
if line_diff &gt; 0
 
exe 'normal ' . line_diff . '^E'
 
elseif line_diff &lt; 0
 
exe 'normal ' . -line_diff . '^Y'
 
endif
 
let &amp;so = so_save
 
 
 
'''Anonymous'''
 
, January 8, 2007 12:33
 
----
 
<!-- parsed by vimtips.py in 0.329770 seconds-->
 

Revision as of 13:33, 7 November 2012

Duplicate tip

This tip is very similar to the following:

These tips need to be merged – see the merge guidelines.

Tip 1454 Printable Monobook Previous Next

created January 1, 2007 · complexity intermediate · author Shotaro Aoyama · version n/a


This is a function to show what C/C++ function/struct/class the cursor is in. I think this method is fast enough for practical use, but it's not complete.

function! GetProtoLine()
  let ret       = ""
  let line_save = line(".")
  let col_save  = col(".")
  let top       = line_save - winline() + 1
  let so_save = &so
  let &so = 0
  let istypedef = 0
  " find closing brace
  let closing_lnum = search('^}','cW')
  if closing_lnum > 0
    if getline(line(".")) =~ '\w\s*;\s*$'
      let istypedef = 1
      let closingline = getline(".")
    endif
    " go to the opening brace
    normal! %
    " if the start position is between the two braces
    if line(".") <= line_save
      if istypedef
        let ret = matchstr(closingline, '\w\+\s*;')
      else
        " find a line contains function name
        let lnum = search('^\w','bcnW')
        if lnum > 0
          let ret = getline(lnum)
        endif
      endif
    endif
  endif
  " restore position and screen line
  exe "normal! " . top . "Gz\<CR>"
  call cursor(line_save, col_save)
  let &so = so_save
  return ret
endfunction

function! WhatFunction()
  if &ft != "c" && &ft != "cpp"
    return ""
  endif
  let proto = GetProtoLine()
  if proto == ""
    return "?"
  endif
  if stridx(proto, '(') > 0
    let ret = matchstr(proto, '\w\+(\@=')
  elseif proto =~# '\<struct\>'
    let ret = matchstr(proto, 'struct\s\+\w\+')
  elseif proto =~# '\<class\>'
    let ret = matchstr(proto, 'class\s\+\w\+')
  else
    let ret = strpart(proto, 0, 15) . "..."
  endif
  return ret
endfunction

" You may want to call WhatFunction in the statusline
set statusline=%f:%{WhatFunction()}\ %m%=\ %l-%v\ %p%%\ %02B

This function works well in the following testcase:

void draw()
{
    // When cursor is here, WhatFunction() shows "draw"
    glClear(GL_COLOR_BUFFER_BIT {{|}} GL_DEPTH_BUFFER_BIT);
}

typedef struct {
    int ident;  // { <- braces in comments are ignored thanks to %. Great!
    int version;    // here it shows "} HEADER"
} HEADER;

# define EX(a, b, c, d)  a
enum CMD_index
#endif
{
EX(CMD_append, "append", ex_append); // here "enum CMD_index..."
};

class Sys {
public:
    load() {
        // NG: here, it shows "Sys" instead of "load"...
    }
};

class Camera : public Object
{
public:
    void init();
};

void Camera::init()
{
    // here WhatFunction shows "init"
}

Comments

I again had some problems with scrolling. This time, side-to-side scrolling in diff mode (specifically no line wrap). When the text was scrolled left, pressing 'h' or 'l' would act as if I'd pressed 'zh' or 'zl'.

Similar to the previous issue, I solved the problem by storing the value returned from wincol() in a variable, at the beginning of GetProtoLine(). Then at the end of GetProtoLine(), if wincol() is different, I scroll appropriately.

So:

  " restore position and screen line
  exe "normal! " . top . "Gz\<CR>"
  call cursor(line_save, col_save)
  let &so = so_save

Became:

  " restore position and screen line
  exe "normal! " . top . "Gz\<CR>"
  call cursor(line_save, col_save)
  let line_diff = winline() - window_line
  if line_diff > 0
    exe 'normal ' . line_diff . '^E'
  elseif line_diff < 0
    exe 'normal ' . -line_diff . '^Y'
  endif
  let &so = so_save

But should be:

  " restore position and screen line
  exe "normal! " . top . "Gz\<CR>"
  call cursor(line_save, col_save)
  let line_diff = winline() - window_line
  " check if we are in diff mode
  if &diff
    if line_diff > 0
      exe 'normal ' . line_diff . '^E'
    elseif line_diff < 0
      exe 'normal ' . -line_diff . '^Y'
    endif
  endif
  let &so = so_save

We need to check if we are in diff mode or it will fail otherwise



Calling WhatFunction() in the status line breaks multi-line actions like "2yy" for me, just one line is copied instead of two. Any idea how to fix that?


To use it, simply enter this (perhaps using a mapping) to show the function name:

:echo WhatFunction()

Or use it in the statusline as already mentioned.

The method of finding opening brace can be replaced by the one of script#1628. That's better?


The regexp used to find the function name, assumes that the function name would not have underscores

present code:

let ret = matchstr(proto, '\w\+(\@=')

could be:

let ret = matchstr(proto, '[[:alnum:]_ ]\+(\@=')

Don't forget that you'll have tildes in destructor names.

So:

let ret = matchstr(proto, '[[:alnum:]_ ]\+(\@=')

could be:

let ret = matchstr(proto, '\~\?[[:alnum:]_ ]\+(\@=')

I set this up to show the function name in my statusline. However, when I was diff-ing two different versions of the same file, and odd scrolling behavior occurred... With the cursor on the bottom line of the window, I pressed 'k', and vi acted as if I pressed 'Ctrl-y'.

I solved the problem by storing the value returned from winline() in a variable, at the beginning of GetProtoLine(). Then at the end of GetProtoLine(), if winline() is different, I scroll appropriately.



A shorter (but not perfect) method

type "[[" - jump to the previous '{' in the first column. Of course functions must look like this:

  type function_name( ... )
  {
      ...
  }

not

  type function_name( ... ) {
     ...
  }


jump back with "CTRL-O"


Jumplist fix

The script modified the :jumplist, to fix this, change normal! % to keepjumps normal! % and exe "normal! " . top . "Gz\<CR>" to exe "keepjumps normal! " . top . "Gz\<CR>".

(BTW, the original reg ex accepts "_", because it is in \w, why should a change be needed?)


I think it could be helpful to add a way to quickly disable it for a buffer:

  " allow to quickly disable it (:let b:noWhatFunction=1)
  if exists("b:noWhatFunction") && b:noWhatFunction
    return ""
  endif

All-in-One-Version

To simplify using all the improvements, here an update C&P-ready:

function! GetProtoLine()
  let ret       = ""
  let line_save = line(".")
  let col_save  = col(".")
  let window_line = winline()
  let top       = line_save - winline() + 1
  let so_save = &so
  let &so = 0
  let istypedef = 0
  " find closing brace
  let closing_lnum = search('^}','cW')
  if closing_lnum > 0
    if getline(line(".")) =~ '\w\s*;\s*$'
      let istypedef = 1
      let closingline = getline(".")
    endif
    " go to the opening brace
    keepjumps normal! %
    " if the start position is between the two braces
    if line(".") <= line_save
      if istypedef
        let ret = matchstr(closingline, '\w\+\s*;')
      else
        " find a line contains function name
        let lnum = search('^\w','bcnW')
        if lnum > 0
          let ret = getline(lnum)
        endif
      endif
      let lines = closing_lnum - line(".")
      let line_rel = line_save - line(".")
      let ret = ret . ':' . line_rel . '/' . lines
    endif
  endif
  "exe "keepjumps normal! " . top . "Gz\<CR>"
  " restore position and screen line
  call cursor(line_save, col_save)
  " needed for diff mode (scroll fixing)
  let line_diff = winline() - window_line
  if line_diff > 0
    exe 'normal ' . line_diff . "\<c-e>"
  elseif line_diff < 0
    exe 'normal ' . -line_diff . "\<c-y>"
  endif
  " sometimes cursor position is wrong after scroll fix, why? Workaround:
  call cursor(line_save, col_save)
  let &so = so_save
  return ret
endfunction

function! WhatFunction()
  " allow to quickly disable it (:let b:noWhatFunction=1)
  if exists("b:noWhatFunction") && b:noWhatFunction
    return ""
  endif
  if &ft != "c" && &ft != "cpp"
    return ""
  endif
  let proto = GetProtoLine()
  if proto == ""
    return "?"
  endif
  let line_info = matchstr(proto, ':\d\+\/\d\+')
  if stridx(proto, '(') > 0
    let ret = matchstr(proto, '\~\?\w\+(\@=')
  elseif proto =~# '\<struct\>'
    let ret = matchstr(proto, 'struct\s\+\w\+')
  elseif proto =~# '\<class\>'
    let ret = matchstr(proto, 'class\s\+\w\+')
  else
    let ret = strpart(proto, 0, 15) . "..."
  endif
  let ret .= line_info
  return ret
endfunction