Programming With Minor Modes (StumpWM Manual)

### 10.1 Programming With Minor Modes ¶

Minor modes get their power from their ability to override and augment generic functions which are called with the minor mode’s scope object as an argument. If you find a function whose behavior you wish to augment or override in the process of writing a minor mode, open an issue or submit a PR to generify the function. Generification is easily done like so:

    (defun somefun (a b)
      "docstring"
      (otherfun (+ a b)))
    ;; the above becomes
    (defgeneric somefun (a b)
      (:documentation "docstring")
      (:method (a b)
        (otherfun (+ a b))))

When defining a minor mode, the programmer may desire to perform setup for the minor mode. This is can be done in three ways. The first is to hang a function upon the minor modes enable hook. However this runs the risk of users potentially clobbering the initialization function, or modifying the hook such that the initialization function is not the first function run. The second way is to define a method for the generic function `update-instance-for-different-class`. This function should specialize upon the minor mode as the second argument. As a final option, one can define before, after, and around methods for the generic function `autoenable-minor-mode` if and only if the method does not access any slots within the object.

One of the pitfalls of minor modes is that they are ultimately enabled by calling `change-class`, which places some restrictions upon where they can be enabled. Specifically, it is implied to be undefined behavior if a minor mode is enabled in an object from within a method which accesses slots of that object. While in practice this has not proven to be an issue at the time of writing, this is undefined behavior and future versions of SBCL may break if this is done.

When writing a minor mode, it is often useful to separate out the desired functionality into its own mixin classes and use those in the superclass list of the minor mode. For example:

    (define-minor-mode my-mode (my-mixin minor-mode) ())

This prevents issues with inheritance and dynamic mixins from cropping up. Since minor modes are just classes, a minor mode can descend from another minor mode. However after enabling the subclass minor mode, the superclass minor mode cannot be enabled. However if the superclass minor mode is enabled first, then the subclass minor mode can be enabled. The easiest way around this is the aforementioned approach of mixins. As an example of the inheritance issue, take the following minor mode definitions:

    (define-minor-mode x () ())
    (define-minor-mode y (x) ())

    (enable-minor-mode 'x)
    (enable-minor-mode 'y) ; both modes are enabled
    ;; As opposed to
    (enable-minor-mode 'y)
    (enable-minor-mode 'x) ; signals an error

When enabling and disabling minor modes theres a set of generic functions in charge of determining what object to mix the minor mode in to and whether or not to mix it.

Function: autoenable-minor-mode mode object ¶

  The core of enabling minor modes within an object. Mixes the minor mode in to the object

Defining a minor mode defines a main method for this generic function which will mix the minor mode into the scope object when called and returns T. This method specializes upon the minor mode symbol and the scope type. The minor mode will only be enabled and the hooks run when the function `ENABLE-WHEN` returns T. Any before after or around methods for this function must not access any slots.

Function: autodisable-minor-mode mode object ¶

  The core of disabling minor modes within an object. Calls the minor modes on-disable function.

Defining a minor mode defines a main method for this generic function which specializes upon the mode symbol and the mode, and removes the minor mode from the object. Any methods for this function must not access any slots.

Function: enable-when mode object ¶

  Define methods for this generic function to control when the minor mode should be enabled.

Outside of autoenabling and autodisabling minor modes, there are several generic functions which dispatch upon minor modes and their names.

Function: minor-mode-global-p minor-mode-symbol ¶

  Return T when MINOR-MODE-SYMBOL denotes a global minor mode

Function: minor-mode-scope minor-mode-symbol ¶

  Return as a keyword the scope of the minor mode

Function: minor-mode-enable-hook minor-mode-symbol ¶

  Returns the minor mode enable hook for a given minor mode symbol. This hook is run whenever the minor mode is enabled via autoenable.

Function: minor-mode-disable-hook minor-mode-symbol ¶

  Returns the minor mode disable hook for a given minor mode symbol. This hook is run whenever the minor mode is disabled via autodisable.

Function: minor-mode-hook minor-mode-symbol ¶

  Returns the minor mode hook for a given minor mode symbol. This hook is run whenever the minor mode is explicitly enabled.

Function: minor-mode-keymap minor-mode ¶

  Return the top map for the minor mode

This function has a set of main methods defined which all call the next method to obtain a list of top maps for every minor mode. Any extra keymaps one wishes to add to the minor mode may be added by defining a main method which calls `call-next-method` and returns a flat list. Similarly, an around method may be used which abides by the same rules.

Function: minor-mode-lighter mode ¶

  Return a string of minor mode lighters.

This function operates similarly to `minor-mode-keymap`, with a main method defined for every minor mode which calls `call-next-method` and returns a flat list. In addition there is a single around method defined which concatenates all these strings together.

There are also a set of regular functions and special variables which which may be of use when working with minor modes.

Function: enable-minor-mode minor-mode &optional scope-object ¶

  Default Values:

        scope-object  nil

  Enable MINOR-MODE. If MINOR-MODE is global, then enable it in all relevant objects. Otherwise enable it in the current object. If SCOPE-OBJECT is provided, use SCOPE-OBJECT instead of the current object, or include it in the list of current objects if MINOR-MODE is global

Function: disable-minor-mode minor-mode &optional scope-object ¶

  Default Values:

        scope-object  nil

  Disable MINOR-MODE in the relevant objects.

Function: list-modes object ¶

  List all minor modes followed by the major mode for OBJECT.

Function: list-minor-modes object ¶

  List all minor modes active in OBJECT

Function: current-minor-modes &optional screen ¶

  Default Values:

        screen  (stumpwm:current-screen)

  Return all currently active minor modes.

Function: minor-mode-enabled-p minor-mode &optional screen ¶

  Default Values:

        screen  (stumpwm:current-screen)

  Return T if MINOR-MODE is active

Function: find-minor-mode minor-mode &optional screen ¶

  Default Values:

        screen  (stumpwm:current-screen)

  Return the minor mode object associated with MINOR-MODE.

Variable: *minor-mode* ¶

  A dynamic variable bound to the minor mode object when executing a minor mode command.

Variable: *minor-mode-enable-hook* ¶

  A hook run whenever a minor mode is enabled. Functions are called with the minor mode symbol and the object they have been added to. This is run when a minor mode is explicitly enabled via enable-minor-mode.

Variable: *minor-mode-disable-hook* ¶

  A hook run whenever a minor mode is disabled. Functions are called with the minor mode symbol and the scope object. This is run when a minor mode is explicitly disabled via disable-minor-mode. This is run AFTER the minor mode has been disabled, and is called with the minor mode and the first object it was disabled in.

Variable: *unscoped-minor-modes* ¶

  A dynamic variable holding all unscoped minor modes as mixed into the same object.

Class: minor-mode ¶

  The root minor mode class. All minor modes are subclasses of this class.
  Direct Superclasses: standard-object
  Direct Subclasses:
  Direct Slots: