[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3 StumpWM Types

All command arguments must be of a defined “StumpWM type”. The following types are pre-defined:

:y-or-n

A yes or no question returning T or NIL.

:variable

A lisp variable

:function

A lisp function

:command

A StumpWM command as a string.

:key-seq

A key sequence starting from *TOP-MAP*

:window-number

An existing window number

:number

An integer number

:string

A string

:key

A single key chord

:window-name

An existing window’s name

:direction

A direction symbol. One of :UP :DOWN :LEFT :RIGHT

:gravity

A gravity symbol. One of :center :top :right :bottom :left :top-right :top-left :bottom-right :bottom-left

:group

An existing group

:frame

A frame

:shell

A shell command

:rest

The rest of the input yet to be parsed.

:module

An existing StumpWM module

Additional types can be defined using the macro define-stumpwm-type. Emacs users who are accustomed to writing more complicated interactive declarations using "(interactive (list …))" forms will find that similar logic can be put into StumpWM type definitions. The macro is called like this:

 
(define-stumpwm-type :type-name (input prompt) body)

The keyword :type-name will then be available for use in defcommand macros. When commands are called, the bodies of these type definitions are called in turn to produce actual argument values.

Type definitions produce their value in one of several ways: by reading it from the argument line bound to a keystroke, by prompting the user to enter a value, or by generating it programmatically.

Within the body of the type definition, the argument “input” is bound to the argument line provided in the command string, and “prompt” to the string prompt provided in the defcommand form. The usual convention is to first check if an argument has been provided in “input” and, if it hasn’t, to prompt for it using “prompt”.

StumpWM provides several convenience functions for handling the value of “input”:

As an example, here’s a new type called :smart-direction. The existing :direction type simply asks for one of the four directions “left”, “right”, “up” or “down”, without checking to see if there’s a frame in that direction. Our new type, :smart-direction, will look around the current frame, and only allow the user to choose a direction in which another frame lies. If only one direction is possible it will return that automatically without troubling the user. It signals an error for invalid directions; it could alternately return a “nil” value in those cases, and let the command handle that.

 
(define-stumpwm-type :smart-direction (input prompt)
  (let ((valid-dirs
         (loop  ; gather all the directions in which there's a neighbouring frame
            with values = '(("up" :up)
                            ("down" :down)
                            ("left" :left)
                            ("right" :right))
            with frame-set =
              (group-frames (window-group (current-window)))
            for dir in values
            for neighbour = (neighbour
                             (second dir)
                             (window-frame (current-window)) frame-set)
            if (and neighbour (frame-window neighbour))
            collect dir))
        (arg (argument-pop input)))  ; store a possible argument
    (cond ((null valid-dirs)  ; no directions, bail out
           (throw 'error "No valid directions"))
          (arg  ; an arg was bound, but is it valid?
           (or (second (assoc arg valid-dirs :test #'string=))
               (throw 'error "Not a valid direction")))
          ((= 1 (length valid-dirs))  ; only one valid direction
           (second (car valid-dirs)))
          (t  ; multiple possibilities, prompt for direction
           (second (assoc (completing-read input prompt valid-dirs
                                           :require-match t)
                          valid-dirs :test #'string=))))))

(defcommand smarty (dir) ((:smart-direction "Pick a direction: "))
  ;; `dir' is a keyword here
  (message "You're going ~a" (string-downcase dir)))

(define-key *root-map* (kbd "R") "smarty right")
Macro: define-stumpwm-type type(input prompt) &body body

Create a new type that can be used for command arguments. type can be any symbol.

When body is evaluated input is bound to the argument-line. It is passed to argument-pop, argument-pop-rest, etc. prompt is the prompt that should be used when prompting the user for the argument.

 
(define-stumpwm-type :symbol (input prompt)
 (or (find-symbol
       (string-upcase
         (or (argument-pop input)
             ;; Whitespace messes up find-symbol.
             (string-trim " "
                          (completing-read (current-screen)
                                           prompt
                                           ;; find all symbols in the
                                           ;;  stumpwm package.
                                           (let (acc)
                                             (do-symbols (s (find-package "STUMPWM"))
                                               (push (string-downcase (symbol-name s)) acc))
                                             acc)))
             (throw 'error "Abort.")))
       "STUMPWM")
     (throw 'error "Symbol not in STUMPWM package")))

(defcommand "symbol" (sym) ((:symbol "Pick a symbol: "))
  (message "~a" (with-output-to-string (s)
                    (describe sym s))))

This code creates a new type called :symbol which finds the symbol in the stumpwm package. The command symbol uses it and then describes the symbol.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated on February 2, 2024 using texi2html 1.82.