Is it possible to shift lines without moving cursor? - text

I often move blocks of text around within a file by e.g. marking the top and bottom of a range and then doing :'t,'b>. I find that having completed the shift, the cursor always moves the the line marked by 'b.
When trying to fine tune the actual amount of the shift required I then have to move back to 't, check the indent with respect to the surrounding text and then repeat the shift.
Is there a way to achieve the same result without the cursor moving lines each shift?

I don't think just pressing
`t
to go back to mark t is big effort.
If you don't want to press any key after the cmd execution, you can execute:
:'t,'b>|norm! 't
Or you don't shift lines with command, you do it in normal mode. First go to the mark t , then:
>'b
The block will be shifted and the cursor will be still on mark t.

Related

Insert visual vim selection in the line below at the same position

I have a tedious task of converting chords from leadsheets into an inline format.
The format I have
G A
Never gonna give you up
F#m Bm
Never gonna let you down
G A F# Bm
Never gonna run around and desert you
And the format I need would b
Never gonna g[G]ive you [A]up
Never gonna l[F#m]et you do[Bm]wn
Never gonna r[G]un a[A]round and d[F#]esert [Bm]you
The problem with a script in Ruby or Python is, that the format isn't very consistent. So there could be newlines, weird characters, sometimes the chords are seperated with a dash... I haven't looked through all of the files, but I suspect more malformed stuff.
So I thought, if I have to go through of every leadsheet by hand, at least I can save some time using vim. This is the mapping I've come up with so far:
nmap <C-X> viWc[]<ESC>PviWx<down>p
Select the chord: viW
delete it and go into insert mode: c
add brackets
exit insert mode: <ESC>
paste the register to the left: P
select the chord again, including the brackets: viW
delete the selection: x
move cursor down, and paste it: p
But I few things I can't figure out is:
Sometimes the chords already have brackets, then I don't want to surround them with more brackets. Any idea how to only add brackets, if the chord isn't already surrounded with them?
It would be cool to do this with whole lines of chords. Sometimes there are multiple chords on the same line, and selecting them one by one is tedious. Any idea on how to operate the mapping above on a whole line?
well point 1 could be solved by adding the brackets around the chords on every second line:
:g/^/s/\[\=\zs[a-zA-Z#]\+\ze]\=/\[\0\]/g|+t+|-d
Credits: https://vi.stackexchange.com/questions/34785/search-and-replace-on-odd-even-numbered-lines-using-g
This however sucks, because it moves arround the chords, so we have to remove all brackets first and replace them with space
:%s/\[\([a-zA-Z#]\+\)\]/\1 /g
Then we can do the first line again, but remove some space too. Since there are no brackets left, it gets simpler (Note we use other brackets to get ride of some side effect the following code has):
:g/^/s/\([a-zA-Z#]\+\) \{0,3\}/\{\1\} /g|+t+|-d
Also we add a trailing whitespace at the end of the line so that the df} command will not move the cursor to a wrong place
Now that we have curly brackets everywhere, we can use reverse search with ?{ and then create a macro that jumps from results to result and moves it down, replaces the curly brackets with normal brackets and then calls itself (recursive macro):
gg0
qqq
?{<CR>
qq
df}jPr]F{r[n#qq
#q
And nearly all should be done.
The result:
Never gonna g[G]ive you [A]up
Never gonna l[F#m]et you dow[Bm]n
Never gonna r[G]un a[A]round and d[F#]esert [Bm]you
Note, we have to search backwards (? instead of /) so we can delete the chords directly.
If you have problems understanding what I did, feel free to ask.

Deleting to beginning of line - d0 leaves extra space

I am trying to delete an indented line to the beginning of the line, with d0, but that leaves an extra space that I must delete with x.
The use case is that often I want to insert a blank line between two lines, and yes, I could use 'o' or 'O' and 'Esc' but often I enter insert mode out of habit and enter a line. The autoindent in vim adds a line with extra space (even with smartindent) so I am left with some dangling space that I have to delete with 'd0x'.
The extra 'x' seems awkward given that 'D' deletes to the end of the line leaving no extra space, and yes I could use '0D' to do the same with in one less stroke. But I would like your opinions as to the best approach for this situation. Thanks.
Addressing the very specific point of why d0 leaves an extra space: The 0 motion is an exclusive motion, which means the last character towards the end of the region is excluded from the operation.
You can use the v modifier to toggle the characterwise motion and make it inclusive:
dv0
This should remove all the characters from the beginning of the line, including the one under the cursor.
If there's some complicated thing you want to do in vim with minimal keystrokes, the usual approach is to just create a macro for it and bind that macro to a specific key sequence.
For example, for your use case of inserting a blank unindented line, you could just bind to O<ESC>0D (or whatever other key sequence you need). You can test this with the keystrokes (in normal mode, and <ESC> is a single press of the ESC key, not the five individual characters):
qdO<ESC>0Dq
Then just go to some line in your file, enter #d and, voila, an unindented blank line.
To make this permanent, just add it to your vimrc file:
let #d='O<ESC>0D'
where, if you're editing it with vim, ESC can be entered as CTRL-VESC.
Another possibility is to just not worry about indents until some point in the future. By all means, use whatever commands you desire to give yourself a blank line (possibly indented) but either fix that before final write by deleting all trailing tabs and spaces:
:g/[ <TAB>]\+$/s///
or run a script on all files to fix this in a batch operation (even better if this is done as part of automatic pre-checks before source code commit), for example:
find . -name *.cpp -exec sed -iE 's/[ \t]+$//' {} \;

How to delete, including the current character?

Let's say I've typed "abcdefg", with the cursor at the end. I want to delete back to the c, so that I only have "abc" left.
Is there a command like d that includes the current character? I know I could do dTcx, but the x feels like a work-around and I suppose there's a better solution.
No. Backward motions always start on the left of the current character for c, y and d which is somehow logical but also unnerving.
The only "clean" solutions I could think of either imply moving to the char after c first and then do a forward delete:
Tcde
or using visual mode:
vTcd
v3hd
But, given your sample and assuming you are entering normal mode just for that correction, the whole thing sounds extremely wasteful to me.
What about staying in insert mode and simply doing ←←←←?
try this:
TcD
this will leave abc for your example... well if the abcdefg is the last word of the line.
if it is not the last word in that line, you may do:
ldTc
or golfing, do it within 3 key-stroke:
3Xx or l4X
See this answer to a similar question : there is a setting to be allowed to go beyond the end of the line
From the doc :
Virtual editing means that the cursor can be positioned where there is
no actual character. This can be halfway into a tab or beyond the end
of the line. Useful for selecting a rectangle in Visual mode and
editing a table.
"onemore" is not the same, it will only allow moving the cursor just
after the last character of the line. This makes some commands more
consistent. Previously the cursor was always past the end of the line
if the line was empty. But it is far from Vi compatible. It may also
break some plugins or Vim scripts. For example because |l| can move
the cursor after the last character. Use with care!
Using the $ command will move to the last character in the line, not
past it. This may actually move the cursor to the left!
The g$ command will move to the end of the screen line.
It doesn't make sense to combine "all" with "onemore", but you will
not get a warning for it.
In short, you could try :set virtualedit=onemore, and see if your environment is stable or not with it.
Use d?c
That will start d mode, search back to 'c' and then delete up to your cursor position.
Edit: nope, that does not include current position...
I may be misunderstanding your request, but does 3hd$ do it?
I would use vFdd in this example. I think it's nicer than the other solutions since the command explicitly shows what to delete. It includes the current character and the specified character when deleting.
v: enter visual mode (mark text)
F: find/goto character backwards
d: the character "d" that will be included for removal.
d: delete command
Since it is visual mode, the cursor can also be moved before executing the actual removal d. This makes the command powerful even for deleting up to a non unique character by first marking a special character close to the character and then adjusting the position.

Can vim markers work with the repeat key?

I regularly use the . key to repeat my last vim command. I'm wondering if there's a way to use it with commands performed using markers. Here's a simple example:
Mark a line of text using m'a
Move down a few lines, e.g. 5j
Indent the lines using >'a -- indents 6 lines
Press . to repeat above command on the same 6 lines -- will only affect 1st line
Is there a way to get vim to apply the same marker range of the previous command when using the . command?
ps. I know the above example would have been easier with 6>>, which works with the ., I'm just using it as an example. I often use markers for more complex/longer commands.
The problem is that the command you're repeating is >'a, but because of the rule "After applying the operator the cursor is mostly left at the start of the text that was operated upon" (from :help operator), >'a leaves the cursor at mark a if that was above your starting position. Then when you repeat >'a you end up with a linewise motion from that line to itself, which only re-indents one line.
Since you're left at the beginning of the block of text, to affect the same block of text again you can use the '] (linewise) or `] (charwise) motions, which move to the end of the block of text just affected. So you can use >'] to indent the same block again, and since your cursor starts and ends at the same position this time, you can repeat it additional times with ..
A simpler choice, though, would be to just use V5j> instead of ma5j>'a. V starts visual mode (linewise) at your current position, 5j moves down 5 lines, and then > indents. And when you repeat using ., the same visual selection still pertains, so you get the desired result whether you moved up or down.

Fast switching between two lines in file in vim

sometimes I have to switch between 2 lines. To do this, I have to pass line number. Are there shortcuts to moving between 2 last 'visited' list. Something similar to '. (it moves to last edited line)
You can use bookmarks, something like ma to mark a bookmark named a, and then 'a to go to it. Naming boomarks a and b for example, you can switch between them with 'a and 'b.
Double-backtick or double single-quote will do exactly that
There is a command that will bounce to the last location you jumped away from. If repeated, it will then return to the jump destination you were just on. If repeated further it will bounce you back and forth between the two locations.
The command has two forms:
``
or
''
ctrl-o and ctrl-i will move backwards and forwards through your history of jump points. A jump point is pretty much any command that moves the cursor more than one line. It will also go back to previous files that were loaded into the current buffer.
See :h jump-motions for more information.

Resources