Tips and Standards
******************

This chapter describes no additional features of SXEmacs Lisp. Instead it gives advice on making effective use of the features described in the previous chapters.

Writing Clean Lisp Programs
===========================

Here are some tips for avoiding common errors in writing Lisp code intended for widespread use:

  * Since all global variables share the same name space, and all functions share another name space, you should choose a short word to distinguish your program from other Lisp programs.  Then take care to begin the names of all global variables, constants, and functions with the chosen prefix.  This helps avoid name conflicts.

     This recommendation applies even to names for traditional Lisp primitives that are not primitives in SXEmacs Lisp---even to cadr. Believe it or not, there is more than one plausible way to define cadr.  Play it safe; append your name prefix to produce a name like foo-cadr or mylib-cadr instead.

     If you write a function that you think ought to be added to SXEmacs under a certain name, such as twiddle-files, do not call it by that name in your program.  Call it mylib-twiddle-files in your program, and send mail to sxemacs-devel@sxemacs.org suggesting we add it to SXEmacs.  If and when we do, we can change the name easily enough.

     If one prefix is insufficient, your package may use two or three alternative common prefixes, so long as they make sense.

     Separate the prefix from the rest of the symbol name with a hyphen, -.  This will be consistent with SXEmacs itself and with most Emacs Lisp programs.

  * It is often useful to put a call to provide in each separate library program, at least if there is more than one entry point to the program.

  * If a file requires certain other library programs to be loaded beforehand, then the comments at the beginning of the file should say so.  Also, use require to make sure they are loaded.

  * If one file FOO uses a macro defined in another file BAR, FOO should contain this expression before the first use of the macro:

          (eval-when-compile (require 'BAR))

     And, of course, BAR should contain (provide 'BAR), to make the require work.  This will cause BAR to be loaded when you byte-compile FOO.  Otherwise, you risk compiling FOO without the necessary macro loaded, and that would produce compiled code that will not work right.  See Compiling Macros.

     Using eval-when-compile avoids loading BAR when the compiled version of FOO is used.

  * If you define a major mode, make sure to run a hook variable using run-hooks, just as the existing major modes do.  See Hooks.

  * If the purpose of a function is to tell you whether a certain condition is true or false, give the function a name that ends in p.  If the name is one word, add just p; if the name is multiple words, add -p.  Examples are framep and frame-live-p.

  * If a user option variable records a true-or-false condition, give it a name that ends in -flag.

  * Please do not define C-c LETTER as a key in your major modes.  These sequences are reserved for users; they are the only sequences reserved for users, so we cannot do without them.

     Instead, define sequences consisting of C-c followed by a non-letter.  These sequences are reserved for major modes.

     Changing all the major modes in Emacs 18 so they would follow this convention was a lot of work.  Abandoning this convention would make that work go to waste, and inconvenience users.

  * Sequences consisting of C-c followed by {, }, <, >, : or ; are also reserved for major modes.

  * Sequences consisting of C-c followed by any other punctuation character are allocated for minor modes.  Using them in a major mode is not absolutely prohibited, but if you do that, the major mode binding may be shadowed from time to time by minor modes.

  * You should not bind C-h following any prefix character (including C-c).  If you do not bind C-h, it is automatically available as a help character for listing the subcommands of the prefix character.

  * You should not bind a key sequence ending in ESC except following another ESC.  That is, it is ok to bind a sequence ending in ESC ESC.

     The reason for this rule is that a non-prefix binding for ESC in any context prevents recognition of escape sequences as function keys in that context.

  * Applications should not bind mouse events based on button 1 with the shift key held down.  These events include S-mouse-1, M-S-mouse-1, C-S-mouse-1, and so on.  They are reserved for users.

  * Modes should redefine mouse-2 as a command to follow some sort of reference in the text of a buffer, if users usually would not want to alter the text in that buffer by hand.  Modes such as Dired, Info, Compilation, and Occur redefine it in this way.

  * When a package provides a modification of ordinary SXEmacs behavior, it is good to include a command to enable and disable the feature, Provide a command named WHATEVER-mode which turns the feature on or off, and make it autoload (see Autoload).  Design the package so that simply loading it has no visible effect---that should not enable the feature.  Users will request the feature by invoking the command.

  * It is a bad idea to define aliases for the SXEmacs primitives.  Use the standard names instead.

  * Redefining a SXEmacs primitive is an even worse idea. It may do the right thing for a particular program, but there is no telling what other programs might break as a result.

  * If a file does replace any of the functions or library programs of standard SXEmacs, prominent comments at the beginning of the file should say which functions are replaced, and how the behavior of the replacements differs from that of the originals.

  * Please keep the names of your SXEmacs Lisp source files to 13 characters or less.  This way, if the files are compiled, the compiled files' names will be 14 characters or less, which is short enough to fit on all kinds of Unix systems.

  * Do not use next-line or previous-line in programs; nearly always, forward-line is more convenient as well as more predictable and robust.  See Text Lines.

  * Do not call functions that set the mark, unless setting the mark is one of the intended features of your program.  The mark is a user-level feature, so it is incorrect to change the mark except to supply a value for the user's benefit.  See The Mark.

     In particular, do not use these functions:

       * beginning-of-buffer, end-of-buffer

       * replace-string, replace-regexp

     If you just want to move point, or replace a certain string, without any of the other features intended for interactive users, you can replace these functions with one or two lines of simple Lisp code.

  * Use lists rather than vectors, except when there is a particular reason to use a vector.  Lisp has more facilities for manipulating lists than for vectors, and working with lists is usually more convenient.

     Vectors are advantageous for tables that are substantial in size and are accessed in random order (not searched front to back), provided there is no need to insert or delete elements (only lists allow that).

  * The recommended way to print a message in the echo area is with the message function, not princ.  See The Echo Area.

  * When you encounter an error condition, call the function error (or signal).  The function error does not return. See Signaling Errors.

     Do not use message, throw, sleep-for, or beep to report errors.

  * An error message should start with a capital letter but should not end with a period.

  * Try to avoid using recursive edits.  Instead, do what the Rmail e command does: use a new local keymap that contains one command defined to switch back to the old local keymap.  Or do what the edit-options command does: switch to another buffer and let the user switch back at will.  See Recursive Editing.

  * In some other systems there is a convention of choosing variable names that begin and end with *.  We do not use that convention in SXEmacs Lisp, so please don't use it in your programs.  Emacs uses such names only for program-generated buffers.  The users will find Emacs more coherent if all libraries use the same conventions.

  * Use names starting with a space for temporary buffers (see Buffer Names), or at least call buffer-disable-undo on them.  Otherwise they may stay referenced by internal undo variables after getting killed.  If this happens before dumping (see Building SXEmacs), this may cause fatal error when portable dumper is used.

  * Indent each function with C-M-q (indent-sexp) using the default indentation parameters.

  * Do not make a habit of putting close-parentheses on lines by themselves; Lisp programmers find this disconcerting.  Once in a while, when there is a sequence of many consecutive close-parentheses, it may make sense to split them in one or two significant places.

  * Please put a copyright notice on the file if you give copies to anyone. Use the same lines that appear at the top of the Lisp files in SXEmacs itself.

Tips for efficient lisp code
============================

Here are ways of improving the execution speed of Lisp programs.

  * Use byte compilation whenever you can.

     Beside the static byte compilation yielding .elc files, you can also use the byte-compile function to create and use compiled objects inline.

          ;; We create a byte compiled predicate and bind it to the variable
          ;; is-minus-one-p.
          ;; Note that we do _NOT_ create a function is-minus-one-p.
          (setq is-minus-one-p
                (byte-compile
                  #'(lambda (a) (zerop (1+ a)))))
            => #<compiled-function (a) "...(5)" [a zerop] 2>

          ;; We use the compiled function object of is-minus-one-p.
          (require 'cl)
          (some is-minus-one-p '(1 2 3 4 -1))
            => t

  * Certain built-in functions are handled specially in byte-compiled code, avoiding the need for an ordinary function call.  It is a good idea to use these functions rather than alternatives.  To see whether a function is handled specially by the compiler, examine its byte-compile property.  If the property is non-nil, then the function is handled specially.

     For example, the following input will show you that aref is compiled specially (see Array Functions) while assoc is not (see Sequence Functions):

          (get 'aref 'byte-compile)
               => byte-compile-two-args

          (get 'assoc 'byte-compile)
               => nil

  * Teach yourself to tag functions with the special quote function (short form is #') instead of using an ordinary quote (short ').  In byte compilation, the byte-compiler will look for function quotes and compile them.  Ordinarily quoted function names will not be investigated nor byte compiled.

     The same applies to anonymous function objects (lambda lists) in non-obvious forms like backquoted macro bodies, or fset constructions in macros of the form (list 'lambda argname ...).

     On the other hand, if cheating the byte compiler is explicitly what you want emacs lisp will also accept the normal quote to refer to the function cell in most cases.

  * If calling a small function accounts for a substantial part of your program's running time, make the function inline (use defsubst. This eliminates the function call overhead.  Since making a function inline reduces the flexibility of changing the program, do not do it unless it gives a noticeable speedup in something slow enough that users care about the speed.  See Inline Functions.

  * Use iteration rather than recursion whenever possible. Function calls are slow in SXEmacs Lisp even when a compiled function is calling another compiled function.

  * Using the primitive list-searching functions memq, member, assq, or assoc is even faster than explicit iteration.  It may be worth rearranging a data structure so that one of these primitive search functions can be used.

  * Use the profile library to profile your program.  See the file profile.el for instructions.

  * If absolute performance timings are of interest do not use profile.el since it redefines the investigated functions and hence slows down their execution.  With a minimal overhead you can use the current-btime function to obtain an absolute time stamp with a microsecond resolution.

     For example we measure the execution time of nreverse for a list of 1000 random numbers.

          ;; initialise the list
          (setq lrn nil)
          (dotimes (i 1000)
            (setq lrn (cons (random) lrn)))
            => omitted

          ;; We use two time variables start and end.
          (progn
            (setq start (current-btime))
            (setq lrn (nreverse lrn))
            (setq end (current-btime)))

          ;; We investigate the time by simply subtracting start from end.
          (- end start)
            => 190

          ;; This means nreverse took about 190 microseconds.

          ;; The real value is highly likely a little less than this.
          ;; Let's measure the overhead.
          (progn
            (setq start (current-btime))
            (setq end (current-btime))
            (- end start))
            => 17

  * Deliberate about your data representation.

     SXEmacs provides a multiplicity of types and containers to store your data.  Which of them suits your purpose best depends on many things

       * Do you want to be compatible to other Emacs flavours?

          Well, in this case you should definitely have a glance at the flavour you want to be compatible with.  Also see Compatibility Tips.

          If compatibility is not an issue, you can benefit in many cases from the large variety of dedicated data types in SXEmacs.  See next item.

       * Do you want speed or comfort or flexibility or memory frugality?

          (Not yet prepared)

  * Consider external tools.  But think first!

     In some cases it is simply appropriate to use external tools.  For example it does not make sense to re-implement the block zipping algorithm of bzip2 in elisp, instead create a process and call the bzip2 binary.

     However, if external tools provide a shared object library the process approach will highly likely be a snail compared to an FFI implementation.  The advantage is simply that FFI calls will not create that much overhead because the available data is simply reused and does not need further steps, e.g. preparing the input data for the external tool, or parsing the results and converting them to lisp data, again.

     Again, think twice! An FFI implementation can waste a large amount of development time.  Moreover, it requires a detailed knowledge of the internal concept of the external resource.  It is very easy to crash your SXEmacs with FFI!

     A safer way of using external libraries in the way FFI does is to create an emodule.  In very time critical scenarios, emodules may even outperform FFI because large parts of a procedure can run at C level without interacting with the lisp engine at all.  You can even use all the usual advantages of C, such as parallelism, multi-threading and similar.  Moreover, if desired you can wrap intermediate results to special containers (using dynacats), and pass these to the lisp level.  Indeed, dynacats which escaped to the lisp level are safe since there is no way to access or modify them.  Of course, you can envisage dedicated interface functions within your emodule but even in that case the actual processing will always take place in your emodule at C level.

     Anyway, emodules suffer from a serious drawback: they have to be built first in order to use them.  In contrast, both the process approach and the FFI implementation just work out of the box.

Tips for writing compatible code
================================

Writing compatible code is very easy whenever a problem is decoupled enough.  That is when your problem is of abstract nature and does not explicitly depend on a certain OS, emacs flavour, external tools, or file system layout.

In that case you would simply divide your code in two parts, the abstract layer which contains the solution of your problem in an abstract (read independent) way, and the implementation layer which contains OS specific, flavour specific, tool specific and/or file system layout specific implementations and which thus provides one or more interfaces for your abstract layer.

Fine, so why are there so many problems between, say, code for FSF Emacs and (S)XEmacs?  Well, programmers are not always professional software designers.  Also, compatibility often plays a minor role, especially in young projects or projects with little man power.  But the most understandable reason might be that one or more pieces of code simply cannot be decoupled or at least not in an efficient way.

Anyway, let us look at very simple compatibility issues.  The most trivial case of course is a problem independent from all of the aforementioned requisites, like sorting a list of numbers ascendingly.  This can be done using only an iteration function (like while), assignment operators (setq), a predicate (<) and the list primitives cons, car, cdr.  All of these routines are available in any emacs on any OS.  Hence compatibility is not an issue.

Nonetheless, even such a simple thing can be transformed into a broadly incompatible mess.  Just assume that programmers choose the way with least obstacles -- some people prefer the term lazy though -- they will definitely use a primitive like sort, stable-sort or sort*.  Or assume that sorting numbers is just a small subproblem of a larger one and the context stipulates that numbers must be arranged in vectors instead of lists.  In such cases consider the following small checklist.

  * Are all the constructors, modifiers and predicates defined?

     Conditionalise with fboundp and boundp constructions like:

          (when (fboundp #'make-hash-table)
            ...)

     or emacs flavours:

          (when (featurep 'sxemacs)
            ...)

     or operating systems, e.g.:

          (when (eq system-type 'linux)
            ...)

  * Do they behave as expected?

     Check for number, order and type of the arguments.  If feasible write a small, simple testcase, like

          (hash-table-p (make-hash-table :size 120 :test #'eq))

     In order to use this sort of test within your code, for example to trigger an implementation based on the success, you could use the condition-case construction:

          (unless
            (condition-case nil
                (prog1
                  (hash-table-p (make-hash-table :size 120 :test #'eq))
                  (garbage-collect))
              (error nil))      ;; return `nil' in case of error

            ...)

  * Does your code depend on other elisp libraries or packages? Perhaps not even distributed ones?

     If feasible consider distributing a compatibility layer (see below). In this case, you must decouple your code such that it can either use the native implementation or the one provided by your compatibility layer.

     If reinventing the wheel is not an issue, consider distributing the foreign requisites along with your code.  This implies of course that you carefully checked the foreign resources for their compatibility. Also, make sure that the licences permit your decision.

     In case there are too many requisite libraries to stuff them all into your package, or if licences forbid this, you should definitely give your users a notice, preferrably with detailed instructions on how to resolve the dependencies, at least include a location where users can fetch a known-to-work version.

  * Does your code depend on external, perhaps OS specific resources, like ssh, apache, C compilers, shared libraries, special hardware and similar?

     This is probably the hardest case and there is definitely no patent remedy.  If you cannot grant compatibility or detect missing necessities for a specific target, you must at least notify your users accordingly.

     If you know other code or projects which manage the situation `better' than you (i.e. with less requisites or better/native support) name those alternatives.  If you do not know alternatives or other approaches seem to far away from your own it is definitely a good idea to explain in great detail what you are trying to do.  This way users get the chance to look for alternatives themselves.

How to write a compatibility layer
----------------------------------

There is no generic approach to do that.  However, there is a general idea which has been mentioned already in the introduction.  Decouple your program so much that you do not call any functions, macros or variables which are suspicious to be incompatible.

Let us work out this idea in a practical scenario.  Imagine you have to deal with aspect ratios as they occur in image data or video material, e.g. 16:9, 16:10 or the like.  Now initial research reveals that both XEmacs 21.5.x and SXEmacs may provide built-in support for rational quotients, whereas XEmacs 21.4.x and GNU Emacs do not.

Now since we know that we only want to multiply fractions with integers, we merely provide this single operation, along with a constructor, a predicate and two accessors.  Note, we will put the detection code along with the two implementations in the following example.  In practice each implementation usually occupies a file of its own and the detection resides at a central location, for example in the library's main file.

     (when
       ;; check if SXEmacs is build with ENT support (bigq submodule)
       (and (featurep 'ent) (featurep 'bigq))

       ;; the constructor (takes two arguments, two rational integers)
       (defalias 'expkg-make-quotient #'//)
       ;; the predicate (takes one argument, a bigq)
       (defalias 'expkg-quotient-p #'bigqp)

       ;; an accessor for the numerator of a quotient (takes a bigq)
       (defalias 'expkg-quotient-num #'numerator)
       ;; an accessor for the denominator of a quotient (takes a bigq)
       (defalias 'expkg-quotient-den #'denominator)

       ;; a * function for quotients by integers
       (defalias 'expkg-mult-quo-int #'*))

     (when
       ;; or is it XEmacs with ratio support? SXE says `t', too, so check
       ;; for non-SXE
       (and (not (featurep 'sxemacs)) (featurep 'ratio))

       (defalias 'expkg-make-quotient #'div)
       (defalias 'expkg-quotient-p #'ratiop)

       (defalias 'expkg-quotient-num #'numerator)
       (defalias 'expkg-quotient-den #'denominator)

       (defalias 'expkg-mult-quo-int #'*))

     ;; just check if expkg-make-quotient is bound already
     (unless (fboundp #'expkg-make-quotient)

       ;; constructor
       (defun expkg-make-quotient (numerator denominator)
         "Return the quotient numerator/denominator"
         ;; we choose to store in a 3 component vector
         (vector 'quotient numerator denominator))

       ;; predicate
       (defun expkg-quotient-p (object)
         "Return `t' if OBJECT is a quotient."
         ;; we check for the vector property, if length equals 3 and
         ;; finally if our indicator is present
         (and (vectorp object)
              (= (length object) 3)
              (eq (aref object 0) 'quotient)))

       ;; num accessor
       (defun expkg-quotient-num (quotient)
         "Return the numerator of QUOTIENT."
         ;; check if QUOTIENT is indeed what we expect
         (if (expkg-quotient-p quotient)
             (aref quotient 1)
           (error "Wrong type argument, quotientp `%s'" quotient)))

       ;; den accessor
       (defun expkg-quotient-den (quotient)
         "Return the denominator of QUOTIENT."
         ;; check if QUOTIENT is indeed what we expect
         (if (expkg-quotient-p quotient)
             (aref quotient 2)
           (error "Wrong type argument, quotientp `%s'" quotient)))

       ;; multiplication
       (defun expkg-mult-quo-int (quo int)
         "Return the product of QUO with INT."
         (if (and (expkg-quotient-p quo)
                  (integerp int))
             (expkg-make-quotient
              ;; new-num <- num * int
              (* (expkg-quotient-num quo) int)
              ;; new-den <- den
              (expkg-quotient-den quo))
           ;; otherwise barf
           (error "Wrong type argument, quotientp `%s', integerp `%s'"
                  quo int))))

Now that's it!  Now we can use the functions defined here to interface the quotient functionality in an abstract way.  Moreover, this example demonstrates how to decouple a concept (quotients in this case) from the actual data type used to represent the concept, in order of appearance quotients can be represented as bigqs, as ratios or as vectors.

However, as you may have noticed not all internals can be abstracted in a sane way.  In our case, the abstract layer will make up quotients of integers.  We simply assumed -- or knew -- that these exist in all emacs flavours and behave identically.

Tips for Documentation Strings
==============================

Here are some tips for the writing of documentation strings.

  * Every command, function, or variable intended for users to know about should have a documentation string.

  * An internal variable or subroutine of a Lisp program might as well have a documentation string.  In earlier Emacs versions, you could save space by using a comment instead of a documentation string, but that is no longer the case.

  * The first line of the documentation string should consist of one or two complete sentences that stand on their own as a summary.  M-x apropos displays just the first line, and if it doesn't stand on its own, the result looks bad.  In particular, start the first line with a capital letter and end with a period.

     The documentation string can have additional lines that expand on the details of how to use the function or variable.  The additional lines should be made up of complete sentences also, but they may be filled if that looks good.

  * For consistency, phrase the verb in the first sentence of a documentation string as an infinitive with ``to'' omitted.  For instance, use ``Return the cons of A and B.'' in preference to ``Returns the cons of A and B.''  Usually it looks good to do likewise for the rest of the first paragraph.  Subsequent paragraphs usually look better if they have proper subjects.

  * Write documentation strings in the active voice, not the passive, and in the present tense, not the future.  For instance, use ``Return a list containing A and B.'' instead of ``A list containing A and B will be returned.''

  * Avoid using the word ``cause'' (or its equivalents) unnecessarily. Instead of, ``Cause Emacs to display text in boldface,'' write just ``Display text in boldface.''

  * Do not start or end a documentation string with whitespace.

  * Format the documentation string so that it fits in an Emacs window on an 80-column screen.  It is a good idea for most lines to be no wider than 60 characters.  The first line can be wider if necessary to fit the information that ought to be there.

     However, rather than simply filling the entire documentation string, you can make it much more readable by choosing line breaks with care. Use blank lines between topics if the documentation string is long.

  * Do not indent subsequent lines of a documentation string so that the text is lined up in the source code with the text of the first line.  This looks nice in the source code, but looks bizarre when users view the documentation.  Remember that the indentation before the starting double-quote is not part of the string!

  * A variable's documentation string should start with * if the variable is one that users would often want to set interactively.  If the value is a long list, or a function, or if the variable would be set only in init files, then don't start the documentation string with *.  See Defining Variables.

  * The documentation string for a variable that is a yes-or-no flag should start with words such as ``Non-nil means...'', to make it clear that all non-nil values are equivalent and indicate explicitly what nil and non-nil mean.

  * When a function's documentation string mentions the value of an argument of the function, use the argument name in capital letters as if it were a name for that value.  Thus, the documentation string of the function / refers to its second argument as DIVISOR, because the actual argument name is divisor.

     Also use all caps for meta-syntactic variables, such as when you show the decomposition of a list or vector into subunits, some of which may vary.

  * When a documentation string refers to a Lisp symbol, write it as it would be printed (which usually means in lower case), with single-quotes around it.  For example: lambda.  There are two exceptions: write t and nil without single-quotes.  In this manual, we normally do use single-quotes for those symbols.

  * Do not write key sequences directly in documentation strings.  Instead, use the \\[...] construct to stand for them.  For example, instead of writing C-f, write \\[forward-char].  When SXEmacs displays the documentation string, it substitutes whatever key is currently bound to forward-char.  This is normally C-f, but it may be some other character if the user has moved key bindings. See Keys in Documentation.

  * In documentation strings for a major mode, you will want to refer to the key bindings of that mode's local map, rather than global ones. Therefore, use the construct \\<...> once in the documentation string to specify which key map to use.

     Do this before the first use of \\[...].  The text inside the \\<...> should be the name of the variable containing the local keymap for the major mode.

     It is not practical to use \\[...] very many times, because display of the documentation string will become slow.  So use this to describe the most important commands in your major mode, and then use \\{...} to display the rest of the mode's keymap.

Tips on Writing Comments
========================

We recommend these conventions for where to put comments and how to indent them:

;
     Comments that start with a single semicolon, ;, should all be aligned to the same column on the right of the source code.  Such comments usually explain how the code on the same line does its job.

     In Lisp mode and related modes, the M-; (indent-for-comment) command automatically inserts such a ; in the right place, or aligns such a comment if it is already present.

     This and following examples are taken from the SXEmacs sources.

          (setq base-version-list                 ; there was a base
                (assoc (substring fn 0 start-vn)  ; version to which
                       file-version-assoc-list))  ; this looks like
                                                  ; a subversion

;;
     Comments that start with two semicolons, ;;, should be aligned to the same level of indentation as the code.  Such comments usually describe the purpose of the following lines or the state of the program at that point.  For example:

          (prog1 (setq auto-fill-function
                       ...
                       ...
            ;; update modeline
            (redraw-modeline)))

     Every function that has no documentation string (because it is used only internally within the package it belongs to), should have instead a two-semicolon comment right before the function, explaining what the function does and how to call it properly.  Explain precisely what each argument means and how the function interprets its possible values.

;;;
     Comments that start with three semicolons, ;;;, should start at the left margin.  Such comments are used outside function definitions to make general statements explaining the design principles of the program. For example:

          ;;; This Lisp code is run in SXEmacs
          ;;; when it is to operate as a server
          ;;; for other processes.

     Another use for triple-semicolon comments is for commenting out lines within a function.  We use triple-semicolons for this precisely so that they remain at the left margin.

          (defun foo (a)
          ;;; This is no longer necessary.
          ;;;  (force-mode-line-update)
            (message "Finished with %s" a))

;;;;
     Comments that start with four semicolons, ;;;;, should be aligned to the left margin and are used for headings of major sections of a program.  For example:

          ;;;; The kill ring

The indentation commands of the Lisp modes in SXEmacs, such as M-; (indent-for-comment) and TAB (lisp-indent-line) automatically indent comments according to these conventions, depending on the number of semicolons.  See Manipulating Comments (The SXEmacs User's Manual).

Conventional Headers for XEmacs Libraries
=========================================

SXEmacs has conventions for using special comments in Lisp libraries to divide them into sections and give information such as who wrote them.  This section explains these conventions.  First, an example:

     ;;; lisp-mnt.el --- minor mode for Emacs Lisp maintainers

     ;; Copyright (C) 1992 Free Software Foundation, Inc.

     ;; Author: Eric S. Raymond <esr@snark.thyrsus.com>
     ;; Maintainer: Eric S. Raymond <esr@snark.thyrsus.com>
     ;; Created: 14 Jul 1992
     ;; Version: 1.2

     ;; Keywords: docs

     ;; This file is part of SXEmacs.
     COPYING PERMISSIONS...

The very first line should have this format:

     ;;; FILENAME --- DESCRIPTION

The description should be complete in one line.

After the copyright notice come several header comment lines, each beginning with ;; HEADER-NAME:.  Here is a table of the conventional possibilities for HEADER-NAME:

Author
     This line states the name and net address of at least the principal author of the library.

     If there are multiple authors, you can list them on continuation lines led by ;; and a tab character, like this:

          ;; Author: Ashwin Ram <Ram-Ashwin@cs.yale.edu>
          ;;      Dave Sill <de5@ornl.gov>
          ;;      Dave Brennan <brennan@hal.com>
          ;;      Eric Raymond <esr@snark.thyrsus.com>

Maintainer
     This line should contain a single name/address as in the Author line, or an address only.  If there is no maintainer line, the person(s) in the Author field are presumed to be the maintainers.  The example above is mildly bogus because the maintainer line is redundant.

     The idea behind the Author and Maintainer lines is to make possible a Lisp function to ``send mail to the maintainer'' without having to mine the name out by hand.

     Be sure to surround the network address with <...> if you include the person's full name as well as the network address.

Created
     This optional line gives the original creation date of the file.  For historical interest only.

Version
     If you wish to record version numbers for the individual Lisp program, put them in this line.

Adapted-By
     In this header line, place the name of the person who adapted the library for installation (to make it fit the style conventions, for example).

Keywords
     This line lists keywords for the finder-by-keyword help command. This field is important; it is how people will find your package when they're looking for things by topic area.  To separate the keywords, you can use spaces, commas, or both.

Just about every Lisp library ought to have the Author and Keywords header comment lines.  Use the others if they are appropriate.  You can also put in header lines with other header names---they have no standard meanings, so they can't do any harm.

We use additional stylized comments to subdivide the contents of the library file.  Here is a table of them:

;;; Commentary:
     This begins introductory comments that explain how the library works. It should come right after the copying permissions.

;;; Change log:
     This begins change log information stored in the library file (if you store the change history there).  For most of the Lisp files distributed with SXEmacs, the change history is kept in the file ChangeLog or may be retrieved with the tla changelog shell command. They are not kept in the source file at all; these files do not have a ;;; Change log: line.

;;; Code:
     This begins the actual code of the program.

;;; FILENAME ends here
     This is the footer line; it appears at the very end of the file. Its purpose is to enable people to detect truncated versions of the file from the lack of a footer line.