dotfiles/.emacs.d/modules/sqrt-dired.el

384 lines
11 KiB
EmacsLisp

;;; -*- lexical-binding: t -*-
(use-package dired
:ensure nil
:custom ((dired-listing-switches "-alh --group-directories-first"))
:commands (dired)
:config
(setq dired-dwim-target t)
(setq wdired-allow-to-change-permissions t)
(setq wdired-create-parent-directories t)
(setq dired-recursive-copies 'always)
(setq dired-recursive-deletes 'always)
(setq dired-kill-when-opening-new-dired-buffer t)
(add-hook 'dired-mode-hook
(lambda ()
(setq truncate-lines t)
(visual-line-mode nil)))
(when my/is-termux
(add-hook 'dired-mode-hook #'dired-hide-details-mode))
(general-define-key
:states '(normal)
:keymaps 'dired-mode-map
"h" #'dired-up-directory
"l" #'dired-find-file
"=" #'dired-narrow
"-" #'my/dired-create-empty-file-subtree
"~" #'eshell
"M-r" #'wdired-change-to-wdired-mode
"<left>" #'dired-up-directory
"<right>" #'dired-find-file
"M-<return>" #'my/dired-open-xdg))
(defun my/dired-home ()
"Open dired at $HOME"
(interactive)
(dired (expand-file-name "~")))
(my-leader-def
"ad" #'dired
"aD" #'my/dired-bookmark-open)
(use-package diredfl
:straight t
:after (dired)
:config
(diredfl-global-mode 1))
(use-package dired-subtree
:after (dired)
:straight t)
(defun my/dired-create-empty-file-subtree ()
(interactive)
(let ((default-directory (dired-current-directory)))
(dired-create-empty-file
(read-file-name "Create empty file: "))))
(defun my/dired-sidebar-toggle ()
(interactive)
(if (not current-prefix-arg)
(dired-sidebar-toggle-sidebar)
(let ((dired-sidebar-follow-file-at-point-on-toggle-open
current-prefix-arg)
(current-prefix-arg nil))
(dired-sidebar-toggle-sidebar))))
(use-package dired-sidebar
:straight t
:after (dired)
:commands (dired-sidebar-toggle-sidebar)
:init
(setq dired-sidebar-follow-file-at-point-on-toggle-open nil)
(general-define-key
:keymaps '(normal override global)
"C-n" `(my/dired-sidebar-toggle
:wk "dired-sidebar"))
:config
(setq dired-sidebar-width 45)
(defun my/dired-sidebar-setup ()
(toggle-truncate-lines 1)
(display-line-numbers-mode -1)
(setq-local dired-subtree-use-backgrounds nil)
(setq-local window-size-fixed nil))
(general-define-key
:keymaps 'dired-sidebar-mode-map
:states '(normal emacs)
"l" #'dired-sidebar-find-file
"h" #'dired-sidebar-up-directory
"=" #'dired-narrow)
(add-hook 'dired-sidebar-mode-hook #'my/dired-sidebar-setup)
(advice-add #'dired-create-empty-file :after 'dired-sidebar-refresh-buffer))
(use-package dired-recent
:straight t
:after dired
:config
(dired-recent-mode)
(general-define-key
:keymaps 'dired-recent-mode-map
"C-x C-d" nil))
(use-package all-the-icons-dired
:straight t
:disabled t
:after (dired)
:if (display-graphic-p)
:hook (dired-mode . (lambda ()
(unless (string-match-p "/gnu/store" default-directory)
(all-the-icons-dired-mode)))))
(use-package nerd-icons-dired
:straight t
:after (dired)
:hook (dired-mode . (lambda ()
(unless (or (file-remote-p default-directory)
(string-match-p "/gnu/store" default-directory))
(nerd-icons-dired-mode))))
:config
(advice-add #'dired-create-empty-file :around #'nerd-icons-dired--refresh-advice))
(use-package dired-open
:straight t
:after (dired)
:commands (dired-open-xdg))
(use-package dired-du
:straight t
:commands (dired-du-mode)
:config
(setq dired-du-size-format t))
(use-package dired-narrow
:straight t
:commands (dired-narrow)
:config
(general-define-key
:keymaps 'dired-narrow-map
[escape] 'keyboard-quit))
(use-package dired-git-info
:straight t
:after dired
:config
(general-define-key
:keymap 'dired-mode-map
:states '(normal emacs)
")" 'dired-git-info-mode))
(use-package avy-dired
:straight (:host github :repo "SqrtMinusOne/avy-dired")
:after (dired)
:init
(my-leader-def "aa" #'avy-dired-goto-line))
(defun my/dired-rsync--refresh ()
(cl-loop for window being the windows
do (with-current-buffer (window-buffer window)
(when (derived-mode-p 'dired-mode)
(revert-buffer)))))
(use-package dired-rsync
:straight t
:after (dired)
:config
(add-to-list 'global-mode-string '(:eval dired-rsync-modeline-status))
(add-hook 'dired-rsync-success-hook #'my/dired-rsync--refresh)
(general-define-key
:states '(normal)
:keymaps '(dired-mode-map)
"C" #'dired-rsync
"gC" #'dired-rsync-transient
"gd" #'dired-do-copy))
(use-package dired-rsync-transient
:straight t
:after (dired))
(defun my/dired-open-this-subdir ()
(interactive)
(dired (dired-current-directory)))
(defun my/dired-kill-all-subdirs ()
(interactive)
(let ((dir dired-directory))
(kill-buffer (current-buffer))
(dired dir)))
(with-eval-after-load 'dired
(general-define-key
:states '(normal)
:keymaps 'dired-mode-map
"s" nil
"ss" 'dired-maybe-insert-subdir
"sl" 'dired-maybe-insert-subdir
"sq" 'dired-kill-subdir
"sk" 'dired-prev-subdir
"sj" 'dired-next-subdir
"sS" 'my/dired-open-this-subdir
"sQ" 'my/dired-kill-all-subdirs
(kbd "TAB") 'dired-hide-subdir))
(defun my/dired-goto-project-root ()
(interactive)
(dired--find-possibly-alternative-file (projectile-project-root)))
(with-eval-after-load 'dired
(general-define-key
:states '(normal)
:keymaps 'dired-mode-map
"H" #'my/dired-goto-project-root))
(defun my/dired-open-xdg ()
"Try to run `xdg-open' to open the file under point."
(interactive)
(when (executable-find "xdg-open")
(let ((file (ignore-errors (dired-get-file-for-visit))))
(start-process "dired-open" nil
"xdg-open" (file-truename file)))))
(defun my/dired-do-async-shell-command (command &optional arg file-list)
(interactive
(let ((files (dired-get-marked-files t current-prefix-arg nil nil t)))
(list
;; Want to give feedback whether this file or marked files are used:
(dired-read-shell-command "& on %s: " current-prefix-arg files)
current-prefix-arg
files)))
(start-process-shell-command
"*Dired Command*" nil
(dired-shell-stuff-it command file-list arg)))
(with-eval-after-load 'dired
(general-define-key
:states '(normal insert)
:keymaps '(dired-mode-map)
"&" #'my/dired-do-async-shell-command))
(defun my/dired-bookmark-open ()
(interactive)
(let ((bookmarks
(mapcar
(lambda (el) (cons (format "%-30s %s" (car el) (cdr el)) (cdr el)))
my/dired-bookmarks)))
(dired
(cdr
(assoc
(completing-read "Dired: " bookmarks nil nil "^")
bookmarks)))))
(defun my/get-good-buffer (buffer-major-mode prompt)
(or
(cl-loop
for buf being the buffers
if (eq (buffer-local-value 'major-mode buf) buffer-major-mode)
collect buf into all-buffers
if (and (eq (buffer-local-value 'major-mode buf) buffer-major-mode)
(get-buffer-window buf t))
collect buf into visible-buffers
finally return (if (= (length visible-buffers) 1)
(car visible-buffers)
(if (= (length all-buffers) 1)
(car all-buffers)
(when-let ((buffers-by-name (mapcar (lambda (b)
(cons (buffer-name b) b))
all-buffers)))
(cdr
(assoc
(completing-read prompt buffers-by-name nil t)
buffers-by-name))))))
(user-error "No buffer found!")))
(defun my/dired-attach-to-telega (files telega-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
(my/get-good-buffer 'telega-chat-mode "Telega buffer: ")))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer telega-buffer
(dolist (file files)
(telega-chatbuf-attach-file file))))
(defun my/telega-save-to-dired (msg arg)
(interactive
(list (telega-msg-for-interactive)
(prefix-numeric-value current-prefix-arg)))
(if (eq arg 4)
(progn
(setq telega-msg-save-dir
(with-current-buffer (my/get-good-buffer 'dired-mode "Dired buffer: ")
(dired-current-directory)))
(telega-msg-save msg))
(setq default-directory (expand-file-name "~"))
(setq telega-msg-save-dir nil)
(telega-msg-save msg)))
(defun my/dired-attach-to-notmuch (files notmuch-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
(my/get-good-buffer 'notmuch-message-mode "Notmuch message buffer: ")))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer notmuch-buffer
(goto-char (point-max))
(dolist (file files)
(let ((type
(or (mm-default-file-type file)
"application/octet-stream")))
(mml-attach-file
file
type
(mml-minibuffer-read-description)
(mml-minibuffer-read-disposition type nil file))))))
(defun my/notmuch-save-to-dired (arg)
(interactive
(list (prefix-numeric-value current-prefix-arg)))
(if (eq arg 4)
(let ((default-directory
(with-current-buffer (my/get-good-buffer 'dired-mode "Dired buffer: ")
(dired-current-directory))))
(notmuch-show-save-part))
(notmuch-show-save-part)))
(defun my/dired-attach-to-ement (files ement-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
(my/get-good-buffer 'ement-room-mode "Ement room buffer: ")))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer ement-buffer
(ement-with-room-and-session
(dolist (file files)
(ement-room-send-file
file
(read-from-minibuffer (format "Message body for %s: " file))
ement-room
ement-session)))))
(defun my/dired-attach-to-mastodon (files mastodon-buffer)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)
(or (cl-loop for buf being the buffers
if (eq (buffer-local-value 'mastodon-toot-mode buf) t)
return buf)
(user-error "No buffer found!"))))
(unless files
(user-error "No (non-directory) files selected"))
(with-current-buffer mastodon-buffer
(dolist (file files)
(mastodon-toot-attach-media
file
(read-from-minibuffer (format "Description for %s: " file))))))
(defun my/dired-attach-to-gptel (files)
(interactive
(list (dired-get-marked-files nil nil #'dired-nondirectory-p)))
(unless files
(user-error "No (non-directory) files selected"))
(dolist (file files)
(gptel-context-add-file file)))
(with-eval-after-load 'dired
(general-define-key
:states '(normal)
:keymaps 'dired-mode-map
"a" nil
"at" #'my/dired-attach-to-telega
"am" #'my/dired-attach-to-notmuch
"ae" #'my/dired-attach-to-ement
"ai" #'my/dired-attach-to-gptel
"an" #'my/dired-attach-to-mastodon))
(with-eval-after-load 'telega
(general-define-key
:keymaps 'telega-msg-button-map
"S" #'my/telega-save-to-dired))
(with-eval-after-load 'notmuch
(general-define-key
:keymaps 'notmuch-show-mode-map
:states 'normal
". s" #'my/notmuch-save-to-dired))
(provide 'sqrt-dired)