How to use the vi editor in linux

Donald Daniel, Feb 2008, revised June 2010

up one level

Open a terminal window in your linux system and click on it to make sure it is active. You will do all your work in the terminal window. If you are not already familiar with linux command line operations in a terminal window you should first read the article how to use linux.

To edit an existing file named "xyz", or create a new file named "xyz", type "vi xyz". When in vi, there are two major modes, the input mode and the edit mode. In the input mode, anything you type goes into the file. In the edit mode you can move around the file, copy, delete etc. Hit the "Esc" key to get from the input mode to the edit mode. When in the edit mode the mouse is not used to move the cursor, keyboard commands are used. The arrow keys move the cursor up, down, right, left. The spacebar moves the cursor to the right. "$" moves the cursor to the end of the present line. The "enter" key moves the cursor to the beginning of the next line. "237" then the "enter" key will move ahead 237 lines in the file. Type "1G" to jump to the top of the file, "G" to move to the end of the file.

When the cursor is moved to a particular letter in a word in the file, press "a" to enter the insert mode after that letter, press "i" to enter the insert mode just before that letter. Type what you want in the insert mode then hit the "Esc" key to leave the insert mode and get back to the edit mode.

To write the file to disk and exit vi, type ":wq". To exit without saving the changes you have made, type ":q!".

DELETE. In the edit mode "d" followed by the spacebar will delete one letter. "5 d" followed by the spacebar will delete 5 letters. "dw" will delete to the end of the word. "dd" will delete the line. "5 dd" will delete the next 5 lines. "u" will "undelete" the last deletion if you make a mistake. "d /xxx" will delete from the present position to where the letters "xxx" are found. Suppose you have a file with many lines that have leading spaces in front of each line, and you would like to delete these leading spaces. The command ":%s/^ //g" will do this, where the number of spaces after the "^" character is the number that you want to delete. The "^" character represents the beginning of a line. To delete all complete lines containing "xyz", use ":g/xyz/d". An example of how to delete carriage returns is given below in the section about line numbers.

MOVING TEXT. Delete what you want to copy. If you want to leave it there before you move elsewhere to copy it, type "u". Then move where you want to copy it. "p" will write out the last deletion on the line below where ever you are when you type "p", as many times as you type "p". To join the line below to the end of the current line, type "J". Suppose you want to copy an external file named "file" to the line below where your cursor is. If the file is in the same directory, type ":r file". If I were in my directory "wkspc/scratch", and wanted to copy a file from my home directory, I would type ":r ~/file", but if I wanted a file from my directory "wkspc/back" I would type ":r ~/wkspc/back/file" or ":r ../back/file", either one would work.

FIND AND REPLACE. "/xxx" will find the next occurrence of "xxx". "n" will find the next one after that. "?xxx" will search backwards. The next example is "/\<cat\>". This will find "cat" without finding "catalog". This is very handy for finding variables in a program you are writing. Another important example is ":%s/\<cat\>/dog/g". This will replace all occurrences of "cat" with "dog" without replacing "catalog" with "dogalog". This is very handy for changing variable names in a program. This command takes into account the conventions of computer programming. Thus "x:=cat+5;" would be changed, but "x:=cat2+5;" would not. Note that spaces are not necessary on either side of "cat". This is probably the most essential feature for any editor that is to be used for writing computer programs. To search for the string "get / http" type "/get \/ http". This is because the the "\" means treat the next character as a character, not a command or a wildcard.

COMMANDS THAT USE LINE NUMBERS. ":nu" tells the number of the line that the cursor is on. ":13,26 w! temp" writes a copy of lines 13 to 26 to an external file named "temp" without deleting the lines. ":125,248 !fmt -uw 65" does word wrap to make all the lines from 125 to 248 equal to or less than 65 characters in length. To remove carriage returns such as windows files have from lines 22 to 44 type ":22,44 !tr -d '\r'". To make all letters from line 125 to line 248 lower case, use ":125,248 !tr A-Z a-z". Using the "!" symbol in this particular way when you are in the vi editor executes a program that is external to the vi editor. To see what else could be done with the "tr" program, when you are NOT in the vi editor enter "man tr".

There are many, many more commands in vi, but these are probably the most important.

