anchor.diff:      (terpri (irc-connection irc))))
   
   (define-command eval (irc text)
  -  (declare (ignore irc))
  -  (format t "[eval] ~A~%" text)
  -  (eval (read-from-string text))
  -  (fresh-line))
  +  (let ((*standard-output* (display-pane irc)))
  +    (format t "[eval] ~A~%" text)
  +    (eval (read-from-string text))
  +    (fresh-line)))
   
   (define-command say (irc text)
  -  (when (and (irc-connection irc) (current-channel irc))
  -    (format t "[~A]<~A> ~A~%" (current-channel irc) (nickname irc) text)
  -    (send (irc-connection irc) "PRIVMSG ~A :~A~%"
  -          (current-channel irc) text)))
  +  (cond ((and (irc-connection irc) (current-channel irc))
  +         (format (display-pane irc) "[~A]<~A> ~A~%" (current-channel irc) (nickname irc) text)
  +         (send (irc-connection irc) "PRIVMSG ~A :~A~%"
  +               (current-channel irc) text))
  +        (t (error "Not connected or not joined to a channel."))))
   
   (define-command me (irc text)
  -  (when (and (irc-connection irc) (current-channel irc))
  -    (format t "[~A]* ~A ~A~%" (current-channel irc) (nickname irc) text)
  -    (send (irc-connection irc) "PRIVMSG ~A :~AACTION ~A~A~%"
  -          (current-channel irc) (code-char 1) text (code-char 1))))
  +  (cond ((and (irc-connection irc) (current-channel irc))
  +         (format (display-pane irc) "[~A]* ~A ~A~%" (current-channel irc) (nickname irc) text)
  +         (send (irc-connection irc) "PRIVMSG ~A :~AACTION ~A~A~%"
  +               (current-channel irc) (code-char 1) text (code-char 1)))
  +        (t (error "Not connected or not joined to a channel."))))
   
   (define-command nick (irc text)
  -  (format t "Changing nickname to ~A.~%" text)
  +  (format (display-pane irc) "~&Changing nickname to ~A.~%" text)
  +  ;; FIXME: Check status.
     (setf (nickname irc) text)
     (when (irc-connection irc)
       (send (irc-connection irc) "NICK ~A~%" (nickname irc))))
   
   (define-command connect (irc text)
     (cond ((not (nickname irc))
  -         (format t "Use /nick to set a nickname before connecting.~%"))
  +         (error "No nickname set. Use /nick to set a nickname before connecting."))
           ((irc-connection irc)
  -         (format t "Already connected.~%"))
  +         (error "Already connected to ~S." (irc-connection irc)))
           (t (multiple-value-bind (address port)
                  (resolve-server-name text)
  -             (setf (irc-connection irc) (sys.net::tcp-stream-connect address port))
  -             (sys.int::process-enable (irc-receive-process irc))
  +             (format (display-pane irc) "Connecting to ~A (~A:~A).~%" text address port)
  +             (setf (mezzanine.gui.widgets:frame-title (frame irc)) (format nil "IRC - ~A" text))
  +             (mezzanine.gui.widgets:draw-frame (frame irc))
  +             (mezzanine.gui.compositor:damage-window (window irc)
  +                                                     0 0
  +                                                     (mezzanine.gui.compositor:width (window irc))
  +                                                     (mezzanine.gui.compositor:height (window irc)))
  +             (setf (irc-connection irc) (sys.net::tcp-stream-connect address port)
  +                   (receive-thread irc) (mezzanine.supervisor:make-thread (lambda () (irc-receive irc))
  +                                                                          :name "IRC receive"))
                (send (irc-connection irc) "USER ~A hostname servername :~A~%" (nickname irc) (nickname irc))
                (send (irc-connection irc) "NICK ~A~%" (nickname irc))))))
   
   (define-command join (irc text)
  -  (if (find text (joined-channels irc) :test 'equal)
  -      (format t "Already joined to ~A.~%" text)
  -      (when (irc-connection irc)
  -        (send (irc-connection irc) "JOIN ~A~%" text)
  -        (push text (joined-channels irc))
  -        (unless (current-channel irc)
  -          (setf (current-channel irc) text)))))
  +  (cond ((find text (joined-channels irc) :test 'string-equal)
  +         (error "Already joined to channel ~A." text))
  +        ((irc-connection irc)
  +         (send (irc-connection irc) "JOIN ~A~%" text)
  +         (push text (joined-channels irc))
  +         (unless (current-channel irc)
  +           (setf (current-channel irc) text)))
  +        (t (error "Not connected."))))
   
   (define-command chan (irc text)
     (when (irc-connection irc)
  -    (if (find text (joined-channels irc) :test 'equal)
  +    (if (find text (joined-channels irc) :test 'string-equal)
           (setf (current-channel irc) text)
  -        (format t "Not joined to channel ~A." text))))
  +        (error "Not joined to channel ~A." text))))
   
   (define-command part (irc text)
     (when (and (irc-connection irc) (current-channel irc))
  
positive.code:            (values (second known) (third known)))
            (t (error "Unknown server ~S~%" name)))))
  
  (defclass irc-client (sys.graphics::character-input-mixin
                        sys.graphics::window-with-chrome
                        sys.int::simple-edit-mixin
                        sys.gray:fundamental-character-input-stream
                        sys.gray:fundamental-character-output-stream
                        sys.gray:unread-char-mixin)
    ((command-process :reader irc-command-process)
     (receive-process :reader irc-receive-process)
     (connection :initform nil :accessor irc-connection)
     (input :reader irc-input)
     (display :reader irc-display)
     (current-channel :initform nil :accessor current-channel)
     (joined-channels :initform '() :accessor joined-channels)
     (nickname :initarg :nickname :accessor nickname))
    (:default-initargs :nickname nil))
  
  ;;; This is just so the graphics manager knows the display needs an update.
  (defclass irc-display (sys.graphics::text-widget) ())
  (defmethod sys.gray:stream-write-char :after ((stream irc-display) character)
    (setf sys.graphics::*refresh-required* t))
  
  (defmethod initialize-instance :after ((instance irc-client))
    (multiple-value-bind (left right top bottom)
        (sys.graphics::compute-window-margins instance)
      (setf (slot-value instance 'display) (make-instance 'irc-display
                                                          :framebuffer (sys.graphics::window-backbuffer instance)
                                                          :x left
                                                          :y top
                                                          :width (- (array-dimension (sys.graphics::window-backbuffer instance) 1)
                                                                    left right)
                                                          :height (- (array-dimension (sys.graphics::window-backbuffer instance) 0)
                                                                     top bottom 1 16)))
      (setf (slot-value instance 'input) (make-instance 'sys.graphics::text-widget
                                                        :framebuffer (sys.graphics::window-backbuffer instance)
                                                        :x left
                                                        :y (+ top
                                                              (- (array-dimension (sys.graphics::window-backbuffer instance) 0)
                                                                 top bottom 1 16)
                                                              1)
                                                        :width (- (array-dimension (sys.graphics::window-backbuffer instance) 1)
                                                                  left right)
                                                        :height 16)))
    (let ((cmd (sys.int::make-process "IRC command"))
          (rcv (sys.int::make-process "IRC receive")))
      (setf (slot-value instance 'command-process) cmd)
      (setf (slot-value instance 'receive-process) rcv)
      (sys.int::process-preset cmd 'irc-top-level instance)
      (sys.int::process-preset rcv 'irc-receive instance)
      (sys.int::process-enable cmd)))
  
  ;;; The IRC-CLIENT stream is used to read/write from the input line, not from
  ;;; the display.
  ;;; Edit-stream expects the stream to be able to do input and output, so
  ;;; *STANDARD-INPUT* is bound to this stream (with line-editing) and
  ;;; *STANDARD-OUTPUT* is bound to the display text widget (no input).
  ;;; READ-CHAR is provided by Character-Input-Mixin.
  (defmethod sys.gray:stream-write-char ((stream irc-client) character)
    (write-char character (irc-input stream))
    (setf sys.graphics::*refresh-required* t))
  (defmethod sys.gray:stream-start-line-p ((stream irc-client))
    (sys.gray:stream-start-line-p (irc-input stream)))
  (defmethod sys.int::stream-cursor-pos ((stream irc-client))
    (sys.int::stream-cursor-pos (irc-input stream)))
  (defmethod sys.int::stream-move-to ((stream irc-client) x y)
    (sys.int::stream-move-to (irc-input stream) x y))
  (defmethod sys.int::stream-character-width ((stream irc-client) character)
    (sys.int::stream-character-width (irc-input stream) character))
  (defmethod sys.int::stream-compute-motion ((stream irc-client) string &optional (start 0) end initial-x initial-y)
    (sys.int::stream-compute-motion (irc-input stream) string start end initial-x initial-y))
  (defmethod sys.int::stream-clear-between ((stream irc-client) start-x start-y end-x end-y)
    (sys.int::stream-clear-between (irc-input stream) start-x start-y end-x end-y)
    (setf sys.graphics::*refresh-required* t))
  (defmethod sys.gray:stream-line-column ((stream irc-client))
    (sys.gray:stream-line-column (irc-input stream)))
  
  (defmethod sys.graphics::window-close-event ((irc irc-client))
    (sys.int::process-disable (irc-command-process irc))
    (sys.int::process-disable (irc-receive-process irc))
    (when (irc-connection irc)
      (close (irc-connection irc)))
    (sys.graphics::close-window irc))
  
  (defmethod sys.graphics::window-redraw ((window irc-client))
    (multiple-value-bind (left right top bottom)
        (sys.graphics::compute-window-margins window)
      (sys.graphics::bitset (sys.graphics::window-height window) (sys.graphics::window-width window)
                            (sys.graphics::window-background-colour (irc-display window))
                            (sys.graphics::window-backbuffer window) top left)
      (sys.graphics::bitset 1 (sys.graphics::window-width window)
                            (sys.graphics::make-colour :gray)
                            (sys.graphics::window-backbuffer window)
                            (+ top
                               (- (array-dimension (sys.graphics::window-backbuffer window) 0)
                                  top bottom 1 16))
                            left)))
  
  (defun irc-receive (irc)
    (let ((*standard-input* irc)
          (*standard-output* (irc-display irc))
          (*error-output* (irc-display irc))
          (*query-io* (make-two-way-stream irc (irc-display irc)))
          (*debug-io* (make-two-way-stream irc (irc-display irc))))
      ;; Should close the connection here...
      (with-simple-restart (abort "Give up")
        (let ((connection (irc-connection irc)))
          (loop (let ((line (read-line connection)))
                  (multiple-value-bind (prefix command parameters)
                      (decode-command line)
                    (let ((fn (gethash command *command-table*)))
                      (cond (fn (funcall fn irc prefix parameters))
                            ((keywordp command)
                             (format t "[~A] -!- ~A~%" prefix (car (last parameters))))
                            ((integerp command)
                             (format t "[~A] ~D ~A~%" prefix command parameters))
                            (t (write-line line)))))))))))
  
  (defvar *top-level-commands* (make-hash-table :test 'equal))
  
  
negative.code:     (values prefix command (nreverse parameters))))
  
  (defun parse-command (line)
    (cond ((and (>= (length line) 1)
                (eql (char line 0) #\/)
                (not (and (>= (length line) 2)
                          (eql (char line 1) #\/))))
           (let ((command-end nil)
                 (rest-start nil)
                 (rest-end nil))
             (dotimes (i (length line))
               (when (eql (char line i) #\Space)
                 (setf command-end i
                       rest-start i)
                 (return)))
             (when rest-start
               ;; Eat leading spaces.
               (do () ((or (>= rest-start (length line))
                           (not (eql (char line rest-start) #\Space))))
                 (incf rest-start)))
             (values (subseq line 1 command-end)
                     (subseq line (or rest-start (length line)) rest-end))))
          (t (values "say" line))))
  
  (defun send (stream control-string &rest arguments)
    "Buffered FORMAT."
  