Fix #2832: filename modifiers replaced with empty strings

This commit is contained in:
Henrik Lissner 2020-04-26 04:12:33 -04:00
parent 077b6f00d4
commit 50ff934ff2
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
5 changed files with 65 additions and 66 deletions

View file

@ -7,7 +7,7 @@
(call-interactively #'doom/escape)))
;;;###autoload
(defun +evil-resolve-vim-path-a (file-name)
(defun +evil-replace-filename-modifiers-a (file-name)
"Take a path and resolve any vim-like filename modifiers in it. This adds
support for most vim file modifiers, as well as:
@ -15,66 +15,65 @@ support for most vim file modifiers, as well as:
See http://vimdoc.sourceforge.net/htmldoc/cmdline.html#filename-modifiers for
more information on modifiers."
(let (case-fold-search)
(let ((origin-buffer (current-buffer))
case-fold-search)
(with-temp-buffer
(save-excursion (insert file-name))
(while (re-search-forward "\\(^\\|[^\\\\]\\)\\(\\([%#]\\)\\(:\\([PphtreS~.]\\|g?s\\)\\)*\\)" nil t)
(catch 'continue
(unless buffer-file-name
(replace-match (match-string 1) t t nil 2)
(throw 'continue t))
(let ((beg (match-beginning 2))
(end (match-end 3))
(path (pcase (match-string 3)
("%" (file-relative-name buffer-file-name))
("#" (and (other-buffer)
(buffer-file-name (other-buffer)))))))
(save-match-data
(goto-char beg)
(while (re-search-forward ":\\([PphtreS~.]\\|g?s\\)" (+ (point) 3) t)
(let* ((modifier (match-string 1))
(global (string-prefix-p "gs" modifier)))
(when global
(setq modifier (substring modifier 1)))
(setq end (match-end 1)
path
(or (when path
(pcase (substring modifier 0 1)
("p" (expand-file-name path))
("~" (concat "~/" (file-relative-name path "~")))
("." (file-relative-name path default-directory))
("t" (file-name-nondirectory (directory-file-name path)))
("r" (file-name-sans-extension path))
("e" (file-name-extension path))
("S" (shell-quote-argument path))
("h"
(let ((parent (file-name-directory (expand-file-name path))))
(unless (file-equal-p path parent)
(if (file-name-absolute-p path)
(directory-file-name parent)
(file-relative-name parent)))))
("s"
(if (featurep 'evil)
(when-let (args (evil-delimited-arguments (substring modifier 1) 2))
(let ((pattern (evil-transform-vim-style-regexp (car args)))
(replace (cadr args)))
(replace-regexp-in-string
(if global pattern (concat "\\(" pattern "\\).*\\'"))
(evil-transform-vim-style-regexp replace) path t t
(unless global 1))))
path))
("P"
(let ((project-root (doom-project-root (file-name-directory (expand-file-name path)))))
(unless project-root
(user-error "Not in a project"))
(abbreviate-file-name project-root)))))
""))
;; strip trailing slash, if applicable
(or (string-empty-p path)
(not (equal (substring path -1) "/"))
(setq path (substring path 0 -1))))))
(replace-match path t t nil 2))))
(replace-regexp-in-string "\\\\\\([#%]\\)" "\\1" (buffer-string) t))))
(let ((buffer-file-name (buffer-file-name origin-buffer)))
(save-excursion (insert file-name))
(while (re-search-forward "\\(^\\|[^\\\\]\\)\\(\\([%#]\\)\\(:\\([PphtreS~.]\\|g?s\\)\\)*\\)" nil t)
(if (null buffer-file-name)
(replace-match (match-string 1) t t nil 2)
(let ((beg (match-beginning 2))
(end (match-end 3))
(path (pcase (match-string 3)
("%" (file-relative-name buffer-file-name default-directory))
("#" (and (other-buffer origin-buffer)
(buffer-file-name (other-buffer origin-buffer)))))))
(save-match-data
(goto-char beg)
(while (re-search-forward ":\\([PphtreS~.]\\|g?s\\)" (+ (point) 3) t)
(let* ((modifier (match-string 1))
(global (string-prefix-p "gs" modifier)))
(when global
(setq modifier (substring modifier 1)))
(setq end (match-end 1)
path
(pcase (and path (substring modifier 0 1))
(`nil "")
("p" (expand-file-name path))
("~" (concat "~/" (file-relative-name path "~")))
("." (file-relative-name path))
("t" (file-name-nondirectory (directory-file-name path)))
("r" (file-name-sans-extension path))
("e" (file-name-extension path))
("S" (shell-quote-argument path))
("h"
(let ((parent (file-name-directory (expand-file-name path))))
(unless (file-equal-p path parent)
(if (file-name-absolute-p path)
(directory-file-name parent)
(file-relative-name parent)))))
("s"
(if (featurep 'evil)
(when-let (args (evil-delimited-arguments (substring modifier 1) 2))
(let ((pattern (evil-transform-vim-style-regexp (car args)))
(replace (cadr args)))
(replace-regexp-in-string
(if global pattern (concat "\\(" pattern "\\).*\\'"))
(evil-transform-vim-style-regexp replace) path t t
(unless global 1))))
path))
("P"
(let ((project-root (doom-project-root (file-name-directory (expand-file-name path)))))
(unless project-root
(user-error "Not in a project"))
(abbreviate-file-name project-root)))))
;; strip trailing slash, if applicable
(or (string-empty-p path)
(not (equal (substring path -1) "/"))
(setq path (substring path 0 -1))))))
(replace-match path t t nil 2))))
(replace-regexp-in-string "\\\\\\([#%]\\)" "\\1" (buffer-string) t)))))
(defun +evil--insert-newline (&optional above _noextranewline)
(let ((pos (save-excursion (beginning-of-line-text) (point)))

View file

@ -108,7 +108,7 @@ g Repeat alignment on all matches in each line"
If BANG is non-nil, open compilation output in a comint buffer.
If BANG, then run ARGUMENTS as a full command. This command understands vim file
modifiers (like %:p:h). See `+evil-resolve-vim-path-a' for details."
modifiers (like %:p:h). See `+evil-replace-filename-modifiers-a' for details."
(interactive "<sh><!>")
(let ((compile-command "make"))
(+evil:compile (if (stringp arguments)
@ -122,7 +122,7 @@ modifiers (like %:p:h). See `+evil-resolve-vim-path-a' for details."
If BANG is non-nil, open compilation output in a comint buffer.
This command understands vim file modifiers (like %:p:h). See
`+evil-resolve-vim-path-a' for details."
`+evil-replace-filename-modifiers-a' for details."
(interactive "<sh><!>")
(compile (evil-ex-replace-special-filenames
(format "%s %s"

View file

@ -159,7 +159,7 @@ directives. By default, this only recognizes C directives.")
;; monkey patch `evil-ex-replace-special-filenames' to improve support for
;; file modifiers like %:p:h. This adds support for most of vim's modifiers,
;; and one custom one: %:P (expand to the project root).
(advice-add #'evil-ex-replace-special-filenames :override #'+evil-resolve-vim-path-a)
(advice-add #'evil-ex-replace-special-filenames :override #'+evil-replace-filename-modifiers-a)
;; make `try-expand-dabbrev' (from `hippie-expand') work in minibuffer
(add-hook 'minibuffer-inactive-mode-hook #'+evil--fix-dabbrev-in-minibuffer-h)

View file

@ -9,10 +9,10 @@
(load! "../autoload/evil")
(before-each
(fset 'resv #'+evil-resolve-vim-path-a)
(fset 'resv #'+evil-replace-filename-modifiers-a)
(spy-on 'doom-project-root :and-call-fake (lambda () project-root)))
;; `evil-ex-replace-special-filenames' / `+evil-resolve-vim-path-a'
;; `evil-ex-replace-special-filenames' / `+evil-replace-filename-modifiers-a'
(describe "file modifiers"
(it "supports basic vim file modifiers"
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")

View file

@ -6,7 +6,7 @@
"TODO"
(interactive "<fsh><!>")
(let ((buffer (+eshell-last-buffer))
(command (+evil-resolve-vim-path-a command)))
(command (+evil-replace-filename-modifiers-a command)))
(cond (buffer
(select-window (get-buffer-window buffer))
(+eshell-run-command command buffer))