Vim how to copy to a real (no relative) line number - vim

I'm working with NeoVim, but for the case I think it's the same if we talk about vim. I have set relative line numbers (set nu rnu) and I know how to copy from the line I currently have the cursor to line x with yxj, but I need to copy more lines than I can see, so I first go to line 247, then I go back to line 127 and I don't know if there's a way to specify that I want to copy to line number 247 (without subtracting, of course).
Regards

The relevant documentation is :help change.txt. I'll highlight a few commands
appearing in the :help copy-move sections of the change.txt help
documentation (there is much more in there!).
You can use the command line to specify the lines to yank (i.e. copy, see
:help :y):
:127,247y
It also works with relative numbers (and patterns - see :help range):
" yank lines 25 before cursor through 3 lines after
" cursor
:-25,+3y
In addition, if you know where you want to put them you can use the t
command (see :help :t):
" copy lines 10 before cursor through 2 lines after
" cursor to 5 lines after the cursor
:-10,-2t+5
You can even mix and match relative and absolute lines (and patterns - see
:help range):
" copy from line 23 through to 10 lines before cursor to
" line 51
:23,-10t51
For completeness there is the m command to move (i.e. cut and paste lines,
see :help :t):
" move lines 12 before the cursor through to the current
" line to line 27
:-12,.m27
The traces.vim plugin
I find this plugin very nice - it highlights ranges for Ex commands as you
type them on the command line (and shows you how the :substitute command will
affect your file as you compose it). It really helped me start to use the
command line more. I have this in my vimrc:
" fyi: there is extensive help documentation that's not on the github page
"immediately highlight numerical ranges once you put the comma :N,N
let g:traces_num_range_preview = 1
" window used to show off-screen matches (just 5 since I only want the gist).
let g:traces_preview_window = "below 5new"
" if value is 1, view position will not be changed when highlighting ranges or
" patterns outside initial view position. I like this since I see it all in the
" preview window setting above
let g:traces_preserve_view_state = 1

Move to line 247,
set a mark, e.g. a, via ma
move to line 127
yank from there to the mark y'a
All in all: 247ggma127ggy'a

Related

How to paste contents of a register specifying a line number?

