Next / Previous / Contents / Shipman's homepage

5.5. ibp-tab-once: Single tab function

This function executes the tab function once. Here is its prologue, and its Cleanroom intended function. “Point” means the cursor's position within the emacs buffer.

ibp.el
(defun ibp-tab-once ()
  "Tab function for IBP data entry.

    [ if (line containing point does not have a tail)
      or (point is beyond the end of the tail) ->
        signal an error and terminate
      else if both point and the end of the line are within the
      same field ->
        buffer  :=  buffer with filler appended from the element of
                    ibp-field-list corresponding to that field, so as
                    to bring the end of line to the end of that field
        point   :=  point advanced past that field
      else ->
        point  :=  point advanced past the field containing point ]"

The “buffer” referred to above is the current editing buffer.

The next step is to start a let function, which creates a local scope in which we can manipulate two local variables:

ibp.el
  (let (line       ;; ibp-line-object for the line containing point
        field)     ;; ibp-field-object for field containing end of line

We call the ibp-analyze-line function to look at the line and return a ibp-line-object that tells us the position of the major parts of the current line.

ibp.el
    ;; [ line  :=  ibp-line-object for the line containing point ]
    (setq line (ibp-analyze-line))

The tab function works only within the tail portion of the line. If the current line has no tail, we must report an error. For the function that tests whether a line has a tail, see Section 5.17, “ibp-line-has-tail-p: Does this line have a tail?”.

ibp.el
    ;; [ if line has a tail -> I
    ;;   else -> error/exit ]
    (if (not (ibp-line-has-tail-p line))
        (error "Tab is valid only on transaction lines with a tail."))

Next we need to figure out which field contains the cursor.

The work of locating the field is done by Section 5.9, “ibp-bracket-field: What field contains a given position?”, which returns null if the cursor is past the tail, or an ibp-field-object otherwise.

ibp.el
    ;; [ if line has a tail ->
    ;;      if point is in the head of line ->
    ;;        field  :=  an ibp-field-object representing the head, with
    ;;                   nil filler
    ;;     if point is in a tail field ->
    ;;       field  :=  an ibp-field-object representing that field and
    ;;                  its filler from ibp-field-list
    ;;     if point is beyond the tail fields ->
    ;;       error/exit ]
    (setq field (ibp-bracket-field line (point)))
    (if (null field)
        (error "You are beyond the fields we know."))

If the end of the line is inside field, we have to fill out the field from the default content. In any case, we leave the cursor at the end of the field. This logic is handled by Section 5.11, “ibp-field-fill: Move to the end of a field”.

ibp.el
    (ibp-field-fill field line)))