This document was originally written in May, 1998, and has been updated periodically to reflect the proposed implementation of and use of major modes in vile.
My goal was to extend the notion of the C mode (cmode) to allow runtime definable major modes.
Originally, vile supported a C mode that included a collection of modes useful for editing C program source:
as well as this builtin functionality:
Both the modes and functionality are extensions of other features in vile. It would be useful to combine modes to support other languages in a similar fashion. Likewise, the autoindention, etc., could be parameterized and made reusable to support other languages. For an initial implementation, I focused on the combining of modes, providing a structure for the parameterization.
One thing that was not clear to many users was the manner in which the C mode was attached to a buffer. It was set as a boolean - if active before a buffer was loaded, then vile checked the file suffix to see if it matched the c-suffixes mode, and if so, set the C mode for the buffer. C mode could also be explicitly set by a ":setl cmode", and unset by ":setl nocmode". In the new scheme,
The search is in normally alphabetic order, by majormode name. The first match each, of suffixes and preamble terminate the search, but a match of suffixes overrides a match of preamble. Use "after" and "before" qualifiers to handle special cases.
In rare circumstances, both suffixes and preamble are needed to distinguish a given mode from another. Use
qualifiers=all
The suffixes and preamble rules can be overridden altogether by specifying $majormode-hook to a script which sets the majormode for the current buffer.
These are the commands which I originally thought necessary:
The {majormode} is a new symbol.
The {minormode} can be any one of the existing buffer modes, except for a {majormode}. To make name-completion simple, we use the term 'submode'.
Later, I added features to make majormodes simpler to configure:
define-majormode c
; Declares a mode 'c', and corresponding symbol 'cmode'
define-submode c suffixes="\\.\\(\\([Cchisyl]\\)\\|CC\\|cc|cpp\\|cxx\\|hxx\\|scm\\)$"
; Specifies the filename suffixes which control whether a newly-loaded
; buffer is set to 'c' mode.
define-submode c tabstop=4
define-submode c shiftwidth=4
; Defines the 'c' tabstop and shiftwidth. If no "define-submode"
; command is given, no separate symbol is defined.
define-majormode perl
define-submode perl preamble "^#.*perl\\>"
define-submode perl suffixes '\.\(pm\|t\)$'
define-submode perl shiftwidth 4
define-majormode perl
~with define-submode perl
preamble "^#.*perl\\>"
suffixes '\.\(pm\|t\)$'
shiftwidth 4
~endwith
For example, in the definition of cshmode, the symbols "fence-XXX" give patterns which vile can use to move the cursor from one if/elif/else/fi marker to the next as you press "%". The other settings such as "suf" in the first block are settings that apply to the majormode itself:
define-mode csh
~with define-submode csh
suf '\.\(csh[^/]*\|login\|logout\)$'
pre '^#!\s*\/.*csh\>\(\s*-[a-z]\+\)*\s*$'
filtername 'vile-sh-filt -k csh'
comment-prefix '^\s*#'
comments '^\s*#\s*$'
fence-if '^\s*\<if\>.*\<then\>'
fence-elif '^\s*\<else\s*if\>'
fence-else '^\s*\<else\>'
fence-fi '^\s*\<endif\>'
~elsewith define-submode csh group 'case'
fence-if '^\s*\<switch\>\s*(.*)'
fence-elif '^\s*\<case\>.*:'
fence-else '^\s*\<default\>\s*:'
fence-fi '^\s*\<endsw\>'
~elsewith define-submode csh group 'loop'
fence-if '^\s*\<foreach\s\+.*\|while\>\s*(.*)'
fence-fi '^\s*\<end\>'
~endwith
This takes a single argument, a majormode name. To follow existing convention, the string "mode" is automatically appended to the given name. Associated modes are defined or modified with the define-submode command. Vile maintains a list of majormodes. Only one majormode can be associated with a buffer (none need be associated). After definition, a majormode can be set or unset just like any other buffer mode:
define-majormode c
; defines "cmode"
setl cmode
; sets the mode for the current buffer
setl nocmode
; clear c mode (existing implementation)
unsetl cmode
; clear c mode
value -> self (local) value -> global (global) value -> major (majormode)
When a majormode is defined, an array of the existing minor mode values is allocated, all pointing to the global modes. The define-submode command modifies these to make them local pointers. When a buffer is associated with a majormode, all of its buffer mode values are pointed to the majormode's values. (To keep the bookkeeping straight, modifying a global buffer mode must also modify the copies of non-local buffer mode values).
This is used to clone an existing majormode, using a new name. The command takes two parameters:
If the new majormode already exists, it is not removed. Instead, settings are copied from the old majormode into the existing majormode. In principle, a series of these commands could be used to merge several different majormodes.
This command sets local values of buffer modes for the given majormode, e.g.,
define-submode c autoindent
define-submode c autoindent tabstop=4
The term "submode" is used in the command rather than the more natural "minor mode" to simplify name-completion.
The following are keywords that aren't minor modes, but are recognized solely by the define-submode command:
{filter} {options}
where {filter} is the filename for the filter, e.g.,
vile-c-filt
and options include:
Other options may be implemented that are specific to a filter program. For instance, vile-c-filt recognizes a -p option to mark preprocessor lines with an error (used for Java).
Currently used only for complex fences, this could be applied to simple fences, and (with new flags not yet defined) extend both styles of fences for indentation and formatting.
if, elif, else, fi
Vile searches through all groups of complex fences for a match before trying simple fences.
Other features which should be controlled by majormodes include limiting the scope of the entab and detab commands.
This command has two forms:
or
Remove the special association of a submode from a majormode.
The original builtin C/C++ majormode description is equivalent to
define-mode c
~with define-submode c
suffix "\\.\\(\\([Cchisyl]\\)\\|CC\\|cc|cpp\\|cxx\\|hxx\\|scm\\)$"
comment-prefix="^\\s*\\(\\s*[#*>]\\)\\+"
comments="^\\s*/\\?\\(\\s*[#*>]\\)\\+/\\?\\s*$"
fence-begin="/\\*"
fence-end="\\*/"
fence-if="^\\s*#\\s*if"
fence-elif="^\\s*#\\s*elif\\>"
fence-else="^\\s*#\\s*else\\>"
fence-fi="^\\s*#\\s*endif\\>"
cindent
~endwith
set cts=8
set c-tabstop=8
define-submode c tabstop=8