Vim function normal mode then execute - vim

I have the following code:
function CSVTableFunc(command)
let cursor = getpos('.')
let l:winview = winsaveview()
normal(ggVG)
execute a:command
call setpos('.', cursor)
call winrestview(l:winview)
endfunction
Basically, what it does is it selects all lines from top to bottom, then executes the command that's passed in the function.
However, before the command is executed, the lines selected before hand are deselected.
What's the thing that I've missed?
Cheers!

A couple problems here.
First, you attempted to use normal(...) as if it's a function. It's not (and if it was, you used it wrong anyway, you'd be missing a call command).
What you actually told Vim was to run the following normal-mode commands:
( - back a sentence
ggVG - roughly, select all text in the buffer
) - forward a sentence
Some experimentation shows this probably actually doesn't cause any problems, but it's wrong, and it could cause problems in other circumstances.
Your bigger problem is that commands don't actually operate on a range unless you tell them to. In visual mode (i.e. when you've selected a range of lines), when you press : you automatically get '<,'> inserted on the command line. This text says "run the command on the visual selection".
Using execute does not automatically insert this range. You'd need to manually put the range at the beginning of the command, if the command supports a range. Since you did not do this, your command only runs with its default range, which is usually the current line. In your case, since you did ggVG before running your command, you probably see the command run on the last line only.
Anyway, you don't need the visual selection. Just use the special range % instead of selecting anything. % means "on every line".
The problem is, some commands may not support a range. For those commands, you will probably need to use a loop, or a :g command, to run the command on each line of interest one by one.

Related

vim: Prevent :exe from quitting after error

I have an error-checking one-liner vim command that looks like the following. It's not directly part of the question but works as an example, so feel free to ignore it:
:'<,'>g/foo{.*}/exe "norm! mxf{lvt}y/\\(foo{\\)\\#!\<C-R>\"\<enter>yy'xP"
Here is an explanation:
:'<,'>g/foo{.*}/ - Run the following command on all highlighted lines with foo{...}
exe "norm! - Start executing normal mode commands on each line
mx - Record the current line
f{lvt}y - Copy everything inside the curly braces of foo{...}
/\\(foo{\\)\\#!\<C-R>\"\<enter> - Forward search to an instance where the string inside the curly braces of foo{...} is not inside foo
yy'xP" - Copy that line, go back to x, and paste it above.
This is basically an error-checking command to see that every time a term is wrapped by foo{, it is always wrapped by foo. However, exe exits on the first case where / (forward search) doesn't find anything. I don't want that to happen.
How do I make exeand :g continue even with errors inside the exe command? I have tried :silent, but that does not save it.
I'd rather keep this as a one-liner, but functions are a second option I am okay with.
:silent alone is not enough. You need to use :silent!. From :help :silent (emphasis mine):
When [!] is added, error messages will also be
skipped, and commands and mappings will not be aborted
when an error is detected.

How to use ":g/regex/d_" without losing current cursor position

In Vim, if you run
:g/some_word/d_
all lines containing "some_word" are removed and the cursor automatically jumps to the place of last deletion. I want the cursor to stay where it was before the operation. How do I accomplish this?
You can't make the cursor stay but you can make it go back to where it was:
:g/some_word/d_|norm ''
The answer by romainl is a good one, and it should do the trick without any additional fuss.
If this is a common problem, and you'd rather not add the additional norm! '' at the end (or type the key sequence when you're done), you could encapsulate it in a command:
command! -nargs=* G call s:G(<q-args>)
function! s:G(args)
let saved_position = winsaveview()
exe 'g'.a:args
call winrestview(saved_position)
endfunction
The :G command will invoke the s:G function with all of its arguments, which saves the position, runs the normal g with these exact arguments, and then restores it. So you'd do :G/some_word/d_ and it would run the command and restore the cursor in the line/column where it started.
Obviously, this only makes sense if you use it often enough and you don't often work on bare Vims (like on remote servers and such). Otherwise, it might be a better idea to try romainl's suggestion, or get used to typing in ''. Your choice.
Also, if the current position happens to be after some of these lines, the cursor might end up in an unexpected place. For example, if your cursor is on line 7 and the command deletes line 3, then you'll be back at line 7, but all the text will have shifted up one line, so you'll be in the "wrong" place. You could probably play around with this function and compensate for the change, but it'll get pretty complicated pretty fast, so I wouldn't recommend it :)
The anwolib plugin provides a handy :KeepView command; you can apply this to any Ex command, so it's even more generic than the :G command suggested by #AndrewRadev:
:KeepView g/some_word/d_

