This section was written by Manas K Laha , Aerospace Engineering Department, IIT Kharagpur, India. This is about a quick and dirty way to create an HTML editor combining vi and Netscape.
If vi (or one of its friends, such as elvis or vim ) is your favorite text editor, as it is mine, you must surely long for a way of creating HTML with it quickly and comfortably. And if with that you could get the convenience of "WYSIWYG", wouldn't you just jump at it? All this is indeed possible, and here we'll see how.
The major hurdles I've found in editing HTML with vi are
The need to write HTML tags. It appears that there are more tags to be written than displayable matter. Moreover, some of these tags have a syntax that is hard to remember.
The need to keep track of whether an opening tag has been given its proper closing tag at the right place (for example, whether a < ol> has a matching < /ol> ).
Difficulty in readily identifying matching pairs of tags.
These can be got around using some of the less used features of vi and friends. In this article I shall use vim for definiteness, but the ideas should apply to classic vi and its other look-alikes as well.
The "abbreviation" feature of vim:
Vim has a feature whereby it is possible to assign a keystroke sequence to represent a string of characters in input mode. This is the ab colon command. For example, the command
:ab tT <tt> </tt>
creates an abbreviation, named tT, for the sequence of characters < tt>< /tt>. Then, in input mode, as soon as the characters tT are typed, they are replaced by the string < tt>< /tt>. Complicated HTML tags may also be abbreviated. The ab definition
:ab aH <a href=?http://?><!? { ?>^M Comments here^M^D </a><!? } ?>
makes aH the shorthand for
<a href=?http://?><!? { ?> Comments here </a><!? } ?>
where the two ^M s cause the two line breaks and the ^D causes the closing < /a> tag to be indented back to be in line with the opening < a> tag. (Indenting the matter enclosed within a matching pair of tags makes reading and editing the raw HTML easier.) The syntax of the tag is outlined, as an aid to memory. The 'Comments here' line is a placeholder, to be replaced with appropriate text.
What are the { and } within HTML comments doing there? Aha! Those are for matching the opening and closing tags (in this case < a> and < /a>). The bracket matching feature of vi (using the % key) is readily usable for the purpose. This can be really helpful when the opening and closing tags are many lines apart and cannot be readily matched 'by eye', such as can be the case with the < ol>< /ol> pair.
This technique can be extended to generate fancier HTML, for example with frames. All one has to do is to define the appropriate abbreviations. For example, the definition
:ab fS <frameset scrolling=?no? frameborder=?0? framespacing=?0? cols=?20%,80%?><!? { ?>^M </frameset> <!? } ?>
makes the string fS a convenient abbreviation for the pair of tags:
<frameset scrolling=?no? frameborder=?0? framespacing=?0? cols=?20%,80%?> <!? { ?> </frameset><!? } ?>
Some tags do not like comments to come in between the opening and closing pair. The ones I have found are < title>< /title> and < a\ href=?mailto:?> < /a>. Luckily, in both these the opening and closing pair are never very far apart, so the braces-within-comments feature is not needed.
How do I tell vim about these abbreviations? I put all of them (and a command to set some of vim's variables) in a file, which I call .vimhtmlrc and which resides in my home directory, and invoke
vim -u ~/.vimhtmlrc index.html
where index.html is the HTML file I want to edit. This is what my .vimhtmlrc file looks like:
ab aH <a href=?http://?><!? { ?>^M Comments here^M^D</a> <!? } ?> ab aM <a href=?mailto:?>^M Comments here^M^D </a> ab bO <body bgcolor=#e0e0e0 text=#000000><!? { ?>^M </body> <!? } ?> ab bR <br> ab cE <center bgcolor=#e0e0e0 text=#000000><!? { ?>^M </center> <!? } ?> ab cM <!? ^M ?> ab cO <code> <!? { ?>^M </code> <!? } ?> ab dL <dl><!? { ?>^M</dl><!? } ?> ab dT <dt> ab fO <font color=#000000>^M </font> ab h1 <h1><!? { ?>^M Heading size 1^M^D </h1> <!? } ?> ab h2 <h2><!? { ?>^M Heading size 2^M^D </h2><!? } ?> ab h3 <h3><!? { ?>^M Heading size 3^M^D </h3> <!? } ?> ab hD <head> <!? { ?>^M </head> <!? } ?> ab hR <hr> ab hT <html> <!? { ?>^M </html> <!? } ?> ab iM <img src=??> ab lI <li> <!? { ?>^M </li> <!? } ?> ab oL <ol> <!? { ?>^M </ol> <!? } ?> ab pR <pre> <!? { ?>^M </pre> <!? } ?> ab tD <td> <!? { ?>^M </td> <!? } ?> ab tL <title>^M Title here^M^D </title> ab tS <table bgcolor=?#d0d0d0?> <!? { ?>^M </table> <!? } ?> ab tT <tt> </tt> ab uL <ul> <!? { ?>^M </ul> <!? } ?> ab xB <b> </b> ab xI <i> </i> ab xP <p> <!? { ?>^M </p> <!? } ?> se ai aw sw=4 ts=4 wm=10 showmode showmatch ruler magic
When the ab commands are put in a file, to be read in by vim at startup, then the leading :is not needed. The last line is a command to set some of vim 's variables. Here is what they mean:
se set: tells vim to activate the options that follow autoindent: begin the next ai line in the same column as this one (and not from column 1) aw autowrite: automatically write file to disk when it changes on a TAB key, move cursor 4 ts=4 characters (and not the normal 8); this is my personal preference sw=4 number of spaces to use for indentation chars from right margin where wm=10 line wrapping starts (useful if one is writing running text and not programs) message on status line to show showmode current mode (for the novice, actually) briefly jump to matching opening '(' or '{' or '[' as showmatch soon as a closing ')' or '}' or ']' is typed; beep if no match ruler show cursor line and column in status line some characters, such as '.' magic and '*', have special meanings in search and replace patterns.
Typing help in a vim window shows the explanations for these options and many more besides.
'WYSIWYG' has two parts to it. To begin with is the fact that Netscape under Unix (and Linux) can be controlled remotely.
That is, you may control the behavior of an already running Netscape through commands of the form
netscape -remote -noraise 'openFile(/home/mlaha/html/index.html)'
(If no Netscape is running, the command just exits with an error message.) This command causes the Netscape browser window to attempt to open the file /home/mlaha/html/index.html. For more on remote controlling Netscape, see "http://home.netscape.com/newsref/std/x-remote.html" .
And then, there is atchange . Jeffrey Copeland and Jeffrey Haemer ( "http://alumni.caltech.edu/~copeland/work/edit-web.html" , "ftp://ftp.ncifcrf.gov/pub/delila/atchange" and "http://www.lecb.ncifcrf.gov/~toms/atchange.html" ) describe a little shell script, called atchange, that waits in the background for a named file to change and then invokes a specified command. Thus,
atchange index.html 'netscape -noraise -remote 'openFile(/home/mlaha/html/index.html)'' &
would cause atchange to run in the background, watching the file index.html and, as soon as it changed, ask Netscape to display it afresh. If you were editing index.html with vi, then, when you saved it (with :w, say), atchange would spring into action and Netscape would update its display.
If you wish to edit another HTML file, you have to quit vim, kill the current invocation of atchange, then start it again with the name of the new file in place of index.html and begin editing that file with vim.
As you may have guessed, atchange can be used in other instances, too. You can make a handy 'WYSIWYG' LaTeX editor by having atchange monitor your LaTeX source and, when it changed, run the necessary programs to convert it to Postscript. The 'WYSIWYG' capability is provided in this case by invoking Ghostview with the monitoring option (-watch) that causes it to redisplay its current Postscript file whenever that file changes. Thus, every time you saved your LaTeX source file in the editor, the Postscript output with the latest changes would be automatically displayed in the Ghostscript window.
#!/usr/local/bin/perl # by Jeff Haemer # and a tip o' the hat to Tom Schneider # who wrote the original version as a shell script # version = 2.07 of atchange 1999 Dec 30 # 1999 Dec 18: Added shell call to /bin/csh so that # atchange works under Linux. # 1999 Feb 5: By setting the PERLCSH variable, the new shell can tell # it has been called by atchange. # The test inside the .cshrc is: #if ( (! $?PERLCSH ) && $?prompt) then # stty erase '^H' # set prompt = "`uname -n` \!% " #endif # This is necessary under Sun Solaris 2.6 because otherwise the # call to stty gives an error message now. # previous change: 1997 Jan 9 # delay time is 0.25 seconds # For current version and other information about this program, see: # http://www.lecb.ncifcrf.gov/~toms/atchange.html # Tom Schneider # National Cancer Institute # Laboratory of Mathematical Biology # Frederick, Maryland 21702-1201 # toms@ncifcrf.gov # http://www.lecb.ncifcrf.gov/~toms/ # 1999 Dec 30: James Haefner (jhaefner@biology.usu.edu) # has found that some changes are needed to make atchange # work under Linux. See the web site for details. # This code will be revised when a good solution is found. $0 =~ s(.*/)(); # basename $usage = "usage: $0 filename cmd | $0 command_file"; @ARGV || die $usage; # check for proper invocation # This allows the .cshrc to know that atchange has called it: $ENV{'PERLCSH'} = "TRUE"; # Haefner Suggestion 1999 Dec 18: ##if default SHELL is sh or csh or tcsh use the following line ###$shell = $ENV{"SHELL"} ? $ENV{"SHELL"} : "/bin/sh"; ##if default SHELL is bash (eg, Linux) use the following line # 1999 Dec 28 - this is not a good idea - untestable by me # $shell = "/bin/csh"; $shell = $ENV{"SHELL"} ? $ENV{"SHELL"} : "/bin/sh"; open(SHELL, "|$shell") || die "Can't pipe to $shell: $!"; select(SHELL); $| = 1; if (@ARGV > 1) { # it's a file and a command $file = shift; # peel off the filename $cmd{$file} = join(" ", @ARGV) . "\n"; # and the command $old{$file} = (stat($file))[9]; # mod time. } else { # it's a program open(PGM, shift) || die "Can't open $_: $!"; $/ = ""; # paragraph mode while(<PGM>) { # first read the program s/#.*\n/\n/g; ($file, $cmd) = /(\S*)\s+([^\000]+)/; $cmd{$file} = $cmd; unless ($file) { print $cmd{$file}; next; } if ($file && ! $cmd{$file}) { warn "odd line"; next; }; $old{$file} = (stat($file))[9]; # mod time. } } while(1) { # sleep 1; # wait a second, then select(undef, undef, undef, 0.25); # wait a quarter second, then foreach (keys %cmd) { # rip through the whole list atchange($_); } } close(SHELL); sub atchange { # if $file has changed, do $cmd{$file} my($file) = @_; my($new); $new = (stat($file))[9]; return 0 if ($old{$file} == $new); while (1) { # wait until it stops changing $old{$file} = $new; sleep 1; $new = (stat($file))[9]; if ($old{$file} == $new) { print $cmd{$file}; return 1; } } }
While editing HTML files with Vim, it is possible to automatically check syntax errors and beautify the code with program like Tidy
(Visit Raggett Tidy , Tidy Project and Beatifier HOWTO ).
Inside Vim (gvim), click on menu Tools->'Set Compiler'->'Tidy' and give command ":make". The :make command will run the tidy and show all errors if any. You can also edit the setting file tidy.vim and customize:
ls /usr/share/vim/vim61/compiler cd /usr/share/vim/vim61/compiler cp tidy.vim tidy.vim.backup man tidy # And the manual page of tidy and see options.. tidy -h | less # See help about using tidy vi tidy.vim
See also related HTML validators section (HTML Beautifier section) in Beatifier HOWTO