Huayu Zhang
Huayu Zhang

Reputation: 207

Understand :iabbrev <buffer> iff if:<left>

I typed :autocmd FileType python :iabbrev <buffer> iff if:<left> as this tutorial told.

The output was

if :

Why is there a space between if and ":"?

Upvotes: 0

Views: 328

Answers (2)

Peter Rincker
Peter Rincker

Reputation: 45157

Abbreviation's are triggered by non-keyword (e.g. ., <cr>, <space>, etc), <esc>, or <c-]>. Typing iff alone will is not enough to expand the abbreviation. You typed iff<space> which is enough to expand the abbreviation and puts the <space> inside your expanded abbreviation. You can use <c-]> to expand abbreviations without inserting any extra characters. e.g. iff<c-]>

Eatchar

I however find using <c-]> to be unappealing. Vim's documentation gives us an alternative, the Eatchar function. This function will consume a key matching some pattern and not output it.

function! Eatchar(pat)
  let c = nr2char(getchar(0))
  return (c =~ a:pat) ? '' : c
endfunction

iabbr <buffer> iff if:<left><c-r>=Eatchar('\s')<cr>

Rails.vim like abbreviations

You can take this even further and make Rails.vim-esque abbreviations which only expand on <tab> or a supplied pattern. Think of these as lightweight snippets.

function! RailsExpand(root, good, ...)
  let c = nr2char(getchar(0))
  if c == "" || c =~ (a:0 ? a:1 : "\t")
    return a:good
  else
    return a:root . c
  endif
endfunction

iabbr <buffer> iff <c-r>=RailsExpand('iff', "if:\<left>")<cr>

Now iff<tab> will expand properly. However defining abbreviations like this is a mess.

function! Railsabbrev(root, good)
  let good = substitute(a:good, '[\"|]', '\\&', "g")
  let good = substitute(good, '<', '\\<lt>', "g")
  let root = substitute(a:root, '[\"|]', '\\&', "g")
  let root = substitute(root, '<', '\\<lt>', "g")
  execute "iabbr <buffer> " . a:root . " <c-r>=RailsExpand(\"" . root . "\", \"" . good . "\")<cr>"
endfunction
command! -nargs=* Railsabbrev call Railsabbrev(<f-args>)

Now you can use :Railsabbrev to define your <tab> expanding abbreviation. Example:

Railsabbrev iff if:<left>

Snippets

Sometimes abbreviations are just too simple or too tricky to maintain for multiline expansions. If this is the case I suggest you look for a good snippet plugin. Good choices are UltiSnips or vim-snipmate. Look at their documentation on how to expand and create your own snippets.

More help

:h Abbreviations
:helpg Eatchar

Upvotes: 1

Tumbler41
Tumbler41

Reputation: 432

I assume you're using the space bar after you type iff? If so, it's because of the <left>. This is positioning your cursor one to the left, i.e. between the f and the ":". Once the space bar is accepted your cursor is in between the two characters so it puts a space between them. You can try the command without the <left> and see if that does what you need. If not, you'll need to let us know exactly what output you're looking for us to be able to help you. Also see: :help abbrev if you haven't already.

Upvotes: 1

Related Questions