select text object in visual mode in vim command - vim

I want to use the tabular plugin to align latex tables. However, I like to write rules within the table as follows:
\begin{tabular}{ll}
\toprule
Column 1 & Column 2 \\
\midrule
Value 1 & Some very long value \\
2 & 3 \\
\end{tabular}
If I use the Tabular plugin "as intended", only the lines with the values will be aligned, but the header row won't.
I can achieve the desired result using the vim-indent-object plugin by selecting all lines with the same indentation (a text object that is selected with ii) and then call the :Tabularize command. However, I struggle to squish all of this into a command. My current approach is:
nnoremap <Leader>at :V ii Tabularize /&<CR>
But the syntax is incorrect, and i get an error when trying to call it. I could not find any hints on how to select the lines and then call a command using this type of mapping. Any help is appreciated.

My approach had 2 issues:
the ii from the vim-indent-object plugin does not seem to work with the nnoremap - it works with a regular nmap.
the : was at the wrong place
the space between the V and the ii was incorrect.
The correct mapping therefore is:
nmap <Leader>at Vii:Tabularize /&<cr>

Related

(Neo)vim substitute over block/regular visual range, and not line visual range

If I highlight a block of text in visual mode in Vim and then press :, I can run a command on it. For example
:'<,'>s/foo/bar/g to substitute,
or :'<,'> !bash to send the lines to the bash shell and get the output,
or :'<,'>sort to sort those lines,
or :'<,'> !some_cli_util to send those lines to some_cli_util
This is fine if the text I want to execute is conveniently on it's own line, but often that isn't the case. For example, if I'm writing docs and want to give and example of a cli command and it's output, then it would be nice to just write:
$ head requirements.txt
and then to select the text head requirements.txt, type : !sh<CR>, and be given the actual output of the command. But in reality, when I select head requirements.txt and type :, then my selection gets expanded to a full-line selection, which causes the leading $ to be clobbered in with the actual command, and so because of the leading $, the command fails.
A less trivial example of where this would be useful, is if I had a LaTeX table like:
\begin{table}
\begin{tabular}{lllll}
col1 & col2 & col3 & col4 & col5 \\
foo19s & fook2e & foojd9 & alfooc & 9dfooj \\
9foo1s & ekfoo2 & lqfoo & alfoo & 9efoo9s \\
1sfoo9 & d9fooe & fooj9d & alsdfo & 9hfooje \\
19sfoo & 9dfooe & lqfoo & dfoo9e & ajfoo
\end{tabular}
\end{table}
and I wanted to replace all the instances of foo with bar, but only in the columns titled col2. If I could block-select only col2, and then execute a substitute command like :`<,`>s/foo/bar/g then this would work. But currently, if I block select only col2 and then press :, Vim will auto-select the entire range of lines that were in my block selection.
Ideally, I'd like vim to be smart enough such that if am in block-visual mode and press :, then it'll use the :`<,`> range selector, but if I'm in line-visual mode and press : then it'll use the :'<,'> range selector.
:h `< tells me that the `< and `> marks do exist, but I can't see how to apply them to commands.
What can I do to enable vim (or neovim) to execute commands on block-selections? or is there an issue open for this problem?
I can't just use the regular visual-line selector :'<,'>s/ba/__/g because that will incorrectly replace all the bazs with __zs.
Yes, you definitely can, but with a more refined search pattern:
:[range]s/ba\zer/__/g
See :help \ze.
--- EDIT ---
As explained in the other answer, Ex commands only work on lines and ranges are ranges of lines. You wont be able to pass something else than one or several lines to :help :s, :help :range! or :help :sort.
There is no way around that.
While the range of Ex commands is always linewise, some of them may honor the visual selection in some way.
In the case of :help :s, what you can do is, again, use a more refined search pattern:
<C-v><motions>
:[range]s/\%V.*\zsfoo\ze.*%V/bar
See :help \%V.
How to get it done is described perfectly in romainl's answer. I'd like to answer the "why?", though.
You wrote:
Ideally, I'd like vim to be smart enough such that if am in block-visual mode and press :, then it'll use the :`<,`> range selector, but if I'm in line-visual mode and press : then it'll use the :'<,'> range selector.
This behavior is explicitly impossible, at least for now (Vim 9.0). Quoting from :h :visual_example:
Currently the ":" command works on whole lines only. When you select part of
a line, doing something like ":!date" will replace the whole line. If you
want only part of the line to be replaced you will have to make a mapping for
it. In a future release ":" may work on partial lines.
Likewise, :h :s says (emphasis mine):
For each line in [range] replace a match of {pattern}
It is a common misconception that Vim would operate on the (block) visual selection only. Not all commands do. Instead, they operate on lines that are selected.
So you'll have to use a line-wise substitution like (as pointed out by romainl and included for the sake of completeness) :s/ba\zer/__/g.
It's a reasonable tool to look for, but as others have pointed out, ranges are only line-wise. For the cases where you'd like to use a selection as an argument to an external program, I'd recommend yanking and pasting in the command-line.
A plugin that might give you a general-purpose solution is vis: https://github.com/vim-scripts/vis. Instead of :'<,'>s/foo/bar/g, you'd execute :'<,'>B s/foo/bar/g, which is less convenient, but will do the trick.

What is are these commands in square brackets doing in Vim?

Doing a Vimgolf exercise that requires you to start with the following:
- One number per line -
-----------------------
2,3,5,7,
11,13,17,
19,23,29,
And then transform it to:
2
3
5
7
11
13
17
19
23
29
One solution given is:
dj3gJV"=[<C-R><C-A>]<CR>pZZ
I'm following everything up to "=[", etc. Doing ":help [" in Vim only reveals some movements with square brackets in normal mode. I think the quotation mark indicates to use a special register, but I'm unclear on the rest of what follows after the equals sign.
1) What's a good way to query Vim's help system to get what's going on with "=[ ..." in visual mode?
2) And, can you explain what is going on with "=[ ..."? (where ... is an abbreviation for the rest of the commands that follow)
You call 'expression register', put List of vim script language and evaluate it.
"= will call 'expression register'. If you put to this register vim-script language expression, it's will be computed.
:help "= for more information about expression register.
:help <C-R> for information about special registers.
:help c_<C-R>_<C-A> insert WORD under cursor. You in Visual mode, so all selection will be inserted.
[2,3,5,7,11,13,17,19,23,29,] this is a List of vim script language. :help List
As you can read in :help "=
If the result is a List each element is turned into a String and used as a line.

Vim - `=` (equalprg) doesn't use expandtab.

I am a python developer and I work for a company where the python convention for indentation is two spaces rather than four.
So I notice this problem when I paste code from vim:
This is the text I am trying to paste:
def four_spaces():
print "hello"
This text is copied in mac from Chrome using <cmd> c. Note that I am using vim in iTerm in the Mac OS X.
Below are the steps for me to pasting this in vim using as I am using a mac:
:set paste Turn Paste mode on
a Append mode
<Cmd> v Pasting in Mac
Result shown in Snippet 4. Note that it's 4 spaces
v kk *Visual mode to select the above
= Fix indentation
Result shown in Snippet 7. Note the ^I
Snippet 4 (listmode on)
def four_spaces():$
print "hello"$
Snippet 7 (listmode on)
def four_spaces():$
^Iprint "hello"$
This is what my .vimrc file looks like for those interested:
https://gist.github.com/anonymous/20b2a1f43125c0d39932bf430c8137dc
Problem:
The problem I am facing with right now is that I have a tab character rather than 2 space when I use =. This is problematic because python relies on tab indentation and it cannot allow tab characters and spaces to co-exist together. I am trying to figure out how come = doesn't use expandtab.
Question:
How can I paste using <Cmd> v and such that:
Vim formats my code properly to 2 spaces
OR how can I get vim's equalprg (=) to use expandtab?

Pasting inside delimiters without using visual selection

In Vim, let's say I want to replace the contents of one String with the content of another.
Original input
var1 = "January"
var2 = "February"
Desired output
var1 = "January"
var2 = "January"
What I would usually do is:
Move cursor to line 1
y i " (yank inner quotes)
Move cursor to the destination quote in line 2
v i " p (visual select inner quotes, paste)
While this works well, I generally try to avoid visual mode when possible, so I am not completely satisfied with my step 4 (v i " p).
Is there any way to specify a "destination paste area" without using Visual mode? I suspect it might be something chained to g, but I can't think of anything.
There are many ways of doing this however using visual mode is the easiest.
Use the black hole register to delete the content then paste. e.g. "_di"P
Do ci"<c-r>0. <c-r> inserts the contents of a register
Simply paste and then move over a character and delete the old text. e.g pldt"
However visual mode still has my vote. I find that the concerns most people have is that using visual mode + paste is that the default register is swap with the selected text and it doesn't repeat well. Good news everybody! The 0 register always stores the last yank. The bad news is visual mode still doesn't repeat well. Take a look at this vimcast episode, Pasting from Visual mode, for more information. It mentions a few plugin that help with this.
I need this so often, I wrote a plugin to simplify and allow maximum speed: ReplaceWithRegister.
This plugin offers a two-in-one gr command that replaces text covered by a {motion} / text object, entire line(s) or the current selection with the contents of a register; the old text is deleted into the black-hole register, i.e. it's gone. It transparently handles many corner cases and allows for a quick repeat via the standard . command. Should you not like it, its page has links to alternatives.
It's not particularly pretty, but here goes:
Go to line one and yi"
Move to line two
Type "_di"hp
That deletes what's in the quotes, but sends the deleted text to a black hole register. Then it moves the cursor back one, and pastes what you yanked from line one.
All in all, you can start on the first line and type yi"j"_di"hp. Why is it that people find vim intimidating? ;)
Alternatively, yank the first line as normal, then drop to line two and type ci"<Ctrl+p> and select the previously yanked text from the menu.
Excerpt from my .vimrc:
" Delete to 'black hole' register
nnoremap <leader>d "_d
vnoremap <leader>d "_d
So, you just need to \di"P as your last step (assuming you use \ as a <leader>).
There is a plugin that addresses this problem precisely. It was presumably born out of the same feeling you're feeling, namely that Visual mode often feels less than ideal to advanced Vim users.
operator-replace – Operator to replace text with register content
With operator-replace installed the replacing goes like this.
Yank the word inside the quotes.
yi"
Move to the target line
j
Replace inside the quotes with the yanked text. (I've set up gr as the replace operator: :map gr <Plug>(operator-replace). Pick your own mapping.)
gri"
Check it out! This is part of the truly excellent textobj/operator frameworks. I couldn't work without them.

Is it possible to object-select a heredoc or "here document" with vim?

One of Vim's great strengths is object-select, offering quick manipulation of content inside words, paragraphs and assorted delimiters.
For example,
vi{
will select everything inside a pair of {} braces.
Is there any equivalent functionality for selecting a here document or heredoc:
<<<HTML
....
....
HTML;
Based on
ErichBSchulz's answer I came up with the following for an heredoc inner select:
nmap <F6> ?<<<<CR>w*kV?<<<<CR>j
?<<<<CR>w " find beginning tag (after <<<)
*k " find matching end tag and go up 1 line
V " enter visual mode
?<<<<CR>j " find beginning tag and go down 1 line
For selecting heredoc's I usually place the cursor at the first line, over the heredoc identifier and press V*
V will start a line selection, and * will start a search, going to the next match of the identifier, the end of the heredoc...
A <<'' heredoc terminated by an empty line is easy, if you're already at the start (?<<^M^M): v} selects from here until the empty line.
Otherwise, in your example the best I can think of is v/^HTML.
There's this plugin that let's you define your own text objects.
http://www.vim.org/scripts/script.php?script_id=2100
I imagine it would be nice to define one so you could say 'yih' (yank in heredoc) so you don't have to explicitly go to the start.
Note I haven't fooled around with this myself.
If you just want a visual select you could.
nnoremap <leader>ih ?HTML<cr>V/HTML<cr>
Thinking about the earlier posts and trying to take them a step closer. This wont be 100% reliable (ie will break if the starting tag occurs within the heredoc but something like:
?<<< "find begining
w " go to starting tag
* " find starting tag
v " enter visual mode (could use Upper V to do an 'ambientish' object select
n " find end tag
e " optional include end tag
Edit: Ken has improved the sequence as above, so I suggest you use his better key mapping for an 'inner' heredoc select:
nmap <F6> ?<<<<CR>w*kV?<<<<CR>j
(this is based on php style heredocs)

Resources