about summary refs log tree commit diff
path: root/configs/shared/emacs/.emacs.d/elpa/nix-mode-20180908.2240/nix-repl.el
blob: 79eeb78d03d7e4acb15f43e437b3afe43b69d811 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
;;; nix-repl.el --- Nix repl -*- lexical-binding: t -*-

;; This file is NOT part of GNU Emacs.

;;; Commentary:

;;; Code:

(defvar nix-prompt-regexp "nix-repl> ")

(require 'comint)
(require 'nix)

(defgroup nix-repl nil
  "nix-repl customizations"
  :group 'nix)

(defcustom nix-repl-executable-args '("repl")
  "Arguments to provide to nix-repl."
  :type 'list)

(define-derived-mode nix-repl-mode comint-mode "Nix-REPL"
  "Interactive prompt for Nix."
  (setq-local comint-prompt-regexp nix-prompt-regexp)
  (setq-local comint-prompt-read-only t))

(defmacro nix--with-temp-process-filter (proc &rest body)
  "Use temp process PROC filter on BODY."
  (declare (indent defun))
  `(let* ((buf (generate-new-buffer " *temp-process-output*"))
          (proc-filter-saved (process-filter ,proc))
          (proc-marker (with-current-buffer buf (point-marker))))
     (set-process-filter ,proc (nix--process-filter buf proc-marker))
     (unwind-protect
         (with-current-buffer buf
           ,@body)
       (set-process-filter ,proc proc-filter-saved)
       (kill-buffer buf))))

;;;###autoload
(defun nix-repl ()
  "Load the Nix-REPL."
  (interactive)
  (pop-to-buffer-same-window
   (get-buffer-create "*Nix-REPL*"))
  (unless (comint-check-proc (current-buffer))
    (nix--make-repl-in-buffer (current-buffer))
    (nix-repl-mode)))

(defalias 'nix-repl-show 'nix-repl)

(defun nix--make-repl-in-buffer (buffer)
  "Make Nix Repl in BUFFER."
  (apply
   'make-comint-in-buffer
   (append `("Nix-REPL" ,buffer ,nix-executable nil)
           nix-repl-executable-args)))

(defun nix-get-completions (proc prefix)
  "Get Nix completions from Nix-repl process PROC and based off of PREFIX."
  (save-match-data
    (nix--with-temp-process-filter proc
                                   (goto-char (point-min))
                                   (process-send-string proc (concat prefix "\t\"" (nix--char-with-ctrl ?a) "\"\n"))
                                   (let ((i 0))
                                     (while (and (< (setq i (1+ i)) 100)
                                                 (not (search-forward-regexp "\"\\([^\"]*\\)\"[\n]*nix-repl>" nil t)))
                                       (sleep-for 0.01))
                                     (let ((new-prefix (match-string 1))
                                           (start-compl (point)))
                                       (if (string-suffix-p " " new-prefix)
                                           (list (substring new-prefix 0 -1))
                                         (process-send-string proc (concat new-prefix "\t\t" (nix--char-with-ctrl ?u) "\n"))
                                         (goto-char start-compl)
                                         (setq i 0)
                                         (while (and (< (setq i (1+ i)) 100)
                                                     (not (search-forward-regexp
                                                           "[\n]+nix-repl>\\|Display all \\([0-9]+\\)" nil t)))
                                           (sleep-for 0.01))
                                         (if (match-string 1)
                                             (progn
                                               (process-send-string proc "n")
                                               '())
                                           (search-backward "\n" nil t)
                                           (split-string (buffer-substring start-compl (1- (point)))))))))))

(defun nix--send-repl (input &optional process mute)
  "Send INPUT to PROCESS.

MUTE if true then don’t alert user."
  (let ((proc (or process (get-buffer-process (current-buffer)))))
    (if mute
        (nix--with-temp-process-filter proc
                                       (process-send-string proc input))
      (process-send-string proc input))))

(defun nix--char-with-ctrl (char)
  "Generate control character CHAR."
  (char-to-string (logand #b10011111 char)))

(defun nix--process-filter (buf marker)
  "Process filter for Nix-rel buffer BUF at MARKER."
  (lambda (_proc string)
    (when (buffer-live-p buf)
      (with-current-buffer buf
        (save-excursion
          (goto-char marker)
          (insert string)
          (set-marker marker (point)))))))

(provide 'nix-repl)
;;; nix-repl.el ends here