emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/inf-clojure 723064d 151/313: [Fix #83] Harden parsing of r


From: ELPA Syncer
Subject: [nongnu] elpa/inf-clojure 723064d 151/313: [Fix #83] Harden parsing of repl responses (#85)
Date: Wed, 11 Aug 2021 10:00:05 -0400 (EDT)

branch: elpa/inf-clojure
commit 723064d2a934549b29d20fd2db054a31862c4f9b
Author: Andrea Richiardi <a.richiardi.work@gmail.com>
Commit: Bozhidar Batsov <bozhidar.batsov@gmail.com>

    [Fix #83] Harden parsing of repl responses (#85)
    
    This patch refactors the process response parsing code and adds more nil 
checks
    and ignore-errors around the reading of LISP expression for both completion 
and
    eldoc.
---
 CHANGELOG.md   |   1 +
 inf-clojure.el | 122 +++++++++++++++++++++++++++++++++++++--------------------
 2 files changed, 80 insertions(+), 43 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1871a9a..3afd462 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 ### Bugs Fixed
 
 * [#77](https://github.com/clojure-emacs/inf-clojure/pull/77): Fix request 
"Eval expression:" if arglists return is `nil`.
+* [#83](https://github.com/clojure-emacs/inf-clojure/pull/85): No such 
namespace: complete.core in lumo REPL.
 
 ## 2.0.0 (2017-05-01)
 
diff --git a/inf-clojure.el b/inf-clojure.el
index 6145974..082d22e 100644
--- a/inf-clojure.el
+++ b/inf-clojure.el
@@ -940,17 +940,22 @@ prefix argument PROMPT-FOR-SYMBOL, it prompts for a 
symbol name."
                (inf-clojure-symbol-at-point))))
     (comint-proc-query (inf-clojure-proc) (format 
(inf-clojure-var-source-form) var))))
 
+;;;; Response parsing
+;;;; ================
+
+(defvar inf-clojure--redirect-buffer-name " *Inf-Clojure Redirect Buffer*")
+
 ;; Originally from:
 ;;   https://github.com/glycerine/lush2/blob/master/lush2/etc/lush.el#L287
