From ecc278b83ba97643a14c3b98c1e8d9b8b0fac307 Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Sun, 7 Jun 2020 15:56:07 +0100 Subject: [PATCH] feat(navigation): Add file/directory size commands to Dired There's two different variants, both callable via M-? in dired buffers. Without a prefix arg it will use `siren-dired-get-disk-usage` which uses the external `du` command to get disk usage, or "space on disk" for item at point or marked files and/or directories. If called with a prefix (C-u M-?) it will instead use `siren-dired-get-size` which is implemented in pure elisp, and recursively gets the actual file sizes for item at point or marked files and/or directories. As the prefix variant is written in pure elisp, it is quite a bit slower for very large directories with thousands of files. --- modules/navigation/siren-dired.el | 55 +++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/modules/navigation/siren-dired.el b/modules/navigation/siren-dired.el index 7b6ae16..e543e45 100644 --- a/modules/navigation/siren-dired.el +++ b/modules/navigation/siren-dired.el @@ -8,6 +8,61 @@ (use-package dired :straight (:type built-in) + :bind (:map dired-mode-map + ("M-?" . siren-dired-display-size)) + + :init + (defun siren-dired-display-size (arg) + "Display disk usage of marked items in Dired. + + When given a PREFIX, display raw size of items instead of disk usage." + (interactive "P") + (if arg + (siren-dired-get-size nil) + (siren-dired-get-disk-usage))) + + ;; Inspired by dired-get-size from: + ;; https://www.emacswiki.org/emacs/DiredGetFileSize + (defun siren-dired-get-disk-usage () + "Display total disk usage of marked items in Dired." + (interactive) + (let ((files (dired-get-marked-files))) + (with-temp-buffer + (shell-command (concat "/usr/bin/env du -sch " + (mapconcat 'shell-quote-argument files " ") + " | tail -n 1") + (current-buffer)) + (message "Size of all marked files: %s" + (progn + (re-search-forward "^\s*?\\([0-9.,]+[A-Za-z]+\\).*total$") + (match-string 1)))))) + + (defun siren-dired-get-size (arg) + "Display the total size of marked files in Dired." + (interactive "P") + (let ((size (siren-file-sizes (dired-get-marked-files)))) + (message "Size of all marked files: %s" + (if arg + (format "%.0f" size) + (file-size-human-readable size 'si))))) + + (defun siren-directory-size (dirname) + "Return the size of DIRNAME in bytes." + (siren-file-sizes (directory-files-recursively dirname ""))) + + (defun siren-file-sizes (filename-list) + "Return the sum of sizes of FILENAME-LIST in bytes." + (apply '+ + (mapcar 'siren-file-size filename-list))) + + (defun siren-file-size (filename) + "Return size of file FILENAME in bytes. + The size is converted to float for consistency. + This doesn't recurse directories." + (float (if (file-directory-p filename) + (siren-directory-size filename) + (file-attribute-size ; might be int or float + (file-attributes filename))))) :config (when (string-match-p "^gnu" (symbol-name system-type))