Thursday, September 5, 2013

Guide Line to vi(m)

vi (VIsual editor) is the standard Unix text editor. It comes with Unix, Linux, and Cygwin (if you are using Windows).

If you are going to use vi I would obtain a copy of vim (vi iMproved) which may well be installed as standard. For instance, with Cygwin vim is standard. To test this, just type "vi" on its own at a command prompt. If you see a page about "VIM - Vi IMproved" then you have vim.

This page will attempt to cover the common commands that I use (as a programmer) - vi(m) is actually much more powerful (and complex) than I will show here, but the basics should be all you need. Many of the things described (like visual mode) are specific to vim, but the basics should apply to both.

Topics on this page in alphabetic order

  • Advanced deletion
  • Advanced movement commands
  • Applying commands to certain lines
  • Automating things
  • The basics
  • Change existing text
  • Changing text
  • Copying, cutting and pasting
  • Delete text
  • Go to lines, find matching text
  • Insert text
  • Line numbers
  • Mapping actions to function keys
  • Marking your work
  • More useful tips for programmers
  • Recording commands
  • Repeat counts
  • Search and replace
  • Setting up your personal favourite settings
  • Shell and filter commands
  • Spellcheck file
  • Splitting and joining lines
  • Tab management
  • Tags
  • Undoing things
  • Visual mode commands
  • Visual mode
  • Why use vi?

Why use vi?

When I first tried using vi I thought that you could not have a more obscure and difficult-to-use text editor, but I found that after memorising half-a-dozen commands that it was really quite simple to use. And, quite powerful. For example, you can do something like "find all lines with 'swordfish' in them, and for those lines only, change 'cat' to 'dog'". Try doing that with your normal editor!
The other reason is you can usually find vi on almost any Unix installation. If you get used to "my favourite editor" - whatever that is - and connect to a different site for troubleshooting, you may well find it is not installed, or only runs under Xwindows, or some other such restriction.
Further, you can do quite fancy things (see below) like do a "make" from inside vi, and then with a single keystroke go to each error message (even in different files), with the cursor being placed on the line in error, so you can fix it. This is quite a time-saver. Similarly with doing "grep" on a group of files.

The basics


If you start doing something and change your mind you can generally press Ctrl+C to cancel it.

Edit a file, look at it, stop editing


Edit a file from command promptvi <filename>
Edit a file from command prompt for reading onlyvi -R <filename>
Edit a file from within vi:e <filename>
Edit a new file from within vi, discard changes to current file:e! <filename>
Reload current file, discarding changes:e!
Go forwards a pageCtrl+F (or PgDn)
Go backwards a pageCtrl+B (or PgUp)
Move around single lines or charactersArrow keys
Save changes:w
Save changes and override protected (read-only) files:w!
Save changes and exit viZZ
Quit:q
Quit and discard changes:q!
Get general help:help
Get help on a command (eg. :set):help set
Notes
  1. Whether keys like PgUp and PgDn work will depend on your keymappings. I find recently that they tend to work without needing to make any changes. In some cases you may need to type "vim (file)" at the command prompt rather than "vi (file)" if both are installed. Otherwise you may set up an alias (at your shell prompt) to equate vi to vim.
  2. Any command starting with these characters:
    • : (colon) - starts a command sequence
    • / (slash) - starts a forwards search
    • ? (question mark) - starts a backwards search
    needs you to press <Enter> to execute them. Until you have done that you can backspace and make corrections.
    These commands are echoed on the bottom line of the screen, so you can see what you are typing. If you have started typing one of those, you see the command being echoed, and change your mind, press Ctrl+C to cancel the command.

Simple example

Let's edit comm.c and then exit ...
vi -R comm.c
(PgDn to look at file)
:q
If you are experimenting then it might be wise to either edit a file you don't care about (eg. a copy) or use the -R option (read-only).
Alternatively, set read-only mode once you have edited the file:
Set read-only mode:set ro

Go to lines, find matching text

