Mark a block of characters in VI/M ex command - vim

It's quite straitforward for VI/M to mark a block of lines from Mth line to Nth line ready to delete, cut & past, or copy & paste.
:M,N d
:M,N m p
:M,N t p
If it's further required for VI/M to mark a block of characters from Ith character of Mth line to Jth character of Nth line, is it possible to accomplish similarly to the above?
#EDIT
Except the next answer asked for visual block mode, how about the option on typing a succinct ex command?
#EDIT 2
To clarify the meaning of a block of characters:
a square block of characters, addressed by visual block mode, directly called upon by pressing Ctrl-v in normal mode
a zipzag area of successive characters, addressed by visual character mode, directly called upon by pressing v in normal mode
a rows region of successive lines, addressed by visual line mode, directly called upon by pressing V in normal mode. In this case, the handy solution in ex mode has been illustrated above when this topic was originally raised.
#SOLUTION
Selecting abitrary zipzag area of successive characters from line M, column I to line N, column J in ex mode exactly like in visual character mode :
mark:
:normal! MggI|vNggJ|
delete:
:normal! MggI|vNggJ|d
yank:
:normal! MggI|vNggJ|y
move to line X column Y
:normal! MggI|vNggJ|dXggY|p
copy to line X column Y
:normal! MggI|vNggJ|yXggY|p
#SOLUTION 2
Selecting abitrary square block of characters from line M, column I to line N, column J in ex mode exactly like in visual block mode :
mark:
:execute "normal! MggI|\<C-v>NggJ|"
delete:
:execute "normal! MggI|\<C-v>NggJ|d"
yank:
:execute "normal! MggI|\<C-v>NggJ|y"
move to line X column Y
:execute "normal! MggI|\<C-v>NggJ|dXggY|p"
copy to line X column Y
:execute "normal! MggI|\<C-v>NggJ|yXggY|p"

You can use visual block mode from an ex command mode using normal!: for example, to select a block (line, column) from (42, 10) to (54, 20) and yank it (both lines must have at least 20 characters or virtualedit=block should be set):
execute "normal! 42gg10|\<C-v>54gg20|y"
. It is very straightforward way to do this, useful only in scripts.
Note that this command has at least following side-effects:
Setting marks '<, '>, '[, '], ''.
Moving a cursor.
Changing registers #", #0.
Adding one item to the jumplist.
Overwriting previous visual selection.
Altering v:count and v:count1 variables.

Ctrl+V enables visual block mode, then you can use the arrow keys to select the block.

Related

Vim shortcut for unindenting till the start of the line

So I'm aware that you can unindent a line with the shortcut Shift+, (or <) and that you can repeatedly apply it by pressing a number before the shortcut -- for example, 5 + < will unindent 5 times.
Is there a way to repeatedly apply unindent until it reaches the start of the line?
One option is ^d0: move to the start of the indented line, then delete to the start of the entire line.
Sometimes it’s just easier to << then mash . to repeat, though.
Moving to the :left
You can move lines to the left with :left . This will remove all indention.
:left
See :h :left for more information.
Putting with indentation
I often find myself wanting to move/cut a block of code and put/paste with the current line's indention level. This can be done with ]p & [p.
Example:
def foo():
pass
if x == 'bar'
print "hello world"
Assuming you are on the if line you can do the following:
dj]p
This will put/paste the block inline with pass yielding:
def foo():
pass
if x == 'bar'
print "hello world"
Note: ]p & [p need the register to be linewise for this to work correctly or use unimpaired.vim
For more help see::h ]p & :h linewise

What are the vim commands that start with g?

