[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/nix-mode bdfe3b3ae3 391/500: Fix nix-get-completions, add
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/nix-mode bdfe3b3ae3 391/500: Fix nix-get-completions, add to nix-repl-mode |
Date: |
Sat, 29 Jan 2022 08:27:46 -0500 (EST) |
branch: elpa/nix-mode
commit bdfe3b3ae35bcb0c7b99e2db7594a110a392a7b2
Author: Ross A. Baker <ross@rossabaker.com>
Commit: Ross A. Baker <ross@rossabaker.com>
Fix nix-get-completions, add to nix-repl-mode
---
nix-repl.el | 132 +++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 103 insertions(+), 29 deletions(-)
diff --git a/nix-repl.el b/nix-repl.el
index 8d9f2d6ed0..82913a250d 100644
--- a/nix-repl.el
+++ b/nix-repl.el
@@ -21,10 +21,20 @@
"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)
+
(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 +68,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 +167,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 2f4bd0f09c 336/500: Release 1.4.1, (continued)
- [nongnu] elpa/nix-mode 2f4bd0f09c 336/500: Release 1.4.1, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 00750803d9 356/500: Don't freeze full executable paths at load time, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 3248864b56 348/500: Add failing tests that check for correct lexing of angle paths., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 8118a807a7 346/500: Handle more edge cases in keywords, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode c2725000ab 349/500: Use pcase-exhaustive instead of pcase in nix-smie--skip-path, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 795cc0c4c5 350/500: Handle angle paths correctly, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode a0fc6db303 365/500: Fix testcase file name., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode f77ae8fb54 380/500: Add more builtins, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode e4e604ae3a 389/500: Release 1.4.4, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 228f9f9d39 387/500: Release 1.4.3, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode bdfe3b3ae3 391/500: Fix nix-get-completions, add to nix-repl-mode,
ELPA Syncer <=
- [nongnu] elpa/nix-mode 70af0efc9f 076/500: Fix antiquote closing brace., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 59e9ca0abd 084/500: Improve fontification, ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 68793d91c5 107/500: Add require 'cl for case statements., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 2221a09aea 108/500: Require 'cl for "case"., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode e4bc711d81 094/500: Add some more modes., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode e1f2e24cc4 104/500: Move separate modes into own files., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 56a87c8d81 087/500: Move nix-flycheck to separate file., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 199e20413e 102/500: Ignore comments for hanging let's., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode fcbaf3e054 106/500: Rename flycheck mode to "nix-flycheck"., ELPA Syncer, 2022/01/29
- [nongnu] elpa/nix-mode 542ae77358 110/500: buffer-substring can't bet <1., ELPA Syncer, 2022/01/29