235 lines
6.6 KiB
EmacsLisp
Executable file
235 lines
6.6 KiB
EmacsLisp
Executable file
;;;
|
|
;;; distel-ie - an interactive erlang shell
|
|
;;;
|
|
;;; Some of the code has shamelessly been stolen from Luke Gorrie
|
|
;;; [luke@bluetail.com] - ripped from its elegance and replaced by bugs.
|
|
;;; It just goes to show that you can't trust anyone these days. And
|
|
;;; as if that wasn't enough, I'll even blame Luke: "He _made_ me do it!"
|
|
;;;
|
|
;;; So, without any remorse, I hereby declare this code to be:
|
|
;;;
|
|
;;; copyright (c) 2002 david wallin [david.wallin@ul.ie].
|
|
;;;
|
|
;;; (it's probably going to be released onto an unexpecting public under
|
|
;;; some sort of BSD license).
|
|
|
|
(eval-when-compile (require 'cl))
|
|
(require 'erlang)
|
|
(require 'erl)
|
|
|
|
(make-variable-buffer-local
|
|
(defvar erl-ie-node nil
|
|
"Erlang node that the session is hosted on."))
|
|
|
|
;;
|
|
;; erl-ie-session
|
|
|
|
(defun erl-ie-session (node)
|
|
"Return the erl-ie-session for NODE, creating it if necessary."
|
|
(interactive (list (erl-ie-read-nodename)))
|
|
|
|
(or (get-buffer (erl-ie-buffer-name node))
|
|
(erl-ie-create-session node)))
|
|
|
|
(defun erl-ie-create-session (node)
|
|
(with-current-buffer (get-buffer-create (erl-ie-buffer-name node))
|
|
(insert "\
|
|
%%% Welcome to the Distel Interactive Erlang Shell.
|
|
%%
|
|
%% C-j evaluates an expression and prints the result in-line.
|
|
%% C-M-x evaluates a whole function definition.
|
|
|
|
")
|
|
(push-mark (point) t)
|
|
|
|
(erlang-mode)
|
|
(erl-session-minor-mode 1)
|
|
(setq erl-ie-node node)
|
|
|
|
;; hiijack stdin/stdout :
|
|
(let ((output-buffer (current-buffer)))
|
|
(setq erl-group-leader
|
|
(erl-spawn (&erl-ie-group-leader-loop output-buffer))))
|
|
|
|
(erl-ie-ensure-registered node)
|
|
|
|
(current-buffer)))
|
|
|
|
(defun erl-ie-read-nodename ()
|
|
"Get the node for the session, either from buffer state or from the user."
|
|
(or erl-ie-node (erl-target-node)))
|
|
|
|
(defun erl-ie-buffer-name (node)
|
|
(format "*ie session <%S>*" node))
|
|
|
|
;;
|
|
;; erl-ie-ensure-registered
|
|
|
|
(defun erl-ie-ensure-registered (node)
|
|
(interactive (list (erl-ie-read-nodename)))
|
|
(erl-spawn
|
|
(erl-send-rpc node 'distel_ie 'ensure_registered '())))
|
|
|
|
|
|
(defun erl-ie-eval-expression (node)
|
|
(interactive (list (erl-ie-read-nodename)))
|
|
(erl-ie-read-nodename)
|
|
(let ((end (point))
|
|
(beg (save-excursion
|
|
(loop do (re-search-backward "^$")
|
|
while (looking-at "end"))
|
|
(point))))
|
|
(erl-ie-evaluate beg end node t)))
|
|
|
|
(defun erl-ie-eval-defun (node)
|
|
(interactive (list (erl-ie-read-nodename)))
|
|
(erl-ie-read-nodename)
|
|
(let* ((beg (save-excursion (erlang-beginning-of-function)
|
|
(point)))
|
|
(end (save-excursion (goto-char beg)
|
|
(erlang-end-of-function)
|
|
(point))))
|
|
(erl-ie-evaluate beg end node)))
|
|
|
|
;;
|
|
;; erl-ie-evaluate
|
|
;;
|
|
;; this is doomed to fail, can end be the smaller value ?
|
|
;; want to change to (interactive "r") somehow ...
|
|
|
|
(defun erl-ie-evaluate (start end node &optional inline)
|
|
"Evaluate region START to END on NODE.
|
|
The marked region can be a function definition, a function
|
|
call or an expression."
|
|
(interactive (list
|
|
(region-beginning)
|
|
(region-end)
|
|
(erl-ie-read-nodename)))
|
|
|
|
(let* ((string (buffer-substring-no-properties start end))
|
|
(buffer (current-buffer)))
|
|
(erl-spawn
|
|
(erl-send (tuple 'distel_ie node)
|
|
(tuple 'evaluate erl-self string))
|
|
|
|
(message "Sent eval request..")
|
|
|
|
;; move cursor to after the marked region
|
|
(goto-char (min (point-max) (1+ end)))
|
|
(erl-receive (buffer inline)
|
|
((['ok value]
|
|
(if inline
|
|
(with-current-buffer buffer
|
|
;; Clear "Sent eval request.." message
|
|
(message "")
|
|
|
|
(let ((my-point (point)))
|
|
(unless (looking-at "^")
|
|
(end-of-line)
|
|
(insert "\n"))
|
|
|
|
(let ((beg (point)))
|
|
;; Insert value, indent all lines of it 4 places,
|
|
;; then draw a " => " at the start.
|
|
(insert value)
|
|
(save-excursion (indent-rigidly beg (point) 5)
|
|
(goto-char beg)
|
|
(delete-region (point) (+ (point) 5))
|
|
(insert " -:-> ")))
|
|
(insert "\n")
|
|
(goto-char my-point)
|
|
(push-mark (point) t)))
|
|
(display-message-or-view (format "Result: %s" value)
|
|
"*Evaluation Result*")))
|
|
|
|
(['msg msg]
|
|
(with-current-buffer buffer
|
|
(message msg)))
|
|
|
|
(['error reason]
|
|
(with-current-buffer buffer
|
|
|
|
;; TODO: should check the buffer for first non-whitespace
|
|
;; before we do:
|
|
(newline 1)
|
|
(insert "Error: ") (insert reason) (newline 1)))
|
|
|
|
(other
|
|
(message "Unexpected: %S" other)))))))
|
|
|
|
|
|
(defun erl-ie-xor (a b)
|
|
"Boolean exclusive or of A and B."
|
|
(or (and a (not b))
|
|
(and b (not a))))
|
|
|
|
;;
|
|
;; &erl-ie-group-leader-loop
|
|
|
|
(defun &erl-ie-group-leader-loop (buf)
|
|
(erl-receive (buf)
|
|
((['put_chars s]
|
|
(with-current-buffer buf
|
|
(insert s))))
|
|
(&erl-ie-group-leader-loop buf)))
|
|
|
|
|
|
;;
|
|
;; erl-ie-show-session
|
|
|
|
(defun erl-ie-show-session (node)
|
|
"Show the session for NODE, creating if necessary."
|
|
(interactive (list (erl-ie-read-nodename)))
|
|
(switch-to-buffer (erl-ie-session node)))
|
|
|
|
;;
|
|
;; erl-ie-copy-buffer-to-session
|
|
|
|
(defun erl-ie-copy-buffer-to-session (node)
|
|
"Open a distel_ie session on NODE with the content of the current buffer.
|
|
The content is pasted at the end of the session buffer. This can be useful
|
|
for debugging a file without ruining the content by mistake."
|
|
(interactive (list (erl-ie-read-nodename)))
|
|
(let ((cloned-buffer (buffer-string)))
|
|
|
|
(with-current-buffer (erl-ie-session node)
|
|
(goto-char (point-max))
|
|
(insert cloned-buffer))
|
|
(erl-ie-popup-buffer node)))
|
|
|
|
;;
|
|
;; erl-ie-copy-region-to-session
|
|
|
|
(defun erl-ie-copy-region-to-session (start end node)
|
|
"Open a distel_ie session on NODE with the content of the region.
|
|
The content is pasted at the end of the session buffer. This can be useful
|
|
for debugging a file without ruining the content by mistake."
|
|
(interactive (list
|
|
(region-beginning)
|
|
(region-end)
|
|
(erl-ie-read-nodename)))
|
|
(let ((cloned-region (buffer-substring-no-properties start end)))
|
|
|
|
(with-current-buffer (erl-ie-session node)
|
|
(goto-char (point-max))
|
|
(set-mark (point)) ; so the region will be right
|
|
(insert cloned-region))
|
|
(erl-ie-popup-buffer node)))
|
|
|
|
|
|
(defun erl-ie-popup-buffer (node)
|
|
(switch-to-buffer (erl-ie-session node)))
|
|
|
|
;; ------------------------------------------------------------
|
|
;; Session minor mode.
|
|
|
|
(define-minor-mode erl-session-minor-mode
|
|
"Minor mode for Distel Interactive Sessions."
|
|
nil
|
|
nil
|
|
'(("\C-j" . erl-ie-eval-expression)
|
|
("\C-\M-x" . erl-ie-eval-defun)))
|
|
|
|
(provide 'distel-ie)
|
|
|