Emacs ringing system: program internals

Here is the documentation for those who'd like to extend or modify this software. For changes by version number, see the changes page.

Data structures

Methods are represented by change-ringing-method structures, each of which has the descriptive information title and nbells and the change data plain, bob, and single, each of which is a list of changes, where a change is a string (used as a vector of small numbers; an actual vector of numbers would work, too) in which each element is the number of the place that the bell in that place goes to next, the places being numbered, and the string indexed, from 1 up i.e. the 0th element is not used. (See the description of ringing:ring-one-change for more details of how to use it.)

change-ringing-method

(defstruct change-ringing-method
  title
  nbells
  plain					; work plus plain lead end
  work					; just the work, no lead end
  plain-lead-end			; just the lead end
  bob
  single
  original-description-string)

The methods parsed from a file are kept in an alist of method name to method definitions, where a method definition is a list of lead end code (as a lisp symbol such as mx) and place notation (as a string). To get the list of methods for a file, use (microSiRiL:parse-file-superficially filename), which uses a cache.

To get the change-ringing-method for a method by name, use (ringing:find-named-method method-name). If you want to find whether the method exists, give a non-nil optional second argument (otherwise it gives an error if the method is not known). This reads the appropriate file for you automatically.

If given a change-ringing-method, ringing:find-named-method returns it. There is also a function ringing:method-name which takes a change-ringing-method and returns the name of it, or, given a string, returns the string. Use this in preference to change-ringing-method-title, for flexibility. By using these two functions, many functions in the emacs-ringing system can take either a method name or a method data structure, converting it as needed.

user-mistakes:method

(defstruct user-mistakes:method
  method				; back to actual method structure
  leads					; array of user-mistakes:lead structures
  )

user-mistakes:lead

