This file documents the various hooks for extending JED. A `hook' is simply a user defined S-Lang function that may be used to extend the editor or to modify how it behaves under certain circumstances. There are two kinds of hooks that vary according to whether the hook is called ``internally'' from the editor by the underlying C code or whether the hook is called from another S-Lang routine. The hooks may be subdivided further according to their scope. They may apply to all buffers (globally), only buffers sharing the same mode (modal), or to a single buffer (local). Global Hooks. The global hooks affect all buffers. They are: 1. `command_line_hook': This hook is called from within the editor to parse the command line arguments. It is defined in the file `site.sl' and cannot be customized by the user. However, the it may be customized by the system manager. In addition to parsing the command line arguments the default value of this hook also loads the user's personal initialization file. 2. `jed_startup_hook': Although this function is defined in `site.sl', it can be changed by a user because it is called after the user initialization file is loaded. This hook is called just prior to the main editing loop of the editor. It also calls the hook `startup_hook' which may be defined by the user as a convenient way to customize `jed_startup_hook'. See `exit_hook' for an example of how this may be exploited. 3. `exit_hook': This hook is called when the intrinsic function `exit_jed' is called. Although it has no default definition does not mean that it is not useful. For example, one could use: define exit_hook() { variable ch; if (BATCH) exit_jed(); flush("Really Exit? "); ch = getkey(); if ((ch == 'Y') || (ch == 'y')) exit_jed (); error ("Aborted!"); } to confirm the exit. Note also that although `exit_jed' calls this function, `exit_hook' will not be called again if it int turn calls `exit_jed'. Also, for MSDOS it might be desirable for the editor to exit in the same directory that it started. This will work: define exit_hook() { variable dir; if (bufferp("*scratch*")) { sw2buf("*scratch*"); (,dir,,) = getbuf_info(); change_default_dir(dir); pop(); } call( "exit_jed" ); } Like many hooks, if an error is generated by the hook, the function that called it will fail and the operation will be aborted. Finally, `exit_hook' and `startup_hook' may be used together to implement a way of saving the state of the editor. A minimal implementation might be: variable Jed_State_File = dircat (getenv ("HOME"), ".jedstate"); define exit_hook () { variable file = buffer_filename (); variable cmd; if (strlen (file)) { % This is mainly for MSDOS to fix the backslash character % used for path names. file = str_quote_string (file, "\\", '\\'); cmd = Sprintf ("() = find_file (\"%s\");", file, 1); cmd = Sprintf ("%s\ngoto_line (%d); goto_column (%d);", cmd, whatline (), what_column (), 3); () = write_string_to_file (cmd, Jed_State_File); } exit_jed (); } define startup_hook () { if (1 == file_status (Jed_State_File)) { () = evalfile (Jed_State_File); () = delete_file (Jed_State_File); } } 4. `suspend_hook': This hook has no default value and is called just before suspending the editor. One might use it as a simple way of prohibiting suspension, e.g., define suspend_hook () { error ("Suspending not allowed."); } 5. `resume_hook': It is called immediately after JED resumes after being suspended. This hook is predefined only on VMS systems. This does not mean that it cannot be used on other systems as well. For example, here is a silly use define resume_hook () { message ("Welcome back!"); } but I am sure that you will think of something more clever. 6. `mode_hook': Immediately after JED loads a file into a buffer, it calls `mode_hook' to set the mode of the buffer. The default value is defined in `site.sl'. This hook is called with with the file name extension of the file as its only parameter. This function sets the mode of the buffer based on the value of the file name extension. There are several ways to customize this hook. The easiest is to simply call the function `add_mode_for_extension' with the mode that is to be associated with a particular extension. For example, suppose that you edit files with names like `main.c++'. To have `c_mode' associated with files of this type, simply call: add_mode_for_extension ("c", "c++"); The important point to realize is that the first parameter is the name of the mode but it should not include the `_mode' part of the mode name. The other way to customize mode_hook is through the function pointer `mode_hook_pointer' which the user can define to set the mode. If the function pointed to by `mode_hook_pointer' returns non-zero, `mode_hook' will return to the calling routine. Specifically, the default value of `mode_hook' looks like: define mode_hook (ext) { if (mode_hook_pointer (ext)) return; . . } One could simple point `mode_hook_pointer' to something like: define set_no_mode (ext) { return 1; } mode_hook_pointer = &set_no_mode; Typically, one would do something useful like: define my_mode_hook (ext) { if (strcmp ("pas", ext)) return 0; my_pascal_mode (); return 1; } mode_hook_pointer = &my_mode_hook; Here `my_pascal_mode' is a hypothetical pascal mode. As a final example, consider the case where one would like to set the mode based on the filename and NOT the extension. For example, the Elm mailer user files of the form `snd.XXX' and one would like to use text mode on such files. Again, the solution is to use the `mode_hook_pointer': define my_mode_hook (ext) { variable file; (file,,,) = getbuf_info (); if (0 != strncmp (file, "snd.", 4)) return 0; text_mode (); return 1; } mode_hook_pointer = &my_mode_hook; Finally, the global variable `Default_Mode' may be pointed to a function to set the mode if a suitable mode was not obtained from the extension. By default, it has the value: Default_Mode = &text_mode; 7. `find_file_hook': This hook is called after a file is read into the editor via the internal function `find_file'. It is passed the full filename of the file read into the buffer. The supplied default for this function simply looks for an autosave file and warns the user if it should be used instead. It might also be used to preprocess the buffer before the user starts to edit it. *** Note: This hook will most like be changed such that it is called beore the file is read in. 8. `format_paragraph_hook': This hook is called after a paragraph is formatted but only if the a prefix argument was given prior to the execution of the internal function `format_paragraph'. That is, the default binding of `format_paragraph' is `ESC q'. Pressing `ESC 1' immediately before pressing `ESC q' will format the paragraph and then call `format_paragraph_hook'. The default definition for this hook left and right justifies the paragraph. 9. `is_paragraph_separator': This hook is called by the editor to locate paragraph delimeters. If defined, it applies globally to all buffers except those which have a local definition (see the `par_sep' hook). The default value is coded in C and basically reduces to: define is_paragraph_separator () { bol(); if (looking_at("\\") or looking_at("%")) return (1); skip_while(); return (eolp()); } which is useful for TeX mode. The hook must simply return a non-zero value if the current line is a paragraph delimeter or zero if it is not. Mode Hooks: These are hooks that get called when the editor enters a particular mode. Usually, one just wants to defined keys. For this purpose, use the `local_setkey' function. 1. `tex_mode_hook': This hook is called when JED starts its TeX mode. Use it to bind certain functions that either have no binding or have one that you do not like, e.g., define tex_mode_hook () { local_unsetkey ("^C"); local_setkey ("latex_do_environment", "^C^E"); local_setkey (" \\alpha", "^Ca"); local_setkey (" \\Alpha", "^CA"); local_setkey (" \\Beta", "^CB"); local_setkey (" \\beta", "^Cb"); % etc... } Notice that in this hook, I have simply set keys `Ctrl-C a', etc... to insert `\alpha', etc... 2. c_mode_hook 3. fortran_hook 4. text_mode_hook 5. mail_hook A useful hook here is to defined Ctrl-C Ctrl-C to send the message al la emacs: define mail_hook () { local_unsetkey ("^C"); local_setkey ("send", "^C^C"); } 6. slang_mode_hook 7. dired_mode_hook 8. fortran_hook Local hooks: These hooks apply to individual buffers. They must be ``declared'' to the buffer using the intrinsic function `set_buffer_hook'. 1. `par_sep': function used to determine where paragraph boundaries are. See the hook `is_paragraph_separator' for more information. 2. `indent_hook': function called after a line is indented by the function `indent_line'. 3. `wrap_hook': function called after a line is wrapped. For example, in writing this document, I want the lines following the numbers to be offset some. So I wrote: define text_mode_wrap_hook () { variable p; push_spot (); go_up(1); bol (); skip_white (); p = POINT; skip_chars ("0-9"); if ((p != POINT) and looking_at (". ")) { go_down(1); bol (); skip_white (); p = what_column (); bol (); trim (); whitespace (p + 3); } pop_spot (); } In fact, I always use this in text_mode so I put in in my `text_mode_hook': define text_mode_hook () { set_buffer_hook ("wrap_hook", "text_mode_wrap_hook"); }