|
|
|
|
;;; haskell-bot.el --- A Lambdabot interaction mode -*- lexical-binding: t -*-
|
|
|
|
|
|
|
|
|
|
;; Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
|
|
|
|
;; Copyright (C) 2001 Chris Webb
|
|
|
|
|
;; Copyright (C) 1998, 1999 Guy Lapalme
|
|
|
|
|
|
|
|
|
|
;; Keywords: inferior mode, Bot interaction mode, Haskell
|
|
|
|
|
|
|
|
|
|
;;; This file is not part of GNU Emacs.
|
|
|
|
|
|
|
|
|
|
;; This file 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 3, or (at your option)
|
|
|
|
|
;; any later version.
|
|
|
|
|
|
|
|
|
|
;; This file 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:
|
|
|
|
|
|
|
|
|
|
;; Purpose:
|
|
|
|
|
;;
|
|
|
|
|
;; To send a Haskell buffer to another buffer running a Bot
|
|
|
|
|
;; interpreter.
|
|
|
|
|
;;
|
|
|
|
|
;; This mode is derived from version 1.1 of Guy Lapalme's
|
|
|
|
|
;; haskell-hugs.el, which can be obtained from:
|
|
|
|
|
;;
|
|
|
|
|
;; http://www.iro.umontreal.ca/~lapalme/Hugs-interaction.html
|
|
|
|
|
;;
|
|
|
|
|
;; This in turn was adapted from Chris Van Humbeeck's hugs-mode.el,
|
|
|
|
|
;; which can be obtained from:
|
|
|
|
|
;;
|
|
|
|
|
;; http://www-i2.informatik.rwth-aachen.de/Forschung/FP/Haskell/hugs-mode.el
|
|
|
|
|
;;
|
|
|
|
|
;;
|
|
|
|
|
;; Installation:
|
|
|
|
|
;;
|
|
|
|
|
;; To use with Moss and Thorn's haskell-mode.el
|
|
|
|
|
;;
|
|
|
|
|
;; http://www.haskell.org/haskell-mode
|
|
|
|
|
;;
|
|
|
|
|
;; add this to .emacs:
|
|
|
|
|
;;
|
|
|
|
|
;; (add-hook 'haskell-mode-hook 'haskell-bot-mode)
|
|
|
|
|
;;
|
|
|
|
|
;;
|
|
|
|
|
;; Customisation:
|
|
|
|
|
;;
|
|
|
|
|
;; The name of the Bot interpreter is in haskell-bot-program-name.
|
|
|
|
|
;;
|
|
|
|
|
;; Arguments can be sent to the Bot interpreter when it is started by
|
|
|
|
|
;; setting haskell-bot-program-args (empty by default) to a list of
|
|
|
|
|
;; string args to pass it. This value can be set interactively by
|
|
|
|
|
;; calling C-c C-s with an argument (i.e. C-u C-c C-s).
|
|
|
|
|
;;
|
|
|
|
|
;; `haskell-bot-hook' is invoked in the *bot* buffer once Bot is
|
|
|
|
|
;; started.
|
|
|
|
|
;;
|
|
|
|
|
;; All functions/variables start with `turn-{on,off}-haskell-bot' or
|
|
|
|
|
;; `haskell-bot-'.
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
(require 'comint)
|
|
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
|
(defgroup haskell-bot nil
|
|
|
|
|
"Major mode for interacting with an inferior Bot session."
|
|
|
|
|
:group 'haskell
|
|
|
|
|
:prefix "haskell-bot-")
|
|
|
|
|
|
|
|
|
|
(define-derived-mode haskell-bot-mode comint-mode "Lambdabot")
|
|
|
|
|
|
|
|
|
|
;; Bot interface:
|
|
|
|
|
|
|
|
|
|
(require 'comint)
|
|
|
|
|
(require 'shell)
|
|
|
|
|
|
|
|
|
|
(defvar haskell-bot-process nil
|
|
|
|
|
"The active Bot subprocess corresponding to current buffer.")
|
|
|
|
|
|
|
|
|
|
(defvar haskell-bot-process-buffer nil
|
|
|
|
|
"*Buffer used for communication with Bot subprocess for current buffer.")
|
|
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
|
(defcustom haskell-bot-program-name "lambdabot"
|
|
|
|
|
"*The name of the Bot interpreter program."
|
|
|
|
|
:type 'string
|
|
|
|
|
:group 'haskell-bot)
|
|
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
|
(defcustom haskell-bot-program-args nil
|
|
|
|
|
"*A list of string args to pass when starting the Bot interpreter."
|
|
|
|
|
:type '(repeat string)
|
|
|
|
|
:group 'haskell-bot)
|
|
|
|
|
|
|
|
|
|
(defvar haskell-bot-load-end nil
|
|
|
|
|
"Position of the end of the last load command.")
|
|
|
|
|
|
|
|
|
|
(defvar haskell-bot-error-pos nil
|
|
|
|
|
"Position of the end of the last load command.")
|
|
|
|
|
|
|
|
|
|
(defvar haskell-bot-send-end nil
|
|
|
|
|
"Position of the end of the last send command.")
|
|
|
|
|
|
|
|
|
|
(defvar haskell-bot-comint-prompt-regexp
|
|
|
|
|
"^lambdabot> "
|
|
|
|
|
"A regexp that matches the Bot prompt.")
|
|
|
|
|
|
|
|
|
|
(defun haskell-bot-start-process (arg)
|
|
|
|
|
"Start a Bot process and invoke `haskell-bot-hook' if not nil.
|
|
|
|
|
Prompt for a list of args if called with an argument."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(if arg
|
|
|
|
|
;; XXX [CDW] Fix to use more natural 'string' version of the
|
|
|
|
|
;; XXX arguments rather than a sexp.
|
|
|
|
|
(setq haskell-bot-program-args
|
|
|
|
|
(read-minibuffer (format "List of args for %s:"
|
|
|
|
|
haskell-bot-program-name)
|
|
|
|
|
(prin1-to-string haskell-bot-program-args))))
|
|
|
|
|
|
|
|
|
|
;; Start the Bot process in a new comint buffer.
|
|
|
|
|
(message "Starting Lambdabot process `%s'." haskell-bot-program-name)
|
|
|
|
|
(setq haskell-bot-process-buffer
|
|
|
|
|
(apply 'make-comint
|
|
|
|
|
"lambdabot" haskell-bot-program-name nil
|
|
|
|
|
haskell-bot-program-args))
|
|
|
|
|
(setq haskell-bot-process
|
|
|
|
|
(get-buffer-process haskell-bot-process-buffer))
|
|
|
|
|
|
|
|
|
|
;; Select Bot buffer temporarily.
|
|
|
|
|
(set-buffer haskell-bot-process-buffer)
|
|
|
|
|
(haskell-bot-mode)
|
|
|
|
|
(setq comint-prompt-regexp haskell-bot-comint-prompt-regexp)
|
|
|
|
|
|
|
|
|
|
;; History syntax of comint conflicts with Haskell, e.g. !!, so better
|
|
|
|
|
;; turn it off.
|
|
|
|
|
(setq comint-input-autoexpand nil)
|
|
|
|
|
(setq comint-process-echoes nil)
|
|
|
|
|
(run-hooks 'haskell-bot-hook)
|
|
|
|
|
|
|
|
|
|
;; Clear message area.
|
|
|
|
|
(message ""))
|
|
|
|
|
|
|
|
|
|
(defun haskell-bot-wait-for-output ()
|
|
|
|
|
"Wait until output arrives and go to the last input."
|
|
|
|
|
(while (progn
|
|
|
|
|
(goto-char comint-last-input-end)
|
|
|
|
|
(not (re-search-forward comint-prompt-regexp nil t)))
|
|
|
|
|
(accept-process-output haskell-bot-process)))
|
|
|
|
|
|
|
|
|
|
(defun haskell-bot-send (&rest string)
|
|
|
|
|
"Send `haskell-bot-process' the arguments (one or more strings).
|
|
|
|
|
A newline is sent after the strings and they are inserted into the
|
|
|
|
|
current buffer after the last output."
|
|
|
|
|
(haskell-bot-wait-for-output) ; wait for prompt
|
|
|
|
|
(goto-char (point-max)) ; position for this input
|
|
|
|
|
(apply 'insert string)
|
|
|
|
|
(comint-send-input)
|
|
|
|
|
(setq haskell-bot-send-end (marker-position comint-last-input-end)))
|
|
|
|
|
|
|
|
|
|
(defun haskell-bot-show-bot-buffer ()
|
|
|
|
|
"Go to the *bot* buffer."
|
|
|
|
|
(interactive)
|
|
|
|
|
(if (or (not haskell-bot-process-buffer)
|
|
|
|
|
(not (buffer-live-p haskell-bot-process-buffer)))
|
|
|
|
|
(haskell-bot-start-process nil))
|
|
|
|
|
(pop-to-buffer haskell-bot-process-buffer))
|
|
|
|
|
|
|
|
|
|
(provide 'haskell-bot)
|
|
|
|
|
|
|
|
|
|
;;; haskell-bot.el ends here
|