branch: externals/hyperbole
commit 4b8f50427ed3fd45b9f4a47c0d948e5b5403f123
Author: bw <r...@gnu.org>
Commit: bw <r...@gnu.org>

    hypb:in-string-p - Fix open quote detection
---
 ChangeLog |   5 ++++
 hypb.el   | 100 +++++++++++++++++++++++++++++++++++---------------------------
 2 files changed, 62 insertions(+), 43 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 62aede9c8f..1b72742011 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2025-05-19  Bob Weiner  <r...@gnu.org>
+
+* hypb.el (hypb:in-string-p): Fix open quote detection heuristics including
+    subtracting quoted delimiters from overall counts.
+
 2025-05-18  Bob Weiner  <r...@gnu.org>
 
 * hui-mouse.el (hkey-alist): Move hui-select clauses up before (hbut:at-p)
diff --git a/hypb.el b/hypb.el
index 9e4c837f1d..40b8bea6fd 100644
--- a/hypb.el
+++ b/hypb.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     6-Oct-91 at 03:42:38
-;; Last-Mod:     18-May-25 at 17:40:45 by Bob Weiner
+;; Last-Mod:     19-May-25 at 01:28:31 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -75,12 +75,13 @@ This should end with a space.")
            (list (format open-regexp "\"\\|'''\\|\"\"\"\\|'")
                  (format close-regexp "\"\\|'''\\|\"\"\"\\|'")))
           ((derived-mode-p 'texinfo-mode)
-           (list (format open-regexp "\"\\|``")
-                 (format close-regexp "\"\\|''")))
+           (list (format open-regexp "``\\|\"")
+                 (format close-regexp "''\\|\"")))
           (t
            (list (format open-regexp "\"")
                  (format close-regexp "\"")))))
-  "Return a list of open/close string delimiter regexps for 
`hypb:in-string-p'."
+  "Return a list of open/close string delimiter regexps for `hypb:in-string-p'.
+Or clauses in regexps must be arranged from longest match to shortest match."
   :type 'sexp
   :group 'hyperbole-commands)
 
@@ -694,47 +695,60 @@ Quoting conventions recognized are:
   Python triple single-quotes:   '''str''';
   Python triple double-quotes:   \"\"\"str\"\"\";
   Texinfo open and close quotes: ``str''."
-  (save-restriction
-    (when (integerp max-lines)
-      (narrow-to-region (line-beginning-position)
-                       (line-end-position max-lines)))
-    ;; Don't use `syntax-ppss' here as it fails to ignore backquoted
-    ;; double quote characters in strings and doesn't work in
-    ;; `change-log-mode' due to its syntax-table.
-    (let ((opoint (point))
-         (start (point-min))
-         (open-match-string ""))
-      (cl-destructuring-bind (open-regexp close-regexp)
-         (eval hypb:in-string-modes-regexps)
-       (cond ((derived-mode-p 'python-mode)
-              (setq open-regexp  (format open-regexp "\"\\|'''\\|\"\"\"\\|'")
-                    close-regexp (format close-regexp 
"\"\\|'''\\|\"\"\"\\|'")))
-             ((derived-mode-p 'texinfo-mode)
-              (setq open-regexp  (format open-regexp "\"\\|``")
-                    close-regexp (format close-regexp "\"\\|''")))
-             (t
-              (setq open-regexp  (format open-regexp "\"")
-                    close-regexp (format close-regexp "\""))))
-       (save-match-data
-         (when (re-search-backward open-regexp nil t)
-           (setq open-match-string (match-string 2))
-           (forward-line 0)
-           (setq start (point))
-           (goto-char opoint)
-           (if (and (derived-mode-p 'texinfo-mode)
-                    (string-equal open-match-string texinfo-open-quote))
+  (save-excursion
+    (save-restriction
+      (when (integerp max-lines)
+       (narrow-to-region (line-beginning-position)
+                         (line-end-position max-lines)))
+      ;; Don't use `syntax-ppss' here as it fails to ignore backquoted
+      ;; double quote characters in strings and doesn't work in
+      ;; `change-log-mode' due to its syntax-table.
+      (let ((opoint (point))
+           (start (point-min))
+           (open-match-string ""))
+       (cl-destructuring-bind (open-regexp close-regexp)
+           (eval hypb:in-string-modes-regexps)
+         (save-match-data
+           (when (and (re-search-backward open-regexp nil t)
+                      (setq open-match-string (match-string 2))
+                      ;; If this is the start of a string, it must be
+                      ;; at the start of line, preceded by whitespace
+                      ;; or preceded by another string end sequence.
+                      (save-match-data
+                        (or (string-empty-p (match-string 1))
+                            (string-search (match-string 1) " \t\n\r\f")
+                            (progn (goto-char (1+ (point)))
+                                   (looking-back close-regexp nil)))))
+             (forward-line 0)
+             (setq start (point))
+             (goto-char opoint)
+             (if (and (derived-mode-p 'texinfo-mode)
+                      (string-equal open-match-string texinfo-open-quote))
+                 (and (cl-oddp (- (count-matches (regexp-quote 
open-match-string)
+                                                 start (point))
+                                  ;; Subtract any backslash quoted delimiters
+                                  (count-matches
+                                   (format "[\\]\\(%s\\)"
+                                           (regexp-quote open-match-string))
+                                   start (point))
+                                  (count-matches (regexp-quote 
texinfo-close-quote)
+                                                 start (point))
+                                  ;; Subtract any backslash quoted delimiters
+                                  (count-matches
+                                   (format "[\\]\\(%s\\)"
+                                           (regexp-quote texinfo-close-quote))
+                                   start (point))))
+                      (search-forward texinfo-close-quote nil t)
+                      t)
                (and (cl-oddp (- (count-matches (regexp-quote open-match-string)
                                                start (point))
-                                (count-matches (regexp-quote 
texinfo-close-quote)
-                                               start (point))))
-                    (save-excursion (search-forward texinfo-close-quote nil t))
-                    t)
-             (and (cl-oddp (count-matches
-                            (format "\\(^\\|[^\\]\\)\\(%s\\)"
-                                    (regexp-quote open-match-string))
-                            start (point)))
-                  (save-excursion (re-search-forward close-regexp nil t))
-                  t))))))))
+                                ;; Subtract any backslash quoted delimiters
+                                (count-matches
+                                 (format "[\\]\\(%s\\)"
+                                         (regexp-quote open-match-string))
+                                 start (point))))
+                    (re-search-forward close-regexp nil t)
+                    t)))))))))
 
 (defun hypb:indirect-function (obj)
   "Return the function at the end of OBJ's function chain.

Reply via email to