How to use the vi editor in linux

Donald Daniel, Feb 2008, revised Jul 2008

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.

To edit an existing file, or create a new file, type "vi filename". 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!".

If you have written your file to disk and got out of vi you will want to see that the file is there. To see what files are in the directory where you are type the linux command "ls". To change to another directory "xxx" that already exists use the command "cd xxx". To change to the parent directory of the directory you are in type "cd ..".

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.

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 copy an external file to the current location type ":r filename". To join the line below to the end of the current line, type "J".

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.

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'".

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

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 mulitple files into one pfile with continuous page numbering. It can force a new page at the start of a new file if you wish.

MODULE print;
(*copyright 1980 donald daniel
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 [ret]'); 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 [ret]'); 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 print.

Since the command "print" is already used by the system, in my ".bashrc" file I add the line "alias print=printx". Then as superuser I move the executable for the above print program to /usr/local/bin/printx and then I as user can type "print" and execute the above program.

up one level