g is a prefix to several commands. e.g. goto to move the cursor, but also gqip to format a paragraph. Where is the reference for all commands that are prefixed with g?
Vim's documentation is http://vimdoc.sourceforge.net/. If you go for the HTML docs, you will find |reference_toc| More detailed information for all commands, which includes |index.txt| alphabetical index of all commands, which -- due to an unfortunate quirk with the doc file named index.txt and linked as index.html -- doesn't actually lead to where you would expect it to lead.
Long story short, http://vimdoc.sourceforge.net/htmldoc/vimindex.html#g is the documentation you are looking for ("Commands starting with 'g'").
Alternatively, type :help *g* in Vim.
(Sorry merlin2011 but your list is somewhat incomplete...)
Some reformatting applied:
2.4 Commands starting with 'g'
char note action in Normal mode
------------------------------------------------------------------
g CTRL-A only when compiled with MEM_PROFILE
defined: dump a memory profile
g CTRL-G show information about current cursor
position
g CTRL-H start Select block mode
g CTRL-] |:tjump| to the tag under the cursor
g# 1 like "#", but without using "\<" and "\>"
g$ 1 when 'wrap' off go to rightmost character of
the current line that is on the screen;
when 'wrap' on go to the rightmost character
of the current screen line
g& 2 repeat last ":s" on all lines
g'{mark} 1 like |'| but without changing the jumplist
g`{mark} 1 like |`| but without changing the jumplist
g* 1 like "*", but without using "\<" and "\>"
g0 1 when 'wrap' off go to leftmost character of
the current line that is on the screen;
when 'wrap' on go to the leftmost character
of the current screen line
g8 print hex value of bytes used in UTF-8
character under the cursor
g< display previous command output
g? 2 Rot13 encoding operator
g?? 2 Rot13 encode current line
g?g? 2 Rot13 encode current line
gD 1 go to definition of word under the cursor
in current file
gE 1 go backwards to the end of the previous
WORD
gH start Select line mode
gI 2 like "I", but always start in column 1
gJ 2 join lines without inserting space
["x]gP 2 put the text [from register x] before the
cursor N times, leave the cursor after it
gQ switch to "Ex" mode with Vim editing
gR 2 enter Virtual Replace mode
gU{motion} 2 make Nmove text uppercase
gV don't reselect the previous Visual area
when executing a mapping or menu in Select
mode
g] :tselect on the tag under the cursor
g^ 1 when 'wrap' off go to leftmost non-white
character of the current line that is on
the screen; when 'wrap' on go to the
leftmost non-white character of the current
screen line
ga print ascii value of character under the
cursor
gd 1 go to definition of word under the cursor
in current function
ge 1 go backwards to the end of the previous
word
gf start editing the file whose name is under
the cursor
gF start editing the file whose name is under
the cursor and jump to the line number
following the filename.
gg 1 cursor to line N, default first line
gh start Select mode
gi 2 like "i", but first move to the |'^| mark
gj 1 like "j", but when 'wrap' on go N screen
lines down
gk 1 like "k", but when 'wrap' on go N screen
lines up
gm 1 go to character at middle of the screenline
go 1 cursor to byte N in the buffer
["x]gp 2 put the text [from register x] after the
cursor N times, leave the cursor after it
gq{motion} 2 format Nmove text
gr{char} 2 virtual replace N chars with {char}
gs go to sleep for N seconds (default 1)
gu{motion} 2 make Nmove text lowercase
gv reselect the previous Visual area
gw{motion} 2 format Nmove text and keep cursor
gx execute application for file name under the
cursor (only with |netrw| plugin)
g#{motion} call 'operatorfunc'
g~{motion} 2 swap case for Nmove text
g<Down> 1 same as "gj"
g<End> 1 same as "g$"
g<Home> 1 same as "g0"
g<LeftMouse> same as <C-LeftMouse>
g<MiddleMouse> same as <C-MiddleMouse>
g<RightMouse> same as <C-RightMouse>
g<Up> 1 same as "gk"
note: 1 = cursor movement command; 2 = can be undone/redone
Open vim. Type :help g.
2.4 Commands starting with 'g' g
tag char note action in Normal mode
------------------------------------------------------------------------------
g_CTRL-A g CTRL-A only when compiled with MEM_PROFILE
defined: dump a memory profile
g_CTRL-G g CTRL-G show information about current cursor
position
g_CTRL-H g CTRL-H start Select block mode
g_CTRL-] g CTRL-] :tjump to the tag under the cursor
g# g# 1 like "#", but without using "\<" and "\>"
g$ g$ 1 when 'wrap' off go to rightmost character of
the current line that is on the screen;
when 'wrap' on go to the rightmost character
of the current screen line
g& g& 2 repeat last ":s" on all lines
g' g'{mark} 1 like ' but without changing the jumplist
g` g`{mark} 1 like ` but without changing the jumplist
gstar g* 1 like "*", but without using "\<" and "\>"
g+ g+ go to newer text state N times
g, g, 1 go to N newer position in change list
g- g- go to older text state N times
g0 g0 1 when 'wrap' off go to leftmost character of
the current line that is on the screen;
when 'wrap' on go to the leftmost character
of the current screen line
g8 g8 print hex value of bytes used in UTF-8
character under the cursor
g; g; 1 go to N older position in change list
g< g< display previous command output
The list above has been truncated for readability.

variable search and replace in vim

I have a list of items that I want to add a method call to. An example is easiest. Here's what I have now:
assists: 12,
level: 14,
deaths: 5,
...
I want to change that list to look like this:
assists: build_average(:assists),
level: build_average(:level),
deaths: build_average(:deaths),
...
Is it possible to add that method call to the end of every line with the name of the key as the argument with a neat Vim expression?
More of a regular expression:
:%s/\(\w\+\):.\+/\1: build_average(:\1),/
Note that this applies to all lines in your file. To only replace in a region, select the region (using V) and then use :s (which results in :<,>s/...).
Using more complex regular expressions in VIM can be tricky, because metacharacters are different from "normal" regular expression syntax (you need to write \+ instead of +, but can use . without escaping it, for example). I found this guide very handy to refer to the special VIM-syntax of regular expressions: http://vimregex.com/#pattern
Alternatively you can record a macro:
q // record macro
q // assign it to letter 'q'
0 // go to start of line
/:<ENTER> // search for ':'
l // move cursor 1 position to the right
d$ // delete to end of line (line is now 'assists:')
yyp // duplicate current line (cursor moves 1 line down)
k // move cursor up
A build_average( // append " build_average("
<ESC> // exit edit mode
J // join next line
A ), // append " ),"
<ESC> // exit edit mode
j // move 1 line down
q // stop recording macro
2#q // execute macro 'q' 2 times
More regexp gymnastics:
:%s/\v(\w+):\s+\zs.*\ze,/build_average(:\1)/
Decrypting it:
:help \v
:help \w
:help \s
:help \zs
:help \ze
:help \1

Vim copy and paste line with a search and replace

Say I've written code that references the x dimension. What is the best way to get vim to duplicate a line of code replacing all references to x to y and to z (best being the most clear method).
Input:
length_x = X_vec.dot(X_vec)**.5
Desired Output:
length_x = X_vec.dot(X_vec)**.5
length_y = Y_vec.dot(Y_vec)**.5
length_z = Z_vec.dot(Z_vec)**.5
Here's my best so far.
function SwitchXtoYZ()
:normal yy
:normal p
:normal! V
:s/X/Y/ge
:normal! V
:s/x/y/ge
:normal p
:normal! V
:s/X/Z/ge
:normal! V
:s/x/z/ge
endfunction
command XtoYZ exec SwitchXtoYZ() | :normal `.
It works, but I feel this is not very vim-y. Bonus points if the cursor returns to where it was before the command XtoYZ was issued (it currently goes the beginning of the second inserted line).
You don't need a function to do that, a macro would be fine for your requirement. Also you can define a macro in your vimrc too, if you like, so that you can have it everytime you open vim.
here is the macro:
qqv<Esc>Y2p:s/x/y/gi<Enter>n:s//z/gi<Enter>`<q
so it was recorded and saved in register q, you can #q to replay it.
explain it a little:
qq " start recording into q
v<esc> " enter visual mode and exit. to let `< work
Y2p " yank current line and paste twice below
:s/x/y/gi<Enter> " x->y sub, case insensitive
n " go to next x (here we could use j too)
:s//z/gi<Enter> " do another sub x->z
`< " back to the old cursor position
q " end recording
if you want to X->Y and x->y, just remove the i flag and add two more :s
The : at the beginning of each line is optional, as are the :normal! V lines.
You are leveraging the Normal commands that you know, which is a good way to start, but IMHO you get cleaner code if you use more Command-mode (ex) commands and functions. I would do something like this:
function! SwitchXtoYZ()
let save_cursor = getpos(".")
copy .
s/X/Y/ge
s/x/y/ge
-copy .
s/X/Z/ge
s/x/z/ge
call setpos('.', save_cursor)
endfun
command! XtoYZ call SwitchXtoYZ()
:help function-list
:help getpos()
:help :call
:help :exec

Get the current line in visual mode from a function

I have a simple vim script that takes a visual block of text and stores it as a list. The problem with the function VtoList() is that it executes after the cursor returns to the start of the visual block, not before it. Because of this, I have no way of getting the line where the visual block ends.
nn <F2> :call VtoList()<CR>
func! VtoList()
firstline = line('v') " Gets the line where the visual block begins
lastline = line('.') " Gets the current line, but not the one I want.
mylist = getline(firstline, lastline)
echo mylist
endfunc
The problem is with line('.'). It should return the current line of the cursor, but before the function is called, the cursor has already returned to the start of the visual block. Thus, I'm only getting a single line instead of a range of lines.
I put together a solution that sets a mark everytime the user hits V and sets another mark before the function is called.
nnoremap V mV
nnoremap <F2> mZ:call VtoList()<CR>
The function works fine if I substitute line('v') and line('.') with line("'V") and line("'Z"), but I want to avoid this solution if I can because it could conflict with a user's mappings.
Is there a way I can get current line of a visual block within a function before the cursor has returned to the start of the visual block?
Don't use :, use <expr>:
function! s:NumSort(a, b)
return a:a>a:b ? 1 : a:a==a:b ? 0 : -1
endfunction
func! VtoList()
let [firstline, lastline]=sort([line('v'), line('.')], 's:NumSort')
let mylist = getline(firstline, lastline)
echo mylist
return ""
endfunc
vnoremap <expr> <F2> VtoList()
Note other changes: let (you forgot it), sort (line where selection starts may be after the line where selection ends), vnoremap (line("v") works only in visual mode), return (expr mappings return value is executed, but you don't need it, you need only side effects). You can replace the second line with
if mode()=~#"^[vV\<C-v>]"
let [firstline, lastline]=sort([line('v'), line('.')], 's:NumSort')
else
let [firstline, lastline]=sort([line("'<"), line("'>")], 's:NumSort')
endif
The reason why your solution is not working is that when : occurs in the mapping, you immediately exit visual mode and enter command mode. line("v") works only in visual mode.
Other note: vnoremap {lhs} : will produce command line already filled with '<,'>. You may have added range to the function definition and use let [firstline, lastline]=sort([a:firstline, a:lastline], 's:NumSort'). But you nevertheless will exit visual mode with :.

Resources