branch: externals/hyperbole commit a2223ca29d16a281e9830a58b39f4c68292a1408 Author: bw <r...@gnu.org> Commit: bw <r...@gnu.org>
hui-select.el - Fix multi-line double-quoted string selection --- ChangeLog | 4 +++ hui-select.el | 101 ++++++++++++++++++++++++++++++++++------------------------ 2 files changed, 63 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5c0ed49ae6..d0a9f318d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,10 @@ * hywiki.el (hywiki-make-referent-hasht): Return hasht when rebuilding from load data. +* hui-select.el (hui-select-string-p): Fix to make multi-line string selection + work properly whether on the opening or closing double quote mark, using + 'scan-sexps'. Update doc string. + 2025-02-05 Mats Lidell <ma...@gnu.org> * hywiki.el (hywiki-add-org-id): Suppress byte compile warnings for calling org-id-get with diff --git a/hui-select.el b/hui-select.el index a67d40a8aa..fd949b42f8 100644 --- a/hui-select.el +++ b/hui-select.el @@ -3,7 +3,7 @@ ;; Author: Bob Weiner ;; ;; Orig-Date: 19-Oct-96 at 02:25:27 -;; Last-Mod: 26-Jan-25 at 17:04:55 by Bob Weiner +;; Last-Mod: 7-Feb-25 at 00:15:47 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -108,6 +108,7 @@ ;;; ************************************************************************ (require 'hvar) +(require 'hypb) ;; for hypb:in-string-p (eval-when-compile (require 'mhtml-mode) ;; for MHTML and HTML modes (require 'sgml-mode) ;; for SGML mode @@ -1036,49 +1037,65 @@ Return the updated cons cell." nil hui-select-region)) + (defun hui-select-string-p (&optional start-delim end-delim) - "Return (start . end) of string whose first line point is in or directly before. -Positions include delimiters. String is delimited by double quotes unless -optional START-DELIM and END-DELIM (strings) are given. -Returns nil if not within a string." - (let ((opoint (point)) - (count 0) - bol start delim-regexp start-regexp end-regexp) - (or start-delim (setq start-delim "\"")) - (or end-delim (setq end-delim "\"")) - ;; Special case for the empty string. - (if (looking-at (concat (regexp-quote start-delim) - (regexp-quote end-delim))) - (hui-select-set-region (point) (match-end 0)) - (setq start-regexp (concat "\\(^\\|[^\\]\\)\\(" - (regexp-quote start-delim) "\\)") - end-regexp (concat "[^\\]\\(" (regexp-quote end-delim) "\\)") - delim-regexp (concat start-regexp "\\|" end-regexp)) - (save-excursion - (beginning-of-line) - (setq bol (point)) - (while (re-search-forward delim-regexp opoint t) - (setq count (1+ count)) - ;; This is so we don't miss the closing delimiter of an empty - ;; string. - (if (and (= (point) (1+ bol)) - (looking-at (regexp-quote end-delim))) + "Return (start . end) of a string. +Works when on a delim or on the first line with point in the +string or directly before it. Positions include delimiters. +String is delimited by double quotes unless optional START-DELIM +and END-DELIM (strings) are given. Returns nil if not within a +string." + (unless start-delim (setq start-delim "\"")) + (unless end-delim (setq end-delim "\"")) + (or (and (equal start-delim "\"") (equal end-delim "\"") + (ignore-errors + (cond ((and (= (char-after) ?\") + (/= (char-before) ?\\)) + (if (hypb:in-string-p) + (hui-select-set-region (scan-sexps (1+ (point)) -1) + (1+ (point))) + (hui-select-set-region (point) (scan-sexps (point) 1)))) + ((and (= (char-before) ?\") + (/= (char-before (1- (point))) ?\\)) + (if (hypb:in-string-p) + (hui-select-set-region (1- (point)) (scan-sexps (1- (point)) 1)) + (hui-select-set-region (scan-sexps (1- (point)) -1) + (point))))))) + (let ((opoint (point)) + (count 0) + bol start delim-regexp start-regexp end-regexp) + ;; Special case for the empty string. + (if (looking-at (concat (regexp-quote start-delim) + (regexp-quote end-delim))) + (hui-select-set-region (point) (match-end 0)) + (setq start-regexp (concat "\\(^\\|[^\\]\\)\\(" + (regexp-quote start-delim) "\\)") + end-regexp (concat "[^\\]\\(" (regexp-quote end-delim) "\\)") + delim-regexp (concat start-regexp "\\|" end-regexp)) + (save-excursion + (beginning-of-line) + (setq bol (point)) + (while (re-search-forward delim-regexp opoint t) (setq count (1+ count)) - (unless (bobp) - (backward-char 1)))) - (goto-char opoint) - ;; If found an even # of starting and ending delimiters before - ;; opoint, then opoint is at the start of a string, where we want it. - (if (zerop (mod count 2)) - (unless (bobp) - (backward-char 1)) - (re-search-backward start-regexp nil t)) - ;; Point is now before the start of the string. - (when (re-search-forward start-regexp nil t) - (setq start (match-beginning 2)) - (when (re-search-forward end-regexp nil t) - (hui-select-set-region start (point)))))))) - + ;; This is so we don't miss the closing delimiter of an empty + ;; string. + (if (and (= (point) (1+ bol)) + (looking-at (regexp-quote end-delim))) + (setq count (1+ count)) + (unless (bobp) + (backward-char 1)))) + (goto-char opoint) + ;; If found an even # of starting and ending delimiters before + ;; opoint, then opoint is at the start of a string, where we want it. + (if (zerop (mod count 2)) + (unless (bobp) + (backward-char 1)) + (re-search-backward start-regexp nil t)) + ;; Point is now before the start of the string. + (when (re-search-forward start-regexp nil t) + (setq start (match-beginning 2)) + (when (re-search-forward end-regexp nil t) + (hui-select-set-region start (point))))))))) ;;; ;;; Code selections ;;;