Vi and Vim Stack Exchange is a question and answer site for people using the vi and Vim families of text editors. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

:help section states:

The "]" and "[" commands stop at the '{' or '}' in the first column. This is useful to find the start or end of a function in a C program.

Is it possible to change the [ and ] commands to jump to a different character or pattern. For example in Markdown, I would like sections defined as titles, lines beginning with # aka the pattern ^#. Similarly in Haskell, I would like it to jump to the next/previous type definition (line containing ::). Both would be set in their respective ftplugin files.

I have tried using map ]] /^#<CR>w but this does not seem to work as expected and leaves text highlighted. It seems like there would be a better way to achieve this.

Is this possible and if so, how would I achieve this?

share|improve this question
up vote 4 down vote accepted

I stole and renamed the function below from $VIMRUNTIME/ftplugin/python.vim :

function! CustomJump(motion) range
    let cnt = v:count1
    let save = @/
    mark '
    while cnt > 0
        silent! execute a:motion
        let cnt = cnt - 1
    endwhile
    call histdel('/', -1)
    let @/ = save
endfunction

and I use it like this in after/ftplugin/javascript.vim to jump from function definition to function definition:

nnoremap <buffer> ]] :call CustomJump('/function')<cr>
nnoremap <buffer> [[ :call CustomJump('?function')<cr>

You could use it like this for markdown:

nnoremap <buffer> ]] :call CustomJump('/^#')<cr>
nnoremap <buffer> [[ :call CustomJump('?^#')<cr>

or like that for haskell:

nnoremap <buffer> ]] :call CustomJump('/::')<cr>
nnoremap <buffer> [[ :call CustomJump('?::')<cr>

But don't forget the awesome :global command:

:g/func/#
:g/^#/#
:g/::/#
share|improve this answer
1  
If my Vim version has :keepjumps, could I remove mark ', and if I have :keeppatterns could I remove let save = @/ and call histdel('/', -1) let @/ = save and replace silent! execute a:motion with something like silent! execute 'keepjumps keeppatterns ' . a:motion? – saginaw Jan 8 at 21:38
1  
Maybe, but you would trade portability for virtually no benefit. – romainl Jan 8 at 22:28
    
I completely misunderstood the purpose of mark ', I thought it was to prevent the jumplist to be modified. But in fact, I think it's the opposite, it's for adding an entry in the jumplist so that you can come back to where you were with '' or ``, sorry. Anyway this is some great code! With this, you can define with autocommands different type of sections for different filetypes. – saginaw Jan 8 at 23:53
    
I'm curious: should that be histdel('/', -1) or histdel('search', -1)? – muru Jan 17 at 18:38
    
@muru, both values are correct, use the one you prefer. See :help hist-names. – romainl Jan 17 at 20:43

The vim-markdown plugin has a function for this in Markdown files:

function! s:JumpToHeader(forward, visual)
  let pattern = '\v^#{1,6}.*$|^.+\n%(\-+|\=+)$'
  if a:visual
    normal! gv
  endif
  if a:forward
    let direction = '/'
  else
    let direction = '?'
  endif
  execute 'silent normal! ' . direction . pattern . "\n"
endfunction

It matches both ATX and setext headers (# foo as well as foo with --- below it). The function is mapped by default to [[ and ]] by the plugin. However, it could benefit from a call to histdel() (as seen in romainl's answer).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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