I usually do a search and replace in vim that looks like this:
:%s/\([\.!?]\|[\.!?]"\)\s\s/\1text /g
So it looks for either a period, exclamation point, question mark, or any of the above followed by a quote and two spaces. It works fine.
But when I map this in my vimrc like so
map <F4> :%s/\([\.!?]\|[\.!?]"\)\s\s/\1text /g<CR>
and then press F4 I get this error message:
E486: Pattern not found: \([\.!?]|[\.!?]"\)\s\s
It is removing the backslash before the pipe for some reason and I have no idea why. Does anyone know how to correct this behavior?
In a :mapping, the pipe character is special. Use <Bar> instead:
:noremap <F4> :%s/\([\.!?]\<Bar>[\.!?]"\)\s\s/\1text /g<CR>
Also, you should use :noremap; it makes the mapping immune to remapping and recursion.
Related
I use rxvt-unicode terminal emulator on Manjaro, and the following two mappings in my .vimrc don't work,
nnoremap <C-PageUp> :tabprevious<CR>
nnoremap <C-PageDown> :tabnext<CR>
even though the following does work
nnoremap <C-t> :tabnew<CR>
I think the reason for the behavior you observe is exactly the one described here.
In other words, something like this (what the rhs is doesn't matter)
nnoremap <C-PageUp> :echo "hello"<CR>
will not work as Vim does not now which escape sequence corresponds to the keycode <C-PageUp>.
Therefore, you can provide it with the escape sequence corresponding to Ctrl-PageUp, as in
nnoremap ^[[5^ :echo "hello"<CR>
where the first two characters of the escape sequence, ^[, are part of a single unit that corresponds to Escape (that's why escape seqeunce).
You can get the whole sequence (which could be different from mine in your terminal, by the way) from insert mode by hitting
Ctrl+VCtrl+PageUp; however, given the meaning of ^[, you can also use Ctrl+VEscape and then type [5^ manually.
Unfortunately, putting set <C-PageUp>=^[[5^ causes error E518. I don't know why.
On the other hand, another solution is the following (again described here)
set <F37>=^[[5^
nnoremap <F37> :echo "ciao"<CR>
where <F37> is one of the extra function keycode Vim provides. I have no clue where this thing is in the :help.
I have my .vimrc in a different path, that I source from my main ~/.vimrc (so I can share same settings across Windows, bash on Windows, etc).
I'm trying to write something in the .vimrc in question, that would make a hotkey for editing said .vimrc, without hard coding the path.
What I currently have is this:
let g:vimrc_path = expand('<sfile>')
:map <Leader>v exec(":e " + g:vimrc_path + "<CR>")
But this doesn't seem to do anything. I've verified that g:vimrc_path is the right value, and that the <Leader>v ends up being called by subbing in echo messages, but I'm not wrapping my head around why the variable I'm trying to define doesn't get expanded correctly.
String concatenation is done with ., not with +, which performs coercion into numbers and addition. But :execute takes multiple arguments (which it space-separates), so you don't actually need this here.
You should use :noremap; it makes the mapping immune to remapping and recursion.
Also, I doubt you need visual and operator-pending modes (:help map-modes), so define this just for normal mode.
:exec[ute is an Ex command, so for a normal-mode mapping, you need to first enter command-line mode. So :exec 'edit' instead of exec ':edit'.
Also, this is not a function (though Vim 8 now also has execute()), so the parentheses are superfluous.
The <silent> avoids the printing of the whole command (you'll notice the loading of the vimrc file, anyway); it's optional.
The fnameescape() ensures that pathological path names are also handled; probably not necessary here.
let g:vimrc_path = expand('<sfile>')
nnoremap <silent> <Leader>v :execute 'edit' fnameescape(g:vimrc_path)<CR>
Alternative
As the script path is static, you can move the variable interpolation from runtime (mapping execution) to mapping definition, and get rid of the variable:
execute 'nnoremap <Leader>v :edit' fnameescape(expand('<sfile>')) . '<CR>'
Strings in vimscript are concatenated with ., not with +. For example:
:echo "Hello"." world!"
will echo
Hello world!
If you were to type
:echo "Hello" + " world!"
vim would echo
0
This is because the + operator is only for numbers, so vim attempts to cast these strings to numbers. If you were to run
:echo "3" + "1"
vim would echo "4".
So basically, you just need to change
:map <Leader>v exec(":e " + g:vimrc_path + "<CR>")
to
:map <Leader>v exec(":e ".g:vimrc_path."<CR>")
Another problem you might have not seen is that "<CR>" evaluates to the literal text "<CR>", so it only messes up your function. If you want a literal carriage return, you would need a backslash. However, you definitely do not want to do this! Seriously, try it out and see.
You can see the issue. It looks for a file that has a literal carriage return at the end of the filename! There is a very simple fix though. Remove the "\<cr>" completely. Since :exec runs ex commands by default, the carriage return (and the colon too for that matter) are unnecessary.
Also, as a nitpick,
The parenthesis are not needed for the "exec" function, and
Use nnoremap instead to avoid recursive mappings.
Taking all of this into consideration, I would simplify it to
:nnoremap <Leader>v :exec "e ".g:vimrc_path<cr>
I want to remap another key combo, say CTRL-G, to function as CTRL-D does (note: not the same as S-Down/PageDown/CTRL-F).
What I have so far is:
nmap ^G :exe 'normal '.&scroll.'^E<CR>'
Bringing up my vim command mode and typing this in, it works perfectly. However, when I save my .vimrc and reload vim, I get the following error when pushing CTRL-G:
E114: Missing quote: '
E15: Invalid expression: 'normal '.&scroll.'
It seems to be stuck at not evaluating the ^E appropriately. However, I have been entirely unsuccessful in using or any other way of specifying CTRL-E. What am I missing here?
^G and ^E are special characters, and do not work well when you put them in the .vimrc. You need to use <C-g> and <C-e>, but since your Ctrl+E is placed inside a string, you need to escape it and write \<C-e>. You also need to use double quotes instead of single quotes - otherwise you can't do the escaping.
In other note - you should probably use nnoremap instead of nmap, so that if you remap <C-e> somewhere else, <C-g> will still behave like the original <C-e>.
I think you can just write <C-E> for CTRL-E.
I've tried:
:map <F2> :.y" :g/<C-R>"/d<CR>
No luck :(
What this does, yank the current line into register "
Then, globally, delete lines that match exactly the line in the register.
It works dandy when I do it manually.
:vmap <F2> ["]yy<ESC><ESC> :g/<C-R>"/d<CR>
Similar to above - I select a few words, whatever - I make a selection, then yank it to register ". I then globally, delete the lines that match whats in the register.
It works dandy when I do it manually.
What am I doing wrong?
You might try this for the first one:
:nnorempa <F2> :silent exe "g/".getline(".")."/d"<CR>
For the second, something like this if you want to delete only the words:
:vmap <F7> y:silent exe "%s/".#"."//g"<CR>
And this if you want to delete the matching lines:
:vmap <F7> y:silent exe "g/".#"."/d"<CR>
You have remapped F2 to :.y" :etc. You need <cr> not a simple space. If you type :.y" in vim and don't hit ENTER but space, nothing will happen.
So:
:nnoremap <f2> :.y"<CR>:g/<C-R>"/d<CR>
could do it.
Still, warning, if your line contains any of /\*[~$^. this could fail. You could use the expression register in order to escape in-place:
:nnoremap <f2> :.y"<CR>:g/<c-r>=escape(#", '/\*[~$^.')<cr>/d<cr>
Still better, without overwriting your default (") register is:
:nnoremap <f2> :g/^<c-r><c-o>=escape(getline('.'), '/\*[~$^.')<CR>$/d<cr>
which will delete all identical lines. Still note that 'ignorecase' or 'smartcase' matter.
First of all - make sure you're using vim :)
vim --version
Here's the mapping I was going for. As I go through lots of data in log files, this will be incredibly useful. Select the area you want to eliminate, then and all instances of highlight area is done for.
NOTE: This does NOT go through the highlighted text and escape any regex characters. So a /, *, ^ will foul it up.
:map <F2> y:g/<C-R>"/d<CR>
:)
I would like to map a key using "map" from within my vimrc file like this:
map <C-I> :split ~/some/file
That command actually works fine.
My question is: how do I call a vim function (in this case, "resolve()") on that file path from within the map/split line. This doesn't work, but hopefully you get the point:
map <C-I> :split =resolve("~/some/file")
Perhaps it uses call()? I'm obviously confused about vim scripting in general. Thanks for your help!
There are two additional ways of doing this which will work outside of a mapping and are safer then using <C-r> (POSIX allows filenames with any byte but \x00, including control codes):
nnoremap <C-i> :execute "split" fnameescape(resolve("~/some/file"))<CR>
nnoremap <C-i> :split `=resolve("~/some/file")`<CR>
In second case no escaping is needed, but filename must not contain newline (it won't hurt, just will produce an error).
Another things to consider:
Use nnoremap, it will enable you to, for example, exchange meanings of ; and : without changing maps and also prevent your map from being spoiled by plugins unless they redefine <Tab> mapping (<C-i> is same as <Tab>). Forced normal mode is here because in other modes it will produce unexpected results.
Escape arguments: fnameescape(resolve("~/some/file")), it will prevent errors for filenames with spaces.
You can write <C-r> where #Austin Taylor suggested to write raw control code. I don't like having any of them inside a file because it will make diffs not viewable in a terminal.
map <C-I> :split ^R=resolve("~/some/file")<cr><cr>
If you are putting this in .vimrc, you type C-v C-r to type the ^R character.