what1fool.info

1 guix and emacs

1.1 interacting with Guix from a REPL

1.1.1 without Geiser

Geiser is the most commonly recommended package for providing a Scheme repl. Depending on your taste this package might not be the best choice for Guix development since it implements a number of features to support working with multiple Scheme implementations.

These features don't help with developing for Guix since Guix is coupled to the Guile implementation.

At the time of this writing I am not sure if I want to understand the additional code that Geiser needs in order to support multiple Scheme implementations. So I am going to write a simplistic package to help me interact with a Guix repl. I might continue to use this code in the future or I might throw it out and go back to Geiser.

This mode will use features provided by comint. I'm using an article by Mickey Petersen as a guide.

guix repl
(defvar guix-repl-shell-script-path "/tmp/guix-repl.sh"
  "Path to the program used by `run-guix-repl`")

(defvar guix-repl-cli-arguments '()
  "Commandline arguments to pass to guix-repl.sh")

(defvar guix-repl-mode-map
  (let ((map (nconc (make-sparse-keymap) comint-mode-map)))
    ;; example
    (define-key map "\t" 'completion-at-point)
    map)
  "basic mode map for guix-repl-mode")

(defvar guix-repl-prompt-regexp "scheme@(guix-user)>"
  ;; TODO make this smarter
  "prompt for `run guix repl`")

(defun run-guix-repl ()
  "Run an inferior instance of `guix-repl-cli' inside Emacs."
  (interactive)
  (let* ((guix-repl-program guix-repl-shell-script-path)
         (buffer (comint-check-proc "Guix-Repl")))
    ;; pop to the "*Guix-Repl*" buffer if the process is dead, the
    ;; buffer is missing or it's got the wrong mode.
    (pop-to-buffer-same-window
     (if (or buffer (not (derived-mode-p 'guix-repl-mode))
             (comint-check-proc (current-buffer)))
         (get-buffer-create (or buffer "*Guix-Repl*"))
       (current-buffer)))
    ;; create the comint process if there is no buffer.
    (unless buffer
      (apply 'make-comint-in-buffer "Guix-Repl" buffer
             guix-repl-program guix-repl-cli-arguments)
      (guix-repl-mode))))

(defun guix-repl--initialize ()
  "helper function to initialize guix repl"
  (setq comint-process-echoes t)
  (setq comint-use-prompt-regexp t))

(define-derived-mode guix-repl-mode comint-mode "Guix"
  "Major mode for 'run-guix'.

\\<guix-repl-mode-map>"
  nil "guix-repl"
  (setq comint-prompt-regexp guix-repl-prompt-regexp)
  (setq comint-prompt-read-only t)
  (set (make-local-variable 'paragraph-separate) "\\'")
  (set (make-local-variable 'font-lock-defaults) '(guix-font-lock-keywords t)) ;; do we really care?
  (set (make-local-variable 'paragraph-start) guix-repl-prompt-regexp))

(add-hook 'guix-repl-mode-hook 'guix-repl--initialize)

(defun guix-repl-eval-definition ()
  (interactive)
  (save-excursion
    (end-of-defun)
    (let ((end (point)))
      (beginning-of-defun)
      (comint-send-region (get-buffer-process "*Guix-Repl*") (point) end))))

This code is far less capable than Geiser, but it has no dependencies and I feel confident that I can rewrite, debug, and extend it as needed. Given my current level of experience with Geiser, I cannot say the same about that package.

1.1.2 with Geiser

Author: Coffee Crayon

Created: 2019-08-13 Tue 10:40

Validate