Scheme version checks
authorJose Antonio Ortega Ruiz <jao@gnu.org>
Wed, 25 Sep 2013 03:10:00 +0000 (25 05:10 +0200)
committerJose Antonio Ortega Ruiz <jao@gnu.org>
Wed, 25 Sep 2013 03:10:00 +0000 (25 05:10 +0200)
And, if you happen to be launching it all the time, a way of skipping
them via a customizable variable.

Should address issue #15.

NEWS
doc/repl.texi
elisp/geiser-base.el
elisp/geiser-guile.el
elisp/geiser-racket.el
elisp/geiser-repl.el

diff --git a/NEWS b/NEWS
index 5cb751c..e5e4606 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,7 @@
 
   New features:
 
-   - Geiser is now available from MELPA.
+   - Geiser is now available from MELPA, with the help of Steve Purcell.
    - Racket: new commands geiser-racket-{show, hide, toggle}-submodules,
      for folding submodule forms in code buffers.
    - Racket: interaction with submodules (entering them and evaluation
@@ -12,6 +12,7 @@
    - Pressing return on a previous expression in the REPL will resend
      it, by Darren Hoo.
    - Improvements to syntax highlighting (define/match in racket).
+   - Version checks for the underlying Scheme process.
 
   Bug fixes:
 
index 8b32de7..acab26e 100644 (file)
@@ -345,16 +345,27 @@ not the case, the variables to tweak are @code{geiser-guile-binary} and
 @code{geiser-racket-binary}, which should be set to a string with the
 full path to the requisite binary.
 
+@cindex Version checking
+Before starting the REPL, Geiser will check wether the version of your
+Scheme interpreter is good enough.  This means that it will spend a
+couple tenths of a second launching and quickly discarding a Scheme
+process, but also that the error message you'll get if you're on the
+wrong Scheme version will be much more informative.  If you one to
+avoid version checks, just check
+@code{geiser-repl-skip-version-check-p} to @code{t} in your
+configuration.
+
 @cindex scheme load path
 @cindex scheme init file
 @cindex GUILE_LOAD_PATH
+@cindex GUILE_LOAD_COMPILED_PATH
 @cindex PLTCOLLECTS
-You can also specify a couple more initialisation parameters.  For Guile,
-@code{geiser-guile-load-path} is a list of paths to add to its load path
-when it's started, while @code{geiser-guile-init-file} is the path to an
-initialisation file to be loaded on start-up.  The equivalent variables
-for Racket are @code{geiser-racket-collects} and
-@code{geiser-racket-init-file}.
+You can also specify a couple more initialisation parameters.  For
+Guile, @code{geiser-guile-load-path} is a list of paths to add to its
+load path (and its compiled load path) when it's started, while
+@code{geiser-guile-init-file} is the path to an initialisation file to
+be loaded on start-up.  The equivalent variables for Racket are
+@code{geiser-racket-collects} and @code{geiser-racket-init-file}.
 
 Note, however, that specifying @code{geiser-guile-init-file} is @i{not}
 equivalent to changing Guile's initialization file (@file{~/.guile}),
index 2569034..e564b0f 100644 (file)
@@ -1,6 +1,6 @@
 ;;; geiser-base.el --- shared bits
 
-;; Copyright (C) 2009, 2010, 2012  Jose Antonio Ortega Ruiz
+;; Copyright (C) 2009, 2010, 2012, 2013  Jose Antonio Ortega Ruiz
 
 ;; This program is free software; you can redistribute it and/or
 ;; modify it under the terms of the Modified BSD License. You should
   (let ((thing (thing-at-point 'symbol)))
     (and thing (make-symbol thing))))
 
+(defun geiser--cut-version (v)
+  (when (string-match "\\([0-9]+\\.[0-9]\\(?:\\.[0-9]+\\)?\\).*" v)
+    (match-string 1 v)))
+
+(defun geiser--version< (v1 v2)
+  (let ((v1 (geiser--cut-version v1))
+        (v2 (geiser--cut-version v2)))
+    (and v1 v2 (version< v1 v2))))
+
 \f
 (provide 'geiser-base)
index 9182807..bc96973 100644 (file)
@@ -289,6 +289,11 @@ This function uses `geiser-guile-init-file' if it exists."
 \f
 ;;; REPL startup
 
+(defconst geiser-guile-minimum-version "2.0")
+
+(defun geiser-guile--version (binary)
+  (shell-command-to-string (format "%s  -c '(display (version))'" binary)))
+
 (defun geiser-guile-update-warning-level ()
   "Update the warning level used by the REPL.
 The new level is set using the value of `geiser-guile-warning-level'."
@@ -364,6 +369,8 @@ it spawn a server thread."
 (define-geiser-implementation guile
   (binary geiser-guile--binary)
   (arglist geiser-guile--parameters)
+  (version-command geiser-guile--version)
+  (minimum-version geiser-guile-minimum-version)
   (repl-startup geiser-guile--startup)
   (prompt-regexp geiser-guile--prompt-regexp)
   (debugger-prompt-regexp geiser-guile--debugger-prompt-regexp)
index 9b98945..59886e3 100644 (file)
@@ -358,7 +358,12 @@ using start-geiser, a procedure in the geiser/server module."
  (with-handlers: 1))
 
 \f
-;;; Startup
+;;; REPL Startup
+
+(defvar geiser-racket-minimum-version "5.3")
+
+(defun geiser-racket--version (binary)
+  (shell-command-to-string (format "%s  -e '(display (version))'" binary)))
 
 (defun geiser-racket--startup (remote)
   (set (make-local-variable 'compilation-error-regexp-alist)
@@ -412,6 +417,8 @@ Use a prefix to be asked for a submodule name."
 (define-geiser-implementation racket
   (unsupported-procedures '(callers callees generic-methods))
   (binary geiser-racket--binary)
+  (minimum-version geiser-racket-minimum-version)
+  (version-command geiser-racket--version)
   (arglist geiser-racket--parameters)
   (repl-startup geiser-racket--startup)
   (prompt-regexp geiser-racket--prompt-regexp)
index 68e4708..ebb74c2 100644 (file)
@@ -105,6 +105,16 @@ expression, if any."
   :type 'boolean
   :group 'geiser-repl)
 
+(geiser-custom--defcustom geiser-repl-skip-version-check-p nil
+  "Whether to skip version checks for the Scheme executable.
+
+When set, Geiser won't check the version of the Scheme
+interpreter when starting a REPL, saving a few tenths of a
+second.
+"
+  :type 'boolean
+  :group 'geiser-repl)
+
 (geiser-custom--defcustom geiser-repl-query-on-exit-p nil
   "Whether to prompt for confirmation on \\[geiser-repl-exit]."
   :type 'boolean
@@ -188,6 +198,13 @@ module command as a string")
 (geiser-impl--define-caller geiser-repl--exit-cmd exit-command ()
   "Function returning the REPL exit command as a string")
 
+(geiser-impl--define-caller geiser-repl--version version-command (binary)
+  "Function returning the version of the corresponding scheme process,
+   given its full path.")
+
+(geiser-impl--define-caller geiser-repl--min-version minimum-version ()
+  "A variable providing the minimum required scheme version, as a string.")
+
 \f
 ;;; Geiser REPL buffers and processes:
 
@@ -355,6 +372,13 @@ module command as a string")
                                     geiser-repl-query-on-kill-p)
     (message "%s up and running!" (geiser-repl--repl-name impl))))
 
+(defun geiser-repl--check-version (impl)
+  (when (not geiser-repl-skip-version-check-p)
+    (let ((v (geiser-repl--version impl (geiser-repl--binary impl)))
+          (r (geiser-repl--min-version impl)))
+      (when (geiser--version< v r)
+        (error "Geiser requires %s version %s but detected %s" impl r v)))))
+
 (defun geiser-repl--start-scheme (impl address prompt)
   (setq comint-prompt-regexp prompt)
   (let* ((name (geiser-repl--repl-name impl))
@@ -363,6 +387,7 @@ module command as a string")
                  `(,(geiser-repl--binary impl)
                    nil
                    ,@(geiser-repl--arglist impl)))))
+    (when (not address) (geiser-repl--check-version impl))
     (condition-case err
         (apply 'make-comint-in-buffer `(,name ,buff ,@args))
       (error (insert "Unable to start REPL:\n"