Section 2.2. Eye to Eye with vi


2.2. Eye to Eye with vi

Java programs consist of Java classes. Java classes are text files with Java statements and expressions. In order to write a Java program, then, you need to be able to enter text into a file. Sounds simple enough.

With Linux and its GNU tools, you have an amazing array of choices for how to do this. Some are GUI tools not unlike simple word processors. Others, like vi and Emacs, predate GUI tools, but provide much the same capability without the luxury (or annoyance) of a mouse or menus. [1]

[1] We realize that vi is famous for being difficult to learn and nonintuitive. The UI design of vi dates back to earliest cursor-addressable display terminals. User interface design has come a long way since then. The vi UI does indeed show its age. But the program refuses to die. Why? Because while simple GUI editors make the easy stuff easy, vi makes the hard stuff easy. You can fall back on pico or kate or other GUI editors if you want, but bear with us. Mastering vi really does pay off.

The editor named vi (pronounced as you would spell it: "vee-eye") is one of the most enduring tools in Linux. Its popularity comes from a combination of power and ubiquityyou can find it on virtually every release of UNIX and Linux since 1985. But it is a powerful editor that can do a lot with only a few keystrokes.

There are actually several variants of vi from which to choose. Each is someone's attempt to go one better on vi, but all retain the same basic syntax and what you learn here will work equally well on any of the vi clones. You can choose among

  • elvis

  • nvi

  • vim

Start up vi by typing the command name at a shell prompt, followed by the name of the file(s) that you want to edit:

 $ vi Account.java 

Keep in mind that vi was developed in the days of character-only video screens. Keyboards didn't always have arrow keys or other special characters, which have since been (largely) standardized by the advent of the IBM PC. In that situation, the authors of vi had only the alphabetic characters to use for all of their commands . . . and did they make good use of those keys! Virtually every letter is used, both lower and upper case, to mean something unique in vi. But don't be put off by the large number of commands to learn; they fit some patterns that will make it easy for you to become proficient in a short time by learning a few commands and applying the patterns.

Note

If you really can't bear to part with your mouse and menus, try gvim. We haven't used it, but we hear that it has support for mice to help with cut and paste and the like. After you learn vi and get a little practice, though, you may find that you're never reaching for your mouse any more when you edit.


There are three modes to vi: the regular vi mode, some extended commands in the ex mode, and the input mode.

The simplest mode is the input mode. In input mode, every character you type becomes part of the text of the file. It's how you enter the bulk of the text for your Java programs. But vi doesn't start up in input mode; you have to "get into" input mode, and then get back out. Once out, you can use other vi commands to save the text and exit vi. More about those in a bit.

Note

Get out of input mode by pressing the Escape key. You can press it more than once, too, just to be sure that you are no longer in input mode. If you are no longer in input mode and you press escape, it will beep at youwith an audible or visual notification, depending on how your terminal window is set to respond.


In both vim and elvis (two popular vi clones) there is a status line at the bottom of the window that will show if you are in input mode. In vim, look in the lower left and elvis, the lower right. When in input mode, you will see a status word displayed like insert or replace.

In the vi mode, the default mode that you start in, all the keystrokes are interpreted as commands to the editor. They are not displayed as characters. So when we describe a command, such as dt;, you can type those three characters but will not see those characters on your screen. Instead you will see some action taken by viin this case it will delete text from your cursor up to the first semicolon on that line, if any (otherwise it will just beep).

There are several ways to get into input mode, depending on where you want to do the insert. When the file you're editing is completely empty, all these commands are equivalent, but for nonempty files, each command will begin input mode in a different place in the file:

  • i inserts before the cursor.

  • I inserts at the beginning of the line.

  • a appends after the cursor.

  • A appends at the end of the line.

  • o "opens" a line for input after the line on which the cursor sits.

  • O "opens" a line for input before the line on which the cursor sits.

