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

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.

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

Easier line referencing

I was wondering if anyone knows of a plugin to enable easier line determination.
I have issues quickly scanning to see what line I was to reference in commands such as t and m
See this screenshot:
If I wanted to quickly reference line 5 (I do have line numbers switched on, I just accidentally cut it out in this screenshot) I find I have to look rather hard to find the correct line number.
so: Is there a plugin which makes referencing lines less eye-straining?
I guess your problem is with those deeper indented lines. sometime it is not easy to "connect" the line number and the line text. If this is the case, you may try followings:
set listchars=tab:>-
(see :h 'listchars' for detail) this line will show the <tab> with certain chars. for example, following screenshot is a formatted maven pom.xml, with relative deeper indent lines. I think it would be ok to read the line numbers of them. E.g. the line 1180-1184.
I hope it helps.
with plugin
If the above doesn't help, e.g. you have spaces not <tab>, you could try a plugin: indentLine, with this you could set a variable g:indentLine_char with the char you like. e.g. > to show indent level clearly.
The link of the plugin: https://github.com/Yggdroot/indentLine
:move and :copy are not limited to line numbers (absolute or relative) only, either as source or as target.
You can use search patterns too:
:m?foo
would move the current line just under the first line matching foo going upward,
:t/bar
would copy the current line just under the first line matching bar going downward,
:?foo?t/bar
would copy the first line matching foo above the current line to just below the first line matching bar going downward, and so on.
You can also use marks:
:'at'b
would copy the line marked a to below the line marked b,
:m''
would move the current line to just below the line you were before the last jump, and so on.

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>])

VIM: Zero-Indexed Line Numbers in :set number

Using VIM, it is easy to display line numbers for any given file with:
:set number
However, the line numbering is 1-indexed, this means that the numbering starts at 1.
Normally this is exactly what i want, however a particular tool I am using to compile my code reports zero-indexed line numbers - that is, line numbers start at zero.
How do I change vim's line numbering to compensate so that viewing the numbers in the vim buffer corresponds to the errors provided by the tool, and in addition jumping to a particular number corresponds to that of the tool as well.
That is, if the tool tells me that there is an error on line 98, I want to jump to that line by typing "98G", not "97G", and I want that line (which is really line 97 in vim) to display "98" in the line number list.
Edit:
While I can filter the output of the tools, while fairly simple it is not a trivial task because the tool also outputs hex values that correspond to each line, which has the same zero-indexed form, and this is is output in informational messages as well, not just for errors, and I have many such projects.
I don't think this is possible; however, assuming the output of your external tool is just text, it would probably be fairly easy to filter the output such that the numbering is 1-indexed to match Vim. Can you give us an example of your output?
Edit
Alternatively, if you call the external command from Vim, you could do something like (basically, add a blank line, run the external command and then delete the blank line):
command! RunMyExternalProgramme call RunMyExternalProgramme()
func! RunMyExternalProgramme()
" Save the old setting of makeprg
let s:savedMakePrg = &makeprg
" Save the screen layout
let s:savedView = winsaveview()
if config_file != ''
" Put a blank line at the start of the file
:1put! =''
" Save
write
" Change makeprg and run it
let &makeprg = '/path/to/programme -options etc'
make
" Delete the blank line
1d
" Save
write
endif
" Restore the screen layout (optional)
call winrestview(s:savedView)
" Restore the old setting of 'makeprg'
let &makeprg = s:savedMakePrg
endfunc
I suggest to wrap your tool in a small script. In the script, either copy the source code and add an empty line at the top of the source or use awk to fix the output (parse the error messages and add 1).
The only way to make vim display line numbers starting with 0 is to patch the source and create a new option (say lno for line number offset) and add this value to the line number. You'd need to patch this in quite a few places (display, goto commands, search patterns, etc). Shouldn't take more than one or two years to make it work :) Good luck on getting the author of Vim to accept this as a patch.
set relativenumber or for short "set rnu"
This starts the count from 0

Vim yanking range of lines

