0
votes

I'm trying to write an elisp function which automatically starts slime if it is not running and then changes to a certain quicklisp package after loading it in the repl. When slime is already running, the following code works. When slime gets started fresh, the quicklisp package gets loaded by slime, but the call to slime-eval-expression-in-repl doesn't seem to be exectued.

(defun cm ()
  "Start CM"
  (interactive)
  (cond ((slime-connected-p)
         (slime-eval '(ql:quickload "cm"))
         (slime-eval-expression-in-repl "(cm)")
         (switch-to-buffer (slime-repl-buffer)))
    (t
         (slime)
         (eval-after-load 'slime
           (progn
             (slime-eval '(ql:quickload "cm"))
             (slime-eval-expression-in-repl "(cm)")
             (switch-to-buffer (slime-repl-buffer)))))))

Below is the code for changing to the package and the function definition of slime-eval-expression-in-repl (adapted from 'slime-eval-last-expression-in repl). How can I solve this?

The common lisp function:

(defun cm (&rest systems)
  (flet ((cmcall (fn &rest args)
           (apply (find-symbol (string fn) :cm) args))
         (cmvar (var)
           (symbol-value (find-symbol (string var) :cm))))
    (setf *package* (find-package :cm))
    (setf *readtable* (cmvar :*cm-readtable*))
    ;; add slime readtable mapping...
    (let ((swank-pkg (find-package :swank)))
      (when swank-pkg
        (let ((sym (intern (symbol-name :*readtable-alist*) swank-pkg)))
          (setf (symbol-value sym)
                (cons (cons (symbol-name :cm) (cmvar :*cm-readtable*))
                      (symbol-value sym))))))
    (let (#-sbcl (*trace-output* nil))
      (dolist (s systems) (use-system s :verbose nil)))
    (cmcall :cm-logo)))

Here the definition of slime-eval-expression-in-repl:

(defun slime-eval-expression-in-repl (expr)
  "Evaluates expression in the Slime REPL.
Switches REPL to current package of the source buffer for the duration. If
used with a prefix argument (C-u), doesn't switch back afterwards."
  (interactive "P")
  (let ((buffer-name (buffer-name (current-buffer)))
        (new-package (slime-current-package))
        (old-package (slime-lisp-package))
        (slime-repl-suppress-prompt t)
        (yank-back nil))
    (with-current-buffer (slime-output-buffer)
      (unless (eq (current-buffer) (window-buffer))
        (pop-to-buffer (current-buffer) t))
      (goto-char (point-max))
      ;; Kill pending input in the REPL
      (when (< (marker-position slime-repl-input-start-mark) (point))
        (kill-region slime-repl-input-start-mark (point))
        (setq yank-back t))
      (unwind-protect
          (progn
            (insert-before-markers (format "\n;;; from %s\n" buffer-name))
            (when new-package
              (slime-repl-set-package new-package))
            (let ((slime-repl-suppress-prompt nil))
              (slime-repl-insert-prompt))
            (insert expr)
            (slime-repl-return)))
      ;; Put pending input back.
      (when yank-back
        (yank)))))

(BTW: I'm aware of similar questions on stackoverflow, but the answers given don't seem to apply here)

1

1 Answers

1
votes

I solved it: It is necessary to use the 'slime-connected-hook rather than eval-after-load. In addition, the function slime-eval-expression-in-repl already exists as 'slime-repl-send-string. Below is my solution. It is a little tricky as I don't want to add the slime-connected-hook permanently.

(defun load-and-start-cm ()
  (slime-eval '(ql:quickload "cm"))
  (slime-repl-send-string "(cm)")
  (switch-to-buffer (slime-repl-buffer)))

(defun load-and-start-cm-remove-hook ()
  "after starting cm remove this hook from slime-connected-hook"
  (load-and-start-cm)
  (setq slime-connected-hook
        (remove 'load-and-start-cm-remove-hook slime-connected-hook)))

(defun cm ()
  "Start CM"
  (interactive)
  (message "entering cm function.")
  (cond ((slime-connected-p)
         (load-and-start-cm))
    (t ;;; temporarily set slime-connected-hook to start cm
         (unless (member 'load-and-start-cm slime-connected-hook)
           (setq slime-connected-hook
                 (append slime-connected-hook '(load-and-start-cm-remove-hook))))
         (slime))))