Function: hypb:in-string-p

hypb:in-string-p is a byte-compiled function defined in hypb.el.

Signature

(hypb:in-string-p &optional MAX-LINES RANGE-FLAG)

Documentation

Return non-nil iff point is within a string.

Point is within the string if it is after the end of the opening quote and before the start of the closing quote, not on it. This is cached by buffer & modified time for speed.

With optional MAX-LINES, an integer, match only within that many lines from point. With optional RANGE-FLAG when there is a match, return list of (in-string-flag start-pos end-pos), where in-string-flag is t or nil and the positions exclude the delimiters; the difference between end and start is the length of the string.

When no buffer edits have occurred, this uses cached results to determine whether in or outside of a string. When no cache hit is found, 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-backslashed quote mark and limits string length to a maximum of 9000 characters.

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'.

Source Code

;; Defined in ~/.emacs.d/elpa/hyperbole-20260822.1645/hypb.el
(defun hypb:in-string-p (&optional max-lines range-flag)
  "Return non-nil iff point is within a string.
Point is within the string if it is after the end of the opening
quote and before the start of the closing quote, not on it.  This
is cached by buffer & modified time for speed.

With optional MAX-LINES, an integer, match only within that many
lines from point.  With optional RANGE-FLAG when there is a
match, return list of (in-string-flag start-pos end-pos), where
in-string-flag is t or nil and the positions exclude the delimiters;
the difference between end and start is the length of the string.

When no buffer edits have occurred, this uses cached results to
determine whether in or outside of a string.  When no cache hit is
found, 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-backslashed quote mark and limits string length to a
maximum of 9000 characters.

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''."

  (unless (and (integerp max-lines) (<= max-lines 0))
    (let* ((buf (current-buffer))
           (tick (buffer-chars-modified-tick))
           (pos (point))
           (cache-entry (gethash buf hypb:in-string-cache)))

      ;; If buffer mod tick has changed, empty the buffer's string range cache
      (when (or (not cache-entry) (/= tick (car cache-entry)))
        (setq cache-entry (list tick)) ; Start a new list with just the tick
        (puthash buf cache-entry hypb:in-string-cache))

      ;; Check for a cache match range.  The cdr of `cache-entry' is a list of
      ;; (in-str-flag start end) ranges.
      (let ((match (cl-find-if (lambda (r)
                                 (and (>= pos (or (nth 1 r) (point-max)))
                                      (<= pos (or (nth 2 r) (point-min)))))
                               (cdr cache-entry)))
            cache-match)
        (when match
          ;; Cache match
          (setq cache-match match))

        ;; Buffer might be narrowed in which case full string would not be
        ;; seen.  If not `kotl-mode', temporarily widen the buffer.
        (save-restriction
          (unless (derived-mode-p 'kotl-mode)
            (widen))
          ;; When no matching cache entry, search for a string match
          (let* ((entry (or cache-match
                            ;; This ignores max-lines, so final result of
                            ;; whether in a string with max-lines may differ
                            ;; from what this returns.  This allows its result
                            ;; to be used in the cache.
                            ;; To call it with the buffer narrowed to
                            ;; according to `max-lines', use:
                            ;; (hypb:narrow-to-max-lines max-lines #'hypb:in-string-no-cache-p t)
                            (hypb:in-string-no-cache-p t)))
                 (in-str (nth 0 entry))
                 (str-start (max (point-min) (or (nth 1 entry) 0)))
                 (str-end (min (point-max) (or (nth 2 entry) 0))))
            (cond ((and (not match) (not hypb:in-string-cache-disable))
                   ;; Add the new range into the buffer's cache
                   (setcdr cache-entry (cons entry (cdr cache-entry))))
                  (match)
                  ((not entry)
                   (setq hypb:in-string-cache-disable t)
                   (error "(hypb:in-string-p): buffer = %s; cache-match = %S; entry = %s; point = %d"
                          (current-buffer) cache-match entry (point))))
	    ;; Ignore if more than `max-lines' matched
	    (when (and in-str str-start str-end
		       (or (null max-lines)
			   (and (integerp max-lines)
                                ;; When computing the number of lines in
                                ;; the string match, ignore any leading and
                                ;; trailing newlines.  This allows for
                                ;; opening and closing quotes to be on
                                ;; separate lines, useful with multi-line
                                ;; strings.
                                (let (newlines)
				  (or (< (setq newlines (count-matches "\n" str-start str-end))
                                         max-lines)
                                      (< (save-excursion
                                           (- newlines
                                              (progn (goto-char str-start)
                                                     (if (looking-at "[\n\r\f\t ]+")
                                                         (count-matches "\n" (match-beginning 0) (match-end 0))
                                                       0))
                                              (progn (goto-char str-end)
                                                     (if (zerop (skip-chars-backward "\n\r\f\t "))
                                                         0
                                                       (count-matches "\n" (point) str-end)))))
                                         max-lines))))))
	      (if range-flag
                  (cond ((zerop str-start)
                         (list nil (point) (point)))
                        (in-str (list (buffer-substring-no-properties str-start str-end) str-start str-end)))
                in-str))))))))