Commit | Line | Data |
---|---|---|
f029f8a7 AK |
1 | ;;; guix-geiser.el --- Interacting with Geiser -*- lexical-binding: t -*- |
2 | ||
3 | ;; Copyright © 2015 Alex Kost <alezost@gmail.com> | |
4 | ||
5 | ;; This file is part of GNU Guix. | |
6 | ||
7 | ;; GNU Guix is free software; you can redistribute it and/or modify | |
8 | ;; it under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation, either version 3 of the License, or | |
10 | ;; (at your option) any later version. | |
11 | ||
12 | ;; GNU Guix is distributed in the hope that it will be useful, | |
13 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;; GNU General Public License for more details. | |
16 | ||
17 | ;; You should have received a copy of the GNU General Public License | |
18 | ;; along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | ||
20 | ;;; Commentary: | |
21 | ||
22 | ;; This file provides functions to evaluate guile code using Geiser. | |
23 | ||
24 | ;;; Code: | |
25 | ||
26 | (require 'geiser-mode) | |
f80a7a6c | 27 | (require 'guix-guile) |
f029f8a7 AK |
28 | |
29 | (defun guix-geiser-repl () | |
30 | "Return the current Geiser REPL." | |
31 | (or geiser-repl--repl | |
32 | (geiser-repl--repl/impl 'guile) | |
33 | (error "Geiser REPL not found"))) | |
34 | ||
35 | (defun guix-geiser-eval (str &optional repl) | |
36 | "Evaluate STR with guile expression using Geiser REPL. | |
37 | If REPL is nil, use the current Geiser REPL. | |
38 | Return a list of strings with result values of evaluation." | |
39 | (with-current-buffer (or repl (guix-geiser-repl)) | |
40 | (let ((res (geiser-eval--send/wait `(:eval (:scm ,str))))) | |
41 | (if (geiser-eval--retort-error res) | |
42 | (error "Error in evaluating guile expression: %s" | |
43 | (geiser-eval--retort-output res)) | |
44 | (cdr (assq 'result res)))))) | |
45 | ||
46 | (defun guix-geiser-eval-read (str &optional repl) | |
47 | "Evaluate STR with guile expression using Geiser REPL. | |
48 | Return elisp expression of the first result value of evaluation." | |
4c68c538 AK |
49 | ;; The goal is to convert a string with scheme expression into elisp |
50 | ;; expression. | |
51 | (let ((result (car (guix-geiser-eval str repl)))) | |
52 | (cond | |
53 | ((or (string= result "#f") | |
54 | (string= result "#<unspecified>")) | |
55 | nil) | |
56 | ((string= result "#t") | |
57 | t) | |
58 | (t | |
59 | (read (replace-regexp-in-string | |
60 | "[ (]\\(#f\\)" "nil" | |
61 | (replace-regexp-in-string | |
62 | "[ (]\\(#t\\)" "t" | |
63 | result | |
64 | nil nil 1) | |
65 | nil nil 1)))))) | |
f029f8a7 AK |
66 | |
67 | (defun guix-repl-send (cmd &optional save-history) | |
68 | "Send CMD input string to the current REPL buffer. | |
69 | This is the same as `geiser-repl--send', but with SAVE-HISTORY | |
70 | argument. If SAVE-HISTORY is non-nil, save CMD in the REPL | |
71 | history." | |
72 | (when (and cmd (eq major-mode 'geiser-repl-mode)) | |
73 | (geiser-repl--prepare-send) | |
74 | (goto-char (point-max)) | |
75 | (comint-kill-input) | |
76 | (insert cmd) | |
77 | (let ((comint-input-filter (if save-history | |
78 | comint-input-filter | |
79 | 'ignore))) | |
80 | (comint-send-input nil t)))) | |
81 | ||
82 | (defun guix-geiser-eval-in-repl (str &optional repl no-history no-display) | |
83 | "Switch to Geiser REPL and evaluate STR with guile expression there. | |
84 | If NO-HISTORY is non-nil, do not save STR in the REPL history. | |
85 | If NO-DISPLAY is non-nil, do not switch to the REPL buffer." | |
86 | (let ((repl (or repl (guix-geiser-repl)))) | |
87 | (with-current-buffer repl | |
88 | ;; XXX Since Geiser 0.8, `geiser-repl--send' has SAVE-HISTORY | |
89 | ;; argument, so use this function eventually and remove | |
90 | ;; `guix-repl-send'. | |
91 | (guix-repl-send str (not no-history))) | |
92 | (unless no-display | |
93 | (geiser-repl--switch-to-buffer repl)))) | |
94 | ||
5a60d569 AK |
95 | (defun guix-geiser-eval-in-repl-synchronously (str &optional repl |
96 | no-history no-display) | |
97 | "Evaluate STR in Geiser REPL synchronously, i.e. wait until the | |
98 | REPL operation will be finished. | |
99 | See `guix-geiser-eval-in-repl' for the meaning of arguments." | |
100 | (let* ((repl (if repl (get-buffer repl) (guix-geiser-repl))) | |
101 | (running? nil) | |
102 | (filter (lambda (output) | |
103 | (setq running? | |
104 | (and (get-buffer-process repl) | |
105 | (not (guix-guile-prompt? output)))))) | |
106 | (comint-output-filter-functions | |
107 | (cons filter comint-output-filter-functions))) | |
108 | (guix-geiser-eval-in-repl str repl no-history no-display) | |
109 | (while running? | |
110 | (sleep-for 0.1)))) | |
111 | ||
f80a7a6c AK |
112 | (defun guix-geiser-call (proc &rest args) |
113 | "Call (PROC ARGS ...) synchronously using the current Geiser REPL. | |
114 | PROC and ARGS should be strings." | |
115 | (guix-geiser-eval | |
116 | (apply #'guix-guile-make-call-expression proc args))) | |
117 | ||
118 | (defun guix-geiser-call-in-repl (proc &rest args) | |
119 | "Call (PROC ARGS ...) in the current Geiser REPL. | |
120 | PROC and ARGS should be strings." | |
121 | (guix-geiser-eval-in-repl | |
122 | (apply #'guix-guile-make-call-expression proc args))) | |
123 | ||
f029f8a7 AK |
124 | (provide 'guix-geiser) |
125 | ||
126 | ;;; guix-geiser.el ends here |