42

I edit a large C, C++, or Java file, say, about 15000 lines, with pretty long function definitions, say, about 400 lines. When the cursor is in middle of a function definition, it would be cool to see the function name in Vim status line.

When we set :set ls=2 in Vim, we can get the file path (relative to the current directory), line number, etc. It would be really cool if we could see the function name too. Any ideas how to get it?

Currently I use [[ to go to start of the function and Ctrl-O to get back to the line I'm editing.

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
Manikandaraj Srinivasan
  • 3,557
  • 5
  • 35
  • 62

8 Answers8

20

To show current function name in C programs add following in your vimrc:

fun! ShowFuncName()
  let lnum = line(".")
  let col = col(".")
  echohl ModeMsg
  echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bW'))
  echohl None
  call search("\\%" . lnum . "l" . "\\%" . col . "c")
endfun
map f :call ShowFuncName() <CR>

Or if you need the "f" key, just map the function to whatever you like.

manav m-n
  • 11,136
  • 23
  • 74
  • 97
  • 2
    Tried most other options, and for me, this is the best and fastest. No need for ctags updates since my code stream is few hundred files, each is few 10k lines. – Ayman Apr 06 '16 at 11:53
  • 2
    The 'n' flag in `search()` won't move the cursor, so a shorter version of this with the same functionality would be: fun! ShowFuncName() echohl ModeMsg echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bWn')) echohl None endfun map f :call ShowFuncName() Reference: run `:help search()` – solidak Jan 19 '17 at 16:37
16

You can use ctags.vim for this, it will show the current function name in the title or status bar.

SOURCE: https://superuser.com/questions/279651/how-can-i-make-vim-show-the-current-class-and-method-im-editing

Community
  • 1
  • 1
Wouter J
  • 41,455
  • 15
  • 107
  • 112
10

Based on @manav m-n's answer

The 'n' flag in search() won't move the cursor, so a shorter version of this with the same functionality would be:

fun! ShowFuncName()
  echohl ModeMsg
  echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bWn'))
  echohl None
endfun
map f :call ShowFuncName() <CR>

Reference: run :help search()

solidak
  • 5,033
  • 3
  • 31
  • 33
2

Having investigated this and the accepted solution, I believe the simplest solution is:

  1. Install Universal Ctags https://ctags.io/

  2. Install Tagbar https://github.com/preservim/tagbar

  3. call tagbar#currenttag() when setting your statusline, e.g. in .vimrc:

    :set statusline=%<%f\ %h%m%r%=%{tagbar#currenttag('%s\ ','','f')}%-.(%l,%c%V%)\ %P

Note that:

  • Spaces must be slash-escaped in the strings you pass to currenttag()...and it's even different between running the command inside vim and putting it in your .vimrc?? Anyway, spaces can be weird, and they're probably something you want when outputting the function name.

  • It took me some digging but the default statusline is

    :set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P

grantpatterson
  • 405
  • 3
  • 11
1

There are several plugins for status line or on-demand with a mapping, e.g.:

Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
1

My solution is as follows:

set stl=%f%h%m%r\ %{Options()}%=%l,%c-%v\ %{line('$')}
fu! PlusOpt(opt)
  let option = a:opt
  if option
    return "+"
  else
    return "-"
  endif
endf

fu! Options()
  let opt="ic".PlusOpt(&ic)
  let opt=opt." ".&ff
  let opt=opt." ".&ft
  if &ft==?"cpp" || &ft==?"perl"
    let text = " {" . FindCurrentFunction() . "}"
    let opt= opt.text
  endif
  return opt

fu! FindCurrentFunction()
  let text =''

  let save_cursor = getpos(".")

  let opening_brace = searchpair('{','','}','bWr', '', '', 100)
  if opening_brace > 0
    let oldmagic = &magic
    let &magic = 1

    let operators='operator\s*\%((\s*)\|\[]\|[+*/%^&|~!=<>-]=\?\|[<>&|+-]\{2}\|>>=\|<<=\|->\*\|,\|->\|(\s*)\)\s*'
    let class_func_string = '\(\([[:alpha:]_]\w*\)\s*::\s*\)*\s*\%(\~\2\|'.operators
    let class_func_string = class_func_string . '\|[[:alpha:]_]\w*\)\ze\s*('

    let searchstring = '\_^\S.\{-}\%('.operators
    let searchstring = searchstring.'\|[[:alpha:]_]\w*\)\s*(.*\n\%(\_^\s.*\n\)*\_^{'

    let l = search(searchstring, 'bW', line(".")-20 )

    if l != 0
      let line_text = getline(l)
      let matched_text = matchstr(line_text, class_func_string)
      let matched_text = substitute(matched_text, '\s', '', 'g')
      let text = matched_text
    endif

    call setpos('.', save_cursor)

    let &magic = oldmagic
  endif

  return text
endfunction

I'm actually attempting to match the C/C++/Java allowed names for functions. This generally works for me (including for overloaded operators) but assumes that the opening { is at column 0 on a line by itself.

I just noticed today that it fails if included in a namespace {}, even if otherwise formatted as expected.

Mark Ping
  • 278
  • 1
  • 6
0

I use https://github.com/mgedmin/chelper.vim for this. It doesn't needs a tags file, instead it parses the source code on the fly.

Marius Gedminas
  • 11,010
  • 4
  • 41
  • 39
0

Based on @solidak solution (which was already based on another one :)

I wanted to always show the function name in the bottom of the terminal. But I had some problems with very large function which I solved that way:

fun! ShowFuncName()
  echohl ModeMsg
  echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bWn'))[:winwidth('%')-3]
  echohl None
endfun

augroup show_funcname
  autocmd CursorMoved * :call ShowFuncName()
augroup end
hsaturn
  • 107
  • 1
  • 4