Go to line 1234 (do not see typing)1234G
Go to line 1234 (see typing):1234
Go to start of file1G
Go to end of fileG
Find (forwards) a line containing "swordfish"/swordfish
Find (forwards) a line using a regular expression/you see .* here
Repeat last searchn
Repeat last search in opposite directionN
Find (backwards) a line containing "swordfish"?swordfish
Find (backwards) a line using a regular expression?you see .* here
Search case insensitive (Ignore Case):set ic
Search with case sensitivity:set noic
Wrap searches back to start of file:set wrapscan
Do not wrap searches:set nowrapscan
Notes - these are probably the most frequent things I do. 'Go to line number', especially if you have a compiler error which gives a line number is very handy. Type the line number directly followed by "G", and you are taken there. Or, if you don't know the line, type "/" followed by a word or regular expression you are looking for. The second way of going to a line number (:1234) is probably easier to use because you can see the number as you type it. If you type "1234G" the number (1234) is not echoed to the screen as you type.
Highlighting - searching with "/" or "?" normally highlights the found word. Sometimes this can be quite annoying, especially if you have searched for something which occurs frequently, like a space. You can turn this off:
:hi clear search
Case-sensitivity - using ":set ic" lets you search with or without matching the exact case of the word you are searching for (eg. if you search for "dog" do you want to match "DOG"?).

Simple example

Let's edit comm.c and go to line 5522. Then find "const".
vi comm.c
:5522
:q
/cons
t

Line numbers

Sometimes it is handy to know what line you are at, or what each line number is.
Show line numbers on the left:set nu
Do not show line numbers on the left:set nonu
Show the current line number:.=
Show total lines in file:=
Show file name, total lines, and current line numberCtrl+G
Show line number of first matching pattern:/pattern/=
Notes - showing lines numbers is particularly useful when you are relating things like error messages (or instructions) to a line number. Also the Ctrl+G trick is useful to remind yourself of what file you are editing.

Simple example

Let's edit comm.c, show line numbers, find the first line with "const" in it (line 70) and go to it:
vi comm.c
:set nu
= :70 :q
:/const
/

Changing text

OK, we can move around the file and find things. Let's start changing stuff ...

Undoing things

When you start going into "change things" mode you will probably need to undo your mistakes. Two useful commands:
Undo last changeu
Undo all changes on current lineU
If things get out of hand, remember:
Quit editor without saving changes:q!
Reload current file, discarding changes:e!

Insert text

All of the changing commands (except "replace next character") go into "insert mode" (usually shown by "-- INSERT --" or "-- REPLACE --" at the bottom of the screen). To exit from Insert Mode, press the Esc key.
Insert after cursori
Insert before cursora
Insert at beginning of lineI
Insert at end of line (append)A
Open (start) new line below cursoro
Open (start) new line above cursorO
The last two are the letter "oh" not a zero. I use the "O" and "o" commands quite a bit to start entering a new line above or below where the cursor currently is.

Change existing text

Replace next characterr
Type over following charactersR
Replace to end of lineC
Note - the "r" command is useful if you just want to make a minor correction (eg. change "A" to "B"). This does not go into Insert Mode, so you don't need to then cancel Insert Mode. To change the character under the cursor to a "B" you would just type "rB".

Delete text

Delete character under cursorx
Delete character to left of cursorX
Delete to end of lineD
Delete entire linedd
These are your basic deletion commands. "x" to scrub out the character under the cursor, "dd" to delete the entire line.

Advanced deletion

Delete next 5 lines5dd
Delete to end of lined$
Delete to start of lined0
Delete to word "swordfish"d/swordfish
Delete to the letter "x"dfx
Delete lines 10 to 20:10,20d
Delete current line and another 5 lines:.,+5d
Delete all lines:%d
Delete current worddw
Find line containing pattern, delete it:/pattern/d
Find line containing "dog", delete until line containing "cat":/dog/,/cat/d
Delete from current line to line containing "foo":.,/foo/d

Copying, cutting and pasting

