[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/nix-mode 5fa017c6ad 393/500: Merge pull request #105 from
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/nix-mode 5fa017c6ad 393/500: Merge pull request #105 from rossabaker/completions |
Date: |
Sat, 29 Jan 2022 08:27:47 -0500 (EST) |
branch: elpa/nix-mode
commit 5fa017c6ad8df662388b5bb1366322e0571d8d1e
Merge: 0cf1ea1e0e c52795de7d
Author: Matthew Bauer <mjbauer95@gmail.com>
Commit: GitHub <noreply@github.com>
Merge pull request #105 from rossabaker/completions
Fix nix-get-completions, add to nix-repl-mode
---
nix-repl.el | 137 +++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 108 insertions(+), 29 deletions(-)
diff --git a/nix-repl.el b/nix-repl.el
index 8d9f2d6ed0..b525091b01 100644
--- a/nix-repl.el
+++ b/nix-repl.el
@@ -21,10 +21,25 @@
"Arguments to provide to nix-repl."
:type 'list)
+(defvar nix-repl-completion-redirect-buffer
+ " *nix-repl completions redirect*"
+ "Buffer to be used to redirect output of readline commands.")
+
+(defcustom nix-repl-completion-output-timeout 1.0
+ "Time in seconds to wait for completion output before giving up."
+ :type 'float)
+
+(defvar nix-repl-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\t" 'completion-at-point)
+ map))
+
(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))
+ (setq-local comint-prompt-read-only t)
+ (add-hook 'completion-at-point-functions
+ #'nix-repl-completion-at-point nil 'local))
(defmacro nix--with-temp-process-filter (proc &rest body)
"Use temp process PROC filter on BODY."
@@ -58,33 +73,97 @@
(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-get-completions (process input)
+ "Get completions for INPUT using native readline for PROCESS."
+ (with-current-buffer (process-buffer process)
+ (let* ((original-filter-fn (process-filter process))
+ (redirect-buffer (get-buffer-create
+ nix-repl-completion-redirect-buffer))
+ (trigger "\t")
+ (new-input (concat input trigger))
+ (input-length
+ (save-excursion
+ (+ (- (point-max) (comint-bol)) (length new-input))))
+ (delete-line-command (make-string input-length ?\b))
+ (input-to-send (concat new-input delete-line-command)))
+ ;; Ensure restoring the process filter, even if the user quits
+ ;; or there's some other error.
+ (unwind-protect
+ (with-current-buffer redirect-buffer
+ ;; Cleanup the redirect buffer
+ (erase-buffer)
+ ;; Mimic `comint-redirect-send-command', unfortunately it
+ ;; can't be used here because it expects a newline in the
+ ;; command and that's exactly what we are trying to avoid.
+ (let ((comint-redirect-echo-input nil)
+ (comint-redirect-completed nil)
+ (comint-redirect-perform-sanity-check nil)
+ (comint-redirect-insert-matching-regexp t)
+ (comint-redirect-finished-regexp nix-prompt-regexp)
+ (comint-redirect-output-buffer redirect-buffer))
+ (set-process-filter
+ process (apply-partially
+ #'comint-redirect-filter original-filter-fn))
+ (process-send-string process input-to-send)
+ ;; Grab output until our dummy completion used as
+ ;; output end marker is found.
+ (when (nix--accept-process-output
+ process nix-repl-completion-output-timeout
+ comint-redirect-finished-regexp)
+ (beginning-of-line)
+ (if (eq (char-after) ?\r)
+ (cdr
+ (split-string
+ (buffer-substring-no-properties
+ (line-beginning-position) (point-min))
+ "[ \f\t\n\r\v]+" t))
+ (search-forward "" nil t)
+ (backward-char)
+ (if (eq (char-before) ?\a)
+ nil
+ (list (buffer-substring-no-properties
(line-beginning-position) (point))))))))
+ (set-process-filter process original-filter-fn)))))
+
+(defun nix--accept-process-output (process &optional timeout regexp)
+ "Accept PROCESS output with TIMEOUT until REGEXP is found.
+Optional argument TIMEOUT is the timeout argument to
+`accept-process-output' calls. Optional argument REGEXP
+overrides the regexp to match the end of output, defaults to
+`comint-prompt-regexp'. Returns non-nil when output was
+properly captured.
+
+This utility is useful in situations where the output may be
+received in chunks, since `accept-process-output' gives no
+guarantees they will be grabbed in a single call."
+ (let ((regexp (or regexp comint-prompt-regexp)))
+ (catch 'found
+ (while t
+ (when (not (accept-process-output process timeout))
+ (throw 'found nil))
+ (when (progn (re-search-backward regexp nil t))
+ (throw 'found t))))))
+
+;;;###autoload
+(defun nix-repl-completion-at-point ()
+ "Completion at point function for Nix using \"nix-repl\".
+See `completion-at-point-functions'."
+ (save-excursion
+ (let ((prefix (and (derived-mode-p 'nix-repl-mode)
+ (executable-find nix-executable)
+ (nix--prefix-bounds))))
+ (pcase prefix
+ (`(,beg . ,end)
+ (list beg end
+ (nix-get-completions
+ (get-buffer-process (current-buffer))
+ (buffer-substring beg end))
+ :exclusive 'no))))))
+
+(defun nix--prefix-bounds ()
+ "Get bounds of Nix attribute path at point as a (BEG . END) pair, or nil."
+ (save-excursion
+ (when (< (skip-chars-backward "a-zA-Z0-9'\\-_\\.") 0)
+ (cons (point) (+ (point) (skip-chars-forward "a-zA-Z0-9'\\-_\\."))))))
(defun nix--send-repl (input &optional process mute)
"Send INPUT to PROCESS.
@@ -93,7 +172,7 @@ 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))
(process-send-string proc input))))
(defun nix--char-with-ctrl (char)
- [nongnu] elpa/nix-mode a5bf79a563 425/500: Merge pull request #120 from znewman01/master, (continued)
- [nongnu] elpa/nix-mode a5bf79a563 425/500: Merge pull request #120 from znewman01/master, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 7593b023a7 405/500: Merge pull request #110 from leungbk/repl-history, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 1fdf8e654a 444/500: Merge pull request #132 from league/master, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 8e20de5ba7 462/500: Merge pull request #134 from nagy/store-path, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 01e37b6761 464/500: Merge pull request #139 from akirak/fix/nix-24-for-25, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 8a05b88eb3 448/500: Fix a typo, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 207e5c0a92 455/500: nix-format.el: Add nix-format-before-save, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 86b7195b3e 010/500: Use warning font lock for upper case vars, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode c81c03b35e 403/500: nix-repl: use history file, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode c19e103eee 430/500: Add support nix 2.4 flakes in search, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 5fa017c6ad 393/500: Merge pull request #105 from rossabaker/completions,
ELPA Syncer <=
- [nongnu] elpa/nix-mode 0380e03203 406/500: Merge pull request #109 from yilinwei/master, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode aef98227cc 419/500: Merge branch 'master' into derived-nix-drv-mode, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode ffcab906b8 407/500: Makefile: add nix-mode project directory to 'load-path' in 'run' target, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode da7e638f2f 451/500: Spell out command argument, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode c4abb64a64 494/500: nix-flake: Add a comment, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 21ed086cca 008/500: Fix flycheck complaints., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 4fe6058fb4 142/500: allow escape sequences inside sh-mode block, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 1268096ba7 136/500: Merge pull request #27 from ljli/close-open-fix, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 676cc65daf 153/500: Add some README doc., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 732ce2f174 169/500: Remove case-fold-search setting, ELPA Syncer, 2022/01/29