anchor.diff:    (update-cursor-position win form)
     (refresh win))
   
  -(defun move-prev-char (win event form)
  -  "Move the cursor to the previous char in the current field."
  -  (with-accessors ((current-field .current-field)) form
  -    (with-accessors ((inptr .fill-pointer)) current-field
  -      (when (> inptr 0)
  -        (decf inptr))))
  -  (update-cursor-position win form)
  -  (refresh win))
  -
  -(defun move-next-char (win event form)
  -  "Move the cursor to the previous char in the current field."
  -  (with-accessors ((current-field .current-field)) form
  -    (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) current-field
  +(defgeneric move-prev-char (window event object)
  +  (:documentation "Move to the previous char in a field or a form."))
  +
  +(defmethod move-prev-char (win event (field field))
  +  "Move the cursor to the previous char in the field."
  +  (with-accessors ((inptr .fill-pointer)) field
  +    (when (> inptr 0)
  +      (decf inptr)))
  +  (update-cursor-position win field)
  +  (refresh win))
  +
  +(defmethod move-prev-char (win event (form form))
  +  "Move the cursor to the previous char in the current field of form."
  +  (move-prev-char win event (.current-field form)))
  +
  +(defgeneric move-next-char (window event object)
  +  (:documentation "Move to the next char in a field or a form."))
  +
  +(defmethod move-next-char (win event (field field))
  +  "Move the cursor to the next char in the field."
  +  (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) field
         (when (< inptr (length inbuf))
  -        (incf inptr))))
  -  (update-cursor-position win form)
  -  (refresh win))
  -
  -;; :backspace, delete one char to the left
  -(defun delete-prev-char (win event form)
  -  "Delete the previous char in the current field, moving the cursor to the left."
  -  (with-accessors ((current-field .current-field)) form
  -    (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) current-field
  -      (when (> inptr 0)
  -        (decf inptr)
  -        (setf inbuf (remove-nth (- (length inbuf) 1 inptr) inbuf))))
  -    ;; we dont have to redraw the complete form, just the changed field.
  -    (draw win current-field))
  -  (refresh win))
  -
  -;; :dc, delete one char to the right
  -(defun delete-next-char (win event form)
  -  "Delete the next char in the current field, not moving the cursor."
  -  (with-accessors ((current-field .current-field)) form
  -    (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) current-field
  -      ;; we can only delete to the right if the inptr is not at the end of the inbuf.
  -      (when (> (length inbuf) inptr)
  -        (setf inbuf (remove-nth (- (length inbuf) (1+ inptr)) inbuf))))
  -    (draw win current-field))
  -  (refresh win))
  -
  -;; TODO: test that char is graphic
  +        (incf inptr)))
  +  (update-cursor-position win field)
  +  (refresh win))
  +
  +(defmethod move-next-char (win event (form form))
  +  "Move the cursor to the next char in the current field of the form."
  +  (move-next-char win event (.current-field form)))
  +
  +(defgeneric delete-prev-char (window event object)
  +  (:documentation "Delete the previous char in the field or form, moving the cursor to the left."))
  +
  +(defmethod delete-prev-char (win event (field field))
  +  "Delete the previous char in the field, moving the cursor to the left."
  +  (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) field
  +    (when (> inptr 0)
  +      (decf inptr)
  +      (setf inbuf (remove-nth (- (length inbuf) 1 inptr) inbuf))))
  +  ;; we dont have to redraw the complete form, just the changed field.
  +  (draw win field))
  +
  +(defmethod delete-prev-char (win event (form form))
  +  "Delete the previous char in the field, moving the cursor to the left."
  +  (delete-prev-char win event (.current-field form)))
  +
  +(defgeneric delete-next-char (window event object)
  +  (:documentation "Delete the next char (character under the cursor) in the field or form, not moving the cursor."))
  +
  +(defmethod delete-next-char (win event (field field))
  +  "Delete the next char (char under the cursor) in the field, not moving the cursor."
  +  (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) field
  +    ;; we can only delete to the right if the inptr is not at the end of the inbuf.
  +    (when (> (length inbuf) inptr)
  +      (setf inbuf (remove-nth (- (length inbuf) (1+ inptr)) inbuf))))
  +  (draw win field))
  +
  +(defmethod delete-next-char (win event (form form))
  +  "Delete the next char (char under the cursor) in the current field of form, not moving the cursor."
  +  (delete-next-char win event (.current-field form)))
  +
  +(defun field-add-char (win char field)
  +  "Add char to the current cursor position in the field."
  +  (if (and (characterp char)
  +           (graphic-char-p char))
  +      (progn
  +        (with-accessors ((width .width) (inbuf .buffer) (inptr .fill-pointer)) field
  +          (let ((len (length inbuf)))
  +            ;; only add chars until we have reached the max width of the field
  +            ;; longer buffers and scrolling are not supported yet.
  +            (unless (>= len width)
  +              ;; if we're at the end of the inbuf
  +              (if (= inptr len)
  +                  ;; just add another char to the inbuf
  +                  (setf inbuf (cons char inbuf))
  +                  ;; if we're in the middle of the field, either insert or replace
  +                  (if (.insert-enabled win)
  +                      (setf inbuf (insert-nth  (- len inptr)      char inbuf))
  +                      (setf inbuf (replace-nth (- len (1+ inptr)) char inbuf))))
  +              ;; both replacing and inserting advance the cursor
  +              (incf inptr))))
  +        ;; after were done with editing, redraw the field.
  +        ;; TODO: redraw the entire field or echo one single char?
  +        (draw win field))
  +      ;; if char is not graphic, simply return nil.
  +      nil))
  +
   (defun form-add-char (win char form)
     "Add char to the current field of the form."
  -  (with-accessors ((current-field .current-field)) form
  -    (with-accessors ((width .width) (inbuf .buffer) (inptr .fill-pointer)) current-field
  -      (let ((len (length inbuf)))
  -        ;; only add chars when we haven reached the max width of the field
  -        ;; longer buffers and scrolling are not supported yet.
  -        (unless (= len width)
  -          ;; if we're at the end of the inbuf
  -          (if (= inptr len)
  -              ;; just add another char to the inbuf
  -              (setf inbuf (cons char inbuf))
  -              ;; if we're in the middle of the field, either insert or replace
  -              (if (.insert-enabled win)
  -                  (setf inbuf (insert-nth  (- len inptr)      char inbuf))
  -                  (setf inbuf (replace-nth (- len (1+ inptr)) char inbuf))))
  -          ;; both replacing and inserting advance the cursor
  -          (incf inptr))))
  -    ;; after were done with editing, redraw the field.
  -    ;; TODO: redraw the entire field or echo one single char?
  -    (draw win current-field))
  -  (refresh win))
  +  (field-add-char win char (.current-field form)))
   
   (defun field-buffer-to-string (field)
     "Return the value of the field buffer (list of chars) as a string."
     (coerce (reverse (.buffer field)) 'string))
   
  -(defun debug-print-field-buffer (win event form)
  +(defun debug-print-field-buffer (win event object)
     (declare (ignore event))
  -  (with-accessors ((current-field .current-field)) form
  -    (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) current-field
  -      (when (> (length inbuf) 0)
  -        (clear win)
  -        (format win "~A ~%" (coerce (reverse inbuf) 'string))
  -        (setf inbuf nil inptr 0)
  -        (draw win form) ))))
  -
  +  (typecase object
  +    (field
  +     (with-accessors ((inbuf .buffer) (inptr .fill-pointer)) object
  +       (when (> (length inbuf) 0)
  +         (clear win)
  +         (format win "~A ~%" (coerce (reverse inbuf) 'string))
  +         (setf inbuf nil inptr 0))))
  +    (form
  +     (with-accessors ((current-field .current-field)) object
  +       (debug-print-field-buffer win event current-field))))
  +  (draw win object))
  +
  +;; TODO: compare to how emacs handles keymaps, add sub-keymaps
  +;; keymap for editing forms comprised of single fields.
   (add-keymap :form-default-keymap
     (make-keymap
   
  
positive.code:       (cons element (cdr list))
        (cons (car list) (replace-nth (1- n) element (cdr list)))))
  
  ;; TODO: rename to clear, make clear a method specialized on fields
  (defun clear-field (win field)
    "Do what (clear win) does, but for a single field.
  
  clear = write space combined with the background char."
    (with-accessors ((pos .position) (width .width)) field
      (setf (.cursor-position win) pos)
      (add-char win #\space :n width)
      (setf (.cursor-position win) pos)
      ;; this is the only place we set the attribute for the whole field
      (change-attributes win width '(:underline))))
  
  ;; TODO: do we need to refresh here?
  (defun update-cursor-position (win object)
    "Update the cursor position of object, which can be a form or a single field."
    (typecase object
      (field
       (with-accessors ((pos .position) (inptr .fill-pointer)) object
         (move win
               (car pos)
               (+ (cadr pos) inptr))))
      (form
       (with-accessors ((current-field .current-field)) object
         (update-cursor-position win current-field)))))
  
  (defgeneric draw (window object)
    (:documentation "Draw forms and their elements like fields and buttons."))
  
negative.code:     ;;#\newline  'debug-print-field-buffer
      :default   'form-add-char))
  
  ;; keymap used for editing single fields which are not part of a form.
  (add-keymap :field-default-keymap
    (make-keymap
  
      ;; Use C-a ^A #\soh 1 to exit the edit loop.
      ;; TODO: what should the exit return?
      #\soh      'exit-event-loop
     
      :left      'move-prev-char
      :right     'move-next-char
      :backspace 'delete-prev-char
      :dc        'delete-next-char
  
      :ic        (lambda (win event form)
                   ;; If an optional argument like form is passed to run-event-loop,
                   ;; the handler functions have to handle it.  
                   (setf (.insert-enabled win) (not (.insert-enabled win))))
  
      ;;#\newline  'debug-print-field-buffer
      :default   'field-add-char))
  
  (defun edit (window object)
    "Allow the used to edit fields or forms."
    (draw window object)
  
    (let ((default-keymap (typecase object
                            (field :field-default-keymap)
                            (form  :form-default-keymap))))
    
      ;; if the user didnt add any event handlers, add the default keymap.
      (with-accessors ((event-handlers .event-handlers)) window
        (unless event-handlers
          (setf event-handlers (get-keymap default-keymap)))))
  
    ;; the optional arg form will be passed by run-event-loop to the
    ;; event handler functions along with win and event.
    (run-event-loop window object))
  