Remember that this is character-based editing, before the days of mice and I-bars. So there is no meta-character for the cursor to show its position between two characters in the file. Instead, the cursor sits on top of a character, and thus inserts or appends will happen before or after that character.

Reminder: Get out of input mode by pressing the Escape key.

Next, let's move the cursor around. The simplest way to do that is one character at a time. Using the (lowercase) h, j, k, and l keysnotice that they're all in a row on QWERTY keyboardsyou have the "arrow" keys for left, down, up, and right. One of the common enhancements for vi clones is to include support for the arrow keys on standard PC keyboards. Even so, the convenience of having the motion keys on the "home row" for touch typists can be a great speedup.

  • h moves left one character.

  • j moves down one line.

  • k moves up one line.

  • l moves right one character; same as a space.

Often, character- or line-at-a-time is too slow. Move to the beginning of the line that you are on with 0 (zero), or to the end of the line with $. Move to the top and bottom of the window with H (think "High") and L (think "Low"). So first type L then hold down j. To move back in a file, first type H then hold down k. That gets the display moving down or up respectively.

  • H ("high") moves to the top line of the window.

  • M ("middle") moves to the middle line of the window.

  • L ("low") moves to the bottom line of the window.

  • 0 moves to the beginning of the line.

  • $ moves to the end of the line.

This may still be too slow for you, especially if you are working your way through a large file. If you want to page up and down half a page at a time, try ^U and ^D (think "up" and "down"). To move a full page at each keystroke, try ^F and ^B (think "forward" and "back").

This may still take a while, especially if you want to get to the absolute beginning or end of the file. For those locations, type a three-character sequence, starting with a colonwhich will jump your cursor to the status line of the windowthen type either zero or the dollar sign, then press the Enter key. For example, :$.

So what's with the colon? Just when you thought you were getting the hang of the vi keystrokes, this odd pattern appears. It's called ex mode, and has to do with the history of vi being built atop the ex editor. Typing the colon got you back giving commands to ex, without the fancier screen-based GUI. (Even editors can have command lines.) There are many powerful search/replace commands that you can do from the ex command line; more on that later. For now, though, remember that you can type the colon, then a line number, then the Enter key and vi will position the cursor (and thus what is displayed on the screen) to that line number. The 0 and $ are just special cases of that more generic way to position your place in the file.

Back to our positioning in the file. Recall that h, j, k, and l will move you one unit (char or line) at a time. Now enhance that motion by typing a number first, then the h, j, k, or l. So to move five lines up type 5k (just be sure you use a lowercase letter). You can move way down in a file by typing something like 2000j which will move down 2,000 lines. If the file doesn't have that many lines, you will find your cursor at the end of the file.

The point here is that almost any vi command can be preceded by a count, to repeat it that many times.

A few more navigation tips. Another useful way to move through text is a word at a time. You can move your cursor forward by a word with the letter w (for "word"). You can move "back" with the letter b. You can move five words at a time with 5w or 5b. See?

The definition of "word" to vi has to do with alphanumerics separated by whitespace, but also by certain punctuation characters. So to vi, the following Java code consists of how many words? Seven.

 myArraylist.doSomething(magical); // cool 

From the beginning of the line, you'd need to type w seven times (or know to type 7wbut how could you guess seven?) To help out, vi uses the uppercase W to skip words defined not by punctuation but solely by white space. Think of it as "bigger" words. And of course B will go "back" by these bigger words. So on our example line, a single W will get you to the start of the comment.

Be sure that you're not just reading these descriptions. Run vi on any file that you can find and practice navigating by lines or words or screens. Once you get the hang of it, it can be so much faster than reaching for the mouse and trying to maneuver the cursor into just the right spot between letters.

Sometimes you can see where you want to go based on the characters of text in the document. See that "x"? That's a relatively rare character on any line of text. If you see a character, your cursor can "find" it if you type f and then the character you are looking for. So fx would search forward on the line for an "x". And Fx would search backward from the cursor. To repeat the search, just type a semicolon (";").