The vi editor is adequate for writing computer programs and simple text applications. If you want to create a document that requires advanced features such as characters that are not on the keyboard like greek letters or math symbols, or embedded graphics in your document, the vi editor can be used to create the source file for a fancy word processing system on linux known as latex, which is found in the "texlive-latex-base" package that can be installed on linux. The instructions are in the "texlive-latex-base-doc" package. This technique is described here. An example of this at this website is given by the pdf document here. The vi editor can also be used to write html web pages. This entire website was written with vi, and the html checked for errors with the linux program "tidy".

After you have finished file "xyz" and got out of the vi editor, you could print it with "lpr xyz". However, this might not be very satisfactory, because the printout would have no left margin, no top and bottom margins, and no page numbers. A slightly better result is obtained with the command "pr -fl 56 -o 8 xyz | lpr". To print out programs with margins and page numbers, I use my print program, given here as Oberon-2 source code. The program does not discard the end of lines that exceed the right margin, it truncates them and wraps the extra part of the line to a new line. The combination of the vi editor and the print program makes a simple text only wordprocessor. This print program does not send the text directly to the printer. It creates a new formatted file called "pfile", which you must then send to the printer with a command such as "lpr pfile". The program can combine multiple files into one pfile with continuous page numbering. It can force a new page at the start of a new file if you wish. From beginning to end, the commands to use this program to print file xyz are: prt, fn xyz, go, q, lpr pfile.

