From 94f8e7768be003adc5d21434657467d29dc6faa5 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Sat, 27 May 2017 13:25:40 +0200 Subject: [PATCH] Add :cp, refactor evil file commands, add tests --- modules/feature/evil/autoload/files.el | 66 ++++++++++++++++++-------- modules/private/hlissner/+commands.el | 1 + test/modules/feature/test-evil.el | 41 +++++++++++++++- 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/modules/feature/evil/autoload/files.el b/modules/feature/evil/autoload/files.el index ee846575e..c32b3cd0b 100644 --- a/modules/feature/evil/autoload/files.el +++ b/modules/feature/evil/autoload/files.el @@ -1,6 +1,6 @@ ;;; feature/evil/autoload/files.el -(defun doom--forget-file (old-path &optional new-path) +(defun +evil--forget-file (old-path &optional new-path) "Ensure `recentf', `projectile' and `save-place' forget OLD-PATH." (when (fboundp 'recentf-add-file) (when new-path @@ -25,29 +25,25 @@ kills the buffer. If FORCE-P, force the deletion (don't ask for confirmation)." (error "File doesn't exist: %s" fname)) ((not (or force-p (y-or-n-p (format "Really delete %s?" fbase)))) - (message "Aborted")) + (message "Aborted") + nil) (t (unwind-protect - (delete-file fname) + (progn (delete-file fname) t) (let ((short-path (file-relative-name fname (doom-project-root)))) (if (file-exists-p fname) (error "Failed to delete %s" short-path) ;; Ensures that windows displaying this buffer will be switched ;; to real buffers (`doom-real-buffer-p') (doom-force-kill-buffer buf t) - (doom--forget-file fname) - (message "Successfully deleted %s" short-path)))))))) + (+evil--forget-file fname) + (message "Successfully deleted %s" short-path) + ))))))) -;;;###autoload (autoload '+evil:move-this-file "feature/evil/autoload/files" nil t) -(evil-define-command +evil:move-this-file (new-path &optional force-p) - "Move current buffer's file to NEW-PATH. Replaces %, # and other vim-esque -filename modifiers (see `+evil*ex-replace-special-filenames'). If FORCE-P, -overwrite the destination file if it exists, without confirmation." - :repeat nil - (interactive "") +(defun +evil--copy-file (old-path new-path &optional force-p) (let* ((new-path (expand-file-name new-path)) - (old-path (file-truename (buffer-file-name))) + (old-path (file-truename old-path)) (new-path (apply #'expand-file-name (if (or (directory-name-p new-path) (file-directory-p new-path)) @@ -64,17 +60,45 @@ overwrite the destination file if it exists, without confirmation." (save-buffer)) (cond ((equal (file-truename old-path) (file-truename new-path)) - (error "Cannot move file to itself")) + (throw 'status 'overwrite-self)) ((and (file-exists-p new-path) (not force-p) (not (y-or-n-p (format "File already exists at %s, overwrite?" short-new-name)))) - (message "Aborted")) + (throw 'status 'aborted)) (t - (rename-file old-path new-path 1) - (kill-this-buffer) - (find-file new-path) - (doom--forget-file old-path new-path) - (message "File successfully moved to %s" - short-new-name))))) + (copy-file old-path new-path t) + short-new-name)))) +;;;###autoload (autoload '+evil:move-this-file "feature/evil/autoload/files" nil t) +(evil-define-command +evil:move-this-file (new-path &optional force-p) + "Move current buffer's file to NEW-PATH. Replaces %, # and other vim-esque +filename modifiers (see `+evil*ex-replace-special-filenames'). If FORCE-P, +overwrite the destination file if it exists, without confirmation." + :repeat nil + (interactive "") + (pcase (catch 'status + (let ((old-path (buffer-file-name))) + (when-let (dest (+evil--copy-file old-path new-path force-p)) + (delete-file old-path) + (kill-this-buffer) + (find-file new-path) + (+evil--forget-file old-path new-path) + (message "File successfully moved to %s" dest)))) + ('overwrite-self (error "Cannot overwrite self")) + ('aborted (message "Aborted")) + (_ t))) + +;;;###autoload (autoload '+evil:copy-this-file "feature/evil/autoload/files" nil nil) +(evil-define-command +evil:copy-this-file (new-path &optional force-p) + "Copy current buffer's file to NEW-PATH. Replaces %, # and other vim-esque +filename modifiers (see `+evil*ex-replace-special-filenames'). If FORCE-P, +overwrite the destination file if it exists, without confirmation." + :repeat nil + (interactive "") + (pcase (catch 'status + (when-let (dest (+evil--copy-file (buffer-file-name) new-path force-p)) + (message "File successfully copied to %s" dest))) + ('overwrite-self (error "Cannot overwrite self")) + ('aborted (message "Aborted")) + (_ t))) diff --git a/modules/private/hlissner/+commands.el b/modules/private/hlissner/+commands.el index 43c97b59d..03594eb9d 100644 --- a/modules/private/hlissner/+commands.el +++ b/modules/private/hlissner/+commands.el @@ -68,6 +68,7 @@ (ex! "todo" #'+ivy:todo) ;; File operations +(ex! "cp" #'+evil:copy-this-file) (ex! "mv" #'+evil:move-this-file) (ex! "rm" #'+evil:delete-this-file) diff --git a/test/modules/feature/test-evil.el b/test/modules/feature/test-evil.el index 8e2a2b55a..a7450e0ae 100644 --- a/test/modules/feature/test-evil.el +++ b/test/modules/feature/test-evil.el @@ -4,6 +4,25 @@ (defalias 'do-it '+evil*ex-replace-special-filenames) +(defmacro do-files! (src dest &rest body) + (declare (indent defun)) + `(let ((it ,src) + (other ,dest)) + (with-temp-file it + (insert "Hello world")) + + (unwind-protect + (progn + (should (file-exists-p it)) + (find-file-literally it) + (should (equal (buffer-string) "Hello world")) + (should (equal (buffer-file-name) it)) + (let ((inhibit-message (not doom-debug-mode))) + ,@body)) + (ignore-errors (delete-file it)) + ,(if dest `(ignore-errors (delete-file other)))))) + +;; (def-test-group! feature/evil (ert-deftest custom-file-modifiers () (let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el") @@ -48,4 +67,24 @@ (should (equal (do-it "%:~") "")) (should (equal (do-it "%:s?e?x?") "")) (should (equal (do-it "%:gs?e?x?") "")) - (should (equal (do-it "%:P") ""))))) + (should (equal (do-it "%:P") "")))) + + (ert-deftest move-this-file () + (do-files! "/tmp/doom-buffer" "/tmp/doom-buffer-new" + (should-error (+evil:move-this-file it)) + (should (+evil:move-this-file other t)) + (should (file-exists-p other)) + (should (not (file-exists-p it))))) + + (ert-deftest copy-this-file () + (do-files! "/tmp/doom-buffer-2" "/tmp/doom-buffer-2-new" + (should-error (+evil:copy-this-file it)) + (should (+evil:copy-this-file other t)) + (should (file-exists-p other)) + (should (file-exists-p it)))) + + (ert-deftest delete-this-file () + (do-files! "/tmp/doom-buffer-3" nil + (should-error (+evil:delete-this-file "this-file-does-not-exist")) + (should (+evil:delete-this-file nil t)) + (should (not (file-exists-p it))))))