branch: externals/hyperbole
commit 2e4857aef4957eb4e1967c09b199385540c52d27
Merge: 2d2b23c3d5 537e70b48b
Author: Robert Weiner <r...@gnu.org>
Commit: GitHub <nore...@github.com>

    Merge pull request #730 from rswgnu/rsw
    
    hypb:in-string-p - Improve performance in large docs; 
kotl-mode:add-prior-cell - Fix to send raw C-u value with "*P"
---
 ChangeLog         | 13 ++++++++++
 hypb.el           | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 kotl/kotl-mode.el | 14 ++++++-----
 3 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7a61caecaf..fa611613d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2025-05-18  Bob Weiner  <r...@gnu.org>
+
+* hypb.el (hypb:in-string-p): Make heuristic to optimize performance; search
+    back only until the beginning of the first line prior to point that 
contains
+    a non-quoted double quote mark.  Also add support for 'texinfo-mode' 
strings
+    where both "String1" and ``String2'' may be used.  Add support for
+    'python-mode' single and triple string delimiters as well.
+          (hypb:in-string-modes-regexps): Add for use in 'hypb:in-string-p'.
+    Allows customization of major modes with unique string delimiters.
+
+* kotl/kotl-mode.el (kotl-mode:add-prior-cell): Fix to send raw C-u value
+    with (interactive "*P") instead of "p".
+
 2025-05-12  Mats Lidell  <ma...@gnu.org>
 
 * test/hmouse-drv-tests.el (hmouse-drv--hkey-actions): Test hkey-actions.
diff --git a/hypb.el b/hypb.el
index af1dc10cb8..9e4c837f1d 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:     27-Apr-25 at 12:03:07 by Bob Weiner
+;; Last-Mod:     18-May-25 at 17:40:45 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -68,6 +68,22 @@
   "Prefix attached to all native Hyperbole help buffer names.
 This should end with a space.")
 
+(defcustom hypb:in-string-modes-regexps
+  '(let ((open-regexp "\\(^\\|[^\\]\\)\\(%s\\)")
+        (close-regexp "\\(^\\|[^\\]\\)\\(%s\\)"))
+     (cond ((derived-mode-p 'python-mode)
+           (list (format open-regexp "\"\\|'''\\|\"\"\"\\|'")
+                 (format close-regexp "\"\\|'''\\|\"\"\"\\|'")))
+          ((derived-mode-p 'texinfo-mode)
+           (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'."
+  :type 'sexp
+  :group 'hyperbole-commands)
+
 (defvar hypb:mail-address-mode-list
   '(fundamental-mode prog-mode text-mode)
   "List of major modes in which mail address implicit buttons are active.
@@ -664,7 +680,20 @@ This will this install the Emacs helm package when needed."
                      help-file))))))
 
 (defun hypb:in-string-p (&optional max-lines)
-  "Return t iff point is within a double quoted string."
+  "Return t iff point is within a string.
+
+To prevent searching back to the buffer start and producing slow
+performance, this limits its count of quotes found prior to point
+to the beginning of the first line prior to point that contains a
+non-quoted quote mark.
+
+Quoting conventions recognized are:
+  double-quotes:                 \"str\";
+  Markdown triple backticks:     ```str```;
+  Python single-quotes:          'str';
+  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)
@@ -672,10 +701,40 @@ This will this install the Emacs helm package when 
needed."
     ;; 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.
-    (save-match-data
-      (and (cl-oddp (count-matches "\\(^\\|[^\\]\\)\"" (point-min) (point)))
-          (save-excursion (re-search-forward "\\(^\\|[^\\]\\)\"" nil t))
-          t))))
+    (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))
+               (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))))))))
 
 (defun hypb:indirect-function (obj)
   "Return the function at the end of OBJ's function chain.
diff --git a/kotl/kotl-mode.el b/kotl/kotl-mode.el
index fdbe04db22..189f6afdd2 100644
--- a/kotl/kotl-mode.el
+++ b/kotl/kotl-mode.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    6/30/93
-;; Last-Mod:      4-May-25 at 11:13:26 by Bob Weiner
+;; Last-Mod:     18-May-25 at 10:16:26 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -2518,12 +2518,13 @@ last cell added.
 Add new cells with optional CONTENTS string, attributes in PLIST,
 a property list, and NO-FILL flag to prevent any filling of
 CONTENTS."
-  (interactive "*p")
+  (interactive "*P")
   (when (null cells-to-add) (setq cells-to-add 1))
-  (unless (and (natnump cells-to-add) (/= cells-to-add 0))
-    (error "(kotl-mode:add-prior-cell): `cells-to-add' must be a positive 
integer"))
-  (if (eq cells-to-add '(4))
+  (if (equal cells-to-add '(4))
       (kotl-mode:add-below-parent)
+    (setq cells-to-add (prefix-numeric-value cells-to-add))
+    (unless (and (natnump cells-to-add) (/= cells-to-add 0))
+      (error "(kotl-mode:add-prior-cell): `cells-to-add' must be a positive 
integer"))
     (cond ((zerop (kotl-mode:backward-cell 1))
           ;; Add preceding sibling if not on first cell at current level
           (kotl-mode:add-cell cells-to-add contents plist no-fill))
@@ -2533,7 +2534,8 @@ CONTENTS."
           (kotl-mode:add-child cells-to-add contents plist no-fill))
          (t
           ;; Add preceding sibling when on level 1 first cell
-          (kotl-mode:add-below-parent cells-to-add contents plist no-fill)))))
+          (kotl-mode:add-below-parent cells-to-add
+                                      contents plist no-fill)))))
 
 (defun kotl-mode:demote-tree (arg)
   "Move current tree a maximum of prefix ARG levels lower in current view.

Reply via email to