3

I like to define some abbreviations like:

cabbr csf cscope find

I thought cabbr would just be interpreted in the : command line. However, when I entered the search mode \, I found that \csf would still be expanded to \cscope find, which definitely was not what I want.
So how to deal with this situation? If I do want to search csf, what should I do? Or there is another kind of abbreviation other than cabbr intended to be valid just in the : command line? Thanks very much!

3 Answers 3

7

What you can do is use an expression abbreviation. This will allow you to use any Vim expression on the right-hand side, instead of just a static string. With getcmdtype() we can check if we're doing a normal Ex command or something else.

cabbr <expr> csf getcmdtype() == ':' ? 'cscope find' : 'csf'

See :help :map-<expr> for the documentation.

1
  • The problem with this solution is that if you have to search and replace the letters 'csf', they get replaced with 'cscope find' i.e. if you try to enter the command: %s/csf /foo /
    – lyderic
    Mar 17, 2022 at 10:37
3

You could also define 2 custom commands :Cab and :Sab which would make the definition of such abbreviations easier.
:Cab would define an abbreviation which would only affect an Ex command, while :Sab would only modify a search.

The following code tries to define these commands:

command! -nargs=+ Cab call s:StrictAbbr(<q-args>, 1)
command! -nargs=+ Sab call s:StrictAbbr(<q-args>, 0)

function! s:StrictAbbr(args, cmd) abort
    let l:lhs = matchstr(a:args, '^\s*\zs\S*')
    let l:rhs = matchstr(a:args, '^\s*\S*\s\+\zs.*')
    if a:cmd
        execute printf("cnoreabbrev <expr> %s getcmdtype() ==# ':' ? '%s' : '%s'", l:lhs, l:rhs, l:lhs)
    else
        execute printf("cnoreabbrev <expr> %s getcmdtype() =~ '[/?]' ? '%s' : '%s'", l:lhs, l:rhs, l:lhs)
    endif
endfunction

Now to define the abbreviation mentioned in your post, you could write :

Cab csf cscope find

And to define the abbreviation which transforms fb in foo bar, but only in a search:

Sab fb foo bar

These abbreviations could be written anywhere in your vimrc, but only after the previous code, otherwise you'll have an error such as:

E492: Not an editor command: Sab fb foo bar

The code is heavily inspired from this post and from the accepted answer.

0

Another solution, that works in every case for me:

cnoreabbrev csf <c-r>=getcmdpos() == 1 && getcmdtype() == ":" ? "cscope find" : "csf"<CR>

Credit: https://vim.fandom.com/wiki/Replace_a_builtin_command_using_cabbrev

2
  • Welcome to this site! :) Could you explain what is the point of reimplementing the <expr> by using the expression register like Martin does in his answer?
    – statox
    Mar 17, 2022 at 11:41
  • Using <expr> doesn't cover the scenario where you would like to search/replace 'csf' : i.e. doing ':%s/csf /foo /' would expand 'csf', replacing it with 'cscope find'. You have to test for the command type (:) AND the command position (1). I couldn't find a way to do this using <expr> :-( i.e. cabbr <expr> getcmdpos() == 1 && getcmdtype() == ":" .... doesn't work for me). I don't know why. I am on 8.2.4464 on Linux (self compiled).
    – lyderic
    Mar 18, 2022 at 14:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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