From 388e5b471170e6341e8b53e1896b4c6246f00511 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Fri, 12 May 2017 12:06:56 +0200 Subject: [PATCH] feature/evil: rewrite :mv & :rm (file move/delete commands) --- core/autoload/buffers.el | 13 ++++ modules/feature/evil/autoload/files.el | 104 +++++++++++++++---------- modules/private/hlissner/+commands.el | 4 +- 3 files changed, 76 insertions(+), 45 deletions(-) diff --git a/core/autoload/buffers.el b/core/autoload/buffers.el index 8dcc54f1a..e00295f7a 100644 --- a/core/autoload/buffers.el +++ b/core/autoload/buffers.el @@ -172,6 +172,19 @@ See `doom-real-buffer-p' for what 'real' means." (kill-buffer buffer))) (eq (current-buffer) buffer))) +;;;###autoload +(defun doom-force-kill-buffer (&optional buffer dont-save) + "Kill BUFFER globally and ensure all windows previously showing BUFFER have +switched to a real buffer." + (interactive) + (let* ((buffer (or buffer (current-buffer))) + (windows (get-buffer-window-list buffer nil t))) + (kill-buffer buffer) + (dolist (win windows) + (with-selected-window win + (unless (doom-real-buffer-p) + (doom/previous-buffer)))))) + ;;;###autoload (defun doom-kill-buffer-and-windows (buffer) "Kill the buffer and delete all the windows it's displayed in." diff --git a/modules/feature/evil/autoload/files.el b/modules/feature/evil/autoload/files.el index 6a5316dc0..ee846575e 100644 --- a/modules/feature/evil/autoload/files.el +++ b/modules/feature/evil/autoload/files.el @@ -1,62 +1,80 @@ ;;; feature/evil/autoload/files.el -;;;###autoload (autoload '+evil:file-delete "feature/evil/autoload/files" nil t) -(evil-define-command +evil:file-delete (&optional bang filename) - "Delete current buffer's file. If BANG, don't ask for confirmation." +(defun doom--forget-file (old-path &optional new-path) + "Ensure `recentf', `projectile' and `save-place' forget OLD-PATH." + (when (fboundp 'recentf-add-file) + (when new-path + (recentf-add-file new-path)) + (recentf-remove-if-non-kept old-path)) + (when (and (projectile-project-p) + (projectile-file-cached-p old-path (projectile-project-root))) + (projectile-purge-file-from-cache old-path)) + (when (bound-and-true-p save-place-mode) + (save-place-forget-unreadable-files))) + +;;;###autoload (autoload '+evil:delete-this-file "feature/evil/autoload/files" nil t) +(evil-define-command +evil:delete-this-file (&optional filename force-p) + "Delete FILENAME (defaults to the file associated with current buffer) and +kills the buffer. If FORCE-P, force the deletion (don't ask for confirmation)." :repeat nil - ;; TODO Test me - (interactive "") + (interactive "") (let* ((fname (file-truename (or filename (buffer-file-name)))) (fbase (file-name-sans-extension (file-name-nondirectory fname))) (buf (current-buffer))) (cond ((not (file-exists-p fname)) (error "File doesn't exist: %s" fname)) - ((not (or bang (y-or-n-p (format "Delete %s?" fbase)))) + ((not (or force-p (y-or-n-p (format "Really delete %s?" fbase)))) (message "Aborted")) (t (unwind-protect (delete-file fname) - (if (file-exists-p fname) - (error "Failed to delete %s" (file-relative-name fname)) - (doom/previous-buffer) - (kill-buffer buf) - (when (bound-and-true-p save-place-mode) - (save-place-forget-unreadable-files)) - (message "Successfully deleted %s" (file-relative-name fname)))))))) + (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)))))))) -;;;###autoload (autoload '+evil:file-move "feature/evil/autoload/files" nil t) -(evil-define-command +evil:file-move (bang dest-path) - "Move current buffer's file to PATH. Replaces %, # and other variables (see -`evil-ex-replace-special-filenames')" +;;;###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 - ;; TODO Test me - (interactive "") - (let* ((dest-path (expand-file-name dest-path)) + (interactive "") + (let* ((new-path (expand-file-name new-path)) (old-path (file-truename (buffer-file-name))) - (new-path (cond ((file-directory-p dest-path) - (expand-file-name (file-name-nondirectory old-path) dest-path)) - ((file-directory-p (file-name-directory dest-path)) - (expand-file-name dest-path)) - (t (user-error "Not a valid destination: %s" dest-path)))) + (new-path (apply #'expand-file-name + (if (or (directory-name-p new-path) + (file-directory-p new-path)) + (list (file-name-nondirectory old-path) new-path) + (list new-path)))) + (new-path-dir (file-name-directory new-path)) (project-root (doom-project-root)) - (short-old-path (file-relative-name old-path project-root)) - (short-new-path (file-relative-name new-path project-root))) - (when (or bang - (y-or-n-p (format (if (file-exists-p new-path) - "File already exists at %s, overwrite?" - "Renaming %s to %s, proceed?") - short-old-path short-new-path))) - (when (buffer-modified-p) - (save-buffer)) - (rename-file old-path new-path 1) - (rename-buffer (file-name-nondirectory new-path)) - (set-visited-file-name new-path) - (set-buffer-modified-p nil) - (when (bound-and-true-p save-place-mode) - (save-place-forget-unreadable-files)) - (setq doom--spaceline-file-path nil) - (message "File '%s' successfully renamed to '%s'" - short-old-path short-new-path)))) + (short-new-name (if (file-in-directory-p new-path project-root) + (file-relative-name new-path project-root) + (abbreviate-file-name new-path)))) + (unless (file-directory-p new-path-dir) + (make-directory new-path-dir t)) + (when (buffer-modified-p) + (save-buffer)) + (cond ((equal (file-truename old-path) + (file-truename new-path)) + (error "Cannot move file to itself")) + ((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")) + (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))))) + diff --git a/modules/private/hlissner/+commands.el b/modules/private/hlissner/+commands.el index be2f7eea1..1d46f6140 100644 --- a/modules/private/hlissner/+commands.el +++ b/modules/private/hlissner/+commands.el @@ -66,8 +66,8 @@ (ex! "todo" '+ivy:todo) ;; File operations -(ex! "mv" '+evil:file-move) -(ex! "rm" '+evil:file-delete) +(ex! "mv" '+evil:move-this-file) +(ex! "rm" '+evil:delete-this-file) ;; Sessions/tabs (ex! "sclear" '+workspace/kill-session)