Assume a text file with 5 lines, each having a line break. This text file is opened in gvim. While in command mode and cursor in line number 1, the content of current line is yanked into default register.
How to paste/put yanked to different line number without moving the cursor? For example, cursor is in line number 1. Yanked content should be put in line number 4. How to do this in gvim without moving the cursor to line number 4?
The cursor position is an important part of command addressing; for interactive editing, it does not make sense to have commands that work "at a distance". (Inside Vimscript you can use low-level functions like setline() to modify arbitrary places, but that should not be part of normal use, and here I disagree with #SergioAraujo's answer, which presents this command as suitable for interactive use.)
Instead, Vim makes it easy to temporarily go to a location and then return back to where you came from. The :help jumplist and especially CTRL-O are for that. Your example paste you be done via 4Gp<C-O> or 4Gp``; to use Ex commands, you have to explicitly set the jump point: m':4put<CR>``. The advantage of working with the jumplist is that the paste target now also became part of it, so you can easily go forward (with <C-I>) to it, too.
Here an example:
:call setline(4, getline(4) . " " . #")
We are setting line 4 to line 4 itself plus space " "
plus default register #" .
Just In case you want just put the content
of the line 1 on the line 4 type:
:call setline(4, getline(1))
Use the :t command (a synonym for :copy). Examples:
:1t 4
:.t 4

How to know in VI which line the cursor is on?

I want to copy paste some lines in vi.
I have a text like
python class1 def:
code code code
...
code code code
last line class1
python class2 def:
code code code
...
code code code
I want to copy the whole class1. I was trying to do it with yNy, so I needed to get N, that is, to count the number of lines the class has.
Then I thought it would be good to get the line number of python class1 def: (let's say X) and the last line class1 (Y), calculate N=Y-X, go to the first line of the class and do the yNy. However, I could not figure out how I can get the line numbers.
So, is there any way to know which line I am in? And in general, is there any other way to copy paste a whole block like the one I indicated?
This is my vi version:
VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Oct 26 2012 16:44:45)
Included patches: 1-547
The current line number can be obtained by :.=. Ctrl-g gives more details including filename, column information, ...
In order to copy a block, go to the start of the line to be copied 0. Hitting v would start the visual mode. Navigate to the last line to be copied. Yank y. (Visual selection is now in buffer.)
Using only normal mode commands:
You can do y} to yank everything from the current line to and including the next empty line, delimiting what Vim considers to be a "paragraph". This may or may not work depending on your coding style.
Still using the notion of "paragraph", you can do yip or yap from anywhere in a "paragraph".
You can set the number option which allows you to see absolute line numbers and therefore be able to do y10G, "yank everything from here to line 10".
You can set the relativenumber option which allows you to see relative line numbers and therefore be able to do y5j, "yank everything from here to 5 lines below".
You can do V/foo<CR>y to yank everything from here to foo linewise.
More generally, you can simply use visual mode to select what you want and yank it.
You can also set a mark on the first line of the class with ma, move the cursor to its last line and do y'a (which sounds like the name of a Lovecraftian deity).
Using Ex commands:
Because the aforementioned number option shows absolute line numbers, you can see that the class ends at line 10 and do :.,10y.
Because the aforementioned relativenumber option shows relative line numbers, you can see that the class ends 5 line below and do :,+5y (dropping the implied .).
Using your statusline (or not):
You can :set ruler to have the current line number displayed on the right side of your statusbar if you have one or on the right side of your command line if you don't have a statusline.
Using Vimscript:
You can use line('.') to retrieve the number of the current line.
Using custom text-objects:
There are a number of custom text-objects available on vim.org for indented blocks, function arguments and many other things. Maybe there is one for Python classes.
More generally, I'd advise you to set either ruler, number or relativenumber permanently in your ~/.vimrc and get used to it.
ruler is the least invasive of the bunch but it's also the most limited: you know where you are but it doesn't help at all when you want to define a target.
number is the most classical and can be used to easily target a specific line.
relativenumber is a bit weird at first and, like number, can be used easily to target a specific line.
Choosing number or relativenumber is, as far as I'm concerned, a matter of taste. I find relativenumber very intuitive, YMMV.
Try the following in command mode
:.= returns line number of current line at bottom of screen
yNy or Nyy copies the next N lines, including the current line
p pastes the copied text after the current line
Additionally,
:set nu! in command mode will turn on/off the line number at the beginning of each line.
let the vim registers do this task. why bother calculating lines
for example if you want to copy line X to line y
1) move your cursor to 1st character of line X.
2) type "ma" . this will save current cursor position in register "a".
3) move cursor to last char of line Y.
4) type "y`a". copy is done
5) p pastes the copied text
This method can work not only lines but block ,words even on characters.

Vim: Replacing a line with another one yanked before

