I would like to copy several lines with line numbers; the text from set number
isn't copied. Is there any way to do this?
3 Answers
You have several alternatives.
Use the
TOhtml
command to let Vim generate an HTML file, which includes the line numbers, and then copy and paste from that file.Replace each line by its line number plus its content, so you can copy it with the line number. This can be done by visually selecting the lines, and using the following substitute command:
:s/^/\=printf("%2d ", line('.'))/
You obviously want to undo this replace after copying using e.g. undo or
:s/^\d\+ //
Create your own command to take care of copying the desired text together with the line numbers. Something like this should work:
fu! s:yank_number(first, last) let start = a:first let l = [] while start <= a:last let l = add(l, printf("%" . len(a:last) . "d %s", start, " " . getline(start))) let start += 1 endwhile return join(l, "\n") . "\n" endfu command! -nargs=0 -range Yank :let @+ = s:yank_number(<line1>, <line2>)
Now select your text and enter
:Yank
, which will copy the range to the+
-register (which should correspond to your system's clipboard, if your Vim was compiled with clipboard functionality (:help
should output+clipboard
, instead of-clipboard
).Use
:redir
::redir @a :silent! :'<,'>number :redir END
or
:redir @a | silent! :'<,'>number | redir END
to pull the numbered lines into register "a". This can be wrapped into a mapping:
:vnoremap <f4> :<home>redir @a<bar>silent! <end>number<bar>redir END<cr>
assuming you always want to trump the same register. If you use it frequently, you might designate a preferred register such as "n" for "(n)umbered" and then only use it for that purpose. Alternatively,
:redir
allows you to redirect to other sinks if you prefer.
DISCLAIMER: The above options have been created from the Vim mailing list thread, using:
If you are one of the above authors, and would like to take credit for it, please let me know, and I will delete the question and answer so that you can re-create it.
-
1You can use
execute()
instead of:redir
to not clobber a register::echo execute("'<,'>#")
. I've also found some weird bugs with:redir
over the years, and generally try to avoid it. Commented May 15, 2019 at 22:02 -
execute()
did not exists back when that question was initially asked Commented May 16, 2019 at 6:35 -
Hi @MartinTournoij .. I use
redir
to load the clipboard with a command's output pretty often. I don't recall ever having problems. OTOH I've only been doing this for, oh, the last 3 years or so so perhaps there were issues but they've since been fixed. Have you had any problems that you recall in that same rough time frame? (Out of curiosity primarily. Thanks.)– B LayerCommented Jul 3, 2019 at 5:53
You can copy the text with the mouse if you do not have the mouse enabled (e.g. set mouse=
), and enable number
.
This will work in any terminal, and also seems to work in the GTK3 version of gvim (but may not work in all gvim versions).
From the perspective of the terminal there is no difference between the number column on the left and the buffer contents; it's all just text. This can be either a good or bad thing, depending on what you want. If you want to copy the number column then it's a good thing :-)
-
1with mouse enabled, I think one can use
shift
+ mouse click to copy. However, this might be problematic, if you have vertical split windows open. Commented May 16, 2019 at 7:42
Why so complicated? The easy way to to this is with the grep
and tee
commands.
Disclaimer: before you start messing with files with the
tee
command make an alias in your.profile
for the command:
alias tee="tee -a"
The
-a
flag tellstee
to append to rather than obliterate the file. Whattee
does specifically is takestdout
and redirects it to files, similar to
echo some text > file.
But it works with what is produced on the terminal.
In order to use tee
properly we need to get some stdout
and that is where grep
comes in.
What you want to do is grep
(find) the text you want to produce which by default will put the text as stdout
. You can also add lines before or after the line you want with -A
, -B
, and -C
flags. Also, to add line number you can add the -n
flag. So if you add -A5
for example, you will get the line you grep for plus 5 lines after that. Similarly with -B5
but in this case you get the line you grep for plus 5 lines before what you grep for. -C5
you get 5 lines before and after meaning 10 lines plus what you grep for. The -n
flag gets you your line numbers.
The command:
grep -n[-ABC][num] "search line" | tee [-a, unless you alias it already] [file]
This command is a lot more simple. You see everything on the screen.
The only drawback (if it is a drawback) is that when grep
adds line numbers, it does so with a colon and each line after that gets a dash like this:
33: text....
34- text....
35- text....
However seeing how you are injecting line numbers to begin with, this is a good visual clue, especially if you have line numbers enabled in your text editor.
It could get real confusing otherwise.
Enjoy.
-
Welcome to Vi and Vim! Interesting answer to the question, but it doesn't really address how this integrates with vim.– D. Ben Knoble ♦Commented Oct 30, 2019 at 22:57
-
1Actually integration is more of a Vim thing which isn't as consistent with the unix way of doing one thing and do it well. Straight up vi is and should be a text editor, thats all it should be resigned to. Grep and tee commands are better suited for those results. Why make life hard. Commented Nov 2, 2019 at 19:24
-
1Not here to argue about the philosophy—vim makes it easy to pull in these tools. My point is this a vi/vim site, so your answer should probably fit into that context.– D. Ben Knoble ♦Commented Nov 2, 2019 at 19:32
tmux
(and possibly other tools), you could achieve this by using the copy mode; assuming you have theset numbers
on.