14. TIPS

This section of the manual explains some of the more complex, obscure, and useful features of elvis. The following subjects are discussed:
  • 14.1 How to debug macros
  • 14.2 What tags are, and how to use them
  • 14.3 Running your compiler from within elvis
  • 14.4 Internationalization
  • 14.1 How to debug macros

    There are two ways to create a macro in elvis: You can either assign a series of commands to a keystroke (or series of keystrokes) via the :map command, or you can store a series of commands in a cut buffer and execute them via the visual @x command. You will often use a combination of techniques, in which :map macro constructs a customized @x macro and runs it.

    Elvis has several features that make debugging macros much easier. For example, you can create a window which continuously displays the contents of a given cut buffer, such as "m, via the command:

    :(Elvis cut buffer m)split

    Note: The cut buffer must exist before you can display it. Cut buffers are created the first time anything is yanked into them.

    The maptrace option allows you to trace the execution of macros. You can either allow it to run through the macro, or wait for a keypress before each mapped command character. You can also use the :break and :unbreak commands to set or clear a breakpoint on a given :map macro. Breakpoints cause the maptrace option to switch from "run" to "step" when that macro is expanded.

    The maplog option can be used to log the trace information to a buffer named "Elvis map log". The idea here is that you will give the command...

    :se mt=r mlog=r ... (or its full-length form, :set maptrace=run maplog=reset) before starting the macro, and then when the macro fails you can give the command... :(Elvis map log)split ... to see what it was doing shortly before the failure. Note that the maplog option has no effect if maptrace is "off".

    Some macros implement amusing animations. Ordinarily, you must turn off the optimize option while running these macros; otherwise elvis wouldn't update the screen until the macro has been completed. However, the maptrace option causes the screen to be updated as characters are removed from the keystroke queue, and this will allow you to see the animation. So if a macro works while maptrace isn't off, but doesn't seem to do anything when maptrace is off, then you probably need to disable the optimize option.

    Warning: Elvis has a single keystroke queue which is shared by all buffers. Because of this, while elvis is running a macro in one window you can't switch to another window and type in commands. Even if the GUI allows you to switch windows without using the keyboard, doing so will simply force the macro to continue execution in the new window. So don't switch windows while a macro is running!

    Here's a debugging methodology that works for me:

    1. Begin by loading the macro package and a test file.
    2. Give the command ":se mt=r mlog=r", and run the macro.
    3. If the macro fails, give the command ":(Elvis map log)split" to find out what commands executed immediately before the failure. In particular look for a :map macro that was expanded shortly before the failure.
    4. Set a breakpoint on that macro with ":break macrokey".
    5. Turn off logging, via ":se mlog=o".
    6. Reload the test file.
    7. Execute the macro again. When the macro with the breakpoint is encounted, elvis will switch to single-step mode. Step slowly through the next few instructions, looking for one which does something unexpected.

    If your macro reveals a bug in elvis, please let me know! My email address is

    kirkenda@cs.pdx.edu
    . Please tell me which version of elvis you're using as reported by the :version command.

    14.2 What tags are, and how to use them

    Tags provide a fast way to locate specific points in a collection of files. This is done by storing a list of tag names, and their corresponding locations, in a file named "tags".

    For C source code, you will typically use a program such as ctags to automatically generate a "tags" file containing tags for each function definition. You can optionally make it generate tags for other interesting points in your source code, such as global variables and data type definitions. To have tags generated for all C source files in the current directory, give a command such as the following:

    ctags -stv *.c *.h

    Once the tags file has been created, you can have elvis start on a given tag via the command:

    elvis -t <var>tagname</var>

    The tagname is the same as the function, variable, or data type that it identifies. Note that you don't need to tell elvis which file that tag is defined in. Whenever elvis is told to go to a tag, it scans the tags file for the requested tag, determines the file name and line from the data there, loads the file, and moves the cursor to correct line of that file. Elvis does all this automatically; you just need to tell it the tagname.

    Once elvis is running, it offers several commands for looking up tags:

    If the tagstack option is set (and it is, by default) then whenever elvis looks up a tag, it saves the old cursor position on a stack. Each window has its own stack. The following commands can be used to come back after you've looked up a tag:

    Elvis can also find tags in other directories. The ELVISPATH environment variable (or tags option) gives the search path for tags files. Each element of the path can be either the name of a directory containing a file named "tags", or the name of a file to be used as a tags file. Both elvis and the ref program obey the ELVISPATH environment variable. You can create tags files in the directories containing your header files and the source code for your library functions. With ELVISPATH set to include those directories, you can then use the visual shift-K command as a quick on-line reference.

    If licensing restrictions prevent you from making the source code for your library functions available to everybody, then you can use ctags' -r flag to create a "refs" file in addition to "tags". The refs file contains a copy of the source code, but with the bodies removed from every function definition. You should be able to make refs readable by everybody. If you don't posess the source code to your libraries, then perhaps you can create a usable tags from the lint libraries.

    Note: In the "html" display mode, hypertext links are implemented as a type of tags. Instead of looking up a word in the "tags" file, elvis will search backward for an <a href=URL> tag, and use the URL to find the referenced location. All of the tag commands are the same, plus there are a couple of new ones: The Enter key looks up a hypertext reference like ^], and the Tab key searches forward for the next hypertext reference.

    14.3 Running your compiler from within elvis

    Elvis can parse most compilers' error messages. When it parses an error message, elvis loads the faulty file, moves the cursor to the line where the error was reported, and shows the descriptive portion of the error message on the bottom row of the window. You can step through all reported errors very quickly, making changes along the way.

    Usually, you will invoke your compiler or "make" utility via the :cc or :make commands. The only difference between these commands is that :cc invokes the program named by the ccprg option, and :make uses the makeprg option.

    Both of those options' values are evaluated using the simpler expression syntax, with $1 set to any extra command-line parameters, and $2 set to the current file name.

    You can also read error messages from some other program with the command ":errlist !program", or read them from a file with the command ":errlist filename".

    I often invoke elvis via the command "elvis +make" so elvis will attempt to compile the program, and move the cursor to the first error (if there are any errors).

    All of the compiler's output text is collected into a buffer named "Elvis error list". If you wish, you can view this list in a separate window via this command:

    :(Elvis error list)split

    Here's how elvis parses each line of compiler output: Starting from the left, it divides the line into "words", which are defined as a series of letters, digits, and/or certain punctuation characters.

    If the word looks like a number, and no line number has been seen yet, then the word is taken to be a line number. If the word is the name of an existing, writable file (or any existing file if the anyerror option is set), then it is taken to be a file name. Other words are ignored.

    When elvis has found both a file name and a line number, then it skips over any whitespace or punctuation immediately following them, and uses the remainder of the line as the error's description.

    If elvis fails to find a file name/line number pair, then it skips that whole line of compiler output.

    Immediately after collecting compiler output, elvis moves the cursor to the source of the first error. After that, you can use :errlist (with no arguments) or the visual * command to step through each following error.

    Each time elvis collects a new set of error messages, it remembers how many lines are in each buffer. Later, when you insert or delete lines to correct an error, elvis can compare the current number of lines to original number of lines, and adjust the reported line numbers accordingly.

    14.4 Internationalization

    Elvis can be configured to translate its messages into different languages, and to use different symbol sets. These things are accomplished via the elvis.msg file and :digraph command, respectively.

    Elvis locates the elvis.msg file during initialization. Ordinarily it searches through each directory named in the ELVISPATH environment variable. However, if there is an environment variable named LC_ALL, LC_MESSAGES, or LANG (listed in order or precedence) which is set to a non-null value, then elvis will look for elvis.msg first in a subdirectory whose name matches the environment variable's value. For example, if ELVISPATH=~/.elvis:/usr/local/lib/elvis, LC_ALL is unset, and LC_MESSAGES=german, then elvis would try to load its messages from...

    1. ~/.elvis/german/elvis.msg
    2. ~/.elvis/elvis.msg
    3. /usr/local/lib/elvis/german/elvis.msg
    4. /usr/local/lib/elvis/elvis.msg

    The digraph table affects more than just keyboard input. It also affects "html" mode, and character type classifications.

    Digraphs are used by the "html" display mode to translate character escapes into characters. For example, when elvis encounters &ntilde; in an HTML document, it tries to find a digraph which combines 'n' with '~'. If there is such a digraph, elvis will use it to display an 'ñ'; if not, then elvis will display a plain 'n' character.

    The digraph table affects the character classes, too. This affects the definition of a "word", as used by the visual w command, among others. A non-ascii character is treated as an uppercase letter if, according to the digraph table, it is the result of combining an ASCII uppercase letter with either a punctuation character or a second uppercase letter. A similar rule holds for lowercase letters.

    Also, elvis tries to find uppercase/lowercase pairs through the digraph table. This is used for case conversions, as performed by the visual ~ command, or the \U metacharacter in the :s/old/new command.

    There is no way to specify a sorting order. This means, in particular, that the regular expression /[a-z]/ will only match the ASCII lowercase letters, not the non-ASCII ones. Sorry.

    The default elvis.ini file tries to load digraphs by executing either elvis.pc8 for Microsoft operating systems, or elvis.lat for any other operating system.

    The "win32" version of elvis has a codepage option which determines which symbol set is used for console output. If you change codepage, you should also adjust your digraph table.