9

I have over 500 abbreviations(iabbr, abbr) and some mappings in my vimrc file from Java, PHP, C/C++ and Latex.

It is not easy to remember right away when I don't use the languages for some time.

I'm wondering whether I can do completion on abbreviation name. Is there any better way to access/manage all these abbreviations?

10

I don't know what's the best way to manage over 500 abbreviations. Maybe in the long term, as @statox explained, you could have a look at snippets to reduce this number.

And if you want to auto-complete abbreviations, you could try the following code:

augroup GetAbbrev
    autocmd!
    autocmd VimEnter * let s:abbrev_list = [] |
                \ call substitute(join(readfile($MYVIMRC), "\n"), '\v%(^|\n)\s*i?%(nore)?ab%[brev]\s+%(%(\<expr\>|\<buffer\>)\s+){,2}(\k+)', '\=add(s:abbrev_list, submatch(1))', 'gn')
augroup END

set completefunc=CompleteAbbrev
function! CompleteAbbrev(findstart, base)
    if a:findstart
        return searchpos('\<\k', 'bcnW', line('.'))[1] - 1
    else
        return filter(copy(s:abbrev_list), 'v:val =~ "^" . a:base')
    endif
endfunction

To use it, you would have to hit C-x C-u after the beginning of an abbreviation.


The autocmd sets up the variable s:abbrev_list which should contain all your abbreviations.

The function CompleteAbbrev() should return a list of candidates based on the word before the cursor.

The 'completefunc' option's value tells Vim which function to call when you hit C-x C-u.
Note that the option is local to the buffer, so you could still use other functions in different kind of buffers, using an autocmd and the FileType event for example.

See :h complete-functions for more info on how the function works.


Another solution would be to use synonyms completion. From :h i_^x^t:

                            *i_CTRL-X_CTRL-T*
CTRL-X CTRL-T       Works as CTRL-X CTRL-K, but in a special way.  It uses
                    the 'thesaurus' option instead of 'dictionary'.  If a
                    match is found in the thesaurus file, all the
                    remaining words on the same line are included as
                    matches, even though they don't complete the word.
                    Thus a word can be completely replaced.

                    For an example, imagine the 'thesaurus' file has a
                    line like this:
                            angry furious mad enraged
                    Placing the cursor after the letters "ang" and typing
                    CTRL-X CTRL-T would complete the word "angry";
                    subsequent presses would change the word to "furious",
                    "mad" etc.
                    Other uses include translation between two languages,
                    or grouping API functions by keyword.

To use this solution, you would have to do 3 things:

  1. Write the {lhs} of all your abbreviations inside a dedicated file.
    For example, /home/user/mysynonyms.txt. And group them around similar themes.
  2. Add the path to this file to the option 'thesaurus':

    set thesaurus+=/home/user/mysynonyms.txt
    
  3. Hit C-x C-t after the beginning of the name of any abbreviation inside a group.

For example, suppose you have the following abbreviations:

iab cfa CFuncA
iab cfb CFuncB
iab cfc CFuncC

iab jfa JavaFuncA
iab jfb JavaFuncB
iab jfc JavaFuncC

iab pfa PhpFuncA
iab pfb PhpFuncB
iab pfc PhpFuncC

You could group them according to the programming language they belong to.
Inside /home/user/mysynonyms.txt, you would write:

cpp cfa cfb cfc
php pfa pfb pfc
java jfa jfb jfc

Now, whenever you hit C-x C-t after the name of an abbreviation (or just its beginning), Vim should display, in the popup menu, all the abbreviations which are on the same line.

Here's how it would look:

enter image description here

Note that the abbreviations don't need to begin with the same characters to be grouped, they could be entirely different. As long as they're on the same line in your synonyms file, Vim will show all of them.

And you don't have to use the programming language to decide in which group put an abbreviation. You could group them according to any meaningful similarity/topic/category you have in mind.

So, when you forget a specific abbreviation, you could type the first letters of a category, hit C-x C-t and choose the relevant one inside the menu.

Edit:
To dump all your abbreviations inside /home/user/mysynonyms.txt, you could use these 3 Ex commands:

:let abbrev_list = []
:call substitute(join(readfile($MYVIMRC), "\n"), '\v%(^|\n)\s*i?%(nore)?ab%[brev]\s+%(%(\<expr\>|\<buffer\>)\s+){,2}(\k+)', '\=add(abbrev_list, submatch(1))', 'gn')
:call writefile(abbrev_list, '/home/user/mysynonyms.txt')

Edit2:
I've added the flag n when the substitute() function is called because you don't need any substitution. Its only purpose is to add an abbreviation inside a list whenever one is found.
But because you have many abbreviations, it could make the process uselessly slow, I don't know. Initially, I didn't put it because I don't know which Vim version you're using. If your version is newer than 7.3.627, it should be ok, otherwise you would have to remove the n flag.

  • fantastic and comprehensive answer. you Rock – 1234 May 12 '16 at 17:52
  • \v%(^|\n)\s*i?%(nore)?ab%[brev]\s+%(%(\<expr\>|\<buffer\>)\s+){,2}(\k+) is not working on my vimrc file – 1234 May 12 '16 at 19:06
  • @JoobLee It works on my system, do you have any error message? Does it work with a more simple (but less reliable) regex like \vi?abbr\s+(\k+)? Could you give me a link with an excerpt of your abbreviations, to see if I can reproduce your issue? – user9433424 May 12 '16 at 19:12
  • @JoobLee If your Vim version is recent enough, add the n flag to the substitute call (I've edited the answer to include it). If you do a search in your vimrc and you copy-paste this \v^\s*i?%(nore)?ab%[brev]\s+%(%(\<expr\>|\<buffer\>)\s+){,2}\zs\k+, does it highlight your abbreviations? – user9433424 May 12 '16 at 19:26
9

A wikia tip suggest a method to selectively display your abbreviations:

You can list all of your abbreviations with

:ab<CR>

(replace ab by iab to list only insert mode abbreviations)

And you can list all the abbreviations with the same prefix with

:ab prefix<CR>

This is not as ideal as a completion on abbreviations but that could be a good way to rapidly have a list of your existing abbreviations.

To make this solution more efficient a good practice would be to create abbreviation specific to a filetype. For example this abbreviation is only useful in a java buffer:

iabbrev syso System.out.println("");

So it is good to define it like this:

autocmd! FileType java :iabbrev <buffer> syso System.out.println("");

The autocommand part allows to create the abbreviation only when you are in a java buffer and the <buffer> option make the abbreviation accessible only from this buffer.

This way :iab will display the abbreviation only when you are in a java buffer. If you have a lot of abbreviations it could be interesting to create a function by filetype which would define all of the abbreviations and let the autocommand call the function. Something like:

autocmd! FileType latex call CreateLatexAbbrev()

function! CreateLatexAbbrev()
    iabbrev <buffer> something something else
    " All the other latex abbreviations
endfunction

Another solution could be to create your own auto-complete function using a list of your abbreviation as a source of keywords.

Finally I have to say that I'm pretty impressed by "over 500 abbreviations", I don't know which ones you are using but maybe it would be interesting for you to have a look at the concept of snippets if you are not familiar with them. As they are templates that are triggered by entering a keyword and pressing a hotkey, they are more flexible than abbreviations, it might allow you to reduce the number of abbreviations you're using. See here for an interesting introduction.

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.