anchor.diff:                                       :title "Editor"
                                        :close-button-p t
                                        :damage-function (mezzanine.gui.widgets:default-damage-function window)))
  -               (line (make-instance 'line))
                  (*editor* (make-instance 'editor
                                           :fifo fifo
  -                                        :pending-redisplay t
                                           :font font
                                           :window window
                                           :frame frame
  -                                        :first-line line
  -                                        :last-line line
  -                                        :point-line line
  -                                        :point-offset 0
  -                                        :point-column-hint 0
  -                                        :window-top-line nil
  -                                        :window-top 0
  -                                        :current-screen nil
  -                                        :current-point-logical-line nil)))
  +                                        :buffer (make-instance 'buffer))))
             (mezzanine.gui.widgets:draw-frame frame)
             (catch 'quit
               (editor-loop)))))))
  
positive.code:                (setf (pending-event *editor*) event)
                 (signal 'pending-input))))))
  
  (defgeneric line-length (line))
  
  (defmethod line-length ((line line))
    (length (data line)))
  
  ;;; Sub-editor. Buffer manipulation.
  
  (defun insert-line ()
    "Insert a new line after the point, splitting the current line if needed.
  The point is positioned at the start of the new line."
    (let* ((current-line (point-line *editor*))
           (new-line (make-instance 'line
                                    :next (next current-line)
                                    :prev current-line
                                    :data (make-array (- (line-length current-line)
                                                         (point-offset *editor*))
                                                      :element-type 'character
                                                      :adjustable t
                                                      :fill-pointer t))))
      (replace (data new-line) (data current-line)
               :start2 (point-offset *editor*))
      (cond ((next current-line)
             (setf (prev (next current-line)) new-line))
            (t (setf (last-line *editor*) new-line)))
      (incf (version current-line))
      (setf (next current-line) new-line
            (fill-pointer (data current-line)) (point-offset *editor*))
      (setf (point-line *editor*) new-line
            (point-offset *editor*) 0
            (point-column-hint *editor*) 0))
    (values))
  
  (defun insert-char (ch)
    "Insert CH after point, then advance point."
    (let ((current-line (point-line *editor*)))
      (cond ((eql (line-length current-line) (point-offset *editor*))
             ;; Inserting at end.
             (vector-push-extend ch (data current-line)))
            (t ;; Inserting in the middle or at the start.
             ;; Make sure the vector is long enough.
             (vector-push-extend ch (data current-line))
             (replace (data current-line) (data current-line)
                      :start1 (1+ (point-offset *editor*))
                      :start2 (point-offset *editor*))
             (setf (aref (data current-line) (point-offset *editor*)) ch)))
      (incf (version current-line)))
    (forward-char))
  
  (defun kill-line ()
    (let ((current-line (point-line *editor*)))
      (cond ((eql (line-length current-line) (point-offset *editor*))
             ;; At end of line. Merge current line with next.
             (when (next current-line)
               (let ((next-line (next current-line))
                     (len (line-length current-line)))
                 (adjust-array (data current-line)
                               (+ len
                                  (line-length next-line))
                               :fill-pointer t)
                 (replace (data current-line) (data next-line)
                          :start1 len)
                 (cond ((next next-line)
                        (setf (prev (next next-line)) current-line))
                       (t (setf (last-line *editor*) current-line)))
                 (setf (next current-line) (next next-line)))))
            (t ;; At start or middle of line. Trim line.
             (setf (fill-pointer (data current-line)) (point-offset *editor*))))
      (incf (version current-line)))
    (values))
  
  (defun delete-one-char-forward ()
    (let ((current-line (point-line *editor*)))
      (cond ((eql (point-offset *editor*) (line-length current-line))
             (kill-line))
            (t
             (replace (data current-line) (data current-line)
                      :start1 (point-offset *editor*)
                      :start2 (1+ (point-offset *editor*)))
             (decf (fill-pointer (data current-line)))
             (incf (version current-line))))))
  
  (defun delete-forward-char (&optional (n 1))
    "Delete the following N characters (previous if N is negative)."
    (cond ((minusp n)
           (setf n (- n))
           (dotimes (i n)
             (when (and (eql (point-line *editor*) (first-line *editor*))
                        (eql (point-offset *editor*) 0))
               (return))
             (backward-char)
             (delete-one-char-forward)))
          (t
           (dotimes (i n)
             (when (and (eql (point-line *editor*) (last-line *editor*))
                        (eql (point-offset *editor*) (line-length (last-line *editor*))))
               (return))
             (delete-one-char-forward))))
    (values))
  
  (defun delete-backward-char (&optional (n 1))
    (delete-forward-char (- n)))
  
  ;;; Point motion.
  
  (defun move-beginning-of-line ()
    (setf (point-offset *editor*) 0
          (point-column-hint *editor*) 0)
    (values))
  
  (defun move-end-of-line ()
    (setf (point-offset *editor*) (line-length (point-line *editor*))
          (point-column-hint *editor*) (line-length (point-line *editor*)))
    (values))
  
  (defun forward-char (&optional (n 1))
    "Move point forward by N characters. N may be negative."
    (cond ((minusp n)
           (setf n (- n))
           (dotimes (i n)
             (let ((current-line (point-line *editor*)))
               (cond ((eql 0 (point-offset *editor*))
                      ;; At start of line.
                      (when (prev current-line)
                        (setf (point-line *editor*) (prev current-line)
                              (point-offset *editor*) (line-length (prev current-line)))))
                     (t ;; Moving within a line.
                      (decf (point-offset *editor*)))))))
          (t
           (dotimes (i n)
             (let ((current-line (point-line *editor*)))
               (cond ((eql (line-length current-line) (point-offset *editor*))
                      ;; At end of line.
                      (when (next current-line)
                        (setf (point-offset *editor*) 0
                              (point-line *editor*) (next current-line))))
                     (t ;; Moving within a line.
                      (incf (point-offset *editor*))))))))
    (setf (point-column-hint *editor*) (point-offset *editor*))
    (values))
  
  (defun backward-char (&optional (n 1))
    (forward-char (- n)))
  
  (defun next-line (&optional (n 1))
    "Move point down by N lines. N may be negative.
  Tries to stay as close to the current column as possible."
    (let ((accessor #'next))
      (when (minusp n)
        (setf n (- n)
              accessor #'prev))
      (dotimes (i n)
        (let* ((current-line (point-line *editor*))
               (new-line (funcall accessor current-line)))
          (cond (new-line
                 (setf (point-offset *editor*) (min (point-column-hint *editor*)
                                                    (line-length new-line))
                       (point-line *editor*) new-line))
                (t (return))))))
    (values))
  
  (defun previous-line (&optional (n 1))
    (next-line (- n)))
  
  ;;; Redisplay.
  
  ;; Lines are currently fixed-height.
  (defun window-rows ()
  
negative.code:   (when (not (mezzanine.gui.compositor:key-releasep event))
      (throw 'next-character
        (if (mezzanine.gui.compositor:key-modifier-state event)
            ;; Force character to uppercase when a modifier key is active, gets
            ;; around weirdness in how character names are processed.
            ;; #\C-a and #\C-A both parse as the same character (C-LATIN_CAPITAL_LETTER_A).
            (sys.int::make-character (char-code (char-upcase (mezzanine.gui.compositor:key-key event)))
                                     :control (find :control (mezzanine.gui.compositor:key-modifier-state event))
                                     :meta (find :meta (mezzanine.gui.compositor:key-modifier-state event))
  