sponsor Vim development Vim logo Vim Book Ad

basic Tip #79: How to use :grep to get a clickable list of function names

 tip karma   Rating 130/40, Viewed by 8237 

Read and edit this tip on the Vim tip wiki. The wiki may have a more recent version of this tip.

created:   June 14, 2001 2:13      complexity:   basic
author:   Flemming Madsen      as of Vim:   6.0


The following function will make a :cwindow window with a line per function
in the current C source file. NOTE: It writes the file as a side effect.

Invoke with ':call ShowFunc()'
You may want to do :nmap <somekey> :call ShowFunc()<CR>

function! ShowFunc()
    
    let gf_s = &grepformat;
    let gp_s = &grepprg;

    let &grepformat; = '%*\k%*\sfunction%*\s%l%*\s%f %*\s%m'
    let &grepprg; = 'ctags -x --c-types=f --sort=no -o -'

    write
    silent! grep %
    cwindow

    let &grepformat; = gf_s
    let &grepprg; = gp_s

endfunc

 rate this tip  Life Changing Helpful Unfulfilling 

<< rotating mail signatures | Restore cursor to file position in previous editing session >>

Additional Notes

[email protected], June 14, 2001 9:11
When I try this from a .c source file:
I get the following error message:

Error detected while processing function ShowFunc:
Regular expressions can't be delimited by letters
Not an editor command:   cwindow
[email protected], June 15, 2001 6:38
I guess this works only with vim 6.0 so cwindow isnt recognized in the above node.
This is a really useful functions. But somehow when I use it on a file opened using explorer.vim it doesnt work as expected. It does list the functions in cwindow but somehow the links dont work. Does anyone know how to fix this.
It the file is opened normally using :e then things work just fine. Very useful, especially with big files.

Thanks.
Parth
Flemming, June 18, 2001 0:14
Some enhancements courtesy of Bill McCarthy:

>     let &grepprg; = 'ctags -x --c-types=f --sort=no -o -'
or just:  let &grepprg; = 'ctags -x --c-types=f --sort=no'
since the '-o -' is redundant with '-x'.
>     write
or better yet:  update
which will not change the filedate on a file that hasn't changed.

leifw at bigfoot , com, July 19, 2001 11:16
I'd suggest that the call to write or update (as noted in the note above) be changed to:
    if (&readonly; == 0) | update | endif
so that you don't get an error message when attempting this on a read only file.
[email protected], September 10, 2001 3:38
for some reason this failes in vim6.0au under unix with file names longer than about 14 characters.  however, if you change
   let &grepformat; = '%*\k%*\sfunction%*\s%l%*\s%f %*\s%m'
to
   let &grepformat; = '%*\k%*\sfunction%*\s%l%*\s%f %m'
then it works fine regardless of file name length.

running on a terminal, if there are a lot of functions in a file then the screen tends to get messed up, which can be fixed by insering a call to redraw after the cwindow call, so you get:
    silent! grep %
    cwindow
    redraw

    let &grepformat; = gf_s
supergrass@gmx.net, February 9, 2002 4:50
WOW! this is absolutely kewl!! thx!!
[email protected], February 25, 2002 20:07
Ok, after installing Exuberant Ctags (ctags.sourceforge.net), and tweaking it a little while, this version of the function works with C, Perl, PHP, Python, Shell and Vim filetypes.

if !exists("*ShowFunc")
  function! ShowFunc()
    let gf_s = &grepformat;
    let gp_s = &grepprg;
    if ( &filetype; == "c" )
      let &grepformat;='%*\k%*\sfunction%*\s%l%*\s%f %m'
      let &grepprg; = 'ctags -x --c-types=f --sort=no'
    elseif ( &filetype; == "perl" )
      let &grepformat;='%*\k%*\ssubroutine%*\s%l%*\s%f %m'
      let &grepprg; = 'ctags -x --perl-types=s --sort=no'
    elseif ( &filetype; == "php" )
      let &grepformat;='%*\k%*\sfunction%*\s%l%*\s%f %m'
      let &grepprg; = 'ctags -x --php-types=f --sort=no'
    elseif ( &filetype; == "python" )
      let &grepformat;='%*\k%*\sfunction%*\s%l%*\s%f %m'
      let &grepprg; = 'ctags -x --python-types=f --sort=no'
    elseif ( &filetype; == "sh" )
      let &grepformat;='%*\k%*\sfunction%*\s%l%*\s%f %m'
      let &grepprg; = 'ctags -x --sh-types=f --sort=no'
    elseif ( &filetype; == "vim" )
      let &grepformat;='%*\k%*\sfunction!%*\s%l%*\s%f %m'
      let &grepprg; = 'ctags -x --vim-types=f --sort=no'
    endif
    if (&readonly; == 0) | update | endif
    silent! grep %
    cwindow
    redraw
    let &grepformat; = gf_s
    let &grepprg; = gp_s
  endfunc
endif


Dave V.
[email protected], March 7, 2002 6:22
It doesn't seem to work or do anything at all for me.

Anyone have any ideas?
[email protected], March 16, 2002 19:56
Ok, couple of small bugs and mistakes fixed.  Try this version:

