How can you create a vim macro that reorders lines? - vim

Let's start off with the text
1 The
2 Quick
3 Brown
4 Fox
5 Jumps
6 Over
7 The
8 Lazy
9 Dog
Let's then say that you want to make the first line the last line repeatedly with a macro. That is, this is the goal state after 1 run
1 Quick
2 Brown
3 Fox
4 Jumps
5 Over
6 The
7 Lazy
8 Dog
9 The
Use case : I want to apply a longer macro with the word The the first time, Quick the 2nd time, etc.
The naive approach works exactly once :
q11Gdd8Gpq
#1 <- This works
#1 <- This breaks
This breaks when repeated. I've tried other approaches which avoid dd (e.g. making a new line above the 1st line, d1j, returning to the 8th line, paste, J to join lines). Everything I try works when run once, but something is changing the macro buffer during this run.
How do you make a macro that does this that can be run multiple times?

This page has the answer, https://vim.fandom.com/wiki/Moving_lines_up_or_down
Outside my specific application (thanks #Amadan in the comments) this is
q1:1m$<cr>q
For me, where I am rotating items in a list with contents after the list, the entire solution ended up being
q1:1m8<cr>q
However for the problem as stated, $ rather than a line number is correct.

This situation does not require a macro: the common idiom is
:global/^/move $

Related

Linux/nix: using pr to format text - how to add line break?

I'm using pr(1) to play with formatting text files. My problem is that textfiles containing long lines is not automatically line break'ed and contd. on the next line. Think of e.g. trying to prepare a text with pr to be printed on an A4-page. I've checked the man page, but I'm confused. Surely there has got to be a way?
An illustrative example:
$ pr -n letter
2021-02-23 08:39 letter Page 1
1 Hi,
2
3 This is a letter with very a long line. It's made to prove my point. This would not fit e.g. an A4-paper. How do I make ``pr`` automatically insert new lines/prepare the text so that it will be possible to read?
4
5 All the best,
6 pr
What I would be looking for is an output like this:
$ pr -n letter
2021-02-23 08:39 letter Page 1
1 Hi,
2
3 This is a letter with very a long line. It's made to prove my
4 point. This would not fit e.g. an A4-paper. How do I make ``pr``
5 automatically insert new lines/prepare the text so that it will
6 be possible to read?
7
8 All the best,
9 pr
Appreciate all tips and tricks for pr masters out there.

A simple solution I could apply to join/concatenate 3 lines of text together using Vim

I was looking for a simple solution I could apply to join/concatenate 3 lines of text together using Vim. I wanted to take a file containing 36 short strings and join every 3 lines, in effect producing just 12 longer lines. (For anyone reading this and wondering why - I was producing a markdown table around some shortcut commands).
So the example is, I had wanted to take:
1 short-line one
2 short-line two
3 short-line three
and have:
1 short-line one 2 short-line two 3 short-line three
across the file.
A simple solution I discovered was:
:%norm 3gJ
% is execute the following command from line 1 to the end. The norm command runs the normal mode commands equivalent to the letters that follow it. g and capital J is the shortcut for join and finally, the 3 is for three 3 lines.
I hope that this might be useful to someone else searching for a simple solution in the future.
You can do it manually by putting the cursor on the first line of the three to be joined.
Then type : followed by .,+2j!
. - Current line
+2 - To 3rd line from current
j! - Join the lines with adding spaces
j - joins adding spaces in between.
Transforms
1 short-line one
2 short-line two
3 short-line three
to
1 short-line one 2 short-line two 3 short-line three
Or record a macro
qq - Start recording (replace second q with any alphabetic character
Poistion cursor on first line to join and Type
`:.,+2j!`
Type q to stop recording
Then move to first lline of next block say on 4 short-line-one of the below
4 short-line one
5 short-line two
6 short-line three
Type #q to repeat macro.
You can make it repeatable but that's more than I have time for today

Indent n rows n times

I am trying to indent several rows several times in Vim and could not figure out if there is a "direct" way to tell Vim to do so. For example, how do I indent 5 rows 5 indentation levels? I could of course do 5>>.... or Ctrl-V, mark 5 rows and then do 5>. But I was looking for something more like 5>5>, but that indents 25 lines one level instead.
You could combine block selection with what you're already doing i.e.
V5j5>
Which would select 5 rows down and indent the selected block 5 steps.
:>>>>>5
is another way.
vip5>
could solve your problem, too, if applicable.
And another slightly less practical (but very precise) one:
:,5le20
where 20 is the exact number of spaces (or tabs and spaces if :set noexpandtab) you want.
one way of doing this - you can make a macro to do that for you.
for example, to save a macro under key a, type following :
qaV5j5>q
q stands for starting/stopping typing onto register.
then, if you type #a macro from register a will be executed and your 5 lines will be indented 5 times. every repeated usage of last macro can be executed by ##.
if that helped, please check http://vim.wikia.com/wiki/Macros
Try this : :1,5s/^/ /

How to select a vertical block with exceeding lines?

In Vim you can use Ctrl+v to select a vertical block of code. This is pretty cool, as this way you can insert a rectangular block of text anywhere in your text. A feature I haven't seen anywhere else yet.
But say I have a text like:
1 abcde
2 abcdefg
3 abcdefg
4 abc
I want to select this full block as vertical block. If I'm on the a of line 1, and start selection, then move down to line 4, I can only move the cursor to the last character c in that line. So the lines above are cut off, giving me this selection:
1 abc
2 abc
3 abc
4 abc
Is there a way to get the full text selected as vertical block?
if you want to select exact 4 lines (including the 1st line), you could:
Ctrl-V$3j
this selects all the texts, but they are not really in a "block", because the first line and the last line have different length.
If you do want have a "block" of text, (appending spaces on those "shorter" lines), you could:
set ve=all
Ctrl-V hhhhh... jjjjj...
by setting ve to all, your cursor could go anywhere. If you like after the selection/copying, you could set the ve back to its original value.
A minute after asking this question i found it out myself. The trick is to press $ on line 4 above. So the full series of keystrokes, if the cursor is on the a of line 1 is:
Ctrl+v3j$
a quick and dirty solution is to insert 4 spaces a the end of line 4.

How can I select multiple lines that are not in a continuous chunk?

I am trying to select multiple lines that are not in a continuous chunk. E.g., I want to select line 1 and 3 simultaneously without selecting line 2:
1. this is line 1
2. this is line 2
3. this is line 3
Initially I thought this would be a trivia task, but after spending quite some time googling around to no avail, I realized this might not be a simple/common task.
Many thanks in advance for your help.
Edit:
Thanks for the responses. I will provide a little more details on how I came up with the question.
I was trying to align a chunk code like the following, using Tabularize:
1. name1="Woof"
2. lucky_dog = lucky( "dog_one"= name1,
3. "dog_two"= name1 )
4. name2="Howl"
I wanted it to align like this:
1. name1 = "Woof"
2. lucky_dog = lucky( "dog_one"= name1,
3. "dog_two"= name1 )
4. name2 = "Howl"
But I cannot do so because Tabularize will take third line into consideration, and align everything into:
1.name1 = "Woof"
2.lucky_dog = lucky( "dog_one"= name1,
3. "dog_two" = name1 )
4.name2 = "Howl"
I believe I could think of some regex trick to archive the desired results, it just occurred to me at first that maybe I could simply select line 1,2,4 and make those align.
Then I realized this is not a easy task.
Hence the question.
Thanks for the responses!
There is now a brilliant plug-in that enables multi-select in Vim: Vim-multiple-cursors:
It's not possible to select different chunks of text in vim.
What you can do instead is identify a common, unique pattern that is shared by the lines you want to act on and use the 'global' ex-command or 'g' to do it like so:
:g/shared unique pattern/ex or normal command here
For example to copy the lines to a register, say the 'a' register:
:g/shared unique pattern/normal "Ayy
To paste them hit "ap
The capital A that comes before yy tells vim that you want to copy and append the lines to the a register.
Like sydill said if you can tell us what exactly you want to do with the lines then we can better help you.

Resources