How to add abbrevs made of more than one word?

I've been trying:

iabbrev a aquilo àquilo
iabbrev a aquele àquele
iabbrev a aquela àquela

What I want to do is have the two words "a aquilo" expand to "àquilo".

But it won't work. Also, I see in the docs for abbrev:

Examples of strings that cannot be abbreviations: "a.b", "#def", "a b", "_$r"

So I'm assuming that it can't be done officially, I wonder if is there a work around?


  • You reassign the same abbreviation several times. Moreover, you do it recursively.
    – Matt
    Jul 4 '19 at 12:45

You can accomplish what you're trying to do by using an expression (introduced using <C-r>=, or using <expr> when defining the abbreviation) and then matching a single "a" word at the end of the text that precedes the word being abbreviated.

When you find that "a" word, then you can expand it to a <C-w>, that will delete that word, followed by the abbreviation you desire.

You can use this function to implement all the "à" (named crase) abbreviations in Portuguese:

function Crase()
    " Get the list of words until this point,
    " including the one being abbreviated.
    let words = split(getline('.')[0:col('.')-2])
    " By default, return the word itself.
    let replacement = words[-1]
    " Check if a word 'a' precedes it.
    if len(words) >=# 2 && words[-2] ==? 'a'
        " Handle capitalization.
        if words[-2] ==# 'A' || words[-1] =~# '^A'
            let replacement = substitute(replacement, '^\ca', 'À', '')
            let replacement = substitute(replacement, '^\ca', 'à', '')
        " Remove the 'a' word and
        " contract the 'crase'.
        return "\<C-w>".replacement
    " Otherwise, no change.
    return replacement

It looks at the sentence so far, then takes the two last words in it (when using iab <expr>, you'll get the word being abbreviated as well.) Then it checks whether the second last word was an "a" or an "A". If that's the case, it will then remove that word (using the "\<C-w>" at the beginning of the expansion), then return the word being abbreviated, just replacing the first character (which must be an "a", lower or uppercase!) with an "à" or an "À".

The function does proper capitalization, so "A aquele" will be expanded to "Àquele", as expected.

Use the function as follows:

inoreabbrev <expr> aquele Crase()
inoreabbrev <expr> Aquele Crase()
inoreabbrev <expr> AQUELE Crase()
inoreabbrev <expr> aquela Crase()
inoreabbrev <expr> Aquela Crase()
inoreabbrev <expr> AQUELA Crase()
inoreabbrev <expr> aquilo Crase()
inoreabbrev <expr> Aquilo Crase()
inoreabbrev <expr> AQUILO Crase()

You can even use it for "a a", turn it into "à", with:

inoreabbrev <expr> a Crase()
inoreabbrev <expr> A Crase()
  • 1
    This is quite clever! Well done! The end should probably be explicitly endif, however.
    – D. Ben Knoble
    Jul 4 '19 at 16:54
  • Also, you can use expand('<cword>') to get the word under the cursor (though this may not work if the abbreviation is triggered with a space—needs testing).
    – D. Ben Knoble
    Jul 4 '19 at 16:55
  • @DBenKnoble Thanks! Fixed :endif (turns out :end is a valid abbreviation for it.) I thought of <cword> but since I also need the preceding word I decided to use getline() instead. (That's what I saw in similar examples too.) Thanks for the feedback!
    – filbranden
    Jul 4 '19 at 17:06

Simply omit the first a and change the abbreviation as a compromise:

inoreabbrev aaquilo àquilo
inoreabbrev aaquele àquele
inoreabbrev aaquela àquela

As should be clear from :help abbrev.

The reason you can't have a aquilo -> àquilo is that vim sees a -> aquilo àquilo. The left-hand-side of the abbreviation must follow certain patterns (see :help abbreviations and then /full-id).

  • You may also be more interested in the 'spell' features of vim
    – D. Ben Knoble
    Jul 4 '19 at 13:43
  • It turns out "aquilo" (that) and "àquilo" (to that) are two different words. This is like trying to abbreviate "you are" into "you're" or "is not" into "isn't".
    – filbranden
    Jul 4 '19 at 14:52
  • @filbranden so what do you want to abbreviate? You cannot have a turn into all of those words unless you have iabbrev a aquilo àquilo aquele ... (and you dont get a choice...). Would aaquilo -> àquilo be acceptable?
    – D. Ben Knoble
    Jul 4 '19 at 14:56
  • I guess you can kind of match what the OP is asking with an :iab <expr>, looking back if there's a preceding "a" word, but not sure you can remove that "a" with an <expr> and that would be required. Yes I'd suggest "aaquilo" as a great compromise, I'd upvote an answer that explains why abbreviations have to be a single word and suggesting that compromise.
    – filbranden
    Jul 4 '19 at 15:02
  • @filbranden apologies... I mistook you for the OP /embarassed
    – D. Ben Knoble
    Jul 4 '19 at 15:28

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.