>From ca4360cc33f56dbfd1fa1367f68d3bd3d0d7c553 Mon Sep 17 00:00:00 2001
From: Mathieu Lirzin
Date: Fri, 24 Jul 2015 12:59:20 +0200
Subject: [PATCH] emacs: Fix guix-guile-program.
* emacs/guix-backend.el: Move to ...
* emacs/guix-backend.el.in: ... here.
(guix-guile-program): Default to the Guile used when building Guix to
avoid breaking guix.el when installing another Guile.
* configure.ac: Adapt to it.
* .gitignore: Likewise.
---
.gitignore | 1 +
configure.ac | 3 +-
emacs/guix-backend.el | 378 ----------------------------------------------
emacs/guix-backend.el.in | 379 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 382 insertions(+), 379 deletions(-)
delete mode 100644 emacs/guix-backend.el
create mode 100644 emacs/guix-backend.el.in
diff --git a/.gitignore b/.gitignore
index c7a6cdd..d3499f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -119,6 +119,7 @@ GTAGS
/emacs/Makefile.in
/emacs/Makefile
/emacs/guix-autoloads.el
+/emacs/guix-backend.el
/emacs/guix-helper.scm
/emacs/guix-init.el
/emacs/guix-profiles.el
diff --git a/configure.ac b/configure.ac
index 2c8b9f0..1cbcffc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -200,7 +200,8 @@ AM_CONDITIONAL([HAVE_EMACS], [test "x$EMACS" != "xno"])
emacsuidir="${guilemoduledir}/guix/emacs"
AC_SUBST([emacsuidir])
-AC_CONFIG_FILES([emacs/guix-init.el
+AC_CONFIG_FILES([emacs/guix-backend.el
+ emacs/guix-init.el
emacs/guix-profiles.el
emacs/guix-helper.scm])
diff --git a/emacs/guix-backend.el b/emacs/guix-backend.el
deleted file mode 100644
index 73a429b..0000000
--- a/emacs/guix-backend.el
+++ /dev/null
@@ -1,378 +0,0 @@
-;;; guix-backend.el --- Communication with Geiser
-
-;; Copyright © 2014 Alex Kost
-
-;; This file is part of GNU Guix.
-
-;; GNU Guix 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 of the License, or
-;; (at your option) any later version.
-
-;; GNU Guix 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 this program. If not, see .
-
-;;; Commentary:
-
-;; This file provides the code for interacting with Guile using Geiser.
-
-;; By default (if `guix-use-guile-server' is non-nil) 2 Geiser REPLs are
-;; started. The main one (with "guile --listen" process) is used for
-;; "interacting" with a user - for showing a progress of
-;; installing/deleting Guix packages. The second (internal) REPL is
-;; used for synchronous evaluating, e.g. when information about
-;; packages/generations should be received for a list/info buffer.
-;;
-;; This "2 REPLs concept" makes it possible to have a running process of
-;; installing/deleting packages and to continue to search/list/get info
-;; about other packages at the same time. If you prefer to use a single
-;; Guix REPL, do not try to receive any information while there is a
-;; running code in the REPL (see
-;; ).
-;;
-;; If you need to use "guix.el" in another Emacs (i.e. when there is
-;; a runnig "guile --listen..." REPL somewhere), you can either change
-;; `guix-default-port' in that Emacs instance or set
-;; `guix-use-guile-server' to t.
-;;
-;; Guix REPLs (unlike the usual Geiser REPLs) are not added to
-;; `geiser-repl--repls' variable, and thus cannot be used for evaluating
-;; while editing scm-files. The only purpose of Guix REPLs is to be an
-;; intermediate between "Guix/Guile level" and "Emacs interface level".
-;; That being said you can still want to use a Guix REPL while hacking
-;; auxiliary scheme-files for "guix.el". You can just use "M-x
-;; connect-to-guile" (connect to "localhost" and `guix-default-port') to
-;; have a usual Geiser REPL with all stuff defined by "guix.el" package.
-
-;;; Code:
-
-(require 'geiser-mode)
-(require 'guix-emacs)
-
-(defvar guix-load-path
- (file-name-directory (or load-file-name
- (locate-library "guix")))
- "Directory with scheme files for \"guix.el\" package.")
-
-(defvar guix-helper-file
- (expand-file-name "guix-helper.scm" guix-load-path)
- "Auxiliary scheme file for loading.")
-
-(defvar guix-guile-program (or geiser-guile-binary "guile")
- "Name of the guile executable used for Guix REPL.
-May be either a string (the name of the executable) or a list of
-strings of the form:
-
- (NAME . ARGS)
-
-Where ARGS is a list of arguments to the guile program.")
-
-
-;;; REPL
-
-(defgroup guix-repl nil
- "Settings for Guix REPLs."
- :prefix "guix-repl-"
- :group 'guix)
-
-(defcustom guix-repl-startup-time 30000
- "Time, in milliseconds, to wait for Guix REPL to startup.
-Same as `geiser-repl-startup-time' but is used for Guix REPL.
-If you have a slow system, try to increase this time."
- :type 'integer
- :group 'guix-repl)
-
-(defcustom guix-repl-buffer-name "*Guix REPL*"
- "Default name of a Geiser REPL buffer used for Guix."
- :type 'string
- :group 'guix-repl)
-
-(defcustom guix-after-start-repl-hook ()
- "Hook called after Guix REPL is started."
- :type 'hook
- :group 'guix-repl)
-
-(defcustom guix-use-guile-server t
- "If non-nil, start guile with '--listen' argument.
-This allows to receive information about packages using an additional
-REPL while some packages are being installed/removed in the main REPL."
- :type 'boolean
- :group 'guix-repl)
-
-(defcustom guix-default-port 37246
- "Default port used if `guix-use-guile-server' is non-nil."
- :type 'integer
- :group 'guix-repl)
-
-(defvar guix-repl-buffer nil
- "Main Geiser REPL buffer used for communicating with Guix.
-This REPL is used for processing package actions and for
-receiving information if `guix-use-guile-server' is nil.")
-
-(defvar guix-internal-repl-buffer nil
- "Additional Geiser REPL buffer used for communicating with Guix.
-This REPL is used for receiving information only if
-`guix-use-guile-server' is non-nil.")
-
-(defvar guix-internal-repl-buffer-name "*Guix Internal REPL*"
- "Default name of an internal Guix REPL buffer.")
-
-(defvar guix-before-repl-operation-hook nil
- "Hook run before executing an operation in Guix REPL.")
-
-(defvar guix-after-repl-operation-hook
- '(guix-emacs-load-autoloads-maybe
- guix-repl-operation-success-message)
- "Hook run after executing successful operation in Guix REPL.")
-
-(defvar guix-repl-operation-p nil
- "Non-nil, if current operation is performed by `guix-eval-in-repl'.
-This internal variable is used to distinguish Guix operations
-from operations performed in Guix REPL by a user.")
-
-(defvar guix-repl-operation-type nil
- "Type of the current operation performed by `guix-eval-in-repl'.
-This internal variable is used to define what actions should be
-executed after the current operation succeeds.
-See `guix-eval-in-repl' for details.")
-
-(defun guix-repl-operation-success-message ()
- "Message telling about successful Guix operation."
- (message "Guix operation has been performed."))
-
-(defun guix-get-guile-program (&optional internal)
- "Return a value suitable for `geiser-guile-binary'."
- (if (or internal
- (not guix-use-guile-server))
- guix-guile-program
- (append (if (listp guix-guile-program)
- guix-guile-program
- (list guix-guile-program))
- ;; Guile understands "--listen=..." but not "--listen ..."
- (list (concat "--listen="
- (number-to-string guix-default-port))))))
-
-(defun guix-start-process-maybe (&optional start-msg end-msg)
- "Start Geiser REPL configured for Guix if needed.
-START-MSG and END-MSG are strings displayed in the minibuffer in
-the beginning and in the end of the starting process. If nil,
-display default messages."
- (guix-start-repl-maybe nil
- (or start-msg "Starting Guix REPL ...")
- (or end-msg "Guix REPL has been started."))
- (if guix-use-guile-server
- (guix-start-repl-maybe 'internal)
- (setq guix-internal-repl-buffer guix-repl-buffer)))
-
-(defun guix-start-repl-maybe (&optional internal start-msg end-msg)
- "Start Guix REPL if needed.
-If INTERNAL is non-nil, start an internal REPL.
-
-START-MSG and END-MSG are strings displayed in the minibuffer in
-the beginning and in the end of the process. If nil, do not
-display messages."
- (let* ((repl-var (guix-get-repl-buffer-variable internal))
- (repl (symbol-value repl-var)))
- (unless (and (buffer-live-p repl)
- (get-buffer-process repl))
- (and start-msg (message start-msg))
- (setq guix-repl-operation-p nil)
- (let ((geiser-guile-binary (guix-get-guile-program internal))
- (geiser-guile-init-file (or internal guix-helper-file))
- (repl (get-buffer-create
- (guix-get-repl-buffer-name internal))))
- (condition-case err
- (guix-start-repl repl
- (and internal
- (geiser-repl--read-address
- "localhost" guix-default-port)))
- (text-read-only
- (error (concat "Couldn't start Guix REPL. Perhaps the port %s is busy.\n"
- "See buffer '%s' for details")
- guix-default-port (buffer-name repl))))
- (set repl-var repl)
- (and end-msg (message end-msg))
- (unless internal
- (run-hooks 'guix-after-start-repl-hook))))))
-
-(defun guix-start-repl (buffer &optional address)
- "Start Guix REPL in BUFFER.
-If ADDRESS is non-nil, connect to a remote guile process using
-this address (it should be defined by
-`geiser-repl--read-address')."
- ;; A mix of the code from `geiser-repl--start-repl' and
- ;; `geiser-repl--to-repl-buffer'.
- (let ((impl 'guile)
- (geiser-guile-load-path (cons guix-load-path
- geiser-guile-load-path))
- (geiser-repl-startup-time guix-repl-startup-time))
- (with-current-buffer buffer
- (geiser-repl-mode)
- (geiser-impl--set-buffer-implementation impl)
- (geiser-repl--autodoc-mode -1)
- (goto-char (point-max))
- (let ((prompt (geiser-con--combined-prompt
- geiser-guile--prompt-regexp
- geiser-guile--debugger-prompt-regexp)))
- (geiser-repl--save-remote-data address)
- (geiser-repl--start-scheme impl address prompt)
- (geiser-repl--quit-setup)
- (geiser-repl--history-setup)
- (setq-local geiser-repl--repls (list buffer))
- (geiser-repl--set-this-buffer-repl buffer)
- (setq geiser-repl--connection
- (geiser-con--make-connection
- (get-buffer-process (current-buffer))
- geiser-guile--prompt-regexp
- geiser-guile--debugger-prompt-regexp))
- (geiser-repl--startup impl address)
- (geiser-repl--autodoc-mode 1)
- (geiser-company--setup geiser-repl-company-p)
- (add-hook 'comint-output-filter-functions
- 'guix-repl-output-filter
- nil t)
- (set-process-query-on-exit-flag
- (get-buffer-process (current-buffer))
- geiser-repl-query-on-kill-p)))))
-
-(defun guix-repl-output-filter (str)
- "Filter function suitable for `comint-output-filter-functions'.
-This is a replacement for `geiser-repl--output-filter'."
- (cond
- ((string-match-p geiser-guile--prompt-regexp str)
- (geiser-autodoc--disinhibit-autodoc)
- (when guix-repl-operation-p
- (setq guix-repl-operation-p nil)
- (run-hooks 'guix-after-repl-operation-hook)
- ;; Run hooks specific to the current operation type.
- (when guix-repl-operation-type
- (let ((type-hook (intern
- (concat "guix-after-"
- (symbol-name guix-repl-operation-type)
- "-hook"))))
- (setq guix-repl-operation-type nil)
- (and (boundp type-hook)
- (run-hooks type-hook))))))
- ((string-match geiser-guile--debugger-prompt-regexp str)
- (setq guix-repl-operation-p nil)
- (geiser-con--connection-set-debugging geiser-repl--connection
- (match-beginning 0))
- (geiser-autodoc--disinhibit-autodoc))))
-
-(defun guix-repl-exit (&optional internal no-wait)
- "Exit the current Guix REPL.
-If INTERNAL is non-nil, exit the internal REPL.
-If NO-WAIT is non-nil, do not wait for the REPL process to exit:
-send a kill signal to it and return immediately."
- (let ((repl (symbol-value (guix-get-repl-buffer-variable internal))))
- (when (get-buffer-process repl)
- (with-current-buffer repl
- (geiser-con--connection-deactivate geiser-repl--connection t)
- (comint-kill-subjob)
- (unless no-wait
- (while (get-buffer-process repl)
- (sleep-for 0.1)))))))
-
-(defun guix-get-repl-buffer (&optional internal)
- "Return Guix REPL buffer; start REPL if needed.
-If INTERNAL is non-nil, return an additional internal REPL."
- (guix-start-process-maybe)
- (let ((repl (symbol-value (guix-get-repl-buffer-variable internal))))
- ;; If a new Geiser REPL is started, `geiser-repl--repl' variable may
- ;; be set to the new value in a Guix REPL, so set it back to a
- ;; proper value here.
- (with-current-buffer repl
- (geiser-repl--set-this-buffer-repl repl))
- repl))
-
-(defun guix-get-repl-buffer-variable (&optional internal)
- "Return the name of a variable with a REPL buffer."
- (if internal
- 'guix-internal-repl-buffer
- 'guix-repl-buffer))
-
-(defun guix-get-repl-buffer-name (&optional internal)
- "Return the name of a REPL buffer."
- (if internal
- guix-internal-repl-buffer-name
- guix-repl-buffer-name))
-
-(defun guix-switch-to-repl (&optional internal)
- "Switch to Guix REPL.
-If INTERNAL is non-nil (interactively with prefix), switch to the
-additional internal REPL if it exists."
- (interactive "P")
- (geiser-repl--switch-to-buffer (guix-get-repl-buffer internal)))
-
-
-;;; Evaluating expressions
-
-(defvar guix-operation-buffer nil
- "Buffer from which the latest Guix operation was performed.")
-
-(defun guix-make-guile-expression (fun &rest args)
- "Return string containing a guile expression for calling FUN with ARGS."
- (format "(%S %s)" fun
- (mapconcat
- (lambda (arg)
- (cond
- ((null arg) "'()")
- ((or (eq arg t)
- ;; An ugly hack to separate 'false' from nil
- (equal arg 'f)
- (keywordp arg))
- (concat "#" (prin1-to-string arg t)))
- ((or (symbolp arg) (listp arg))
- (concat "'" (prin1-to-string arg)))
- (t (prin1-to-string arg))))
- args
- " ")))
-
-(defun guix-eval (str &optional wrap)
- "Evaluate guile expression STR.
-If WRAP is non-nil, wrap STR into (begin ...) form.
-Return a list of strings with result values of evaluation."
- (with-current-buffer (guix-get-repl-buffer 'internal)
- (let* ((wrapped (if wrap (geiser-debug--wrap-region str) str))
- (code `(:eval (:scm ,wrapped)))
- (ret (geiser-eval--send/wait code)))
- (if (geiser-eval--retort-error ret)
- (error "Error in evaluating guile expression: %s"
- (geiser-eval--retort-output ret))
- (cdr (assq 'result ret))))))
-
-(defun guix-eval-read (str &optional wrap)
- "Evaluate guile expression STR.
-For the meaning of WRAP, see `guix-eval'.
-Return elisp expression of the first result value of evaluation."
- ;; Parsing scheme code with elisp `read' is probably not the best idea.
- (read (replace-regexp-in-string
- "#f\\|#" "nil"
- (replace-regexp-in-string
- "#t" "t" (car (guix-eval str wrap))))))
-
-(defun guix-eval-in-repl (str &optional operation-buffer operation-type)
- "Switch to Guix REPL and evaluate STR with guile expression there.
-If OPERATION-BUFFER is non-nil, it should be a buffer from which
-the current operation was performed.
-
-If OPERATION-TYPE is non-nil, it should be a symbol. After
-successful executing of the current operation,
-`guix-after-OPERATION-TYPE-hook' is called."
- (run-hooks 'guix-before-repl-operation-hook)
- (setq guix-repl-operation-p t
- guix-repl-operation-type operation-type
- guix-operation-buffer operation-buffer)
- (let ((repl (guix-get-repl-buffer)))
- (with-current-buffer repl
- (geiser-repl--send str))
- (geiser-repl--switch-to-buffer repl)))
-
-(provide 'guix-backend)
-
-;;; guix-backend.el ends here
diff --git a/emacs/guix-backend.el.in b/emacs/guix-backend.el.in
new file mode 100644
index 0000000..c283131
--- /dev/null
+++ b/emacs/guix-backend.el.in
@@ -0,0 +1,379 @@
+;;; guix-backend.el --- Communication with Geiser
+
+;; Copyright © 2014 Alex Kost
+;; Copyright © 2015 Mathieu Lirzin
+
+;; This file is part of GNU Guix.
+
+;; GNU Guix 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 of the License, or
+;; (at your option) any later version.
+
+;; GNU Guix 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 this program. If not, see .
+
+;;; Commentary:
+
+;; This file provides the code for interacting with Guile using Geiser.
+
+;; By default (if `guix-use-guile-server' is non-nil) 2 Geiser REPLs are
+;; started. The main one (with "guile --listen" process) is used for
+;; "interacting" with a user - for showing a progress of
+;; installing/deleting Guix packages. The second (internal) REPL is
+;; used for synchronous evaluating, e.g. when information about
+;; packages/generations should be received for a list/info buffer.
+;;
+;; This "2 REPLs concept" makes it possible to have a running process of
+;; installing/deleting packages and to continue to search/list/get info
+;; about other packages at the same time. If you prefer to use a single
+;; Guix REPL, do not try to receive any information while there is a
+;; running code in the REPL (see
+;; ).
+;;
+;; If you need to use "guix.el" in another Emacs (i.e. when there is
+;; a runnig "guile --listen..." REPL somewhere), you can either change
+;; `guix-default-port' in that Emacs instance or set
+;; `guix-use-guile-server' to t.
+;;
+;; Guix REPLs (unlike the usual Geiser REPLs) are not added to
+;; `geiser-repl--repls' variable, and thus cannot be used for evaluating
+;; while editing scm-files. The only purpose of Guix REPLs is to be an
+;; intermediate between "Guix/Guile level" and "Emacs interface level".
+;; That being said you can still want to use a Guix REPL while hacking
+;; auxiliary scheme-files for "guix.el". You can just use "M-x
+;; connect-to-guile" (connect to "localhost" and `guix-default-port') to
+;; have a usual Geiser REPL with all stuff defined by "guix.el" package.
+
+;;; Code:
+
+(require 'geiser-mode)
+(require 'guix-emacs)
+
+(defvar guix-load-path
+ (file-name-directory (or load-file-name
+ (locate-library "guix")))
+ "Directory with scheme files for \"guix.el\" package.")
+
+(defvar guix-helper-file
+ (expand-file-name "guix-helper.scm" guix-load-path)
+ "Auxiliary scheme file for loading.")
+
+(defvar guix-guile-program "@GUILE@"
+ "Name of the guile executable used for Guix REPL.
+May be either a string (the name of the executable) or a list of
+strings of the form:
+
+ (NAME . ARGS)
+
+Where ARGS is a list of arguments to the guile program.")
+
+
+;;; REPL
+
+(defgroup guix-repl nil
+ "Settings for Guix REPLs."
+ :prefix "guix-repl-"
+ :group 'guix)
+
+(defcustom guix-repl-startup-time 30000
+ "Time, in milliseconds, to wait for Guix REPL to startup.
+Same as `geiser-repl-startup-time' but is used for Guix REPL.
+If you have a slow system, try to increase this time."
+ :type 'integer
+ :group 'guix-repl)
+
+(defcustom guix-repl-buffer-name "*Guix REPL*"
+ "Default name of a Geiser REPL buffer used for Guix."
+ :type 'string
+ :group 'guix-repl)
+
+(defcustom guix-after-start-repl-hook ()
+ "Hook called after Guix REPL is started."
+ :type 'hook
+ :group 'guix-repl)
+
+(defcustom guix-use-guile-server t
+ "If non-nil, start guile with '--listen' argument.
+This allows to receive information about packages using an additional
+REPL while some packages are being installed/removed in the main REPL."
+ :type 'boolean
+ :group 'guix-repl)
+
+(defcustom guix-default-port 37246
+ "Default port used if `guix-use-guile-server' is non-nil."
+ :type 'integer
+ :group 'guix-repl)
+
+(defvar guix-repl-buffer nil
+ "Main Geiser REPL buffer used for communicating with Guix.
+This REPL is used for processing package actions and for
+receiving information if `guix-use-guile-server' is nil.")
+
+(defvar guix-internal-repl-buffer nil
+ "Additional Geiser REPL buffer used for communicating with Guix.
+This REPL is used for receiving information only if
+`guix-use-guile-server' is non-nil.")
+
+(defvar guix-internal-repl-buffer-name "*Guix Internal REPL*"
+ "Default name of an internal Guix REPL buffer.")
+
+(defvar guix-before-repl-operation-hook nil
+ "Hook run before executing an operation in Guix REPL.")
+
+(defvar guix-after-repl-operation-hook
+ '(guix-emacs-load-autoloads-maybe
+ guix-repl-operation-success-message)
+ "Hook run after executing successful operation in Guix REPL.")
+
+(defvar guix-repl-operation-p nil
+ "Non-nil, if current operation is performed by `guix-eval-in-repl'.
+This internal variable is used to distinguish Guix operations
+from operations performed in Guix REPL by a user.")
+
+(defvar guix-repl-operation-type nil
+ "Type of the current operation performed by `guix-eval-in-repl'.
+This internal variable is used to define what actions should be
+executed after the current operation succeeds.
+See `guix-eval-in-repl' for details.")
+
+(defun guix-repl-operation-success-message ()
+ "Message telling about successful Guix operation."
+ (message "Guix operation has been performed."))
+
+(defun guix-get-guile-program (&optional internal)
+ "Return a value suitable for `geiser-guile-binary'."
+ (if (or internal
+ (not guix-use-guile-server))
+ guix-guile-program
+ (append (if (listp guix-guile-program)
+ guix-guile-program
+ (list guix-guile-program))
+ ;; Guile understands "--listen=..." but not "--listen ..."
+ (list (concat "--listen="
+ (number-to-string guix-default-port))))))
+
+(defun guix-start-process-maybe (&optional start-msg end-msg)
+ "Start Geiser REPL configured for Guix if needed.
+START-MSG and END-MSG are strings displayed in the minibuffer in
+the beginning and in the end of the starting process. If nil,
+display default messages."
+ (guix-start-repl-maybe nil
+ (or start-msg "Starting Guix REPL ...")
+ (or end-msg "Guix REPL has been started."))
+ (if guix-use-guile-server
+ (guix-start-repl-maybe 'internal)
+ (setq guix-internal-repl-buffer guix-repl-buffer)))
+
+(defun guix-start-repl-maybe (&optional internal start-msg end-msg)
+ "Start Guix REPL if needed.
+If INTERNAL is non-nil, start an internal REPL.
+
+START-MSG and END-MSG are strings displayed in the minibuffer in
+the beginning and in the end of the process. If nil, do not
+display messages."
+ (let* ((repl-var (guix-get-repl-buffer-variable internal))
+ (repl (symbol-value repl-var)))
+ (unless (and (buffer-live-p repl)
+ (get-buffer-process repl))
+ (and start-msg (message start-msg))
+ (setq guix-repl-operation-p nil)
+ (let ((geiser-guile-binary (guix-get-guile-program internal))
+ (geiser-guile-init-file (or internal guix-helper-file))
+ (repl (get-buffer-create
+ (guix-get-repl-buffer-name internal))))
+ (condition-case err
+ (guix-start-repl repl
+ (and internal
+ (geiser-repl--read-address
+ "localhost" guix-default-port)))
+ (text-read-only
+ (error (concat "Couldn't start Guix REPL. Perhaps the port %s is busy.\n"
+ "See buffer '%s' for details")
+ guix-default-port (buffer-name repl))))
+ (set repl-var repl)
+ (and end-msg (message end-msg))
+ (unless internal
+ (run-hooks 'guix-after-start-repl-hook))))))
+
+(defun guix-start-repl (buffer &optional address)
+ "Start Guix REPL in BUFFER.
+If ADDRESS is non-nil, connect to a remote guile process using
+this address (it should be defined by
+`geiser-repl--read-address')."
+ ;; A mix of the code from `geiser-repl--start-repl' and
+ ;; `geiser-repl--to-repl-buffer'.
+ (let ((impl 'guile)
+ (geiser-guile-load-path (cons guix-load-path
+ geiser-guile-load-path))
+ (geiser-repl-startup-time guix-repl-startup-time))
+ (with-current-buffer buffer
+ (geiser-repl-mode)
+ (geiser-impl--set-buffer-implementation impl)
+ (geiser-repl--autodoc-mode -1)
+ (goto-char (point-max))
+ (let ((prompt (geiser-con--combined-prompt
+ geiser-guile--prompt-regexp
+ geiser-guile--debugger-prompt-regexp)))
+ (geiser-repl--save-remote-data address)
+ (geiser-repl--start-scheme impl address prompt)
+ (geiser-repl--quit-setup)
+ (geiser-repl--history-setup)
+ (setq-local geiser-repl--repls (list buffer))
+ (geiser-repl--set-this-buffer-repl buffer)
+ (setq geiser-repl--connection
+ (geiser-con--make-connection
+ (get-buffer-process (current-buffer))
+ geiser-guile--prompt-regexp
+ geiser-guile--debugger-prompt-regexp))
+ (geiser-repl--startup impl address)
+ (geiser-repl--autodoc-mode 1)
+ (geiser-company--setup geiser-repl-company-p)
+ (add-hook 'comint-output-filter-functions
+ 'guix-repl-output-filter
+ nil t)
+ (set-process-query-on-exit-flag
+ (get-buffer-process (current-buffer))
+ geiser-repl-query-on-kill-p)))))
+
+(defun guix-repl-output-filter (str)
+ "Filter function suitable for `comint-output-filter-functions'.
+This is a replacement for `geiser-repl--output-filter'."
+ (cond
+ ((string-match-p geiser-guile--prompt-regexp str)
+ (geiser-autodoc--disinhibit-autodoc)
+ (when guix-repl-operation-p
+ (setq guix-repl-operation-p nil)
+ (run-hooks 'guix-after-repl-operation-hook)
+ ;; Run hooks specific to the current operation type.
+ (when guix-repl-operation-type
+ (let ((type-hook (intern
+ (concat "guix-after-"
+ (symbol-name guix-repl-operation-type)
+ "-hook"))))
+ (setq guix-repl-operation-type nil)
+ (and (boundp type-hook)
+ (run-hooks type-hook))))))
+ ((string-match geiser-guile--debugger-prompt-regexp str)
+ (setq guix-repl-operation-p nil)
+ (geiser-con--connection-set-debugging geiser-repl--connection
+ (match-beginning 0))
+ (geiser-autodoc--disinhibit-autodoc))))
+
+(defun guix-repl-exit (&optional internal no-wait)
+ "Exit the current Guix REPL.
+If INTERNAL is non-nil, exit the internal REPL.
+If NO-WAIT is non-nil, do not wait for the REPL process to exit:
+send a kill signal to it and return immediately."
+ (let ((repl (symbol-value (guix-get-repl-buffer-variable internal))))
+ (when (get-buffer-process repl)
+ (with-current-buffer repl
+ (geiser-con--connection-deactivate geiser-repl--connection t)
+ (comint-kill-subjob)
+ (unless no-wait
+ (while (get-buffer-process repl)
+ (sleep-for 0.1)))))))
+
+(defun guix-get-repl-buffer (&optional internal)
+ "Return Guix REPL buffer; start REPL if needed.
+If INTERNAL is non-nil, return an additional internal REPL."
+ (guix-start-process-maybe)
+ (let ((repl (symbol-value (guix-get-repl-buffer-variable internal))))
+ ;; If a new Geiser REPL is started, `geiser-repl--repl' variable may
+ ;; be set to the new value in a Guix REPL, so set it back to a
+ ;; proper value here.
+ (with-current-buffer repl
+ (geiser-repl--set-this-buffer-repl repl))
+ repl))
+
+(defun guix-get-repl-buffer-variable (&optional internal)
+ "Return the name of a variable with a REPL buffer."
+ (if internal
+ 'guix-internal-repl-buffer
+ 'guix-repl-buffer))
+
+(defun guix-get-repl-buffer-name (&optional internal)
+ "Return the name of a REPL buffer."
+ (if internal
+ guix-internal-repl-buffer-name
+ guix-repl-buffer-name))
+
+(defun guix-switch-to-repl (&optional internal)
+ "Switch to Guix REPL.
+If INTERNAL is non-nil (interactively with prefix), switch to the
+additional internal REPL if it exists."
+ (interactive "P")
+ (geiser-repl--switch-to-buffer (guix-get-repl-buffer internal)))
+
+
+;;; Evaluating expressions
+
+(defvar guix-operation-buffer nil
+ "Buffer from which the latest Guix operation was performed.")
+
+(defun guix-make-guile-expression (fun &rest args)
+ "Return string containing a guile expression for calling FUN with ARGS."
+ (format "(%S %s)" fun
+ (mapconcat
+ (lambda (arg)
+ (cond
+ ((null arg) "'()")
+ ((or (eq arg t)
+ ;; An ugly hack to separate 'false' from nil
+ (equal arg 'f)
+ (keywordp arg))
+ (concat "#" (prin1-to-string arg t)))
+ ((or (symbolp arg) (listp arg))
+ (concat "'" (prin1-to-string arg)))
+ (t (prin1-to-string arg))))
+ args
+ " ")))
+
+(defun guix-eval (str &optional wrap)
+ "Evaluate guile expression STR.
+If WRAP is non-nil, wrap STR into (begin ...) form.
+Return a list of strings with result values of evaluation."
+ (with-current-buffer (guix-get-repl-buffer 'internal)
+ (let* ((wrapped (if wrap (geiser-debug--wrap-region str) str))
+ (code `(:eval (:scm ,wrapped)))
+ (ret (geiser-eval--send/wait code)))
+ (if (geiser-eval--retort-error ret)
+ (error "Error in evaluating guile expression: %s"
+ (geiser-eval--retort-output ret))
+ (cdr (assq 'result ret))))))
+
+(defun guix-eval-read (str &optional wrap)
+ "Evaluate guile expression STR.
+For the meaning of WRAP, see `guix-eval'.
+Return elisp expression of the first result value of evaluation."
+ ;; Parsing scheme code with elisp `read' is probably not the best idea.
+ (read (replace-regexp-in-string
+ "#f\\|#" "nil"
+ (replace-regexp-in-string
+ "#t" "t" (car (guix-eval str wrap))))))
+
+(defun guix-eval-in-repl (str &optional operation-buffer operation-type)
+ "Switch to Guix REPL and evaluate STR with guile expression there.
+If OPERATION-BUFFER is non-nil, it should be a buffer from which
+the current operation was performed.
+
+If OPERATION-TYPE is non-nil, it should be a symbol. After
+successful executing of the current operation,
+`guix-after-OPERATION-TYPE-hook' is called."
+ (run-hooks 'guix-before-repl-operation-hook)
+ (setq guix-repl-operation-p t
+ guix-repl-operation-type operation-type
+ guix-operation-buffer operation-buffer)
+ (let ((repl (guix-get-repl-buffer)))
+ (with-current-buffer repl
+ (geiser-repl--send str))
+ (geiser-repl--switch-to-buffer repl)))
+
+(provide 'guix-backend)
+
+;;; guix-backend.el ends here
--
2.4.3