(defstruct user-mistakes:lead
  method				; back to user-mistakes:method
  place					; which place bell
  row-faults				; each kind of fault, per row
					; (including the non-faults!
					; this is as count vector [ down places up ]
  which-row				; where we are
  attempts                              ; how many times we've tried this lead
  perfects				; how many times we've rung this lead perfectly
  total-faults				; how many faults we've made on this lead altogether
  latest-faults				; how many faults we've made last time we rang this
  )

Method groups

The list of method groups is stored as an alist of group names to group definitions, where a group definition is as follows:

(defstruct method-groups:method-group
  "Description of a group of methods."
  title stage
  ;; There are two forms of this: if stage=0, methods is an alist of method
  ;; names (in their short form, e.g. "Cambridge") to nil; if stage>0, it
  ;; is an alist of method names (in their full form, e.g. "Cambridge Surprise Major")
  ;; to method structures.
  methods
  code-letters
  title-style-default
  style-default
  layout-default)
where methods is an alist of method names to change-ringing-methods (when the group has been instantiated at a particular stage) or nil (if the group hasn't specified what stage it's at, and the user hasn't been asked). You should get the backbone of the list of groups via the function method-groups:all-groups (which will handle the ephemeral groups for you) and the group definition bodies via method-groups:group-methods, which will fill in the change-ringing-methods (they may be nil in the result of method-groups:all-groups).

Program structure

The elisp files linked to below may not be present individually on the server, but when you've downloaded the package, they will be reachable from your local copy of this file, which is included in the archive for download.

ringing.el
Loads the other files, and does the configuration.
beer.el (Basis Emacs Engine for Ringing)
This contains the central routines of the system, which run from lists of changes as described below. If you're writing extensions to this system, this is probably where you'll want to hook in. From the top level, you'll probably want to call ringing:ring-from-rounds, but the most useful routines to understand are ringing:ring-one-change and ringing:ring-changes.
(ringing:ring-one-change row change)
Applies change to change and returns the result. The arguments may both be strings or vectors (they are usually strings). Its arguments are as follows:
row
a row of bells, starting from index position 1, for example " 123456\n" (character 0 of the string, and any characters beyond those used by the method, are copied over unchanged, which may be useful for marking lines in various ways; my higher-level code in this software stores a newline at the end of each row, so it is automatically inserted in the buffer as results are displayed). It doesn't matter what the characters in here are; they'll normally either be numbers (or letters for higher-numbered bells) but could be dots, spaces and asterisks for drawing just the line bells, for example.
change
Each element of this is the position that that bell will go to next; the character in the 0th element is ignored. For example, the first change of Plain Hunt on 6 (as a vector, to avoid displaying control characters in this web page) is [ 0 2 1 4 3 6 5 ].
(ringing:ring-changes row changes continue-fn continue-args display-fn display-args)
which from row rings changes; each time it first calls ringing:ring-one-change and then calls continue-fn on
  • the resulting row
  • remaining changes
  • continue-args
each time.
If it returns
a string or array
that is used as the next row;
a list
the car of it is used as the next row, and the cdr of it as a continuation of changes.
The display-fn and display-args are then used similarly, but the result is ignored. ringing:ring-changes returns the resulting row when all of changes (including any continuations added by fn) have been used.
The continue-fn is normally used for adding lead ends.
(ringing:ring-from-rounds method continue-function continue-args display-function display-args)
This is the main entry point for beer.el. It is similar to ringing:ring-changes but sets up rounds as the starting point, and initializes various useful variables. There is also ringing:ring-from-rounds-plain, which is similar (and has the same arguments) but skips anything to do with displaying the results -- it is meant for proving compositions, etc.
(ringing:advance-changes row changes)
Starts from row and works forward changes, without any callbacks.
(ringing:retreat-changes row changes)
Returns the row from which you would have had to start to get to row by ringing changes, without any callbacks.
place-notation.el
Hairy parsing routines; oddly enough, these take advantage of Lisp being only partly a functional programming language.
ringing-methods.el
Manages the list of known methods.
method-library.el
Reads microSiRiL method library files.
bell-numbers.el
Converts between characters and numbers, and handles movements relative to the previous position of your bell.
manual-ringing.el
Handles main ringing input from the user.
plain-courses.el
Handles plain courses.
touches.el
Handles touches. These can be entered as strings of lead ends, or (soon) in the common tabular notation (the latter is not completely implemented yet). There is some skeletal code here that I'm not really meaning to release at the stage, but have put here on the net to give me a chance to look at it with more experienced ringers on their machines -- don't expect it to work entirely, but feel welcome to tell me where my understanding is mistaken!
stages.el
Handles numbers of bells (e.g. minor=6).
method-display.el
The higher-level part of outputting lines, numbers and so on.
method-lines.el
Outputs changes with the lines drawn beside the numbers. Lines are drawn with * for the blue line, and . for the red line. Optionally, real lines are drawn between the rows, using \, |, and /.
bell-colours.el
Colours the digits and lines using emacs faces.
mSiRiL-mode.el
Major mode for microSiRiL files.
ermm.el
Emacs Ringing Multi-Media is the place to put hacks for outputting the bell strokes in whatever cute ways you like. At the moment it just uses mini-ropes.el (q.v.) but will probably sometime get sound added.
mini-ropes.el
Draws miniature bell-ropes going up and down to represent handstroke and backstroke.
teacher.el
Teaching code, to throw random place bells at you from suitable collections of methods; and also intensive teaching code.
method-groups.el
Handles a directory of files of method groups, which look like this:
# Plain methods
p Plainbob
p Stclementscollegebob
where the code at the start of the line is the non-numeric part of the name of the file to look in in the method library, and the rest of the line is the name of the method. Comment lines begin with a #.
ps-config.el
Manages the configuration of PostScript style control variables.
ps-line.el
Output methods in PostScript.
general-header.ps
PostScript used by ps-line.el.
crib-line.el
Outputs a one-lead crib sheet for the help window.
placenotation-mode.el
Place notation grid editor / explorer.
composition-checker.el
Entry point is ringing:check-touch, which checks whether a given composition is true; may be supplied with rows rung so far to check against, so it can be used incrementally to see whether you can add a particular sequence of calls to something you've already started.
ringing-menu.el
Provides menu access to the rest of the package.
touch-book.el
Maintains a list of what you have rung so far, and how successfully.
user-mistakes.el
Keeps track of the user's mistakes, for use while teaching.
test.el
May from time to time contain test and debugging routines.

[John's ringing page] [John's home] Back to emacs-ringing index.
John C. G. Sturdy
Last modified: Thu Jul 30 09:14:16 1998