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

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

[nongnu] elpa/cider 398b370e8e 2/4: Workaround for `ansi-color-apply' Em


From: ELPA Syncer
Subject: [nongnu] elpa/cider 398b370e8e 2/4: Workaround for `ansi-color-apply' Emacs bug#53808 (#3154)
Date: Sat, 5 Mar 2022 02:57:55 -0500 (EST)

branch: elpa/cider
commit 398b370e8e8a7f7750b08676a16d4cfbaad0a027
Author: ikappaki <34983288+ikappaki@users.noreply.github.com>
Commit: GitHub <noreply@github.com>

    Workaround for `ansi-color-apply' Emacs bug#53808 (#3154)
    
    Enabled only in Emacs versions < 29.
    
    https://debbugs.gnu.org/cgi/bugreport.cgi?bug=53808.
    
    Also fixed a couple of old linter docstring warnings.
---
 cider-mode.el            |  2 +-
 cider-repl-history.el    |  2 +-
 cider-repl.el            | 59 ++++++++++++++++++++++++++++++------
 test/cider-repl-tests.el | 79 ++++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 118 insertions(+), 24 deletions(-)

diff --git a/cider-mode.el b/cider-mode.el
index b8a12f1557..3897a612e6 100644
--- a/cider-mode.el
+++ b/cider-mode.el
@@ -765,7 +765,7 @@ with the given LIMIT."
     value))
 
 (defun cider--compile-font-lock-keywords (symbols-plist core-plist)
-  "Return a list of font-lock rules for symbols."
+  "Return a list of font-lock rules for symbols in SYMBOLS-PLIST, CORE-PLIST."
   (let ((cider-font-lock-dynamically (if (eq cider-font-lock-dynamically t)
                                          '(function var macro core deprecated)
                                        cider-font-lock-dynamically))
diff --git a/cider-repl-history.el b/cider-repl-history.el
index ff77613182..4a4c7c87c6 100644
--- a/cider-repl-history.el
+++ b/cider-repl-history.el
@@ -344,7 +344,7 @@ case return nil."
         (error "No CIDER history item here")))))
 
 (defun cider-repl-history-current-string (pt &optional no-error)
-  "Find the string to insert into the REPL by looking for the overlay at PT
+  "Find the string to insert into the REPL by looking for the overlay at PT.
 Might error unless NO-ERROR set."
   (let ((o (cider-repl-history-target-overlay-at pt t)))
     (if o
diff --git a/cider-repl.el b/cider-repl.el
index 674c0279dc..123e541723 100644
--- a/cider-repl.el
+++ b/cider-repl.el
@@ -593,13 +593,51 @@ Return the position of the prompt beginning."
         (set-marker cider-repl-prompt-start-mark prompt-start)
         prompt-start))))
 
-(defun cider-repl--flush-ansi-color-context ()
-  "Flush ansi color context after printing.
-When there is a possible unfinished ansi control sequence,
- `ansi-color-context` maintains this list."
-  (when (and ansi-color-context (stringp (cadr ansi-color-context)))
-    (insert-before-markers (cadr ansi-color-context))
-    (setq ansi-color-context nil)))
+(defun cider-repl--ansi-color-apply (string)
+  "Like `ansi-color-apply', but does not withhold non-SGR seqs found in STRING.
+
+Workaround for Emacs bug#53808 whereby partial ANSI control seqs present in
+the input stream may block the whole colorization process."
+  (let* ((result (ansi-color-apply string))
+
+         ;; The STRING may end with a possible incomplete ANSI control seq 
which
+         ;; the call to `ansi-color-apply' stores in the `ansi-color-context'
+         ;; fragment. If the fragment is not an incomplete ANSI color control
+         ;; sequence (aka SGR seq) though then flush it out and appended it to
+         ;; the result.
+         (fragment-flush?
+          (when-let (fragment (and ansi-color-context (cadr 
ansi-color-context)))
+            (save-match-data
+              ;; Check if fragment is indeed an SGR seq in the making. The SGR
+              ;; seq is defined as starting with ESC followed by [ followed by
+              ;; zero or more [:digit:]+; followed by one or more digits and
+              ;; ending with m.
+              (when (string-match
+                     (rx (sequence ?\e
+                                   (? (and (or ?\[ eol)
+                                           (or (+ (any (?0 . ?9))) eol)
+                                           (* (sequence ?\; (+ (any (?0 . 
?9)))))
+                                           (or ?\; eol)))))
+                     fragment)
+                (let* ((sgr-end-pos (match-end 0))
+                       (fragment-matches-whole? (or (= sgr-end-pos 0)
+                                                    (= sgr-end-pos (length 
fragment)))))
+                  (when (not fragment-matches-whole?)
+                    ;; Definitely not an partial SGR seq, flush it out of
+                    ;; `ansi-color-context'.
+                    t)))))))
+
+    (if (not fragment-flush?)
+        result
+
+      (progn
+        ;; Temporarily replace the ESC char in the fragment so that is flushed
+        ;; out of `ansi-color-context' by `ansi-color-apply' and append it to
+        ;; the result.
+        (aset (cadr ansi-color-context) 0 ?\0)
+        (let ((result-fragment (ansi-color-apply "")))
+          (aset result-fragment 0 ?\e)
+          (concat result result-fragment))))))
 
 (defvar-local cider-repl--ns-forms-plist nil
   "Plist holding ns->ns-form mappings within each connection.")
@@ -672,7 +710,9 @@ namespaces.  STRING is REPL's output."
   (put-text-property 0 (length string) 'help-echo 'cider-locref-help-echo 
string)
   string)
 
-(defvar cider-repl-preoutput-hook '(ansi-color-apply
+(defvar cider-repl-preoutput-hook `(,(if (< emacs-major-version 29)
+                                       'cider-repl--ansi-color-apply
+                                      'ansi-color-apply)
                                     cider-repl-highlight-current-project
                                     cider-repl-highlight-spec-keywords
                                     cider-repl-add-locref-help-echo)
@@ -729,8 +769,7 @@ Before inserting, run `cider-repl-preoutput-hook' on 
STRING."
                                  'font-lock-face face
                                  'rear-nonsticky '(font-lock-face)))
         (setq string (cider-run-chained-hook 'cider-repl-preoutput-hook 
string))
-        (insert-before-markers string)
-        (cider-repl--flush-ansi-color-context))
+        (insert-before-markers string))
       (when (and (= (point) cider-repl-prompt-start-mark)
                  (not (bolp)))
         (insert-before-markers "\n")
diff --git a/test/cider-repl-tests.el b/test/cider-repl-tests.el
index 777a7b715e..2fcfbfe77e 100644
--- a/test/cider-repl-tests.el
+++ b/test/cider-repl-tests.el
@@ -106,9 +106,35 @@
         (cider-repl--emit-output (current-buffer) "a\n" 
'cider-repl-stdout-face)
         (cider-repl--emit-output (current-buffer) "b\n" 
'cider-repl-stdout-face)
         (cider-repl--emit-output (current-buffer) "c\n" 
'cider-repl-stdout-face)
-        (cider-repl--emit-output (current-buffer) "d\n" 
'cider-repl-stdout-face)
+        ;; split at ESC
+        (cider-repl--emit-output (current-buffer) "" 'cider-repl-stdout-face)
+        (cider-repl--emit-output (current-buffer) "[32md\n" 
'cider-repl-stdout-face)
+        ;; split at ESC [
+        (cider-repl--emit-output (current-buffer) "[" 'cider-repl-stdout-face)
+        (cider-repl--emit-output (current-buffer) "33me\n" 
'cider-repl-stdout-face)
 
-        (expect (buffer-string) :to-equal "a\nb\nc\nd\n")
+        ;; split at ESC [n
+        (cider-repl--emit-output (current-buffer) "[3" 
'cider-repl-stdout-face)
+        (cider-repl--emit-output (current-buffer) "1mf\n" 
'cider-repl-stdout-face)
+
+        ;; split at ESC [nm
+        (cider-repl--emit-output (current-buffer) "" 
'cider-repl-stdout-face)
+        (cider-repl--emit-output (current-buffer) "g\n" 
'cider-repl-stdout-face)
+
+        ;; split at ESC [n;
+        (cider-repl--emit-output (current-buffer) "[1;" 
'cider-repl-stdout-face)
+        (cider-repl--emit-output (current-buffer) "33mh\n" 
'cider-repl-stdout-face)
+
+        ;; split at ESC [n;n
+        (cider-repl--emit-output (current-buffer) "[0;31" 
'cider-repl-stdout-face)
+        (cider-repl--emit-output (current-buffer) "mi\n" 
'cider-repl-stdout-face)
+
+        ;; split at ESC [n;nm
+        (cider-repl--emit-output (current-buffer) "" 
'cider-repl-stdout-face)
+        (cider-repl--emit-output (current-buffer) "j\n" 
'cider-repl-stdout-face)
+
+        (expect (buffer-substring-no-properties (point-min) (point-max))
+                :to-equal "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n")
         (expect (get-text-property 1 'font-lock-face)
                 :to-equal '(foreground-color . "black"))
         (expect (get-text-property 3 'font-lock-face)
@@ -116,20 +142,35 @@
         (expect (get-text-property 5 'font-lock-face)
                 :to-equal '(foreground-color . "red3"))
         (expect (get-text-property 7 'font-lock-face)
-                :to-equal '(foreground-color . "red3"))))))
+                :to-equal '(foreground-color . "green3"))
+        (expect (get-text-property 9 'font-lock-face)
+                :to-equal '(foreground-color . "yellow3"))
+        (expect (get-text-property 11 'font-lock-face)
+                :to-equal '(foreground-color . "red3"))
+        (expect (get-text-property 13 'font-lock-face)
+                :to-equal '(foreground-color . "green3"))
+        (expect (get-text-property 15 'font-lock-face)
+                :to-equal '((foreground-color . "yellow3") bold))
+        (expect (get-text-property 17 'font-lock-face)
+                :to-equal '(foreground-color . "red3"))
+        (expect (get-text-property 19 'font-lock-face)
+                :to-equal '((foreground-color . "green3") italic))
+        ))))
 
 (defun simulate-cider-output (s property)
   "Return properties from `cider-repl--emit-output'.
 PROPERTY should be a symbol of either 'text, 'ansi-context or
 'properties."
-  (with-temp-buffer
-    (with-testing-ansi-table cider-testing-ansi-colors-vector
-      (cider-repl-reset-markers)
-      (cider-repl--emit-output (current-buffer) s nil))
-    (pcase property
-      (`text (substring-no-properties (buffer-string)))
-      (`ansi-context ansi-color-context)
-      (`properties (substring (buffer-string))))))
+  (let ((strings (if (listp s) s (list s))))
+    (with-temp-buffer
+      (with-testing-ansi-table cider-testing-ansi-colors-vector
+                               (cider-repl-reset-markers)
+                               (dolist (s strings)
+                                 (cider-repl--emit-output (current-buffer) s 
nil)))
+      (pcase property
+        (`text (substring-no-properties (buffer-string)))
+        (`ansi-context ansi-color-context)
+        (`properties (substring (buffer-string)))))))
 
 (describe "cider-repl--emit-output"
   (it "prints simple strings"
@@ -142,7 +183,21 @@ PROPERTY should be a symbol of either 'text, 'ansi-context 
or
       (expect (simulate-cider-output "\033hi" 'text)
               :to-equal "\033hi\n")
       (expect (simulate-cider-output "\033hi" 'ansi-context)
-              :to-equal nil)))
+              :to-equal nil)
+
+      ;; Informational: Ideally, we would have liked any non-SGR
+      ;; sequence to appear on the output verbatim, but as per the
+      ;; `ansi-color-apply' doc string, they are removed
+      ;;
+      ;; """Translates SGR control sequences into text properties.
+      ;;    Delete all other control sequences without processing them."""
+      ;;
+      ;; e.g.:
+      (expect (simulate-cider-output
+               "\033[hi" 'text) :to-equal "i\n")
+      (expect (simulate-cider-output
+               '("\033[" "hi") 'text) :to-equal "i\n")
+      ))
 
   (describe "when the escape code is valid"
     (it "preserves the context"



reply via email to

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