function! ShowFunc(sort)
  let gf_s = &grepformat;
  let gp_s = &grepprg;
  if ( &filetype; == "c" || &filetype; == "php" || &filetype; == "python" ||
     \ &filetype; == "sh" )
    let &grepformat;='%*\k%*\sfunction%*\s%l%*\s%f %m'
    let &grepprg; = 'ctags -x --'.&filetype.;'-types=f --sort='.a:sort
  elseif ( &filetype; == "perl" )
    let &grepformat;='%*\k%*\ssubroutine%*\s%l%*\s%f %m'
    let &grepprg; = 'ctags -x --perl-types=s --sort='.a:sort
  elseif ( &filetype; == "vim" )
    let &grepformat;='%*\k%*\sfunction%*\s%l%*\s%f %m'
    let &grepprg; = 'ctags -x --vim-types=f --language-force=vim --sort='.a:sort
  endif
  if (&readonly; == 0) | update | endif
  silent! grep %
  cwindow 10
  redraw
  let &grepformat; = gf_s
  let &grepprg; = gp_s
endfunc

I map this function to F3 to produce a list in the order the functions appear in the file or Shift-F3 to list them in alphabetical order.

noremap <F3>   <ESC>:call ShowFunc("no")<CR><ESC>
noremap <S-F3> <ESC>:call ShowFunc("yes")<CR><ESC>

And last be sure you have Exuberant CTags installed or it won't work.

Dave V.
[email protected], April 17, 2002 6:08
I am using vim 6.1 on Unix, it's seems like not working at all. When I do F3 or Shift F3, VIM screen refreshes but nothing else
Himanshu
[email protected], April 27, 2002 21:34
Do you have filetype detection enabled?

If not, add "filetype on" to your .vimrc.

Dave V.
[email protected], July 19, 2002 0:21
This is really cool!  Is there any chance someone could add a java case as well.  I don't really understand whats happening here but adding it to the c et al case doesn't work.
[email protected], August 3, 2002 21:50

Try this:
elseif ( &filetype; == "java" )
    let &grepformat;='%*\k%*\sclass%*\s%l%*\s%f %m'
    let &grepprg; = 'ctags -x --java-types=c --sort='.a:sort

If this produces blank results, then you can try changing the last line to:
    let &grepprg; = 'ctags -x --java-types=c --language-force=java --sort='.a:sort

Good luck,

Dave

[email protected], August 24, 2002 16:57
I increased the number of file types supported to 19.

You can now search for
1. Classes - Java
2. Functions - Awk, C, C++, Fortran, Lisp, Pascal, PHP, Python, Ruby, Shell Scripts, Scheme, Slang, and Vim
3. Macros - Makefiles
4. Procedures - Expect, and Tcl
5. Subroutines - Perl and Rexx

C, Shell Scripts, Vim, Expect, Tcl and Perl are well tested.  The rest work on the few tests that I have given them.  Let me know of any bugs and I'll work them out.

Additionally, I changed it so that it opens a dynamically sized cwindow based on the height of the window it was called from and/or the number of links in the results.  An empty search returns a cwindow a single line tall.  

Last, I packaged this function as a script (vimscript #397) to make it easier to install, and to get it out of my vimrc file.

Dave Vehrs
[email protected], August 27, 2002 8:17
I installed the exuberant-ctags deb file from unstable (after having the same error from testing) and all I get is this error:
ctags: unrecognized option `--c-types=f'

It seems the problem is with ctags but it also seems to be version 5.3 and I can see that line referenced as an example in the man page.  
[email protected], November 7, 2004 9:28

dear sir how do you  sh convert this into straight forward PERL.


                  

                   #!/usr/bin/sh
if test $# -ne "2"
then
        echo ""
        echo Error:  Usage: $0 rooms
        echo ""
        exit 1
fi
if test ! -f $1
then
        echo ""
        echo Error:  File '$1' does not exist
        echo ""
        exit 2
fi

if test -z "`grep -i $2 $1`"
then
        echo ""
        echo Error:  No records found for '$2' building
        echo ""
        exit 3
else
echo ""
echo List of rooms in '$2' building in ascending seat_capacity order
echo ""
grep -i $2 $1 $3  | sort  -b -n -k3  
echo ""
fi
exit 0
set
[email protected], November 7, 2004 9:29

dear sir how do you  sh convert this into straight forward PERL.


                  

                   #!/usr/bin/sh
if test $# -ne "2"
then
        echo ""
        echo Error:  Usage: $0 rooms
        echo ""
        exit 1
fi
if test ! -f $1
then
        echo ""
        echo Error:  File '$1' does not exist
        echo ""
        exit 2
fi

if test -z "`grep -i $2 $1`"
then
        echo ""
        echo Error:  No records found for '$2' building
        echo ""
        exit 3
else
echo ""
echo List of rooms in '$2' building in ascending seat_capacity order
echo ""
grep -i $2 $1 $3  | sort  -b -n -k3  
echo ""
fi
exit 0
set
If you have questions or remarks about this site, visit the vimonline development pages. Please use this site responsibly.
Questions about Vim should go to the maillist. Help Bram help Uganda.
   
Sponsored by Web Concept Group Inc. SourceForge.net Logo