You create a new editing mode by creating a file called mode-mode.tcl, where mode is the name of the new mode. This file can live in any of the directories ~/.tk/jeditmodes, $tk_library/jedit/jeditmodes, or $tk_library/jeditmodes. (The directories are searched in that order.)
proc mode:vmail:init { t } {
global MODEPREFS
j:read_prefs -array MODEPREFS -prefix vmail \
-directory ~/.tk/jeditmodes -file vmail-defaults {
{textfont default}
{textwidth 80}
{textheight 24}
{textwrap char}
{sabbrev 0}
{dabbrev 0}
{autobreak 1}
{autoindent 0}
{savestate 0}
{buttonbar 1}
{buttons {
jedit:cmd:done
jedit:cmd:save
}}
{menu,editor 1}
{menu,file 1}
{menu,edit 1}
{menu,prefs 0}
{menu,abbrev 1}
{menu,filter 1}
{menu,format 0}
{menu,display 0}
{menu,mode1 1}
{menu,mode2 1}
{menu,user 1}
}
}
(Actually, you can leave out the preferences you don't want to
override in your mode in the list you give to
j:read_prefs.) This code fragment sets the defaults for the various modespecific
preferences for your new mode, although a user can still override
them (for this particular mode) on the
ModeSpecific Preferences panel.
Note that the mode:mode:init procedure gets an argument t. That's the name of the text widget whose mode is being set, so you can do things like configure tags or add bindings if you need to.
If you need to refer to the widget's toplevel (for instance, to add new userinterface components), you can do that with the command `jedit:text_to_top $t'. If you do anything in mode:mode:init that shouldn't persist if the user changes modes, you should also provide a procedure called mode:mode:cleanup (which will also be called with the text widget as its sole argument) to undo your changes. For instance, if you pack an entry for the user to type a cryptographic key into the toplevel window in mode:crypt:init, you should create a mode:crypt:cleanup procedure to remove it. (Both procedures would need to use jedit:text_to_top to get the name of the toplevel window.)
Alternatively, to create a custom buttonbar, you can define a procedure called mode:mode:mkbuttons with code similar to the following:
proc mode:vmail:mkbuttons { w t } {
j:buttonbar $w -pady 2 -buttons [format {
{send { } {jedit:cmd:done %s}}
{sign { } {mode:vmail:insert_sig %s}}
} $t $t]
$w.b configure -bitmap @/some/path/send.xbm
$w.b configure -bitmap @/some/path/sign.xbm
return $w
}
This procedure gets both the name of the toplevel widget and the
name of the text widget. It should create the buttonbar as
a child of the toplevel and return its path, but not pack it itself.
This method lets you create buttons that don't correspond to
registered commands, or buttons that don't look like normal
jedit buttons.
mode:mode:pre_read_hook
filename
widget
mode:mode:read
filename
widget
mode:mode:post_read_hook
filename
widget
mode:mode:pre_write_hook
filename
widget
mode:mode:write
filename
widget
mode:mode:post_write_hook
filename
widget
mode:mode:pre_quit_hook
widget
mode:mode:quit
widget
mode:mode:pre_close_hook
widget
mode:mode:close
widget
mode:mode:pre_spacebar_hook
widget
mode:mode:spacebar
widget
mode:mode:post_spacebar_hook
widget
mode:mode:pre_tabkey_hook
widget
mode:mode:tabkey
widget
mode:mode:post_tabkey_hook
widget
mode:mode:pre_returnkey_hook
widget
mode:mode:returnkey
widget
mode:mode:post_returnkey_hook
widget
mode:mode:pre_paste_hook
widget
mode:mode:post_paste_hook
widget
mode:mode:pre_xpaste_hook
widget
mode:mode:post_xpaste_hook
widget
mode:mode:autoindent
widget
If a
mode:mode:pre_..._hook or
mode:mode:post_..._hook procedure is defined, it will be called before or after the
relevant action. If one of the procedures without `_hook' is defined, it will be called
instead of the default action.
Note that the behaviour of the `Close' command and it's corresponding modespecific procedures is linked to that of the `Quit' command and it's corresponding modespecific procedures. If there is only one window open, choosing `Close' is exactly like choosing `Quit', and will trigger mode:mode:pre_quit_hook and mode:mode:quit if they exist rather than the corresponding `Close' hooks. The mode:mode:pre_close_hook and mode:mode:close procedures are called only when there's more than one window open. This means that if you define them, you usually want to take similar actions in the corresponding `Quit' hooks.
##################################################
# define the Vmail menu:
##################################################
proc mode:vmail:mkmenu1 { menu t } {
j:menubutton $menu $menu.m {Vmail}
j:menu:commands $menu $t {
mode:vmail:insert_sig
jedit:cmd:done
}
}
(In this example,
mode:vmail:insert_sig is a procedure defined elsewhere in the
mail-mode.tcl file.) It's easiest to create menus with the procedures
in the
jmenu.tcl library, but you can create them however you like.
Note that the mode:mode:mkmenu1 procedure has to create the menubutton itself (but not pack it), and it has no control over the name of the menubutton widget.
If you want to create two modespecific menus, you can also define a mode:mode:mkmenu2 procedure; the requirements are the same as for mode:mode:mkmenu1.
Specifying `-embedded 1' is necessary the `Quit' command from working. (Otherwise the user could exit your entire application by choosing `Quit'.) It also changes the default contents of the File menu.
Other options you can specify include
If you specify mode, the window will be in that mode; otherwise jedit will guess the mode based on the filename.
If you specify mode and also define all the necessary procedures for that mode in your code before calling jedit:jedit (such as mode:mode:init), you can tightly constrain the behaviour of the resulting jedit window, essentially creating a custom mode for your application without having to provide a separate mode file to define it.
If you specify line (and it's a valid number), then the insert point will be positioned at the beginning of the lineth line of text after the file is loaded; this is used to implement the vistyle +linenumber commandline syntax that lots of applications expect in an editor (e.g. to position the cursor at the beginning of the body, rather than the beginning of the header, of a mail or news message.)
You can use
filecommands and
buttons to put arbitrary commands on the File menu and on the buttonbar.
These commands can either be standard
jedit commands (for whose names you'll want to consult the
jedit source code and/or the
tclIndex file in the
jstools library directory) or new commands defined by your code.
(For instance, a mail program using
jedit to compose mail might want to add a `Send' command.) If
you create your own commands, they should be of the form
something:cmd:command, for instance,
mail:cmd:send, and you'll want to read the documentation for the
jcommand.tcl library (and probably
jldb.tcl as well).