Easy motion vim plugin mapping issue

I have the vim EasyMotion plugin installed.
Pressing,
<Leader><Leader>f searches forward from the current line.
<Leader><Leader>F searches backward from the current line.
Is there a way to search the entire visible part of the buffer only using 'f'? I would ideally not want to use two different bindings for searching forwards and backward. One single binding to search the entire visible portion of the buffer would be most ideal.
You can try a mapping like this:
nnoremap <leader><leader>f :execute "/\\%>" . line('w0') . "1\\%<" . line('w$') . "l"<left>
That's a confusing syntax, so I'll unpack it.
line('w0') and line('w$') return the line numbers of the first and last visible lines in the buffer, respectively, so you use them to find the range for the visible part.
The / search command allows a range to be specified, but with an odd syntax. The format is /\%>Xl\%<Yl where X is the line to start from and Y is the line to end at.
It's not possible to just drop the results from line() into a normal / invocation, but we can build a string, using . to join segments together, and once the command is built, pass it in to :exec to make it happen.
Finally, there's the <left>. That's for cursor positioning. When you execute <leader><leader>f, the whole mapping fires as though you were typing it, so you end up with the full :exec command on the line, and it ends with a ", but you want to type inside those quotes. Alternatively, you could remove "<left> from the end of the mapping, but then you'll have to remember to close the quote after typing your search term.
I'm not familiar with EasyMotion, so this may not give you exactly what you were asking for (I realized this after I typed up the answer), but it will let you run a search in the currently visible part of a buffer only, and you can probably adapt it to EasyMotion's purposes without too much difficulty.

Vim: How to handle newlines when storing multiple commands in registers?

