Function: completion--sifn-requote

completion--sifn-requote is a byte-compiled function defined in minibuffer.el.gz.

Signature

(completion--sifn-requote UPOS QSTR)

Source Code

;; Defined in /usr/src/emacs/lisp/minibuffer.el.gz
    (file-error nil)))               ;PCM often calls with invalid directories.

(defun completion--sifn-requote (upos qstr)
  ;; We're looking for (the largest) `qpos' such that:
  ;; (equal (substring (substitute-in-file-name qstr) 0 upos)
  ;;        (substitute-in-file-name (substring qstr 0 qpos)))
  ;; Big problem here: we have to reverse engineer substitute-in-file-name to
  ;; find the position corresponding to UPOS in QSTR, but
  ;; substitute-in-file-name can do anything, depending on file-name-handlers.
  ;; substitute-in-file-name does the following kind of things:
  ;; - expand env-var references.
  ;; - turn backslashes into slashes.
  ;; - truncate some prefix of the input.
  ;; - rewrite some prefix.
  ;; Some of these operations are written in external libraries and we'd rather
  ;; not hard code any assumptions here about what they actually do.  IOW, we
  ;; want to treat substitute-in-file-name as a black box, as much as possible.
  ;; Kind of like in rfn-eshadow-update-overlay, only worse.
  ;; Example of things we need to handle:
  ;; - Tramp (substitute-in-file-name "/foo:~/bar//baz") => "/scpc:foo:/baz".
  ;; - Cygwin (substitute-in-file-name "C:\bin") => "/usr/bin"
  ;;          (substitute-in-file-name "C:\") => "/"
  ;;          (substitute-in-file-name "C:\bi") => "/bi"
  (let* ((ustr (substitute-in-file-name qstr))
         (uprefix (substring ustr 0 upos))
         qprefix)
    (if (eq upos (length ustr))
        ;; Easy and common case.  This not only speed things up in a very
        ;; common case but it also avoids problems in some cases (bug#53053).
        (cons (length qstr) #'minibuffer-maybe-quote-filename)
      ;; Main assumption: nothing after qpos should affect the text before upos,
      ;; so we can work our way backward from the end of qstr, one character
      ;; at a time.
      ;; Second assumption: If qpos is far from the end this can be a bit slow,
      ;; so we speed it up by doing a first loop that skips a word at a time.
      ;; This word-sized loop is careful not to cut in the middle of env-vars.
      (while (let ((boundary (string-match "\\(\\$+{?\\)?\\w+\\W*\\'" qstr)))
               (and boundary
                    ;; Try and make sure we keep the largest `qpos' (bug#72176).
                    (not (string-match-p "/[/~]" qstr boundary))
                    (progn
                      (setq qprefix (substring qstr 0 boundary))
                      (string-prefix-p uprefix
                                       (substitute-in-file-name qprefix)))))
        (setq qstr qprefix))
      (let ((qpos (length qstr)))
        (while (and (> qpos 0)
                    (string-prefix-p uprefix
                                     (substitute-in-file-name
                                      (substring qstr 0 (1- qpos)))))
          (setq qpos (1- qpos)))
        (cons qpos #'minibuffer-maybe-quote-filename)))))