I'm a C# developer who has just recently decided to expand my knowledge of the tools available to me. The first tool I've decided to learn is Vi/Vim. Everything has been going well so far, but there are a couple of questions I can't seem to find the answer to:
Lets say I wanted to yank a range of lines. I know there are many ways of doing so, but I would like to do it by line number. I figured it would be similar to how the substitute commands work, something like 81,91y. Is there a way to do this?
I'm a little confused about the g command in normal mode. It seems to do a myriad of things and I can't really determine what the g command does at its core. I'm confused on whether or not it's a motion command or a kind of "catch all" for other commands ran through normal mode. Can someone please explain this or point me to a reference that gives a good explanation of the g command?
Yank lines 81-91
:81,91y<enter>
If your fingers don't like to find the : and , keys, this would work as well (go to line 81, yank 11 lines)
81gg11yy
My only use of g is 5gg. To go to the 5th line. 22gg: 22nd line. As jimbo said, it's really only a modifier for some other commands.
For completeness, (http://vim.wikia.com/wiki/Power_of_g) explains a lot of how g works in command mode.
You can also copy the current lines to your present cursor location using 't'.
:81,91t.<enter>
This will paste the lines 81-91 under the line the cursor is on.
I learned this from http://vimcasts.org which is an excellent resource on VIM.
I also like to use vim's relative line number option which means I can just enter:
:-10,-7ya a
to yank the text into named buffer a.
N.B. Specifying A will append what you're yanking to the current contents of buffer a.
Don't forget you can also copy blocks of text and move blocks of text around as well with the similar commands:
:-10,-7co .
means copy the four lines of text 10 lines above to below the current line, and
:-10,-7mo .
means move the four lines of text 10 lines above to below the current line.
The G command goes to a certain line number, if it's accompanied by a count value. 81G puts you on line 81.
The y command can be combined with a movement, like G. So to yank everything until line 91 you can use y91G.
Together you get:
81Gy91G
Go to line 81, then yank while going to line 91.
g doesn't do anything by itself. It's one of a couple meta-commands that holds a bunch of sorta-unrelated commands.
z is yet another command like that.
In addition to :91,96y a which yanks (y) lines 91 through 96 into register a, (pasted with "ap), the yanked lines can be appended to the register with:
:91,96y A
I.e. the capitalization of the A register causes an appending operation into register a instead of an overwrite. Capitalization of the register always works like this, e.g. :let #A=';' appends a ; to register a.
Using plus (+) or minus (-) references lines relative to the current cursor position:
:-10,+10y b
I.e. it would yank(y) 21 lines around the current cursor position and put them in register b.
An absence of input actually represents the current cursor position as well, which means that this:
:-5,y a
would yank the text from 5 lines above to current cursor position into named buffer a, and:
:,+5y a
would yank the 5 lines after the current cursor position into buffer a.
Note: If you have a macro in buffer a it was just overwritten by the previous yank, as yank registers and macro registers are really the same thing. Which is why, coincidentally, you can paste a macro, edit it, and then yank it back into it's register. I personally use letters reached by my left hand for yanks, and letters reached by my right hand for macros.
Moving blocks of text around, looks like this:
:+10,+13m.
which means move the four lines positioned 10 lines ahead of current cursor, to below the current line.
Addendum
I previously confused ya in :91,95ya a to be somehow synonymous with ya{motion} where the motion was supplied by 91,95. This was incorrect and the "a" in ya is completely unnecessary. In my defense, my help yank does not convey that ya is a possible alias of yank.
The best solution would be to enter "visual mode", by pressing v. And after selecting lines just copy them by pressing y. Then paste copied lines by pressing p.
Vim's :help index describes g as:
|g| g{char} extended commands, see |g| below
Scroll down (or :help g) for a list.
As a long time Vi/Vim user I tend to use 'marks' instead of line numbers (or 'line markers'). It works like this: m is the 'mark' character; then use any letter to identify/name the mark. To return to a mark preface the named mark with a single quote ( 'a)These marks can be used as the range. Examples:
File:
<line 1>
<line 2>
<line 3>
<line 4>
<line 5>
When in command mode move cursor to line 2, typema. scroll to line 4, typemb.
To yank from mark a to mark b type:
:'a,'byank
To delete from mark a to mark b type:
:'a,'bdel
To search from mark a to mark b and replace 'ine' with 'ink':
:'a,'bs/ine/ink/g
To copy mark a through mark b and paste below the current position (the 'dot' always references the line where the cursor currently is positioned):
:'a,'bco .
Shift lines of code, between mark a through mark b, one tab to the right (use opposite chevron, <, to move left):
:'a,'b>
In command mode you can move back to marks by simply typing 'a to move back to the line marked a. Typing '' moves you back to previous position (unfortuantely only remembers the previous position, not two back).
You can yank to named buffers, copy, delete lines, search&replace just portions of your code, etc. without needing to know the line numbers.
To yank lines from line number 81 to 91 :
approach 1: 81gg11yy
not bad but you have to do little bit of math to find out how many lines to yank
approach 2: 81gg then shift+v then 91gg then y
BEST IN MY OPINION because this is straight forward, you only have to know the obvious thing i.e from which line number to which line number you want to yank

Resources