At least once per day i have the following situation:
A: This line should also replace line X
...
X: This is line should be replaced
I believe that I don't perform that task efficiently.
What I do:
Go to line A: AG (replace A with the line number)
Yank line A: yy
Go to line X: XG (replace X with the line number)
Paste line A: P
Move to old line: j
Delete old line: dd
This has the additional disadvantage that line X is now in the default register, which is annoying if I find another line that should be replaced with A. Yanking to and pasting from an additional register ("ayy, "aP) makes this simple task even less efficient.
My Questions:
Did I miss a built-in Vim command to replace a line yanked before?
If not, how can I bind my own command that leaves (or restores) the yanked line in the default register?
Vp: select line, paste what was yanked
What I would do :
36G (replace 36 with the line number you want to go to)
Y
70G (replace 70 with the line number you want to go to)
Vp
You don't have to leave normal mode, but it does yank the line. You can however use V"0p which will always put the line yanked in step 2.
This has the additional disadvantage
that line X is now in the default
register, which is annoying if I find
another line that should be replaced
with A.
To delete text without affecting the normal registers, you can use the Black hole register "_:
"_dd
Building on the answers that suggest using Vp or VP to paste over a line -- to avoid changing the contents of the yank register I find the most ergonomic command is simply:
VPY
yy
j (move to the line you want to replace),and then
Vp (uppercase v and then p, will replace with the yanked content)
I would use commandline (Ex) mode and do the following two commands
:XmA
:Ad
This simply moves line X to just under A, then deleting A moves that line up
For example
:7m3
:3d
Move to the start of the first line.
y, $ – copy the line without the linebreak at the end
Move to the start of the target line.
V, p – replace just one target line
c, c, Ctrlr, 0, Esc – replace the target line with the original yank
Move to the start of the next target line.
. – repeats the command issued at 4.2.
Notes:
4.1 is y, $ because if you do y, y or Y you will copy the linebreak, and Ctrlr, 0 actually adds the linebreak below your target line.
4.2 replaces V p, which doesn’t work with repeat because technically the last action is delete, so . would just delete a line.
If anyone knows how to issue ‘replace current line with register’ from EX mode (command line), I would like to hear from you (and to know where you found the documentation). There may be a repeatable EX command which is faster than 4.2 and/or does not have the linebreak caveat.
You can also do:
Vy (in normal mode at the line you want to copy)
Vp (in normal mode at the line you want to replace)
Doesn't create spaces or line ends.
Cursor is placed at the start of the copied text.
The same keys can be used to yank/paste more than one line.
V (in normal mode at what you want to yank)
(use jk to move the selection)
y (to yank the selection)
V (in normal mode at where you want to paste)
(use jk to move the selection)
p (to replace the selection with the yanked lines)
Here's what I would do
Move beginning of line A, AG (where A is a line number obviously)
Yank line to some register, e.g. a (without new line). Type "ay$
Move to insert line, XG
Substitute line, S
Insert from register a, Ctrl-Ra
You can use this with visual mode.
Go to line A: AG
Select the line with visual mode: VESC
go to line X: XG
Enter substitute mode for the line: S
Paste the line you copied: shift+insert (or whatever other you mapping you have for pasting from the clipboard).
In light of the recent comment by cicld (thank you!), I see that I didn't grasp the original issue fully. Moving the line is not appropriate, but copying is (since the line is yanked.) So I would revise it to:
:1t20:20d_
Copy the 1st line (:t command is an alias for :copy) after line 20 (will place it on line 21)
Delete line 20, putting the deleted line into the 'blackhole' register (_) (i.e. not affecting the current yank buffer)
As mentioned in the recent comment, this will not affect the current cursor position.
You can use this commands in Normal Mode:
:AmX | Xd
the m command is for m[ove], which moves the line number A after the line number X, if you want to copy instead of move the line, use co[py]. the d command is for d[elete].
You can move(copy using co) a range of lines using
:start,end m X
:ay (where a is the line number. Example :20y). This yanks a line(pun intended).
Vp
I find it easier to use Ex command for this; ex. to move line 9 to 46:
:46|9m.|-1d
This will move the cursor to line 46, move line 9 below the current,
then delete the previous line (since moved line is the current one).
Or using mark(s), using mark 'a':
:46ma a|9m'a|'ad
I often have to Y one line and replace it in multiple places, each of which have a different value (which means that I can't do a regex).
Y to yank the desired original line
and then on every line that you'd like to replace, VpzeroY
i would simple use the "Black hole" register:
given:
nnoremap < C-d > "_dd
the solution would be:
< C-d >yy
If you only want to change part of the line you can do that this way:
Move to position of what part of text you want to copy
y,$ - Yank from cursor to EndOfLine
move to position where you want to replace
v,$,p - replace from cursor to EndOfLine with contents of register

Prepending a character followed by the line number to every line

I'm hand-editing CNC Gcode text files and need a way to reference locations in the file and on the toolpath.
I want to modify every line in the text file so that it begins with the the upper case letter N followed by the line number, incremented in tens for each successive line, then a whitespace followed by the original text on that line. How can I do this in Vim?
I'm not sure about vi, but (since you're using the vim tag) Vim allows you to accomplish your task as follows:
Adjust the first line by hand (insert a N10 at the beginning of the line), then put the cursor at the beginning of the next line.
Press qb to start recording a macro (the b names the register used to store the macro; feel free to use a different letter -- and definitely do use a different letter if you've got something useful stashed away in b).
Move the cursor upward to the beginning of the previous line (which you have adjusted by hand). Press v to start visual selection mode, then f to move the cursor to the next space on the line (if you use a single space as your whitespace separator, that is; adjust this step if you're using a tab or multiple spaces).
Press y to yank the selected text. This will also remove the visual selection.
Move the cursor to the beginning of the next line. Press P to insert the previously yanked text before the cursor, that is, on the very beginning of the line.
Move the cursor to the numeric part of the line header. Press 10 C-a (1, 0, control + A) to increment that number by 10.
Move the cursor to the beginning of the next line. Press q to stop recording the macro.
Press 10000000 #b to execute the macro 10000000 times or until it hits the end of the file. This should be enough to take care of all the lines in your file, unless it is really huge, in which case use a bigger number.
...or use Vim to write a simple script to do the job in whichever language you like best, then run it from a terminal (or from withing Vim with something like :!./your-script-name). ;-)
The following command will prepend ‘N<line number * 10>’ to every line:
:g/^/exe 'normal! 0iN' . (line('.')*10) . ' '
You can do it easily in Vim with this:
:%s/^/\=line(".")*10 . " "/
This replaces the start of every line with the result of an expression that gives the line number times ten, followed by a space.
I have not timed it, but I suspect it might be noticeably faster than the other Vim solutions.
Cheating answer:
:%!awk '{print "N" NR "0", $0}'
There are two ways to implement that without resorting to external
tools: via a macro or by using Vimscript. In my opinion, the first way
is a little cumbersome (and probably not as effective as the solution
listed below).
The second way can be implemented like this (put the code into your
.vimrc or source it some other way):
function! NumberLines(format) range
let lfmt = (empty(a:format) ? 'N%04d' : a:format[0]) . ' %s'
for lnum in range(a:firstline, a:lastline)
call setline(lnum, printf(lfmt, lnum, getline(lnum)))
endfor
endfunction
The NumberLines function enumerates all lines of the file in a given
range and prepends to each line its number according to the provided
printf-format (N%04d, by default).
To simplify the usage of this function, it is convenient to create
a command that accepting a range of lines to process (the whole file,
by default) and a optional argument for the line number format:
command! -range=% -nargs=? NumberLines <line1>,<line2>call NumberLines([<f-args>])

Change wrap width in a text file using Vim

I want to format srt subtitle text files to avoid wrapping problems on my media player.
I need to set a line wrap width to a number of characters e.g. 43
I can do this with Editplus, its a built in function and works well. The reason I want to do it in Vim, firstly Editplus is only available on the PC and the secondly Vim is badass.
I have found the following solution on the net..
:set tw=43
gggqG
It does work, but not exactly how I want it.
E.g.
I have this text:
557
00:47:39,487 --> 00:47:42,453
I will have to complete some procedures,
and I asked you to check out what they are for me
after I format it, I get:
557 00:47:39,487 --> 00:47:42,453 I will
have to complete some procedures, and I
asked you to check out what they are for
me
It seems to ignore line breaks/CRs. As you can see the "I will" has been added to the first line.
How do I get it to not ignore line breaks?
EDIT: apoligies about the formatting, first time using stackoverflow!
You could use the whitespace option of formatoptions and make the lines you want to wrap end in whitespace.
:set tw=43
:set fo+=w
:g/^\a/s/$/ /
gggqG
The third line adds a space on the end of any line starting with a letter and fo+=w stops gq from joining lines that don't end in spaces.
See:
:help fo-table
:help 'formatoptions'
:help gq
:help :g
Edit in response to comments
:g/^\a/s/$/ /
This translates to:
:g/ " Search the file
^\a " For lines starting (^) with an alphabetic character (\a - equivalent to [A-Za-z])
/ " Then on each line that the regexp matches (i.e. each line starting with an alphabetic character)
s/ " Substitute...
$ " The end of line (zero-width match at the end of the line)
/ / " With a space (slashes are delimiters)
The global (:g) command will only operate on the current file, but the textwidth and formatoptions lines will last for the whole session. If you want those options to only be used on the current buffer, use :setlocal instead:
:setlocal tw=43
:setlocal fo+=w
:help :setlocal
If the only lines you want to wrap are the ones that start with text (ignore the ones that start with numbers) you can use the following.
:g/^[a-zA-Z]/normal gqq
This will run p00ya's command on each text line in the file.
With the following text (i.e. only 3 lines):
557
00:47:39,487 --> 00:47:42,453
I will have to complete some procedures, and I asked you to check out what they are for me
Use gqq (format current line) on the 3rd line after setting tw. Formatting by paragraph will not work since vim will treat all 3 lines as part of the same paragraph (paragraphs only end with a blank line).
While not exactly robust (or elegant), if you can assume that the subtitle lines do not begin with numbers, you can configure Vim to treat them as comments.
:set comments=:0,:1,:2,:3,:4,:5,:6,:7,:8,:9
gggqG
Lines starting with 0-9 will be treated as comments and won't be merged together with the text.
I can't see exactly what the issue is due to the formatting of your post, but you might want to checkout the 'formatoptions' setting in vim's help, specifically :he fo-table which contains a bunch of customization flags.
This link might be useful.

Resources