# Programming with jedit

## Introduction

This document describes aspects of `jedit` relevant to Tk/Tcl programmers and advanced `jedit` users, including how to write new editing modes (or modify existing ones) and how to incorporate `jedit` windows in your own applications.

## Writing Editing Modes

(This section isn't quite finished, but it should have enough to get you started, if you also look at the code for existing editing modes, especially `hook-mode`, which is a demonstration of the various facilities available.)

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.)

### Initialisation and Preferences

The bare minimum a new mode file should have in it is a procedure `mode:` mode`:init` (where mode is the name of the mode) which contains code like the following, to set modespecific preferences`:`

`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.)

### NaturalLanguage Strings

If your mode defines any new strings to display to the user, you should define them at the top of the mode file with `j:ldb:set_defaults`. (Languagespecific strings are provided in the file `$jstools_library/jldb/jeditmodes/`mode`-mode/`lg, where mode is the name of the mode and lg is the two-letter ISO abbreviation for the language. See jldb.tcl for more information.)

### Buttonbars

You can specify the buttons that are to appear on the buttonbar for your mode by providing them as the ``buttons`' default when you read in your modespecific preferences with `j:read_prefs` in your initialisation procedure. Currently there's no user interface to allow your users to override this default; this is on my agenda for a future version.

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.

### Procedure Names

I recommend that the names of any procedures you define in your mode file start with ``mode:` mode`:'`, where mode is the name of the mode. At present, nothing enforces this, but it will help ensure that your mode doesn't conflict with other modes. (Remember, the user can have more than one `jedit` window open at a time, and they can be in different modes). Future versions of `jedit` may require this naming convention.

### `Hook' Procedures

You can further customise the behaviour of the editor in your new mode by creating any of the following procedures:

`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.

### Registering New Commands

If you define new commands in your mode, you should register them using the `j:command:register` procedure. This allows you to use the commands in menus created with `j:menu:commands`.

### ModeSpecific Menus

If you want to create a special menu for your `jedit` mode, you can create a procedure called `mode:` mode`:mkmenu1`, where mode is the name of your mode. It will receive two arguments: the name of a menubutton to create, and the name of the `jedit` text widget this menu is attached to. As an example, here's the procedure that define's the `vmail` mode's `Mail' menu:

`##################################################
# 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`.

### Command Accelerators

I don't yet have a mechanism for automatically applying modespecific command accelerators using the information provided by `j:ldb:binding`. In fact, if you provide bindings in the string database for modespecific commands, they may be applied to other windows, in different modes. For now, I recommend using explicit Tk `bind`(n) commands in `mode:` mode`:init` to set up modespecific command accelerators. I also recommend using Meta-1 through Meta-9 for modespecific command accelerators if possible; they're reserved for that purpose, so they won't conflict with other bindings, and they're automatically cleared when the user switches modes.

## Embedding jedit in Other Applications

Almost all the functionality of `jedit` is in libraries, so if you write your own Tkbased applications, you can easily incorporate `jedit` into them. You need to include a little bit of code at the beginning of your application to allow it to use the jstools libraries; this is described in the Usage section of their documentation. Essentially, you need to make sure the `auto_path` Tcl variable is set properly to find the libraries. Then you can say
`jedit:jedit -embedded 1` [`-iconic 1`]`` [`-window` w]
[`-mode` mode]`` [`-line` line]`
` [`-filecommands fcmds`]`` [`-buttons` buttons]
[`-width` width]`` [`-height` height]
[`-file` filename]
to edit a file (or open a new empty document window, if you don't specify ``-file` filename'). The `jedit:jedit` procedure returns the name of the toplevel (or existing frame) used for the new `jedit` window, so you can manipulate it with your code after it's created (for instance, to set its position or invoke commands in it).

Specifying ``-embedded 1`' is necessary to keep 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

- `-mode` mode
  mode specifies the editing mode to use (e.g. `code`, `jhtml`, etc.)
- `-line` line
  line specifies a line to position the cursor on after the file is opened
- `-filecommands` filecommands
  filecommands is a list of `jedit` command procedures that defines what will appear on the `File' menu. The default is
  `{
  jedit:cmd:load
  jedit:cmd:save
  jedit:cmd:saveas
  jedit:cmd:print
  -
  jedit:cmd:insfile
  -
  jedit:cmd:close
  jedit:cmd:done
  }`
  which is the same as the default menu entries except for the absence of the `New Window' and `Quit' commands.
- `-buttons` buttons
  buttons is a list of `jedit` command procedures that defines what buttons will appear in the buttonbar (if the user has the buttonbar displayed). The default is `{}`, which means to use the default buttonbar for the mode.
- `-command` command
  command is a Tcl command which will be executed after the window is closed; it can be used (for instance) to examine a file after the user has (presumably) changed it.
- `-width` width and `-height` height
  width and height are dimensions (in characters) for the new text widget. (Due to packing constraints, the text widget may end up being wider than specified.)

If the window w doesn't already exist, it will be created as a new toplevel window of class `Jedit`. (If you don't specify it, an arbitrary window name will be chosen.) It's fine for w to exist already, though; that way you can include an entire `jedit` window inside another window.

If you specify mode, the window will be in that mode; otherwise `jedit` will guess the mode based on the filename.

If you specify ``-iconic 1`', then the new `jedit` window will be created iconified.

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 `vi`style `+`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).
``