user1978019
user1978019

Reputation: 3336

vim: execute keystroke in function without triggering function

I am trying to write a vim function that conditionally changes the behavior of the enter key. I want the enter key to sometimes indent, other times behave "normally". By normally I mean that if a series of cases doesn't apply, act like the function/mapping doesn't exist. The trouble I'm running into is that I'm using <CR> as my trigger to invoke the function, and thus I'm not sure how to just say "oh, none of these cases apply, execute a <CR> as if this mapping was never defined."

As an example, consider this in my .vimrc, which indents the line if it starts with an a, otherwise triggers a carriage return. (My vimscript is very novice, so this function might not be correct, but I think the idea remains...)

function! SpecialEnter()
    let line=getline(".")
    if line =~ '\va*'
        " at least one space then a valid indentation
        normal! >>
    else 
        " just do the regular thing
        " echo "in else"
       call feedkeys("\<CR>")
    endif
endfunction   


inoremap <CR> <Esc>:call SpecialEnter()<CR>

This is somewhat simplified from what I'm actually trying to do, but the concept is the same. I'm looking for a way to say "none of my if statements applied, act like this mapping doesn't exist". Is there a way to do this?

Upvotes: 1

Views: 320

Answers (1)

romainl
romainl

Reputation: 196546

You need to give your mapping the <expr> flag. With this, the right hand side of your mapping is evaluated as an expression.

Here is an example taken from my config where I return different prompts for different commands:

cnoremap <expr> <CR> CCR()

" make list-like commands more intuitive
function! CCR()
    let cmdline = getcmdline()
    command! -bar Z silent set more|delcommand Z
    if cmdline =~ '\v\C^(ls|files|buffers)'
        " like :ls but prompts for a buffer command
        return "\<CR>:b"
    elseif cmdline =~ '\v\C/(#|nu|num|numb|numbe|number)$'
        " like :g//# but prompts for a command
        return "\<CR>:"
    elseif cmdline =~ '\v\C^(dli|il)'
        " like :dlist or :ilist but prompts for a count for :djump or :ijump
        return "\<CR>:" . cmdline[0] . "j  " . split(cmdline, " ")[1] . "\<S-Left>\<Left>"
    elseif cmdline =~ '\v\C^(cli|lli)'
        " like :clist or :llist but prompts for an error/location number
        return "\<CR>:sil " . repeat(cmdline[0], 2) . "\<Space>"
    elseif cmdline =~ '\C^old'
        " like :oldfiles but prompts for an old file to edit
        set nomore
        return "\<CR>:Z|e #<"
    elseif cmdline =~ '\C^changes'
        " like :changes but prompts for a change to jump to
        set nomore
        return "\<CR>:Z|norm! g;\<S-Left>"
    elseif cmdline =~ '\C^ju'
        " like :jumps but prompts for a position to jump to
        set nomore
        return "\<CR>:Z|norm! \<C-o>\<S-Left>"
    elseif cmdline =~ '\C^marks'
        " like :marks but prompts for a mark to jump to
        return "\<CR>:norm! `"
    elseif cmdline =~ '\C^undol'
        " like :undolist but prompts for a change to undo
        return "\<CR>:u "
    else
        return "\<CR>"
    endif
endfunction

Upvotes: 1

Related Questions