I have a file where I store snippets of vim commands. When I need a snippet, I yank it and then execute it with #". The snippets are stored as a script, one line per command, like this:
:s/foo/bar/g
:echo "hello"
:s/1/2/g
Edit: I removed normal mode commands from the example, as they were not part of the problem.
Now this procedure doesn't work anymore: when executing the snippet, it just stops at the first line as if waiting for a newline.
Is there an option somewhere affecting how # is executed? I'm pretty sure it was working some time ago...
Substituting the newline with a ^M character works but makes the file more difficult to handle.
Additional information:
Here's another symptom: when I yank a snippet, if I execute it with #" it stops at the first line as I just explained. But if I execute it with :# it works. But the help file doesn't seem to imply any difference in how the two commands treat the register's content...
I don't think the problem is ^M vs. ^J. Vim macros will treat either one as a valid end-of-line character for recorded macros. I think the problem is extra newlines.
In your example, there's at least one spurious newline after 2j, and unless you're particularly careful when copying the snippet, there's probably another one after 10k as well. These extra newlines are like pressing <Enter> in Normal mode -- they move the cursor down one line.
Here's what I think you want the snippet to look like:
:s/foo/bar/g
2j:s/1/2/g
10k
(Even that's a little misleading -- you'd still have to be careful not to copy the newline after the 10k.)
Why do these extra newlines make such a big difference? Well, for one thing, they cause you to be at least one line away from where you expect to be, which throws off anything you want to do on a particular line (like execute the :s// command).
More importantly, however -- and this is what I think is happening in your example -- is that Vim stops macro playback if the macro attempts to use <Enter> on the last line of a buffer. (I'm guessing Vim considers it an error, and any error causes a macro to stop running.)
Here's an example. Suppose you've got this snippet stored in register x:
4j
:echo "Done"
(Notice the newline after 4j.)
Furthermore, suppose you have the following five lines (and only these five lines) in a buffer:
line 1
line 2
line 3
line 4
line 5
If you now press #x on line 1, the :echo "Done" never executes. Vim moves the cursor down 4 lines to line 5, then attempts to move down one more line because of the extra newline, but it can't. The macro stops executing at that point, before the :echo command gets a chance to run.
However, it works if you change the x register to this:
4j:echo "Done"
So to return to your original example, I'll bet what's happening is that the extra newline after 2j is attempting to move your cursor somewhere it can't go, and that causes the macro to stop. The bottom line of the screen contains the last command executed (:s/foo/bar/g), which makes it look like Vim is waiting for you to press Return.
Finally, I'd strongly recommend using another method to store and execute Vim command sequences. The technique you're using is tolerable for simple cases, but it's fragile and doesn't scale well. Vim has a full scripting language that includes functions and custom commands, and it can be used to do all the things you're doing now, but in a much more robust fashion. Vim scripting is a big topic, but I'd start here:
:help script
Be sure to read about the :normal command, which lets you execute Normal-mode commands (like 2j and 10k) within scripts.
Good luck!
I finally found the culprit. Somehow I had a command mapping on <C-J> in my .vimrc file. When read with the default cpoptions, this turned into a mapping on <NL>.
How I found out: I noticed that when starting vim with -u ~/.vimrc, it would indeed execute yanked snippets. I generated a session file with and without that commandline option and compared them. This way I found out that a different set of cpoptions where used to read the same .vimrc file, so that in one case the mapping was indeed on <C-J>, in the other it was converted into a mapping on <NL>!
If someone has a similar problem, I suggest to look carefully at the currently set command mappings, with :cmap.

How to repeat a command with substitution in Vim?

In Unix the ^ allows you to repeat a command with some text substituted for new text. For example:
csh% grep "stuff" file1 >> Results
grep "stuff" file1
csh% ^file1^file2^
grep "stuff" file2
csh%
Is there a Vim equivalent? There are a lot of times I find myself editing minor things on the command line over and over again.
Specifically for subsitutions: use & to repeat your last substitution on the current line from normal mode.
To repeat for all lines, type :%&
q: to enter the command-line window (:help cmdwin).
You can edit and reuse previously entered ex-style commands in this window.
Once you hit :, you can type a couple characters and up-arrow, and it will character-match what you typed. e.g. type :set and it will climb back through your "sets". This also works for search - just type / and up-arrow. And /abc up-arrow will feed you matching search strings counterchronologically.
There are 2 ways.
You simply hit the . key to perform an exact replay of the very last command (other than movement). For example, I type cw then hello to change a word to "hello". After moving my cursor to a different word, I hit . to do it again.
For more advanced commands like a replace, after you have performed the substition, simply hit the : key then the ↑ up arrow key, and it fills your command line with the same command.
To repeat the previous substition on all lines with all of the same flags you can use the mapping g&.
If you have made a substitution in either normal mode :s/A/B/g (the current line) or visual mode :'<,>'s/A/B/g (lines included in the current selection) and you want to repeat that last substitution, you can:
Move to another line (normal mode) and simply press &, or if you like, :-&-<CR> (looks like :&), to affect the current line without highlighting, or
Highlight a range (visual mode) and press :-&-<CR> (looks like :'<,'>&) to affect the range of lines in the selection.
With my limited knowledge of Vim, this solves several problems. For one, the last visual substitution :'<,'>s/A/B/g is available as the last command (:-<UP>) from both normal and visual mode, but always produces an error from normal mode. (It still refers to the last selection from visual mode - not to the empty selection at the cursor like I assumed - and my example substitution exhausts every match in one pass.) Meanwhile, the last normal mode substitution starts with :s, not :'<,'>s, so you would need to modify it to use in visual mode. Finally, & is available directly from normal mode and so it accepts repetitions and other alternatives to selections, like 2& for the next two lines, and as user ruohola said, g& for the entire file.
In both versions, pressing : then & works as if you had pressed : and then retyped s/A/B/, so the mode you were in last time is irrelevant and only the current cursor line or selection determines the line(s) to be affected. (Note that the trailing flags like g are cleared too, but come next in this syntax too, as in :&g/: '<,'>&g. This is a mixed blessing in my opinion, as you can/must re-specify flags here, and standalone & doesn't seem to take flags at all. I must be missing something.)
I welcome suggestions and corrections. Most of this comes from experimentation just now so I'm sure there's a lot more to it, but hopefully it helps anyway.
Take a look at this: http://vim.wikia.com/wiki/Using_command-line_history for explanation.

Resources