;;; mu.el --- play on a MUSH or MUD within Emacs
;; Copyright (C) 2001 Alex Schroeder
;; Emacs Lisp Archive Entry
;; Filename: mu.el
;; Version: 1.0.0
;; Keywords: comm, games
;; Author: Alex Schroeder
;; Maintainer: Alex Schroeder
;; Description: Play in a MUSH or MUD within Emacs.
;; Compatibility: Emacs20
;; This file is not part of GNU Emacs.
;; This is free software; you can redistribute it and/or modify it under
;; the terms of the GNU General Public License as published by the Free
;; Software Foundation; either version 2, or (at your option) any later
;; version.
;;
;; This is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
;; for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
;; MA 02111-1307, USA.
;;; Commentary:
;; This is is a MUSH or MUD client. Instead of using telnet or
;; standalone client to connect to your favorite MUSH or MUD, you can
;; use mu.el to play within Emacs.
;; I used to play using tinymud.el, but decided to rewrite it based on
;; comint-mode. :)
;; Before playing, customize `mu-worlds'. Then use `mu-open' to open a
;; connection to one of the worlds. This will automaticall create a mu
;; connection buffer and a mu buffer. You can type commands in either
;; buffer and send them to the host with RET. The output will be in the
;; mu connection buffer.
;; If you load ansi-color.el, you should be able to get ANSI colors.
;;; Code:
(require 'comint)
(load "ansi-color" t)
(defgroup mu nil
"A MUSH or MUD client."
:group 'processes)
(defcustom mu-worlds nil
"List of worlds you play in.
Each element WORLD of the list has the form
\[NAME HOST PORT CHARACTER PASSWORD]
NAME identifies the connection, HOST and PORT specify the network
connection, CHARACTER and PASSWORD are used to connect automatically.
Note that this will be saved in your `custom-file' -- including your
passwords! If you don't want that, specify nil as your password."
:type '(repeat
(vector :tag "World"
(string :tag "Name")
(string :tag "Host")
(integer :tag "Port")
(string :tag "Char")
(string :tag "Pwd")))
:group 'mu)
;; Accessing the fields
(defsubst mu-world-name (world)
"Return the name for WORLD as a string."
(concat (aref world 3) "@" (aref world 0)))
(defsubst mu-world-network (world)
"Return the network details for WORLD as a cons cell (HOST . PORT)."
(cons (aref world 1) (aref world 2)))
(defsubst mu-world-character (world)
"Return the character for WORLD as a string."
(aref world 3))
(defsubst mu-world-password (world)
"Return the password for WORLD as a string."
(aref world 4))
;;; Modes
(defvar mu-input-mode-map
(let ((map (make-sparse-keymap)))
(if (functionp 'set-keymap-parent)
(set-keymap-parent map text-mode-map); Emacs
(set-keymap-parents map (list text-mode-map))); XEmacs
(if (functionp 'set-keymap-name)
(set-keymap-name map 'mu-input-mode-map)); XEmacs
(define-key map (kbd "") 'mu-send)
map)
"Mode map used for `mu-input-mode'.
Based on `text-mode-map'.")
(defvar mu-connection nil
"Local variable for the connection.")
(defun mu-input-mode (&optional conn)
"Major mode to type commands for the mu connection.
This is called a mu input buffer.
Use \\[mu-open] to open a connection.
Use \\[mu-choose-connection] to choose a connection.
Use \\[mu-send] to send commands to the current connection.
This function will run `mu-input-mode-hook' at the end.
\\{mu-input-mode-map}"
(interactive)
(setq conn (or conn mu-connection (mu-get-connection)))
(kill-all-local-variables)
(setq major-mode 'mu-input-mode)
(setq mode-name "MU* Input")
(use-local-map mu-input-mode-map)
;; Make each buffer in mu-input-mode remember the current connection.
(set (make-local-variable 'mu-connection) conn)
;; Run hook
(run-hooks 'mu-input-mode-hook))
(defvar mu-connection-mode-map
(let ((map (make-sparse-keymap)))
(if (functionp 'set-keymap-parent)
(set-keymap-parent map comint-mode-map); Emacs
(set-keymap-parents map (list comint-mode-map))); XEmacs
(if (functionp 'set-keymap-name)
(set-keymap-name map 'mu-connection-mode-map)); XEmacs
;; (define-key map (kbd "C-j") 'mu-accumulate-and-indent)
map)
"Mode map used for `mu-connection-mode'.
Based on `comint-mode-map'.")
(defvar mu-world nil
"Local variable for the world connected to.
This is an entry from `mu-worlds'.")
(defun mu-connection-mode (world)
"Major mode for a mu connection.
Use \\[comint-send-input] to send commands.
Use \\[mu-open] to open other connections.
Use \\[mu-input-buffer] to create a mu input buffer.
This function will run `mu-connection-mode-hook' at the end.
\\{mu-connection-mode-map}"
(comint-mode)
(setq major-mode 'mu-connection-mode)
(setq mode-name "MU* Conn")
(use-local-map mu-connection-mode-map)
(set (make-local-variable 'mu-world) world)
(setq fill-column 80)
(add-to-list 'comint-output-filter-functions 'mu-fill)
;; User stuff.
(run-hooks 'mu-connection-mode-hook))
(put 'mu-connection-mode 'mode-class 'special)
;;; Opening connections
(defvar mu-world-history nil
"History for `mu-get-world'.")
(defun mu-get-world ()
"Let the user choose a world from `mu-worlds'.
The return value is a cons cell, the car is the name of the connection,
the cdr holds the connection defails from `mu-worlds'."
(let ((world-completions
(mapcar (lambda (w)
(cons (mu-world-name w) w))
mu-worlds)))
(cdr (assoc (completing-read "World: " world-completions
nil t nil mu-world-history)
world-completions))))
(defun mu-open (world)
"Create a new mu connection."
(interactive (list (mu-get-world)))
(message "Opening connection...")
(let ((buf (make-comint (mu-world-name world) (mu-world-network world))))
(pop-to-buffer buf)
(when (mu-world-password world)
(mu-login world))
(mu-connection-mode world)
(mu-input-buffer buf)
(message "Opening connection...done")))
;; (defun mu-reconnect ()
;; "Reconnect the current buffer.
;; Usefull if your modem just hung up on you and you don't want to kill the
;; mu connection buffer. Just reconnect it."
;; (interactive)
;; (unless (and (boundp 'mu-world) mu-world)
;; (error "This is not a mu connection buffer"))
;; (let ((name (mu-world-name mu-world))
;; (net (mu-world-network mu-world)))
;; (when (get-buffer-process (current-buffer))
;; (delete-process (get-process name)))
;; (open-network-stream name (concat "*" name "*")
;; (car net) (cdr net))
;; (goto-char (point-max))
;; (setq comint-last-input-start (point-marker)
;; comint-last-input-end (point-marker)
;; comint-last-output-start (point-marker)
;; comint-accum-marker (point-marker))
;; (set-marker comint-accum-marker nil)
;; (set-marker (process-mark (get-buffer-process (current-buffer)))
;; (point))))
(defun mu-login (world)
"Login for WORLD in the current buffer.
This just sends the login string and hopes for the best."
(process-send-string
(current-buffer)
(format "\nconnect %s %s\n"
(mu-world-character world)
(mu-world-password world))))
;; Creating mu mode buffers
(defun mu-input-buffer (buf)
"Create a mu input buffer for connection BUF.
The current buffer must be a mu connection."
(interactive (list (mu-get-connection)))
(set-buffer buf)
(pop-to-buffer
(get-buffer-create (concat "*Input for " (mu-world-name mu-world) "*")))
(mu-input-mode buf))
(defvar mu-connection-history nil
"History for `mu-get-connection'.")
(defun mu-get-connection ()
"Let the user choose a connection from all buffers.
Only buffers with `mu-world' set are eligible.
Note that `default-value' of `mu-world' must be nil for this to work."
(let ((buffers (buffer-list))
buf conns)
(while buffers
(setq buf (car buffers)
buffers (cdr buffers))
(set-buffer buf)
(when mu-world
(setq conns (cons (cons (mu-world-name mu-world) buf) conns))))
(cdr (assoc (completing-read "Connection: " conns
nil t nil mu-connection-history)
conns))))
;; Sending stuff
(defun mu-send ()
"Send current line to the current connection.
The current connection is stored in `mu-connection'."
(interactive)
(unless mu-connection
(error "No connection"))
(let ((pos (point)))
(save-excursion
(beginning-of-line)
(process-send-string
mu-connection
(concat (buffer-substring-no-properties (point) pos) "\n"))))
(when (looking-at "\\'")
(newline)))
;; Receiving stuff
(defun mu-fill (str)
"Fill text received from the host.
This fills each line between `comint-last-output-start' and the buffer's
`process-mark'."
(save-excursion
(let ((pos (point-marker)))
(goto-char comint-last-output-start)
(while (< (point) pos)
(let (start)
(beginning-of-line)
(setq start (point))
(forward-line)
(fill-region start (point) nil t))))))
(provide 'mu)
;;; mu.el ends here
               (
geocities.com/timessquare/6120)                   (
geocities.com/timessquare)