MODULE prt;
(*copyright 1980 donald daniel. Originally in pascal,
converted to Oberon in 2008.  This program is free software:
you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General
Public License along with this program.  If not, see
http://www.gnu.org/licenses/.  *)
IMPORT In,Out,Msg,Files,TextRider;
CONST strlngth=10;strlngth2=50;bell=7;formfeed=12;lf=10;cr=13;
fn=1;tm=2;lm=3;sp=4;sl=5;pl=6;ll=7;go=8;ff=9;pn=10;
npn=11;menu=12;init=13;q=15;er=20;
TYPE 
str=ARRAY strlngth OF CHAR; str2=ARRAY strlngth2 OF CHAR;
cma=ARRAY 22 OF str;
VAR resv:Msg.Msg;invar,outvar:Files.File;
infile:TextRider.Reader; outfile:TextRider.Writer;
cmdara:cma; command:LONGINT; filename: str2;
strng:str; pagenum,line,pagelength,linelength,
topmarg,leftmarg,centerpage,chnum:LONGINT;
ch:CHAR; numpg,topofpage,leftofpage:BOOLEAN;

PROCEDURE readword(VAR s:str);
VAR ch:CHAR; i:LONGINT;
BEGIN
In.Char(ch);WHILE ch=' ' DO In.Char(ch);END;
i:=0;REPEAT s[i]:=ch;INC(i);In.Char(ch);
UNTIL ((ch=' ')OR(ch=0AX)); s[i]:=00X;
END readword;

PROCEDURE readln(VAR s:str2);
VAR ch:CHAR; i:LONGINT;
BEGIN
In.Char(ch);WHILE ch=' ' DO In.Char(ch);END;
i:=0;REPEAT s[i]:=ch;INC(i);In.Char(ch);
UNTIL ch=0AX; END readln;

PROCEDURE leftmg;
VAR i:LONGINT;
BEGIN FOR i:=1 TO leftmarg DO outfile.WriteChar(" ");END;
leftofpage:=FALSE END leftmg;

PROCEDURE topmg;
VAR i:LONGINT;
BEGIN
FOR i:=1 TO topmarg DO outfile.WriteLn;END;
chnum:=1;topofpage:=FALSE;leftofpage:=TRUE END topmg;

PROCEDURE newpage;
BEGIN
centerpage:=linelength DIV 2 + leftmarg;
IF topofpage THEN topmg;END;
WHILE line<=(pagelength-2)DO
outfile.WriteLn;line:=line+1 END; outfile.WriteLn;
IF numpg=TRUE THEN outfile.WriteLInt(pagenum,centerpage);END;
outfile.WriteLn; outfile.WriteChar(CHR(formfeed));
line:=1;chnum:=1;pagenum:=pagenum+1;topofpage:=TRUE;
leftofpage:=TRUE; END newpage;

PROCEDURE outchar;
BEGIN 
IF ORD(ch)=lf THEN outfile.WriteChar(CHR(cr));END;
outfile.WriteChar(ch);chnum:=chnum+1;END outchar;

PROCEDURE inputline;
BEGIN
WHILE (~ infile.Eol()) DO 
IF topofpage THEN topmg;END;
IF leftofpage THEN leftmg;END;
infile.ReadChar(ch);
IF ORD(ch)=formfeed THEN newpage ELSE outchar; END;
IF ((chnum>linelength)&(~ infile.Eol())) THEN line:=line+1;
IF(line>(pagelength-2))THEN newpage ELSE outfile.WriteLn;
leftofpage:=TRUE;chnum:=1;END;END; END(*while*);
infile.ReadLn;outfile.WriteLn; 
leftofpage:=TRUE;line:=line+1;chnum:=1;
END inputline;

PROCEDURE printfile;
BEGIN
chnum:=1;
invar:=Files.Old(filename,{Files.read},resv);
infile:=TextRider.ConnectReader(invar);
WHILE ~(infile.res#Files.done) DO inputline;
IF line>(pagelength-2)THEN newpage;END; END(*while*);
invar.Close; Out.String('end of file');Out.Ln;
END printfile;

PROCEDURE determine(VAR cmdvar:LONGINT);
VAR cmi:LONGINT;strvar:str;
BEGIN
cmdvar:=er; readword(strvar);
FOR cmi:=fn TO q DO 
IF (cmdara[cmi]=strvar)THEN cmdvar:=cmi;END;END;
IF cmdvar=er THEN Out.Char(CHR(bell));
Out.String('<---<< error');Out.Ln;END;END determine;

PROCEDURE initvar;
BEGIN
cmdara[fn]:='fn'; cmdara[tm]:='tm'; cmdara[lm]:='lm';
cmdara[sp]:='sp'; cmdara[sl]:='sl'; cmdara[pl]:='pl';
cmdara[ll]:='ll'; cmdara[go]:='go'; cmdara[q]:='q';
cmdara[ff]:='ff'; cmdara[pn]:='pn'; cmdara[npn]:='npn';
cmdara[menu]:='menu'; cmdara[init]:='init'; filename:='';
leftmarg:=10;topmarg:=6; pagenum:=1;line:=1;
linelength:=65;pagelength:=53; topofpage:=TRUE;numpg:=TRUE;
END initvar;

PROCEDURE menuproc;
BEGIN
Out.String('MENU');Out.Ln;
Out.String('fn filename [enter]'); Out.Ln;
Out.String('pn for page numbering or npn for no numbering=');
IF numpg THEN Out.String('pn') 
ELSE Out.String('npn');END; Out.Ln;
Out.String('the next few items may be entered'); Out.Ln;
Out.String('as item [space] value [enter]'); Out.Ln;
Out.String('sp startpage='); Out.LongInt(pagenum,2);Out.Ln;
Out.String('ll linelength='); Out.LongInt(linelength,2);
Out.String('  pl pagelength=');Out.LongInt(pagelength,2);Out.Ln;
Out.String('tm top margin=');Out.LongInt(topmarg,2);
Out.String('  lm left margin=');Out.LongInt(leftmarg,2); Out.Ln;
Out.String('the remaining items have no value');Out.Ln;
Out.String('go to process file. You can process as many');
Out.Ln;Out.String('files as you want before you type q.');
Out.Ln;
Out.String('ff to formfeed before starting next file');
Out.Ln;
Out.String('menu to see this menu');Out.Ln;
Out.String('init to reinitialize to default values'); Out.Ln;
Out.String('q to quit processing files and write result to pfile'); 
Out.Ln;
Out.String('lpr pfile to print when finished');Out.Ln;
END menuproc;

BEGIN
initvar;
outvar:=Files.New('pfile',{Files.write},resv);
outfile:=TextRider.ConnectWriter(outvar);
menuproc; determine(command);
WHILE command # q DO
CASE command OF 
fn: readln(filename);| 
sp: In.LongInt(pagenum);In.Line(strng);|
pl: In.LongInt(pagelength);In.Line(strng);|
ll: In.LongInt(linelength);In.Line(strng);| 
pn: numpg:=TRUE| npn: numpg:=FALSE| 
tm: In.LongInt(topmarg);In.Line(strng);|
lm: In.LongInt(leftmarg);In.Line(strng);| 
go: printfile| ff: newpage| menu: menuproc| 
init: initvar|
er:|END(*CASE*);
determine(command) END(*WHILE*); END prt.

up one level