If you delete some text using the deletion commands described above you have "cut" the text. However it is saved in an internal buffer and can be pasted somewhere else. Simply move the cursor to where you want it and:
Paste after cursorp
Paste before cursorP
vi calls copying "yanking", and thus uses the letter Y.
To copy text without deleting it you need to "yank" it. The yank commands are similar to the deletion commands, like this:
Yank to end of liney$
Yank to start of liney0
Yank to word "swordfish"y/swordfish
Yank to letter "g"yfg
Yank entire lineY
Yank lines 5 to 105,10y
After yanking you can paste as described above (or there is no point to yanking in the first place).

Advanced movement commands

Go forwards a wordw
Go backwards a wordb
Go to end of worde
Go to start of line0
Go to end of line$
Go to top of screenH
Go to middle of screenM
Go to bottom of screenL
Go (forwards) to letter "x" on current linefx
Go (backwards) to letter "x" on current lineFx
Go to next occurrence of word under cursor*
Go to previous occurrence of word under cursor#
Find a control character (eg. Tab)/(Ctrl+V)(Tab)
Go backwards a sentence(
Go forwards a sentence)
Go backwards a paragraph{
Go forwards a paragraph}
The command "go to start of line" is a zero, not an "oh". You can use Ctrl+V in insert or command mode to literally insert the next character.

Repeat counts

Most commands have a "repeat count" that you can optionally type first. To do a repeat count just type the number before the command. It will not be echoed, so type carefully!
For example:
Delete 5 lines5dd
Delete 5 characters5x
Delete 5 words5dw
Replace next 5 characters5r
Yank (copy) next 7 lines7Y
Go to line 10001000G
Paste copy buffer 10 times10p
Insert 40 hyphens40i-<Esc>
Insert the line "swordfish" 10 times10oswordfish<Esc>
Find the 5th occurrence of "swordfish"5/swordfish
In the above examples <Esc> means press the Esc key.

Splitting and joining lines

Split a line (insert a return)i<Enter><Esc>
Join two lines (current and next)J
Join next 10 lines10J
Join lines 10 to 20:10,20j
Splitting is basically breaking a line into two by inserting a newline. Joining is reversing that process by removing the newline.

Search and replace

Change "nick" to "fred" on current line:s/nick/fred/
Change "nick" to "fred" on the next 5 lines:.,+4 s/nick/fred/
Change "nick" to "fred" on lines 100 to 200, all occurrences:100,200 s/nick/fred/g
Capitalise every word in the entire file:% s/\<./\u&/g
Insert ">" at the start of every line:% s/^/>/
Insert "// nick" at the end of every line:% s;$;// nick;
Special characters for line sequences:
  • . is the current line
  • $ is the last line
  • % is every line
  • +5 means 5 lines from current line
  • -5 means 5 lines before current line

Applying commands to certain lines

You can use the ":g" (global) command to find matching lines (using a regular expression) and then apply a command to those lines. For example:
Find lines containing "fruit" and change "apple" to "orange" on them:g/fruit/s/apple/orange/g
Delete all blank lines:g/^$/d
Find lines NOT containing "nick", append "oops" to them:g! /nick/normal A oops
The third example above shows you you can use the "normal" command inside a command, to tell vi to use a normal character (in this case A for append) as part of a command.

Shell and filter commands

List directory:! ls
See processes:! ps
Sort lines 20 to 30:20,30 ! sort
Sort entire file!G sort
Translate next sentence to upper case!) tr '[a-z]' '[A-Z]'
Word count file (save first):!wc %
Look up manual entry for strstr:!man strstr
Insert "ls" command output into window:r !ls

Tags

Tags let you go to the definition of a function (in C or C++) without having to scan lots of source files (with grep) and work out which ones contain the function and which merely refer to it.
First, make a tag file, like this:
ctags *.c *.cpp *.h
(In recent versions of Linux I have had to use gctags instead of ctags).
This should produce a file "tags" in the current directory.
Now you can go straight to a function, without knowing which file it is in, like this:
vi -t game_loop
Once inside vi you can put the cursor on a word and go to its definition:
Go to function under cursorCtrl+]
Go backCtrl+T
Go to function xyz:tag xyz

Automating things

Compiling from within vi and going to errors

