Next / Previous / Contents / Shipman's homepage

5.10. ibp-bracket-tail-field: What tail field contains the cursor?

This function tries to find which tail field contains the cursor, and returns an ibp-field-object if successful. If the cursor is not within any tail field, it returns nil.

This function assumes that ibp-field-list is globally defined as a list of field-def objects that describe the format of the tail fields.

ibp.el
;; - - -   i b p - b r a c k e t - t a i l - f i e l d   - - -

(defun ibp-bracket-tail-field (line)
  "Finds the tail field containing point, if any.

    [ if (line is a ibp-line-object for the line containing point)
      and (line is a type that has a tail) ->
        if point is within a tail field ->
          return an ibp-field-object describing that field
        else ->
          return nil ]
----------------------------------------------------------------"

First we open a let scope, and define some local variables:

flag

Set initially to 'scanning, this variable is changed to 'found if we found the correct field, or 'not-found if we go past the end of the line.

fieldx

Points to the current element of ibp-field-list.

n-fields

Points to the last+1 element of ibp-field-list.

field-def

Holds the current field-def object from ibp-field-list.

f-beg

Holds the position of the beginning of the current field.

f-end

Holds the last+1 position of the current field.

f-len

Holds the length of the current field.

ibp.el
  (let (flag                 ;; Changing this value exits the while loop
        fieldx               ;; Indexes ibp-field-list
        n-fields             ;; Index of last element of ibp-field-list
        field-def            ;; Holds each field-def object in turn
        f-beg                ;; Walks the start columns of each field
        f-end                ;; End of the current field
        f-len)               ;; Length of the current field

We set up initial values before walking the record.

ibp.el
    ;; [ flag      :=  'scanning
    ;;   fieldx    :=  0
    ;;   n-fields  :=  index of last element of ibp-field-list
    ;;   f-beg     :=  location of tail of line ]
    (setq flag 'scanning)
    (setq fieldx 0)
    (setq n-fields (length ibp-field-list))
    (setq f-beg (ibp-line-tail line))

The while loop runs until the value of flag is changed to something other than 'scanning.

ibp.el
    ;; [ if point is within a field whose length is given in
    ;;   elements fieldx through (n-fields - 1) of ibp-field-list ->
    ;;     flag   :=  'found
    ;;     f-beg  :=  position of the start of that field
    ;;     f-end  :=  position of the end of that field
    ;;   else ->
    ;;     flag   :=  'not-found
    ;;     f-beg  :=  anything
    ;;     f-end  :=  anything ]
    (while (eq flag 'scanning)

Here is the intended function for the body of this loop:

ibp.el
      ;; [ if fieldx >= n-fields ->
      ;;     flag  :=  'not-found
      ;;   else if point is within a field starting at f-beg and having
      ;;   length field-lengths[fieldx] ->
      ;;     flag  :=  'found
      ;;   else ->
      ;;     f-beg   :=  f-beg + ibp-field-list[fieldx].len
      ;;     fieldx  :=  fieldx + 1 ]

If fieldx has exceeded the number of fields in ibp-field-list, set flag to 'not-found, and we are done.

ibp.el
      (if (>= fieldx n-fields)
          (setq flag 'not-found)

The progn construct executes all the functions inside it, and returns the value of the last one. First we set up the values of the loop variables by extracting them from the fieldxth element of ibp-field-list.

ibp.el
        (progn         ;; The field exists, is point in it?
          (setq field-def (elt ibp-field-list fieldx))
          (setq f-len (ibp-field-def-len field-def)) ;; Get the length...
          (setq f-end (+ f-beg f-len))        ;; ...and end of next field

If the cursor is at or beyond f-beg, and it is before f-end, we have found the field containing the cursor; we set flag to 'found so the loop will terminate successfully.

ibp.el
          (if (and (>= (point) f-beg)   ;; Is f-beg<=point<f-end?
                  (< (point) f-end))
              (setq flag 'found)         ;; Yes, found it

If the cursor isn't in the current field, move f-beg to the end of the field, increment fieldx, and go around the loop again.

ibp.el
            (progn                       ;; No, keep looking
              (setq f-beg f-end)
              (setq fieldx (1+ fieldx)))))))

If the loop terminated unsuccessfully, flag will now be 'not-found, so we should return nil to signify that we couldn't find the cursor's field. If it was successful, we package up an ibp-field-object made from the current field beginning and end positions, along with the default field content from ibp-field-list, and return that to the caller.

ibp.el
    ;; [ if flag is 'not-found ->
    ;;     return nil
    ;;   else ->
    ;;     return an ibp-field-object whose .beg=f-beg, .end=f-end,
    ;;     and .filler=ibp-field-list[fieldx].filler ]
    (if (eq flag 'not-found)
        nil
      (ibp-field-object f-beg f-end
                    (ibp-field-def-filler (elt ibp-field-list fieldx))))))