14

I am a new user of vim (gvim in windows), and have found abbreviations a nice time saver - however they would be even better if i could stop the trailing whitespace at times.

I have some directories that i use a lot, and so i added some abbreviation/path pairs to my _vimrc:

:ab diR1 C:/dirA/dira/dir1/
:ab diR2 C:/dirA/dirb/dir2/ 

etc ...

Now when i type diR1 <space> i get C:/dirA/dira/dir1/[]| where the whitespace is represented by [] and the cursor is the | character. I would like to get rid of the [] == whitespace.

This is a minor complaint: however you seem to be able to customise everthing else in Vim so i figured i'd ask -- is it possible to avoid the trailing whitespace when one uses abbreviations in vim?

An alternate tool used within Vim is a good answer - my objective is to save re-typing frequently used directory structures, but to have the cursor handy as i would almost always add something to the end, such as myFile.txt.

The trailing white space (doubtless due to the fact that the space triggered the abbreviation) which i backspace over before adding myFile.txt to the end is less annoying than typing the whole thing over and over, but it would be ideal if i could avoid doing so ...

ricardo
  • 8,195
  • 7
  • 47
  • 69

3 Answers3

22

pb2q answer is exactly what you want in your current scenario, but does not fully answer the question presented in the title. This exact problem is addressed in the vim help file. See :helpgrep Eatchar. The example it gives is this:

You can even do more complicated things.  For example, to consume the space
typed after an abbreviation: >
   func Eatchar(pat)
      let c = nr2char(getchar(0))
      return (c =~ a:pat) ? '' : c
   endfunc
   iabbr <silent> if if ()<Left><C-R>=Eatchar('\s')<CR>

You would put the Eatchar function in your ~/.vimrc file and then use like so in your abbreviations:

iabbr <silent> diR1 C:/dirA/dira/dir1/<c-r>=Eatchar('\m\s\<bar>/')<cr>

This would "eat" any trailing white space character or a slash. Note that I used iabbr instead of just abbr, because it is rare to actually want abbreviations to expand in command line mode. You must be careful with abbreviations in command line mode as they will expand in unexpected places such as searches and input() commands.

For more information see:

:h abbreviations
:helpgrep Eatchar
:h :helpgrep
Community
  • 1
  • 1
Peter Rincker
  • 43,539
  • 9
  • 74
  • 101
  • 1
    +1. thanks that's helpful. I understand it (i think) down to the `('\m\s\|\/')` bit. i am not confident with vim regex just yet. can you please explain? – ricardo Aug 08 '12 at 23:33
  • Vim's regex's have different levels of `'magic'`. `\m` will use `magic` for the current regex. `\|` allows the regex to branch so either a whitespace (`\s`) or a slash (`/`). Vim is funny in that many regex components need to be escaped with a backslash. If you wanted a more Perl like regex you can use `\v\s|/`. The `\v` means very magic and less things need to be escaped. Please note that I had an error in regex in the post above. It should be `\m\s\|/`. Also the `|` character will be interpreted incorrectly for this mapping and needs to be changed to ``. I have corrected my post. – Peter Rincker Aug 08 '12 at 23:55
  • at the moment, when i enter it with the `=Eatchar('\m\s|\/')` i get the following error: `Error detected while pricessing C:\vim\abrevs.txt: line 3: E35: No previous regular expression` (i source my abbrev file in my _vimrc). by trial and error i found that removing everything following the `` works -- thus, at this point i have `:iabbr diR1 C:/dirA/dira/dir1/`, and i do not get the whitespace at the end. – ricardo Aug 08 '12 at 23:59
  • 1
    The issue is that the `|` is getting interpreted as vim's operator that separates 2 different commands. This means `|` needs to be escaped as a key so instead of `|` it should be ``. The entire command will now be: `iabbr diR1 C:/dirA/dira/dir1/=Eatchar('\m\s\/')` – Peter Rincker Aug 09 '12 at 00:15
  • I have asked a follow up question regarding a multi-line case of the Eatchar problem: http://stackoverflow.com/questions/11877160/how-to-eatchar-in-a-multi-line-vim-abbreviation – ricardo Aug 09 '12 at 05:13
  • 1
    Note that the `=Eatchar('\s')` part needs to be last, so if you want to reposition the cursor, do it first, i.e. `iabbr pr print("")2hi=Eatchar('\m\s')`, not `iabbr pr print("")=Eatchar('\m\s')2hi` – Terry Brown Oct 11 '18 at 20:45
15

This is possible, without more customization than just abbrev.

The abbreviation is being triggered by the space character, as you know. The space is a non-keyword character, and remains after the abbreviation is expanded.

But there are other ways to trigger the expansion, such as other non-keyword characters, including /. So if you instead define your abbreviations like this:

:ab diR1 C:/dirA/dira/dir1

That is, without the trailing path separator, then you can type diR1/, have the abbreviation expand for you because of the slash /, and continue typing, appending to your path with a file name.

Alternately, you can force abbreviation expansion using Ctrl-]. That is, type the abbreviation: diR1, with no following space or other non-keyword character, and then type Ctrl-]. The abbreviation will be expanded and you'll remain in insert mode, and can append your file name to the expanded path.

Check out :help abbreviations, there may be something else useful for you there, including more complicated constructions for always consuming e.g. the space character that triggered the abbreviation.

pb2q
  • 58,613
  • 19
  • 146
  • 147
  • 1
    wonderful. i adjusted my abbreviation and now trigger it with `/`. I am sure i'll also use the `Ctrl-]` method at times as well, for other abbreviations. I must have missed these bit of the docs. Many thanks. – ricardo Aug 08 '12 at 08:02
1

Instead of abbreviations, you could use mappings. They're expanded as soon as you have typed the last character of the mapping, so there won't be a trailing space:

:inoremap diR1 c:/dirA/dira/dir1

The downside for this approach is that the letters you type while a mapping could be expanded are not displayed until the mapping is finished. This takes some using used to.

René Nyffenegger
  • 39,402
  • 33
  • 158
  • 293