A mode to place “foo” at the beginning of each line and highlight it.1
Copyright (c) 2007 Günter Milde (milde users.sf.net) Released under the terms of the GNU General Public License (ver. 2 or later)
Contents
Actually, this is a manual and template for the creation of Jed extension scripts (“modes”). It assumes you to have basic knowledge of S-Lang and Jed and know how to use its help system (Using the help browser from Jedmodes is recommended.)
Support loading this mode with require("foo");:
provide("foo");
To find out what the foo mode does, try:
M-x evalbuffer M-x foo-mode
and have a look at the Mode menu.
You can use the foo_mode_hook to define your own shortcuts, e.g.
define foo_mode_hook(mode) { local_setkey("start_line_with_foo(\"bar \")", "^A"); }
Also, have a look at the Custom variables.
from Jed’s standard library:
require("comments"); require("keydefs"); % symbolic names for keys
from http://jedmodes.sf.net/:
autoload("close_buffer", "bufutils");
(from http://jedmodes.sf.net/) Browse documentation:
#if (expand_jedlib_file("browse_url.sl") != "") autoload("browse_url", "browse_url"); #endif
Use custom_variable() to provide user-configurable options.
These variables can be defined and initialized by users but will be set to the default value if they do not exist at evaluation time.
%!%+ %\variable{Foo_Insertion} %\synopsis{String to insert with \var{start_line_with_foo}} %\usage{String_Type Foo_Insertion = "foo "} %\description % The string that will be inserted by the function % \sfun{start_line_with_foo}. %\seealso{foo_mode, start_line_with_foo} %!%- custom_variable("Foo_Insertion", "foo ");
The implements() function may be used to name the local namespace. Doing so will enable access to the members of the namespace from outside the unit:
implements("foo");
Note
The default scope of definitions changes:
Definition |
without implements |
with implements |
---|---|---|
private define fun |
private |
private |
static define fun |
static |
static |
define fun |
public |
static |
public define fun |
public |
public |
make_ini can generate autoloads for all functions that are defined with define public. To put a function in the “Global” namespace but prevent generation of an autoload, use e.g. define public (with 2 spaces).
Define quasi-constants or variables for inter-function communication as private if they are only used in this compilation unit (file) and as static if they should be accessible with the namespace->name notation. (Do this after the implements, as otherwise the variables become inaccessible.)
% the name of the mode, keymap, and syntax table private variable mode = "foo"; static variable foo_word_chars = get_word_chars()+ "_";
It helps the end-user a lot, if you provide on-line help text with the public functions. The tmtools mode at Jedmodes helps with formatting, the tm and make_ini modes makes it aviable to the Jed help system.
%!%+ %\function{start_line_with_foo} %\synopsis{Prepend line with the sting in\var{Foo_Insertion}} %\usage{ start_line_with_foo(insertion=Foo_Insertion)} %\description % Prepend the current line with the string given in the custom % variable \var{Foo_Insertion} or in the optional argument \var{insertion}. %\example % While %#v+ % start_line_with_foo() %#v- % inserts by default "foo " at the beginning of the line, you can override % this by setting \var{Foo_Insertion} or by e.g. %#v+ % start_line_with_foo("bar ") %#v- %\notes % Please document all public functions to the user can get online-help % via the Help menu. % \var{tm_make_doc} is a nice help in creating in-source documentation % in the "tm" format used by Jed %\seealso{foo_mode, Foo_Insertion} %!%- public define start_line_with_foo() % (insertion=Foo_Insertion) { variable insertion; if (_NARGS) % optional argument present insertion = (); else insertion = read_mini("start every line with:", Foo_Insertion, ""); push_spot(); bol; insert(insertion); pop_spot(); }
Internal functions are best commented with a short abstract line:
% give a message() with help usage. static define small_help() { message("<RET>:Insert Foo q:Quit foo mode"); }
Static functions that are intended for use from other modules, should have an on-line help text too:
%!%+ %\function{foo->normalize_modename} %\synopsis{find the normalized form of a mode} %\usage{foo->normalize_modename(mode)} %\description % take a mode name and do some guesses for the associated slang-function %\example % To do this for the current mode, use e.g. %#v+ % normalize_modename(what_mode, pop) %#v- % (the `pop' will pop the second return value of `what_mode'). %\notes % A related function is in bufutils.sl. %\seealso{normalized_modename} %!%- static define normalize_modename(mode) { variable modstr = extract_element (mode, 0, ' '); if (modstr == "") modstr = "no"; if (is_defined (modstr)) return modstr; modstr += "_mode"; if (is_defined (modstr)) return modstr; modstr = strlow (modstr); if (is_defined (modstr)) return modstr; error ("Mode " + modstr + " is not defined."); } % return to the mode that was used before static define quit_foo() { runhooks(normalize_modename(get_blocal_var("previous_mode"))); update(0); }
Instead of defining your own (un)commenting functions, provide an interface to comments.sl:
set_comment_info (mode, "#foo: ", " :foo#", 7);
Syntax table (non-DFA):
create_syntax_table (mode); define_syntax ("#foo:", ":foo#", '%', mode); % Comments define_syntax ("([{", ")]}", '(', mode); % Delimiters define_syntax ("0-9a-zA-Z", 'w', mode); % Words define_syntax ("-+0-9.", '0', mode); % Numbers define_syntax (",", ',', mode); % Delimiters define_syntax (";", ',', mode); % Delimiters define_syntax ("-+/&*=<>|!~^", '+', mode); % Operators set_syntax_flags (mode, 0);
Keywords:
() = define_keywords_n(mode, "foo", 3, 0);
More versatile but also more complicated. See also Help>Browse_Docs>dfa.
DFA is not available for all versions of Jed, therefore we put the code in a preprocessor section.
#ifdef HAS_DFA_SYNTAX create_syntax_table (mode); % clear the non-DFA entries private define setup_dfa_callback (mode) { dfa_define_highlight_rule("[0-9]*", "number", mode); dfa_define_highlight_rule (sprintf("[%s]*foo[%s]*", foo_word_chars, foo_word_chars), "keyword", mode); dfa_define_highlight_rule ("#foo:.*:foo#", "comment", mode); dfa_build_highlight_table(mode); } dfa_set_init_callback (&setup_dfa_callback, mode); enable_dfa_syntax_for_mode(mode); #endif
Building a DFA highlight table can take considerable time. For complex highlight schemes, it makes sense to cache the table. The cache file will be created
at first use of the mode, or
in a preprocessing step (preparse.sl or update_dfa_cache_files() from make_ini.
In the second case, the section between the lines %%% DFA_CACHE_BEGIN %%% and %%% DFA_CACHE_END %%% will be evaluated in a temporary buffer. Therefore, no references to non-public variables or functions are allowed here. (Notice that mode inside the setup_dfa_callback() refers to the argument of the function.):
#ifdef HAS_DFA_SYNTAX %%% DFA_CACHE_BEGIN %%% private define setup_dfa_callback(mode) { variable foo_word_chars = get_word_chars()+ "_"; dfa_enable_highlight_cache("foo.dfa", mode); dfa_define_highlight_rule("[0-9]*", "number", mode); dfa_define_highlight_rule ("[%s]*foo[%s]*", foo_word_chars, foo_word_chars, "keyword", mode); dfa_define_highlight_rule ("#foo:.*:foo#", "comment", mode); dfa_build_highlight_table(mode); } dfa_set_init_callback (&setup_dfa_callback, "foo"); %%% DFA_CACHE_END %%% enable_dfa_syntax_for_mode(mode); #endif
Be carefull not to overwrite existing keybindings (if no good reason exists for this).
Remember that not all users use the emacs (or cua or ide …) emulation.
You can bind to static functions if the mode sets up a named namespace.
definekey_reserved() uses the (user-configurable) _Reserved_Key_Prefix to avoid clashes.
!if (keymap_p(mode)) make_keymap(mode); definekey_reserved(mode+"->small_help", "?", mode); definekey_reserved(mode+"->quit_foo", "q", mode); definekey_reserved("start_line_with_foo","^M", mode); % Return
The mode function is called to set a Jed buffer in a special editing mode. It should:
call set_mode(mode, flag) to actually set the mode,
activate the syntax highlight table,
activate the keymap,
register the mode menu
optionally set additional “mode info” fields and do some housekeeping actions,
provide a mode_hook, so users can add their favourite shortcuts.
%!%+ %\function{foo_mode} %\synopsis{An example mode} %\usage{Void foo_mode()} %\description % A mode to place "foo" at the beginning of a line. % Also highlights all foos. %\example %#v+ % foo_mode(); % () = what_mode(); % returns two items % message(()); %#v- %\notes % Actually, foo.sl is a commented template for writing jed modes. %\seealso{mode_set_mode_info, slang_mode, set_mode, what_mode} %!%- public define foo_mode() { ($1, ) = what_mode(); define_blocal_var("previous_mode", $1); set_mode(mode, 4); use_syntax_table(mode); use_keymap(mode); mode_set_mode_info(mode, "init_mode_menu", &foo_menu); mode_set_mode_info(mode, "fold_info", "#{{{\r#}}}\r\r"); mode_set_mode_info(mode, "word_chars", foo_word_chars); run_mode_hooks(mode + "_mode_hook"); }