From 655d0c1e870d8957974961c8bfc989a75096c60a Mon Sep 17 00:00:00 2001 From: Michael Gauland
Date: Sat, 5 Jan 2013 08:03:19 +1300 Subject: [PATCH] Modify ob-scheme.el to use geiser. --- lisp/ob-scheme.el | 198 ++++++++++++++++++++++++++++++++-------------------- 1 files changed, 122 insertions(+), 76 deletions(-) diff --git a/lisp/ob-scheme.el b/lisp/ob-scheme.el index 74e9a94..9e39c72 100644 --- a/lisp/ob-scheme.el +++ b/lisp/ob-scheme.el @@ -1,8 +1,8 @@ ;;; ob-scheme.el --- org-babel functions for Scheme -;; Copyright (C) 2010-2013 Free Software Foundation, Inc. +;; Copyright (C) 2010-2012 Free Software Foundation, Inc. -;; Author: Eric Schulte +;; Authors: Eric Schulte, Michael Gauland ;; Keywords: literate programming, reproducible research, scheme ;; Homepage: http://orgmode.org @@ -33,27 +33,16 @@ ;; - a working scheme implementation ;; (e.g. guile http://www.gnu.org/software/guile/guile.html) ;; -;; - for session based evaluation cmuscheme.el is required which is -;; included in Emacs +;; - for session based evaluation geiser is required, which is available from +;; ELPA. ;;; Code: (require 'ob) -(eval-when-compile (require 'cl)) - -(declare-function run-scheme "ext:cmuscheme" (cmd)) +(load-library "geiser-impl") (defvar org-babel-default-header-args:scheme '() "Default header arguments for scheme code blocks.") -(defvar org-babel-scheme-eoe "org-babel-scheme-eoe" - "String to indicate that evaluation has completed.") - -(defcustom org-babel-scheme-cmd "guile" - "Name of command used to evaluate scheme blocks." - :group 'org-babel - :version "24.1" - :type 'string) - (defun org-babel-expand-body:scheme (body params) "Expand BODY according to PARAMS, return the expanded body." (let ((vars (mapcar #'cdr (org-babel-get-header params :var)))) @@ -65,70 +54,127 @@ ")\n" body ")") body))) -(defvar scheme-program-name) + +(defvar org-babel-scheme-repl-map (make-hash-table :test 'equal) + "Map of scheme sessions to session names.") + +(defun cleanse-org-babel-scheme-repl-map () + "Remove dead buffers from the REPL map." + (maphash + (lambda (x y) + (when (not (buffer-name y)) + (remhash x org-babel-scheme-repl-map))) + org-babel-scheme-repl-map)) + +(defun org-babel-scheme-get-session-buffer (session-name) + "Look up the scheme buffer for a session; return nil if it doesn't exist." + (cleanse-org-babel-scheme-repl-map) ; Prune dead sessions + (gethash session-name org-babel-scheme-repl-map)) + +(defun org-babel-scheme-set-session-buffer (session-name buffer) + "Record the scheme buffer used for a given session." + (puthash session-name buffer org-babel-scheme-repl-map)) + +(defun org-babel-scheme-get-buffer-impl (buffer) + "Returns the scheme implementation geiser associates with the buffer." + (with-current-buffer (set-buffer buffer) + geiser-impl--implementation)) + +(defun org-babel-scheme-get-repl (impl name) + "Switch to a scheme REPL, creating it if it doesn't exist:" + (let ((buffer (org-babel-scheme-get-session-buffer name))) + (or buffer + (progn + (run-geiser impl) + (if name + (progn + (rename-buffer name t) + (org-babel-scheme-set-session-buffer name (current-buffer))) + ) + (current-buffer) + )))) + +(defun org-babel-scheme-make-session-name (buffer name impl) + "Generate a name for the session buffer. + +For a named session, the buffer name will be the session name. + +If the session is unnamed (nil), generate a name. + +If the session is 'none', use nil for the session name, and +org-babel-scheme-execute-with-geiser will use a temporary session." + (let ((result + (cond ((not name) + (concat buffer " " (symbol-name impl) " REPL")) + ((string= name "none") nil) + (name)))) + result)) + +(defun org-babel-scheme-execute-with-geiser (code output impl repl) + "Execute code in specified REPL. If the REPL doesn't exist, create it +using the given scheme implementation. + +Returns the output of executing the code if the output parameter +is true; otherwise returns the last value." + (let ((result nil)) + (with-temp-buffer + (insert (format ";; -*- geiser-scheme-implementation: %s -*-" impl)) + (newline) + (insert (if output + (format "(with-output-to-string (lambda () %s))" code) + code) + ) + (geiser-mode) + (let ((repl-buffer (save-current-buffer (org-babel-scheme-get-repl impl repl)))) + (when (not (eq impl (org-babel-scheme-get-buffer-impl (current-buffer)))) + (message "Implementation mismatch: %s (%s) %s (s)" impl (symbolp impl) + (org-babel-scheme-get-buffer-impl (current-buffer)) + (symbolp (org-babel-scheme-get-buffer-impl (current-buffer))))) + (setq geiser-repl--repl repl-buffer) + (setq geiser-impl--implementation nil) + (geiser-eval-region (point-min) (point-max)) + (setq result + (if (equal (substring (current-message) 0 3) "=> ") + (replace-regexp-in-string "^=> " "" (current-message)) + "\"An error occurred.\"")) + (when (not repl) + (save-current-buffer (set-buffer repl-buffer) + (geiser-repl-exit)) + (set-process-query-on-exit-flag (get-buffer-process repl-buffer) nil) + (kill-buffer repl-buffer)) + (setq result (if (or (string= result "#