-(defun inf-clojure-results-from-process (process command &optional beg-string 
end-string)
-  "Send COMMAND to PROCESS.
+(defun inf-clojure--process-response (command process &optional beg-string 
end-string)
+  "Send COMMAND to PROCESS and return the response.
 Return the result of COMMAND starting with BEG-STRING and ending
 with END-STRING if non-nil.  If BEG-STRING is nil, the result
 string will start from (point) in the results buffer.  If
 END-STRING is nil, the result string will end at (point-max) in
-the results buffer.  It cuts out the output from
-`inf-clojure-prompt` onwards unconditionally."
-  (let ((work-buffer " *Inf-Clojure Redirect Work Buffer*"))
+the results buffer.  It cuts out the output from and including
+the `inf-clojure-prompt`."
+  (let ((work-buffer inf-clojure--redirect-buffer-name))
     (save-excursion
       (set-buffer (get-buffer-create work-buffer))
       (erase-buffer)
@@ -963,29 +968,68 @@ the results buffer.  It cuts out the output from
       ;; Collect the output
       (set-buffer work-buffer)
       (goto-char (point-min))
-      ;; Skip past the command, if it was echoed
-      (and (looking-at command)
-           (forward-line))
-      (let* ((beg (if beg-string
-                      (progn (search-forward beg-string nil t) 
(match-beginning 0))
-                    (point)))
-             (end (if end-string
-                      (search-forward end-string nil t)
-                    (point-max)))
-             (buffer-string (buffer-substring-no-properties beg end)))
-        (when (and buffer-string (string-match inf-clojure-prompt 
buffer-string))
-          (substring buffer-string 0 (match-beginning 0)))))))
+      (let* ((beg (or (when (and beg-string (search-forward beg-string nil t))
+                        (match-beginning 0))
+                      (point-min)))
+             (end (or (when end-string
+                        (search-forward end-string nil t))
+                      (point-max)))
+             (prompt (when (search-forward inf-clojure-prompt nil t)
+                       (match-beginning 0))))
+        (buffer-substring-no-properties beg (or prompt end))))))
+
+(defun inf-clojure--nil-string-match-p (string)
+  "Return true iff STRING is not nil.
+This function also takes into consideration weird escape
+character and matches if nil is anywhere within the input
+string."
+  (string-match-p "\\Ca*nil\\Ca*" string))
+
+(defun inf-clojure--some (data)
+  "Return DATA unless nil or includes \"nil\" as string."
+  (cond
+   ((null data) nil)
+   ((and (stringp data)
+         (inf-clojure--nil-string-match-p data)) nil)
+   (t data)))
+
+(defun inf-clojure--read-or-nil (response)
+  "Read RESPONSE and return it as data.
+
+If response is nil or includes the \"nil\" string return nil
+instead.
+
+Note that the read operation will always return the first
+readable sexp only."
+  ;; The following reads the first LISP expression
+  (inf-clojure--some
+   (when response
+     (ignore-errors (read response)))))
+
+(defun inf-clojure--process-response-match-p (match-p proc form)
+  "Eval MATCH-P on the response of sending to PROC the input FORM.
+Note that this function will add a \n to the end (or  )f the string
+for evaluation, therefore FORM should not include it."
+  (when-let ((response (inf-clojure--process-response form proc)))
+    (funcall match-p response)))
+
+(defun inf-clojure--some-response-p (proc form)
+  "Return true iff PROC's response after evaluating FORM is not nil."
+  (inf-clojure--process-response-match-p
+                  (lambda (string)
+                    (not (inf-clojure--nil-string-match-p string)))
+                  proc form))
+
+;;;; Commands
+;;;; ========
 
 (defun inf-clojure-arglists (fn)
   "Send a query to the inferior Clojure for the arglists for function FN.
 See variable `inf-clojure-arglists-form'."
-  (let* ((arglists-snippet (format (inf-clojure-arglists-form) fn))
-         (arglists-result (inf-clojure-results-from-process (inf-clojure-proc) 
arglists-snippet))
-         (arglists-data (when arglists-result (read arglists-result))))
-    (cond
-     ((null arglists-data) nil)
-     ((stringp arglists-data) arglists-data)
-     ((listp arglists-data) arglists-result))))
+  (thread-first
+      (format (inf-clojure-arglists-form) fn)
+    (inf-clojure--process-response (inf-clojure-proc) "(" ")")
+    (inf-clojure--some)))
 
 (defun inf-clojure-show-arglists (prompt-for-symbol)
   "Show the arglists for function FN in the mini-buffer.
@@ -1051,26 +1095,18 @@ See variable `inf-clojure-buffer'."
     (or proc
         (error "No Clojure subprocess; see variable `inf-clojure-buffer'"))))
 
+(defun inf-clojure--list-or-nil (data)
+  "Return DATA if and only if it is a list."
+  (when (listp data) data))
+
 (defun inf-clojure-completions (expr)
   "Return a list of completions for the Clojure expression starting with EXPR."
-  (let* ((proc (inf-clojure-proc))
-         (comint-filt (process-filter proc))
-         (kept "")
-         completions)
-    (set-process-filter proc (lambda (_proc string) (setq kept (concat kept 
string))))
-    (unwind-protect
-        (let ((completion-snippet
-               (format
-                (inf-clojure-completion-form) (substring-no-properties expr))))
-          (process-send-string proc completion-snippet)
-          (while (and (not (string-match inf-clojure-prompt kept))
-                      (accept-process-output proc 2)))
-          (setq completions (read kept))
-          ;; Subprocess echoes output on Windows and OS X.
-          (when (and completions (string= (concat (car completions) "\n") 
completion-snippet))
-            (setq completions (cdr completions))))
-      (set-process-filter proc comint-filt))
-    completions))
+  (when (not (string-blank-p expr))
+    (thread-first
+        (format (inf-clojure-completion-form) (substring-no-properties expr))
+      (inf-clojure--process-response (inf-clojure-proc) "(" ")")
+      (inf-clojure--read-or-nil)
+      (inf-clojure--list-or-nil))))
 
 (defconst inf-clojure-clojure-expr-break-chars " \t\n\"\'`><,;|&{(")
 
@@ -1232,7 +1268,7 @@ to suppress the usage of the target buffer discovery 
logic."
   "Return MATCH-P on the result of sending FORM to PROC.
 Note that this function will add a \n to the end of the string
 for evaluation, therefore FORM should not include it."
-  (funcall match-p (inf-clojure-results-from-process proc form nil)))
+  (funcall match-p (inf-clojure--process-response form proc nil)))
 
 ;;;; Lumo
 ;;;; ====



reply via email to

[Prev in Thread] Current Thread [Next in Thread]