Searching for a string is another good way to move your way through a file. To search forward, type a slash (/), then the characters for which you want to search, and end the string with a second slash and then Enter: [2]

[2] The second slash is optional in most vi implementations, but used for consistency with the same command in ex mode which has optional suffix characters.

 /myArrayList/ 

To search backwards (towards the first line of the file) use the question mark rather than the slash to bracket your search string. In either case, to jump to the next occurrence, type n, or 27n to jump to the 27th occurrence. Whether you are searching forward (/) or backward (?), using uppercase N will reverse the direction as it searches for the next occurrence. So, you can search forward with /myVar/ and then press n for each next occurrence forward. If you go too far, just type N to back up. Similarly, if you were going backwards looking for an occurrence of a constructor, say something like: ?new HotClass?; then each n will search toward the top of the file, and each N will search toward the end of file.

In both cases, when you hit the top or bottom of the file, vi will wrap and keep searching from the opposite end, though a warning message will appear in the status bar.

OK, enough navigation. Let's start modifying text.

Copy and paste operations can be done easily on whole lines. Just yank and put the lines. You can yank a single line or several at a time (e.g., 7y) and then a single put (p) will deposit a copy just after the current line (the line where your cursor sits). If you want to put the text before, not after, the current line, use uppercase P.

Go ahead. Try it on the file you're practicing on. It's the best way to get a feel for what we're describing here.

Cut and paste operations involve deleting the lines, not just copying them. This gets us into our third and final kind of syntax in vi, the double letter commands. Use dd to delete a line. Try it and you will find that the line your cursor is on just got deleted, and the cursor now rests comfortably on the next line. To paste that line back, use the same p or P that we used for to put the lines that we had copied (a.k.a. "yanked") above.

But why the dd? What's with the double letters? Think of "delete" for d and then add another letter to describe how much you want to deletedw for "delete word" or dW for "delete the bigger words" (see above). So why dd for a line? We don't know for a fact, but we suspect that it's just for speed. You can also follow a d with the h, j, k, or l of our cursor movement, and that will delete either a character or a line in the appropriate direction.

A faster way (one keystroke, not two) to delete a single character is with the x key. And of course 5x, or 27x, will delete multiple characters. But if you're deleting many characters you will probably get it done faster by deleting "words" (dw or dW).

Another powerful way to delete text is to delete it from the cursor up to a specific character. The sequence dt; will delete from the cursor up to (but not including) the semicolon on the current line. If there is no semicolon, vi will beep, and no change will be made. To delete from the cursor up to and including the semicolon, use df;.

Everything you've just learned about delete is also true for change, the c in vi. You can combine it with itself (cc) to change a whole line. You can combine it with w to change a word (cw), or you can change from the cursor up to the next semicolon (ct;), and so on.

Change does the delete, then puts you in input mode. (Notice the reminder on the status line.) Remember, to get out of input mode and back into vi mode, press the Escape key.

Sometimes you've done too much, and you'd like to undo what you've just done. Typing u will undo the last change that you made. But here's a difference between the classic vi and some of the new, improved versions. In classic vi, if you type another u, then you are telling vi to undo what it just didwhich was an undo. So the undo of an undo remakes the change that you had originally made. But in vim, "vi improved," typing u again and again will just keep undoing previous changes. If you want to undo the undo, in vim, you need to type :redo and then Enter.

The vi editor has shortcuts for helping you to change the indentation of your code. Typing two less-than signs (<<) will shift the line to the left; typing two greater-than signs (>>) will shift the line to the right. Typing a number first and then the less-than or greater-than signs will shift that many lines at once. But how far will they shift? The default is usually set at eight, but you can set it to any value you want. In ex mode you can set all sorts of values and flags, customizing vi's operation. The value we're interested in here is shiftwidth which can be abbreviated sw. So the command would be :set sw=4 if you want each shift to move by four characters. For more about this, and how to make it your default, see Section 2.2.4.

