Mode Module Specification for Lpe This document specifies the requirements for writing a language module for lpe. These modules specify the behavior of lpe when working with different specific languages. The module format is the shared library format for the host system. Modules can modify the behavior of lpe be exporting one or more of the following functions: mode_accept: automatically detect when to use this module mode_init: initialize a buffer using this module mode_uninit: clean up module-specific parts of the buffer mode_enter: prepare to switch to this module mode_leave: prepare to switch away from this module mode_flashbrace: flash braces mode_highlight: do syntax highlighting mode_indent: perform custom auto-indentation mode_extkey: handle a module-specific key binding All of these functions are optional -- a module may export whichever of them it desires, providing it adheres to the guidelines for good module behavior (later in this document). The next sections describe the role of each function and how to write it in greater detail. ** mode_accept **************************************************************** Automatically detects when to use this module. If this function is exported, then lpe will call it in an attempt to discover a mode for a newly opened file. When opening a file for which it does not know the appropriate mode, lpe scans all installed modules and calls mode_accept until one of them accepts the mode. If this function is not exported, then this mode will never be automatically selected -- it will only be used if explicitly requested but the user. Parameters: buf - the buffer. All elements are guaranteed to be initialized except for buf->mode and any values that mode_init must set. Return Value: 0 - do not use this module to open the file non-zero - use this module to open the file Hints: * Generally speaking, modes should accept based on a filename suffix, which can be checked by looking at buf->name, or the contents of the first line of a file, which are available in buf->text. For examples, look at perlmode, which checks both the suffix and the first line when deciding whether to accept. * Do not perform any initialization in mode_accept. If the user specifies a mode explicitly, mode_accept will not be called; not even for the mode that was specified. Initialization should be performed in mode_init instead. ** mode_init ****************************************************************** Initializes a buffer. If this function is exported, lpe will call it when a buffer is opened using this mode, or when this mode is set on a buffer that is already open. Among other setup tasks, mode_init should initialize several attributes of the buffer: hardtab, autoindent, flashbrace, offerhelp, highlight, and mode_name. The initial values for these variables can be read from the dotfile via a call to get_option. Parameters: buf - the buffer Hints: * All modes should, generally speaking, export mode_init to perform at least the setup tasks mentioned above. If that doesn't happen, a very basic default configuration will be provided, and the user won't see the mode name on the status bar. * buf->mode.data is reserved specifically for modules to use in associating new attributes with a buffer. It can be cast to an appropriate value and used to store information, or it can be used to point to an extended attributes struct allocated by malloc in mode_init. In the latter case, mode_uninit can be used to free the memory allocated in mode_init. * If the value of buf->mode_name is non-NULL at the call to mode_init, then the buffer has been opened under a different mode. In this case, the buffer flags such as hardtab and autoindent should probably not be reset to default values, since the user may have explicitly set them while in the old mode. ** mode_uninit **************************************************************** Cleans up module-specific parts of the buffer. If exported, lpe will call mode_uninit when a buffer is closed, so that resources used by this module to manage the buffer can be freed. Parameters: buf - the buffer Hints: * The most common use for mode_uninit will probably be to free(buf->mode.data) after allocating it in mode_init. Any cleanup that should be performed when switching buffers, even if the old buffer is not closed, should be placed in mode_leave instead. * A call to mode_uninit does not guarantee that a buffer is being closed. The user may have requested a different mode. Therefore, the function should not perform destructive actions on the contents of the buffer. ** mode_enter ***************************************************************** Prepares to switch to this module. If this function is exported, lpe will call it prior to switching to a buffer that uses this mode. This provides an opportunity for the mode to set things up so that the new mode can be displayed. Parameters: buf - the buffer Hints: * Primarily, mode_enter is used to do two things: set colors for syntax highlighting, and set module-specific key bindings. ** mode_leave ***************************************************************** Prepares to switch away from this module. If this function is exported, lpe will call it just before switching away from a buffer using this module. Parameters: buf - the buffer ** mode_flashbrace ************************************************************ Flashes braces according to the rules of the mode. If the function is exported by the module, then it is called every time a character is pressed with the intent that if the character is considered a brace, then the module will flash the cursor temporarily back to its match. The function should examine the buffer, and pass it back with the position set to the brace to flash to. Parameters: buf - the buffer Return: 0 = do not do any brace flashing 1 = yes, flash the braces to the position set in this function -1 = do not flash and print a warning about mismatched braces ** mode_highlight ************************************************************* Does syntax highlighting. If the function is exported, then mode_highlight will be called as appropriate when drawing the screen. See cmode.c for an example of how the parameters are used, and notice that the 'idx' and 'state' parameters are both input and output parameters. They should be modified in place to reflect the amount of work done by that call and the ending state, so that the function can be called again and start in the right place. Parameters: buf - the buffer ln - the line needing to be highlighted lnum - line number of the highlighted line idx - index of the beginning of the text remaining to be written after call, index of the first character not yet handled state - state information at index idx (-1 for unknown state) after call, state information at final value of idx Return Value: Palette index of the text style to use in drawing processed text ** mode_indent **************************************************************** Performs custom auto-indentation. If exported, it is passed every keystroke so that it can update the indent if desired. Parameters: buf - the buffer ch - the character that was typed ** mode_extkey **************************************************************** Handles a module-specific key binding. If exported, this function is called every time a command is received that is not a standard lpe command. The module can then use that command to perform special handling that makes sense for this buffer mode. Modules can use this to add mode-specific commands to a buffer. Parameters: buf - the buffer c - the command number that was received ******************************************************************************* Guidelines for Good Module Behavior: 1. Anything that is done in mode_init should be undone in mode_uninit. For example, if mode_init allocates memory with malloc, mode_uninit should use free to release that memory. 2. Anything that is done in mode_enter should be undone in mode_leave. Since these functions are generally used to set palette entries and key bindings in S-Lang, mode_leave should typically call init_slang_keys to restore the default key bindings, and if necessary SLtt_set_color to restore palette entry 0 to a reasonable value. Palette entries greater than 0 do not matter. 3. Modules should remember that palette index 0 will be used to draw the banner and '$' scrolling markers as well as whatever they use it for in the drawing code. Therefore, it shouldn't be set to anything that's too awfully extravagant. 4. If a module implements syntax highlighting for a programming language, it should include highlight.h to get colors for many lexical elements. Any extensions to those defaults should be placed in palette indexes greater than or equal to 64 so that highlight.h can be extended in the future without the risk of conflicts. 5. Modules which perform custom key bindings should use values above 0x2000 to represent their bindings. This prevents conflicts with standard key bindings as the standard bindings grow. 6. Modes which create extra key bindings should use multi-key commands that begin with Ctrl-Q. This ensures that these keys do not conflict with any standard key bindings.