You can save your changes, run "make" to compile, and view errors, very easily ...
Save file:w
Run "make":make
Go to next error:cn
Go to previous error:cp
This is fabulously powerful. It lets you skim through all your errors, with vi opening the right file and positioning the cursor on the line in error.
See below for how to map actions (like ":cn") to function keys to speed up the process.

Mapping actions to function keys

Map the action :cnext to <F6>:map <f6> :cnext<cr>
Map the action :cprevious to <F7>:map <f7> :cprevious<cr>
Map the action :make to <F8>:map <f8> :make<cr>
Map the action :close to <F12>:map <f12> :close<cr>
After entering the above commands you could compile by simply hitting F8, then look at each error by hitting F6.

More useful tips for programmers

Go to definition of word under cursorgd
Go to global definitiongD
Find matching bracket, brace, #if, #endif%
Do a grep:grep foo *.c
After grep, go to next occurrence:cn
Get a file (eg. an #include file) whose name is under cursorgf
Auto complete (in insert mode) - match forwardsCtrl+X Ctrl+N
Auto complete (in insert mode) - match previousCtrl+X Ctrl+P
Make an abbreviation (eg. cca = "const char *"):ab cca const char *
Turn syntax colouring on:syntax on
Turn syntax colouring off:syntax off
Execute any shell command:! command
Indent selected lines with C-style indenting=
For formatting of C code there are also other options you can use like "autoindent", "smartindent", "cindent", and "indentexpr". (Use :help (topic) to see more about those options). You can turn these on (eg. :set cindent) to automatically indent your coding as you type. Also, in conjunction with syntax colouring, you can see if you have made a syntax error (eg. not closed a quote, left off a bracket), as the syntax colouring algorithm will highlight in red sequences that do not seem correct.

Spellcheck file

Save file first:w!
Spell check it:! ispell %
Edit fixed file:e %

Tab management

Tabs can be annoying in source files, as they do not necessarily line up when you use different value tab stops. You can manage them in vi like this:
Set tabs to every 4 characters:set ts=4
Convert tabs to spaces in future:set et
Do not expand tabs:set noet
Fix existing tabs (convert to spaces):%retab
Show tabs visually, and end-of-lines:set list
Do not show tabs and end-of-lines:set nolist

Visual mode

vi can be a bit difficult to follow when you are trying to do something to a block of lines (for example, do I want line 8843 through to 8903 or 8904?), so vim has a "visual mode" where you can actually see lines highlighted in inverse.
First, "mark" a block of lines (or characters) by going to the start of the block, and then using one of the following:
Character modev
Line modeV
Block modeCtrl+V
Re-mark previous blockgv
The differences are:
  • Character mode - from somewhere inside one line to somewhere inside another (ie. can be a part line)
  • Line mode - will be whole lines
  • Block mode - from (say) column 5 at line 10, to column 60 in line 20 (a square block of text)
Then use the cursor movement commands (search, arrow, go to line, whatever) to mark the other end of the block, and either:
Do some command(see below)
Cancel visual modeEsc
Go to other end of blocko

Other ways of establishing a visual block

A word (with white space)vaw
Inner wordviw
A WORD (with white space)vaW
Inner WORDviW
A sentence (with white space)vas
Inner sentencevis
A paragraph (with white space)vap
Inner paragraphvip
A ( ... ) block (includes brackets)vab
Inner ( ... ) blockvib
A { ... } block (includes braces)vaB
Inner { ... } blockviB
A "word" is a sequence of letters, numbers, underscores. A "WORD" is a sequence that is terminated by spaces. The difference would apply in cases like a(b) - if the cursor is on "a" a "word" is "a" however a "WORD" is "a(b)".
Here is an example, from C source code. Say you have the following code, and you want to select the code inside the inner { ... } characters. Put the cursor in the middle (eg. on CON_EDITING) and type "viB" and the "inner block" (text in bold) will be highlighted.
if ( d->pagepoint )
{
if ( !pager_output(d) )
{
if ( d->character
&& ( d->connected == CON_PLAYING
|| d->connected == CON_EDITING ) )
save_char_obj( d->character );
FALSE);
d->outtop = 0;
close_socket(d,
}
}
Here is another method of selecting a visual block of C code. Say we have the following code and we want to highlight everything inside the "while" loop. Put the cursor on the first "{" and type "v%". That will go into visual mode and move to the end of the block. The highlighted code will be in bold.
while ( usecDelta >= 1000000 )
{
usecDelta -= 1000000;
secDelta += 1;
}

Visual mode commands

See below for meanings of notes in brackets.
Switch case~
Deleted
Change (4)c
Yanky
Shift right (4)>
Shift left (4)<
Filter through external command (1)!
Filter through 'equalprg' option command (1)=
Format lines to 'textwidth' length (1)gq
You can also do the following on the selected block:
Start ex command for highlighted lines (1):
Change (4)r
Changes
Change (2)(4)C
Change (2)S
Change (2)R
Deletex
Delete (3)D
Delete (2)X
Yank (2)Y
Join (1)J
Make uppercaseU
Make lowercaseu
Find tagCtrl+]
Block insertI
Block appendA
Notes
  1. Always whole lines
  2. Whole lines when not using CTRL-V.
  3. Whole lines when not using CTRL-V, delete until the end of the line when using CTRL-V.
  4. When using CTRL-V operates on the block only.