Any command that you do may be worth repeating. Say, you just shifted 14 lines and you'd like to shift them further. Or you just deleted five lines, and would like to delete five more. Well, you could just retype the command, but an easier way is just to type the period (.) and let vi repeat it for you.

2.2.1. Exiting

There are three ways of exiting vi (ZZ, :q, :q!) that you should know. The correct one to use depends on whether or not you want to save the changes to the file and on whether or not you have saved your changes.

  • ZZ saves and quits in one step (three keystrokes).

  • :w writes what you've been editing but doesn't quit.

  • :w filename writes what you've been editing to a new file named filename; it will complain (and not write out anything) if the file already exists.

  • :7,.w! filename writes lines from line 7 up to and including the current line to the named file, clobbering any previous contents (think of the "!" as meaning "and don't argue with me!").

  • :q quits, provided you've saved your changes (e.g., with :w).

  • :q! quits without saving any changes to the file.

  • :n doesn't exit vi, but moves on to the next file if you started up with more than one file to edit (e.g., vi Fir.java Pine.java). When you've reached the last file in the list, you need to quitfor example, with :q.

2.2.2. Search and Replace

We've mentioned searching for a string with / or ?, but what about replacing? Once you've located a string with /, you can use cw or C or R or other such commands to effect the change. Search for the next occurrence with n, and then you can repeat your change (the last c, s, r, and so on) by typing the period "." that will repeat that last substitution, insert, and so on.

But what if you want to make 225 substitutions? Typing n.n.n.n.n.n. would get old after a while. Here, the ex mode, like any good command line, comes to the rescue to help with repetitive tasks.

If we want to search and replace all occurrences of one string for another, we can use the command

 :1,$s/one string/another/ 

Almost all ex commands take an address range, that is, the lines of the file over which they will operate. If just one line number is given, the command will operate on that one line. Two numbers, separated by commas, represent the start and end linesinclusiveof the operation. The first line is line 1, so a 0 as line number would mean "before the first line." The line where the cursor is currently located is just "." (a period). The last line of the file can be represented by the dollar sign ($). You can even do some simple math on the addressesfor example, .+2 meaning the second line in front of the cursor's current line.

Tip

There is a shortcut for the 1,$ address range. Use % to mean "all lines"for example, %s/one string/another/.


Here are a few more substitution examples along with an explanation for each.

 .,$s/here/eternity/ 

From here to the end of the file, replace here with eternity.

 27,$-5s/lost/found/ 

From line 27 to the 5th line prior to the end of the file, replace lost with found.

 s/here/now/ 

Replace here with now, on the current line only.

