Created
July 27, 2026 03:36
-
-
Save knu/3c495877aa373b8a8f7fed065dcd9d16 to your computer and use it in GitHub Desktop.
Start Dired from Finder or the current directory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ;;; dired-start-dwim.el --- Start Dired intelligently -*- lexical-binding: t; -*- | |
| ;; Copyright (c) 2026 Akinori MUSHA | |
| ;; SPDX-License-Identifier: BSD-2-Clause | |
| ;; Author: Akinori MUSHA <knu@iDaemons.org> | |
| ;; Package-Requires: ((emacs "27.1")) | |
| ;; Keywords: files, mac | |
| ;;; Commentary: | |
| ;; `dired-start-dwim' opens the files selected in the frontmost macOS | |
| ;; Finder window. On other systems, or when Finder is unavailable, it | |
| ;; opens `default-directory'. When diredfd is installed, the resulting | |
| ;; buffer also follows Finder's sort order. | |
| ;;; Code: | |
| (require 'cl-lib) | |
| (require 'dired) | |
| (require 'subr-x) | |
| (declare-function diredfd-do-sort "diredfd" (sort-key sort-order)) | |
| (defun dired-start-dwim--osa-script (script) | |
| "Run AppleScript SCRIPT and return its output." | |
| (if (fboundp 'mac-osa-script) | |
| (mac-osa-script script) | |
| (let ((osascript (executable-find "osascript"))) | |
| (unless osascript | |
| (error "Cannot find osascript")) | |
| (with-temp-buffer | |
| (unless (zerop (process-file | |
| osascript nil t nil | |
| "-ss" "-l" "AppleScript" "-e" script)) | |
| (error "AppleScript failed: %s" (string-trim (buffer-string)))) | |
| (string-trim-right (buffer-string)))))) | |
| (defun dired-start-dwim--finder-selected-files () | |
| "Return files selected in the frontmost Finder window." | |
| (let* ((output | |
| (car | |
| (split-string-and-unquote | |
| (dired-start-dwim--osa-script | |
| " | |
| tell application \"Finder\" | |
| if (count windows) is 0 | |
| make new Finder window to path to Downloads folder | |
| end if | |
| set selected to selection | |
| set current to POSIX path of ((target of front Finder window) as text) | |
| end tell | |
| set n to count selected | |
| set output to \"\" | |
| if n is 0 then | |
| set output to current | |
| else if n is 1 then | |
| set output to POSIX path of (selected as string) & \"\\n\" | |
| else | |
| repeat with i from 1 to n | |
| set output to output & (POSIX path of (item i of selected as string)) & \"\\n\" | |
| end repeat | |
| end if | |
| if output is not \"\" then | |
| return output | |
| end if | |
| ")))) | |
| (files (and output (split-string output "\n" t)))) | |
| files)) | |
| (defun dired-start-dwim--finder-sort-spec () | |
| "Return the sort key and order of the frontmost Finder window." | |
| (when-let* | |
| ((output | |
| (car | |
| (split-string-and-unquote | |
| (dired-start-dwim--osa-script | |
| " | |
| tell application \"Finder\" | |
| tell list view options of front Finder window | |
| set col to sort column | |
| return (name of col as text) & \" \" & (sort direction of col as text) | |
| end tell | |
| end tell | |
| ")))) | |
| ((string-match "\\`\\(.+\\) column \\(normal\\|reversed\\)\\'" output))) | |
| (cons | |
| (pcase (match-string 1 output) | |
| ("name" 'filename) | |
| ("modification date" 'time) | |
| ("size" 'size) | |
| ("kind" 'extension) | |
| (_ 'filename)) | |
| (if (string= (match-string 2 output) "reversed") | |
| 'desc | |
| 'asc)))) | |
| (defun dired-start-dwim--start (&optional file-or-files switches) | |
| "Start Dired with FILE-OR-FILES selected. | |
| FILE-OR-FILES may be a single file, a directory, or a list of | |
| files and directories. Pass optional SWITCHES to `dired'." | |
| (let ((files (if (stringp file-or-files) | |
| (list file-or-files) | |
| (or file-or-files (list default-directory))))) | |
| (if (= (length files) 1) | |
| (let* ((file (expand-file-name (or (car files) default-directory))) | |
| (directory (if (file-directory-p file) | |
| file | |
| (file-name-directory file))) | |
| (buffer (dired directory switches))) | |
| (with-current-buffer buffer | |
| (revert-buffer) | |
| (dired-goto-file | |
| (if (file-directory-p file) | |
| (concat (file-name-as-directory file) "..") | |
| file))) | |
| (switch-to-buffer buffer)) | |
| (let* ((files (mapcar #'expand-file-name files)) | |
| (root | |
| (file-name-directory | |
| (cl-reduce #'fill-common-string-prefix files))) | |
| (buffer (dired root switches))) | |
| (with-current-buffer buffer | |
| (revert-buffer) | |
| (dolist (file files) | |
| (let ((directory root)) | |
| (dolist | |
| (component | |
| (butlast | |
| (split-string (file-relative-name file root) "/" t))) | |
| (setq directory (expand-file-name component directory)) | |
| (when (file-directory-p directory) | |
| (dired-maybe-insert-subdir directory))) | |
| (when (dired-goto-file file) | |
| (save-excursion (dired-mark 1)))))) | |
| (switch-to-buffer buffer))) | |
| (when (and (bound-and-true-p hl-line-mode) | |
| (fboundp 'hl-line-highlight)) | |
| (hl-line-highlight)))) | |
| ;;;###autoload | |
| (defun dired-start-dwim () | |
| "Start Dired from Finder selection or `default-directory'. | |
| On macOS, use the files selected in the frontmost Finder window. | |
| When diredfd is available, also follow Finder's sort order." | |
| (interactive) | |
| (let* ((use-finder (eq system-type 'darwin)) | |
| (files | |
| (and use-finder | |
| (ignore-errors | |
| (dired-start-dwim--finder-selected-files)))) | |
| (sort-spec | |
| (and files | |
| (fboundp 'diredfd-do-sort) | |
| (ignore-errors | |
| (dired-start-dwim--finder-sort-spec))))) | |
| (dired-start-dwim--start files) | |
| (when sort-spec | |
| (diredfd-do-sort (car sort-spec) (cdr sort-spec))))) | |
| (provide 'dired-start-dwim) | |
| ;;; dired-start-dwim.el ends here |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment