Vimscript Operator-Pending Mappings yields "Trailing characters" error - vim

I am trying to reproduce the example in chapter 15 of Steve Losh's "Learn Vimscript the Hard Way" (http://learnvimscriptthehardway.stevelosh.com/chapters/15.html), in the section called "Changing the Start."
First, I start vim with the following command:
vim -u NONE foo
to ensure that no plugins are loaded.
Next I type
print foo(bar)
in the buffer and then enter
:onoremap in( :<c-u>normal! f(vi(<cr>
Finally, I place the cursor over the "p" in "print" and enter cin(. The status line displays:
:<c-u>normal! f(vi(<cr>
with a blinking cursor at the end. I hit enter and the status line then displays:
E488: Trailing characters
The expected outcome, according to the book, is that vim will delete the contents of the parentheses and place you in insert mode between them.
Here is the version info:
VIM - Vi IMproved 8.0 (2016 Sep 12, compiled May 2 2017 03:55:34)
MacOS X (unix) version
Included patches: 1-596
Compiled by Homebrew

TL;DR: use vim -u DEFAULTS foo instead.
That should keep Vim in 'nocompatible' mode, which is needed for <Key> codes to be recognized in mappings.
The symptoms you describe are consistent to having < included in 'cpoptions', which is documented to:
Disable the recognition of special key codes in <> form in mappings, abbreviations, and the "to" part of menu commands. For example, the command :map X <Tab> results in X being mapped to "<Tab>" (5 characters) when < is included; but "^I" (^I is a real <Tab>) when < is excluded.
That is consistent with you getting the literal result of your mapping in your command-line, without proper expansion of the <c-u> and <cr> key codes.
The defaults for 'cpoptions' are:
Vim default: "aABceFs",
Vi default: all flags
So this means < (along with all other flags) will be included by default in Vi mode, which is triggered when 'compatible' is set (or, perhaps more accurately, when 'nocompatible' is not set.)
It turns out that when you use -u NONE in your command-line starting Vim, it will start in 'compatible' mode.
You can use instead -u DEFAULTS, which is quite similar to -u NONE, but it will still load the defaults.vim script shipped with Vim runtime, which will among other things set 'nocompatible'.
From the docs:
When -u DEFAULTS (all uppercase) is passed, this has the same effect as -u NONE, but the defaults.vim script is loaded, which will also set 'nocompatible'.
Using the -u argument with another argument than DEFAULTS has the side effect that the 'compatible' option will be on by default. This can have unexpected effects.

Related

Vim in terminal is slow

I'm using vim in the terminal a log and I'm getting frustrated with its slow performance. I'm on Debian Jessie using Gnome.
If I open a file in vim do a block select and I to insert on multiple lines there is always a delay from when I press esc to when the change is inserted.
If I do the the same thing in gvim the change is imidiate.
I have tried adding
set ttyfast
set lazyredraw
In my ~/.vimrc but that does not make any noticeable difference.
$ vim --verion
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 20 2015 15:31:14)
Included patches: 1-930
This is completely normal.
In Vim, some special keys (like the cursor keys) are implemented as <Esc> followed by some other character. Therefore, Vim waits a bit after your press <Esc> to determine if you actually wanted <Esc> or if you wanted something else like <Esc>A (<Up>).
See :help 'timeout', :help 'timeoutlen', :help 'ttimeout', and :help 'ttimeoutlen'.

Override a builtin command with cabbrev

I'm trying to override 'w' in vim so it would call an external program and filter the buffer instead of writing to a file. There are very good examples across the internet about how to do that. I tried one from vim.wikia.com, but vim always complains with E488: Trailing characters. This is the command in my vimrc:
cabbrev w <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'W' : 'w')<CR>
I'm not very familiar with vim script. I tried removing <CR> from the end of the line with no luck.
UPDATE
Since I want to run vim as customized as possible I run it with the -u flag. I noticed that vim behaves differently when using that flag compared to running it without it
With the -u flag the expanded abbreviation is what needs to be evaluated as code.
Without the flag, the abbreviation is what it is intended to be (here I enter the cabbrev rule from vim's prompt)
Regarding the -u flag vim's man page says this:
-u {vimrc} Use the commands in the file {vimrc} for
initializations. All the other initializations
are skipped. Use this to edit a special kind of files. It can also be used to skip all
initializations by giving the name "NONE". See ":help initialization" within vim for more
details.
Apparently when this flag is used the initialization from
vim /etc/vimrc is not performed and there I found this option:
set nocompatible
vim's help about compatible option:
This option has the effect of making Vim either more Vi-compatible, or
make Vim behave in a more useful way. This is a special kind of
option, because when it's set or reset, other options are also changed
as a side effect. CAREFUL: Setting or resetting this option can have
a lot of unexpected effects: Mappings are interpreted in another way,
undo behaves differently, etc. If you set this option in your vimrc
file, you should probably put it at the very start.
...
When a vimrc or gvimrc file is found while Vim is starting up,
this option is switched off, and all options that have not been
modified will be set to the Vim defaults. Effectively, this means
that when a vimrc or gvimrc file exists, Vim will use the Vim
defaults, otherwise it will use the Vi defaults. (Note: This doesn't
happen for the system-wide vimrc or gvimrc file, nor for a file given
with the -u argument).
set nocompatible makes the cabbrev syntax from the question work

what are the commands that can work in vi and not in vim?

Vim is an ascendant text editor to vi and is 99% compatible to the latter can someone tell me what is the 1%. I mean the command that can be executed in vi mode and not in vim.
You'll find the list at :help vi-differences. The only noted omission from Vim is the open mode; in Vim, :open is only emulated.
The runtime behavior can be controlled via the 'cpoptions' option; each letter in it stands for one vi-compatibility; most are turned off in Vim-mode (i.e. with :set nocompatible, or when a .vimrc file is found).

set complete+=k[file] not working for whole line completion?

I have ~/.bash_history that contains lines such as sudo apt-get install, aplay foo.wav, etc. I thought it would be convenient if I could use these lines for completing whole lines while writing shell scripts.
:h compl-whole-line says:
CTRL-X CTRL-L
Search backwards for a line that starts with the
same characters as those in the current line before
the cursor. Indent is ignored. The matching line is
inserted in front of the cursor.
** The 'complete' option is used to decide which buffers
are searched for a match. Both loaded and unloaded
buffers are used.**
Note the asterisks I inserted. :h 'complete' says:
k k{dict} scan the file {dict}. Several "k" flags can be given,
patterns are valid too. For example: >
:set cpt=k/usr/dict/*,k~/spanish
So I thought :set complete+=k~/.bash_history would do the job. It didn't.
Start vim with
$ vim -u NONE -N
then
:set complete+=k~/.bash_history
:set complete?
" complete=.,w,b,u,t,i,k~/.bash_history
, I enter to the insert mode (i), and when I type
su<C-x><C-l>
, vim says Whole line completion (^L^N^P) Pattern not found. The completion is working for words, so when I type
su<C-p>
sudo is suggested.
What am I missing? How can I use my history for whole line completion without :sp ~/.bash_history?
set complete+=k[file] has nothing to do with line completion: whatever file you give to it will only be used as a source by dictionary completion (<C-x><C-k>) and keyword completion (<C-n>/<C-p>).
:help i_ctrl-x_ctrl-l is clear: line completion only works with lines found in loaded and unloaded buffers. Since ~/.bash_history is not loaded as a buffer, line completion will obviously never use it as a source.
So yes, the only practical solution is to load that file.
:sp ~/.bash_history is not really optimal, though, because a) it takes too much room, both physically and in your buffer list, and b) it requires way too many keystrokes.
The "too much room" part of the problem is easily solved with a more suited command:
:badd ~/.bash_history
The "too many keystrokes" part of the problem could be solved with an autocommand that runs the command above each time you edit a shell script:
augroup shell
autocmd!
autocmd BufNewFile,BufRead *.sh badd ~/.bash_history
augroup END

How to exit from "vim -y" in console?

Accidentally I typed vim -y install python-requests instead of yum ... and I do not know how to exit from vim now. Standard option with shift + : + q! does not work. Are there any options how to exit from vim without killing it?
With -y (easy mode), Vim defaults to insert mode, and you cannot permanently exit to normal mode via <Esc>. However, like in default Vim, you can issue a single normal mode command via <C-O>. So to exit, type <C-O>:q!<CR>.
Alternatively, there's a special <C-L> mapping for easy mode that returns to normal mode.
-y option makes vim start in easy mode, you can type CTRL-L to return to normal mode and then type :q! to exit.
I use the gVim Easy, and it works for me to add the set im! in the .gvimrc.
gVim Easy v.s. gVim
It's good to remember that vim and vim -y (gVim Easy) are almost identical except for these differences:
vim starts out in NORMAL mode; vim -y starts out in INSERT mode.
Esc, Ctrl-[, and Ctrl-C exit INSERT mode in vim. However, these do not work in vim -y. Instead, these have been replaced with Ctrl-L.
And it's good to remember this important similarity as well:
In INSERT mode, both vim and vim -y will allow you to use the Ctrl- commands that work during INSERT mode. Examples include:
Ctrl-T to indent the current line.
Ctrl-D to dedent (that is, un-indent) the current line.
Ctrl-N and Ctrl-P to auto-complete the word currently being typed.
Ctrl-R x to paste the contents of register x where the cursor is.
and, relevant to this thread:
Ctrl-O to temporarily enter NORMAL mode to issue one NORMAL-mode command (after which you'll immediately return to INSERT mode).
Hopefully you'll see that this last one (the Ctrl-O command) will allow you to save (with :w), save-and-quit (with :wq), discard unsaved changes (with :e!), as well as simply quit-without-saving (with :q!).
You can also use Ctrl-O followed by a non-ex command, like u (for "undo"), dd (to delete the current line), ZZ (to save-and-quit), and ZQ (to quit-without-saving).
So if you're not familiar with using Ctrl- commands in vim's INSERT mode, I strongly recommend learning at least the Ctrl-O command, as remembering that will help you figure out how to exit (and save documents in) vim -y. (While knowledge of Ctrl-L will help with vim -y, knowledge of Ctrl-O will help in both vim -y and vim.)
Key Takeaways
If there are only two things you remember from this post, remember these:
vim's normal way of exiting INSERT mode (that is, Esc, Ctrl-[, and Ctrl-C) have been replaced with Ctrl-L in vim -y (Vim Easy).
The INSERT mode command of Ctrl-O works just as well in vim -y (Vim Easy) as it does in vim. So you can use it to your advantage to execute any NORMAL commands you want.

Resources