Each line that has a match will do the substitution on only the first occurrence of the string. If you want to change all occurrences on those lines, you append a g (for "global" substitution) to the end of the command. Consider this snippet of Java:

 class tryout {   int tryout;   tryout(int startval) { // make a new tryout     tryout = startval;   } // tryout constructor   // a tryout-like resetting   public void   setTryout(int toval) {     tryout = toval;   }   // willfindtryoutinhere } // class tryout 1,$s/tryout/sample/ 

Works as expected except for line 5, where "tryout" appears as the constructor name but also in the comment.

 1,$s/tryout/sample/g 

Works better (note the trailing g). But neither command can deal with "Tryout" in the setTryout method name. That's because of the uppercase "T", which doesn't match "tryout".

 1,$s/Tryout/Sample/g 

Will make the substitution in that method name.

Tip

Remember to precede these commands with a colon (":") to put you into ex mode which puts your cursor on the status bar of the window.


2.2.3. The Joy of Regular Expressions

The substitution command really becomes powerful when you start using regular expressions. Our examples so far have only had plain alphanumeric characters between the slashes of the substitution. But other characters take on special meanings inside the search and replace strings. Table 2.1 shows just a few.

Table 2.1. Regular expression character meanings

Character

Meaning

^

The beginning of the line.

$

The end of the line.

.

Any single character.

*

Zero or more repetitions of the previous expression.

+

One or more repetitions of the previous expression.

[]

Any of the characters inside the brackets will matche.g., [abc] matches any of a, b, c. Ranges are allowed tooe.g., [a-z].

&

When used on the right-hand side, stands for whatever was found with the search string on the left-hand side (for an example, see Table 2.2).


From this small collection we can do some useful things. We show just a few in Table 2.2. All commands begin with :1,$ to say that the substitution will be attempted from the first through the last line of the file. [3] You could use a smaller range for any of these substitutions, as we discussed above.

[3] Note that % is valid substitute for 1,$.

Table 2.2. Some useful vi substitutions

Command

Explanation

:1,$s/ *$//

Removes all (any number of) trailing blanksthat is, looks for zero or more blanks followed immediately by the end of line, and replaces them with nothing (no characters between the last two slashes).

:1,$s/^.*$/""/

Puts quotes around the text of each and every line.

:1,$s/^"//

Removes the leading quote from any line that starts with one.

:1,$s/"$//

Removes the trailing quote from any line that ends with one.


There is so much more that could be said about regular expressions. They are one of the most powerful features for making big changes with few keystrokes. It's an integral part of sed, Perl, and other tools. It's in such demand that it has been added to Java for better pattern matching. See Section 2.6 for ways to learn more about regular expressions.

2.2.4. Starting Off Right: .exrc

You can preset certain behaviors in vi by putting ex commands in a file called .exrc in your home directory. Those commands will be read whenever you invoke vi and before you begin typing commands.

Here's a simple but useful .exrc example:

 " set my favorite options: set autoindent shiftwidth=4 set ignorecase 

As you can see from the example, settings can be combined on one line. Note also that these lines do not begin with a colon. A colon is needed if you type these lines from within vibecause you need to get into ex mode; but since these are assumed to be ex commands (hence the name .exrc) they are going straight to the ex side of vi and no colon is needed. Comment lines begin with a double quote; the rest of the line is ignored, and doesn't need a matching quote.

The ignorecase command tells vi to ignore any difference between upper- and lowercase characters when searching for text with the / or ? commands. The single character searches on the current line (f and F) are not affected by this setting. The default for vi is noignorecase, which means case is significant.

The autoindent setting (can be abbreviated ai) means that when you do an o or O to open a line after or before (o versus O) the line on which your cursor rests, vi will automatically add whitespace so that the text that you enter begins at the same column where the current line begins.

For example, suppose you are editing an if statement like this:

 if (userBalance < minDaily) {     userAccount.chargeFees(); } 

With your cursor on the middle line, if you type an o or O, the new (blank) line will open with your cursor at the fifth character position, right in line with the "u" of userAccount. If you find that your cursor is flush left when you try this, then you need to set autoindent. You can do this from within vi by typing :set ai or the longer :set autoindent. The leading ":" is importantit gets you to ex mode. (Don't forget to press Enter at the end of the command.)

The shiftwidth setting tells vi how many character positions to move text left or right with each << (left) or >> (right) command, as well as when typing ^D and ^T in input mode. When typing text in input mode, people often use the Tab key to indent their text, for example inside an if or for statement. You can do this in vi, and the actual tab character will be the character in your text. But if you want tighter indenting, use the ^T (that's Control-T, "T" for Tab, we suppose) to increase your indent and ^D to decrease your indent while in input mode. The vi editor will automatically compute how much whitespace to use and will put an optimal combination of tabs and spaces as needed to line things up. Alternately, you can have vi always expand tabs into spaces and not mix tabs and spaces, but just use spaces, with set expandtab. (Remember to add a ":" if you want to type this from the command line.)



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net