diff --git a/MODES b/MODES index 595aec0..a8a55d8 100644 --- a/MODES +++ b/MODES @@ -36,3 +36,73 @@ to be taken. They do this via self.bindings, a dictionary mapping action names Modes subclass mode2.Fundamental, and they call mode2.Fundamental.__init__ to run the standard mode initialization (including building the default bindings dictionary); they can later modify or overwrite this dictionary if they choose. + +There are at least 3 optional behaviors modes can make use of: + + 1. Syntax highlighting + 2. Indentation level detection + 3. Tag (parenthesis, brace, bracket, etc.) matching + +Not all modes can (or should) make use of these features: they are primarily +useful in modes having to do with programming languages, or other structured +documents. + +4. Syntax highlighting + +Syntax highlighting uses a hybrid lexing/parsing process to break each line of +the buffer down into one or more lexical tokens; these tokens are primarily +used to highlight parts of the buffer different colors. The colors to use are +defined by self.colors, a dictionary mapping token-names to a tuple consisting +of at least a foreground color and a background color. + +Explaining how to write a Grammar is outside the scope of this document; see +lex2.py and mode/*.py for examples. Some important points to note: + + * Regexes are applied to only one line of the document at a time. + * All regexes must match at least one character. + * All tokens must consist of at least one character. + * A rule that matches must generate one or more tokens. + * Any input not matched by a rule will end up in a "null" token. + * Tokens can't "look" for other tokens (but they can use 0-width assertions + to test for data on the current line). + +5. Indentation level detection + +Indentation level detection hooks into the basic 'insert-tab' action; rather +than inserting 4 spaces (which is the default), it will instead determine the +correct "tab depth" for this line of the buffer, and insert/remove spaces from +the beginning of the line in order to reach the correct number. + +To implement this, you must create a Tabber class and assign it to self.tabber +in the mode. At a minimum, a tabber must support the following methods: + + * __init__(self, mode) + * get_level(self, y) + * region_added(self, p, lines) + * region_removed(self, p1, p2) + +Tabber classes can often be tricky to implement correctly. tab2.Tabber provides +a lot of base functionality that is probably useful; also, you may want to try +looking at tab2.StackTabber, which provides even more base support. + +6. Tag matching + +Tag matching allows a closing tag (such as ")") to "show" the corresponding +opening tag (such as an earlier "(") to help orient the user. Currently, tags +are assumed to be single characters, although in the future it's easy to imagine +multi-character tags being useful. Currently they are not supported. + +This support is very easy to add, assuming that the mode has a grammar. In most +cases, here is how it works: + + a. In the mode, create 4 tuples: + * opentokens: tuple of lexical tokens which can be opentags + * opentags: dictionary mapping opentag strings to closetag strings + * closetokens: tuple of lexical tokens which can be closetags + * closetags: dictionary mapping closetag strings to opentag strings + + b. Also in the visecmode, create or instantiate actions who subclass + method.CloseTag (e.g. method.CloseParen) and assign them the appropriate + binding (e.g. '('). + + c. Enjoy!