5

VIM knows to identify the start and end of code functions with the [[ and ]} commands. How might I use this to colour the gutters or line number backgrounds differently for each function?

The issue is that I often maintain large PHP files written by inexperienced people who lack the concept of maintainability. These files often contain tens of function definitions each spanning thousands of lines. My current nightmare is a function that spans over 3000 lines in a file of 18000 lines. Narrowing plugins don't work very well with PHP (I'll elaborate on that in the comments if needed) so I need another way of determining when I've ned into another function.

My line of thinking is to base a random colour on a hash of the function name, and use that colour as the background for the line numbers. I've gone up and down the vim documentation and googling but have come up with absolutely nothing that could help me. I'm using standard VIM in a KDE Konsole session on Kubuntu:

$ vim --version
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Oct 20 2014 16:09:22)
Included patches: 1-273
Modified by pkg-vim-maintainers@lists.alioth.debian.org
Compiled by buildd@
Huge version without GUI.  Features included (+) or not (-):
+acl             +farsi           +mouse_netterm   +syntax
+arabic          +file_in_path    +mouse_sgr       +tag_binary
+autocmd         +find_in_path    -mouse_sysmouse  +tag_old_static
-balloon_eval    +float           +mouse_urxvt     -tag_any_white
-browse          +folding         +mouse_xterm     -tcl
++builtin_terms  -footer          +multi_byte      +terminfo
+byte_offset     +fork()          +multi_lang      +termresponse
+cindent         +gettext         -mzscheme        +textobjects
-clientserver    -hangul_input    +netbeans_intg   +title
-clipboard       +iconv           +path_extra      -toolbar
+cmdline_compl   +insert_expand   -perl            +user_commands
+cmdline_hist    +jumplist        +persistent_undo +vertsplit
+cmdline_info    +keymap          +postscript      +virtualedit
+comments        +langmap         +printer         +visual
+conceal         +libcall         +profile         +visualextra
+cryptv          +linebreak       +python          +viminfo
+cscope          +lispindent      -python3         +vreplace
+cursorbind      +listcmds        +quickfix        +wildignore
+cursorshape     +localmap        +reltime         +wildmenu
+dialog_con      -lua             +rightleft       +windows
+diff            +menu            -ruby            +writebackup
+digraphs        +mksession       +scrollbind      -X11
-dnd             +modify_fname    +signs           -xfontset
-ebcdic          +mouse           +smartindent     -xim
+emacs_tags      -mouseshape      -sniff           -xsmp
+eval            +mouse_dec       +startuptime     -xterm_clipboard
+ex_extra        +mouse_gpm       +statusline      -xterm_save
+extra_search    -mouse_jsbterm   -sun_workshop    -xpm
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
  fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H     -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: gcc   -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed -o vim        -lm -ltinfo -lnsl  -lselinux  -lacl -lattr -lgpm -ldl    -L/usr/lib/python2.7/config-x86_64-linux-gnu -lpython2.7 -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions
6

Here's a different solution which may be of help: put the current function name in the statusline:

enter image description here

Vim doesn't really have a concept of a "dynamic" statusline; but we can work around that by setting a new statusline on certain autocmd events and/or key mappings.


First, let us define a statusline:

set statusline=
let &statusline .= '%<%f '        " Filename, truncate right
let &statusline .= '%h%m%r'       " [Help] [modified] [read-only]
let &statusline .= " PHP_FUN "

" Save the statusline, we need this later
let g:original_statusline = &statusline

Since you can't append a part to the statusline (the default is empty), you need to "re-create" the original which is what the first 3 lines do. We will replace the text PHP_FUN later on.

See :help 'statusline' and Chapter 17 of Learn Vimscript the Hard Way


Next, we need some code to get the PHP function name, and put that in the statusline:

fun! PHPFunctionInStatusLine()
    " Not a PHP file; remove the "PHP_FUN" part
    if &filetype != 'php'
        let &statusline = substitute(g:original_statusline, 'PHP_FUN', '', '')
        return
    endif

    " Save the cursor position
    let l:save_cursor = getpos(".")

    " Search for the previous function definition
    call search('\s\=function\s', 'bc')

    " Get this line, and prepare it for displaying
    let l:line = substitute(getline('.'), '^\s*', '', '')
    let l:line = substitute(l:line, ' \={ \=', '', '')

    " Put it in the statusline
    let &statusline = substitute(g:original_statusline, 'PHP_FUN', ' ' . l:line . ' ', '')

    " Go back to where we were
    call setpos('.', l:save_cursor)
endfun

The contents of this function should be obvious: we used the saved g:original_statusline variable as a "template", try to find a function, and put it in place of PHP_FUN. For non-PHP files we blank this out.

You can run :call PHPFunctionInStatusLine(), and you should see something like the screenshot above.


To make it fill in the function name automatically, we can define some autocommands, for example:

augroup php
    autocmd!
    " When entering the buffer
    autocmd BufEnter * call PHPFunctionInStatusLine()

    " Starting & leaving Insert mode
    autocmd InsertEnter,InsertLeave *.php call PHPFunctionInStatusLine()

    " The user doesn't press a key for a while in normal & insert mode
    autocmd CursorHold,CursorHoldI *.php call PHPFunctionInStatusLine()

    " Moving the cursor in normal & insert mode
    " This won't be very fast!
    "autocmd CursorMoved,CursorMovedI *.php call PHPFunctionInStatusLine()
augroup end

The status line won't be updated instantly when you move to a new function, you can achieve that with the CursorMoved autocmd, but this is run every time the cursor is moved, so this won't be very fast.

You could also strategically run this function on some key mappings, for example for n:

nnoremap n n:silent call PHPFunctionInStatusLine()<CR>
nnoremap N N:silent call PHPFunctionInStatusLine()<CR>

This will first run n, and immediately after that this function to update the statusline.

Another useful mapping might be:

cnoremap <CR> <CR>:silent call PHPFunctionInStatusLine()<CR>

This will update the statusline after we've pressed the enter key in the Vim command-line.

  • This is absolutely terrific. I have been toying around with getting the function name in the statusbar for years, with varying levels of success. This post answers all the questions that I had and resolved all the issues that I had. I can't accept it as the answer because it does not address the question, so I'll go ask that question in a new thread. Thank you! – dotancohen May 13 '15 at 18:32
  • Here is a good place to answer this answer, so that I could accept it. Thanks. – dotancohen May 13 '15 at 18:38
  • 2
    @dotancohen Thanks :-) I'm not sure of a new question is really required; your "core problem" description reads "I need another way of determining when I've ned into another function.", which is what this answer tries to solve, although It does this in a rather different way than you asked for, but that's because I think what you're asking for is not possible (could be wrong, of course) ... – Martin Tournoij May 13 '15 at 22:18
  • Accepted for resolving the issue. Thanks! – dotancohen May 16 '15 at 13:55
3

You can't highlight line numbers individually.

Signs may help you but you would need to place an awful lot of them to achieve your goal. See :help signs.

When I find myself in a similar situation, I just use folding:

zM    " close every fold
zA    " open the current fold 
  • Thank you. I'll play with folding a bit and see how useful that is. I'll go over the help section for signs, I didn't read that yet as I thought that the term signs refers only to Chris's plugin, not a native feature. – dotancohen May 13 '15 at 8:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.