Function: combobulate-cursor--update-function

combobulate-cursor--update-function is a natively compiled function defined in combobulate-cursor.el.

Signature

(combobulate-cursor--update-function BUF TAG)

Documentation

Return a function that updates the overlays in BUF with TAG.

This function is intended to be used in post-command-hook to update the overlays in BUF with TAG. It is returned as a closure that captures the minibuffer text at the time of its creation.

Overlays must be valid combobulate-refactor field overlays.

Source Code

;; Defined in /nix/store/b5fvrwzi3zvkabyzx0in6gw1cj963z46-emacs-packages-deps/share/emacs/site-lisp/combobulate-cursor.el
(defun combobulate-cursor--update-function (buf tag)
  "Return a function that updates the overlays in BUF with TAG.

This function is intended to be used in `post-command-hook' to
update the overlays in BUF with TAG. It is returned as a closure
that captures the minibuffer text at the time of its creation.

Overlays must be valid `combobulate-refactor' field overlays."
  (lambda ()
    (let ((idx 0)
          ;; nab the minibuffer text here (before we change the
          ;; current buffer) as we return a closure that runs in
          ;; `post-command-hook' inside the minibuffer prompt
          ;; machinery, and the minibuffer contents function will,
          ;; despite its name, happily return the contents of
          ;; *whatever* buffer is the current buffer, whether it is
          ;; actually a minibuffer or not.
          (minibuffer-text (minibuffer-contents)))
      (with-current-buffer buf
        (let ((ovs (combobulate--refactor-get-overlays combobulate-cursor--refactor-id)))
          (mapc (lambda (ov)
                  (when (overlay-get ov 'combobulate-refactor-field-enabled)
                    ;; Essential. There's a million things in here
                    ;; that throw errors left and right that'll cause
                    ;; `post-command-hook' to eject us from future
                    ;; updates if it gets a signal.
                    (ignore-errors
                      (combobulate--refactor-update-field
                       ov tag
                       (let* ((to (query-replace-compile-replacement minibuffer-text t))
                              ;; `replace-eval-replacement' and
                              ;; `query-replace-compile-replacement'
                              ;; rewrites `\,(...)'  elisp forms and
                              ;; detects regexp backslash groups such
                              ;; as `\N' and rewrites them as
                              ;; `(match-string N)' ---
                              ;; great. However, we cannot use this
                              ;; feature as it assumes match data is
                              ;; set (as it ordinarily would be in a
                              ;; normal search&replace loop) and the
                              ;; coterie of functions that depend on
                              ;; it.
                              ;;
                              ;; As we're effectively hacking up the
                              ;; replace machinery to work with
                              ;; Combobulate's refactoring system, we
                              ;; either need to rewrite uses of
                              ;; `match-string' to a custom function
                              ;; of our own choosing; ensure match
                              ;; data is set so it matches the field
                              ;; overlays in the buffer, which is
                              ;; complex; or just `cl-letf' it here
                              ;; temporarily.
                              (replacement-text
                               (cl-letf  (((symbol-function 'match-string)
                                           (lambda (n &optional _string)
                                             (overlay-get
                                              (nth
                                               ;; Asking for the 0th
                                               ;; match means we want
                                               ;; the current
                                               ;; overlay's text.
                                               (if (= n 0)
                                                   idx
                                                 ;; Subtract 1 because 0
                                                 ;; refers to the whole
                                                 ;; match
                                                 (1- n))
                                               ovs)
                                              'combobulate-refactor-field-original-text))))
                                 (or (replace-eval-replacement
                                      (cond
                                       ((null to) "")
                                       ((stringp to)
                                        (list 'concat to))
                                       (t (cdr to)))
                                      idx)
                                     ""))))
                         (replace-regexp-in-string
                          combobulate-cursor-substitute-match
                          (lambda (sub)
                            ;; Avoid using any sort of matching
                            ;; functions here that touches match
                            ;; data. It does not work well due to
                            ;; `replace-regexp-in-string' doing its own
                            ;; thing with the data.
                            ;;
                            ;; Thankfully,
                            ;; `combobulate-cursor-substitute-match'
                            ;; is set to match backslash groups and
                            ;; they are syntactically simple: the
                            ;; first character is a backslash and the
                            ;; rest is a number. Extracting the number
                            ;; is as simple as the substring without
                            ;; the backslash.
                            (if-let (matched-ov
                                     (let ((num (string-to-number (substring sub 1))))
                                       ;; The number 0 is special. In
                                       ;; an ordinary search&replace
                                       ;; loop it refers to the whole
                                       ;; match. Here we repurpose it
                                       ;; to mean the original text of
                                       ;; the CURRENT field.  Also,
                                       ;; subtract 1 to account for
                                       ;; the 0-based whole match
                                       ;; index.
                                       (if (= num 0) (nth idx ovs) (nth (1- num) ovs))))
                                (overlay-get matched-ov 'combobulate-refactor-field-original-text)
                              ;; No match, return the default text in the minibuffer.
                              minibuffer-text))
                          replacement-text))
                       ;; required, as we need to ensure `default-text' is
                       ;; set to a default value that won't cause issues
                       ;; down the road if the eval replacement call does
                       ;; not yield anything.
                       ""))
                    (cl-incf idx)))
                ovs))))))