An example of visual mode?

OK, let's say we have a visual block highlighted. Try these:
Delete itd
Copy itY
Change "apple" to "orange" in the block:s/apple/orange/g
Turn into C++ comments:s.^.//.
Turn into C comments:s-^.*$-/* & */-

Marking your work

If you need to jump backwards and forwards between a couple of places you can "mark" them ...
Mark current position as "x"mx
Go to position "x"`x
Show list of known marks:marks
That character before the "x" is a back-quote - on my keyboard on the top-left corner, under the tilde (~) symbol. Marks can be in a different file to the current one.

Recording commands

Finally, let's do an example of recording commands for repeating later.
Record a sequenceq(letter)(commands)q
Play back sequence@(letter)
See what is in registers:reg
You record a sequence into a lower-case register (a-z), eg.
qa:s/fish/chips/q
The command above (starting and ending with "q") records into register "a" the sequence ":s/fish/chips/".
Then whenever you want to repeat that command you can type "@a".

Example of recording

Whilst writing this page I wanted to convert every second sequence of:
<td> (something) </td>
to:
<td><code><font size=2> (something) </font></code></td>
Doing a "find and replace" would have been tedious, as I would have had to skip every second item found. I was able to do it quite quickly by recording a macro. To do this I typed:
qa
2/<td>
:s/<td>/<td><code><font size=2>/
:s$</td>$</font></code></td>$
$
q
The sequence above did the following:
  1. Start recording (q) under register "a"
  2. Search for the second occurence of <td> (hence the leading "2" on the line)
  3. Change "<td>" to "<td><code><font size=2>"
  4. On the same line change "</td>" to "</font></code></td>". I used a $ as the search delimiter because the character "/" was in the text to be searched for.
  5. Go to the end of the current line ($) so the next search would begin at the next <td>
  6. Stop recording (q)
Then I moved to the start of the file (1G), turned search wrapping off (:set nowrapscan) and typed "999@a". This executed macro "a" 999 times. In fact, it stopped before 999 times because the search failed after it got to the end of file.

Setting up your personal favourite settings

If you have some personal favourite settings like:
  • Spaces for tabs
  • Whether searches are highlighted or not
  • Syntax colouring on or off
  • Mapping function keys to special functions
you can have them processed automatically by putting them into a file named ".vimrc" in your home directory (see ":help vimrc" inside vim for more details).
For example, your .vimrc file might have in it:

set ts=4   " tab stops every 4 characters
set expandtab  " tabs to spaces

map <f6> :cnext<cr>   " next error after a make or grep
map <f7> :cprevious<cr> " previous error
map <f12> :close<cr>    " close current window (eg. help)

syntax on  " syntax colouring on

hi clear search  " do not highlight searched-for words

No comments:

Post a Comment