Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs dired - using predefined variable

Tags:

emacs

dired

In emacs dired I want to do something I do quite often in Microsoft PowerShell.

In PowerShell, I have a set of folders that I always use, and I assign their full path to global variables in my profile script (similar to init.el in the emacs world) e.g:

$standardTemp = "C:\Long\Path\To\Folder"

If I am in another folder and I want to copy something to the above folder, I do:

copy myFile $standardTemp

Even more useful as a feature, is if I put a backslash after $standardTemp, it will expand it out, so I can go into subfolders if I need to. This is a very awesome feature and saves me a lot of time.

With the dired copy command can I do something similar, if I define variables with e.g. setq in my init.el file?

like image 468
Tahir Hassan Avatar asked Sep 29 '22 04:09

Tahir Hassan


1 Answers

How about something like this?

;; Use ido
(require 'ido)
(ido-mode t)

;; Make a hash table to hold the paths
(setq my-target-dirs (make-hash-table :test 'equal))

;; Put some paths in the hash (sorry for Unix pathnames)
(puthash "home" "/home/jhrr/" my-target-dirs)
(puthash "target" "/home/jhrr/target/" my-target-dirs)

;; A function to return all the keys from a hash.
(defun get-keys-from-hash (hash)
  (let ((keys ()))
    (maphash (lambda (k v) (push k keys)) hash)
    keys))

;; And the function to prompt for a directory by keyword that is looked
;; up in the hash-table and used to build the target path from the
;; value of the lookup.
(defun my-dired-expand-copy ()
  (interactive)
  (let* ((my-hash my-target-dirs)
         (files (dired-get-marked-files))
         (keys (get-keys-from-hash my-hash)))
    (mapc (lambda (file)
            (copy-file file
                       (concat
                        (gethash
                         (ido-completing-read
                          (concat "copy " file " to: ") keys) my-hash)
                        (file-name-nondirectory file))))
          files)))

It's not exhaustively tested as I just whipped it up in 10 minutes, but it does the job and it can handle multiple files.

You will need to open the dired buffer in the directory the files are in and mark each file you want to copy with 'm', then invoke my-dired-expand-copy and it will prompt you for a target destination (in the form of a keyword from the hash-table we set-up) for the file before, finally, copying the file over to the directory that maps to the target keyword.

It doesn't quite cover the sub-directories use-case you mention, but it shouldn't be too hard to get there given a bit more hacking.

UPDATE:

This should now prompt you to be able to descend into subdirectories from an original target; maybe not the most mind-shatteringly wonderful UX on the whole, but, it works:

(defun my-dired-expand-copy-2 ()
  (interactive)
  (let* ((my-hash my-target-dirs)
         (files (dired-get-marked-files))
         (keys (get-keys-from-hash my-hash)))
    (mapc (lambda (file)
            (let ((target (gethash
                           (ido-completing-read
                            (concat "copy " file " to: ") keys) my-hash)))
              (if (y-or-n-p "Descend?")
                  ;; Descend into subdirectories relative to target dir
                  (let ((new-target (ido-read-directory-name "new dir: " target))) 
                    (copy-file file (concat new-target
                                            (file-name-nondirectory file)))
                    (message (concat "File: " file " was copied to " new-target)))
                ;; Else copy to root of originally selected directory
                (copy-file file (concat target (file-name-nondirectory file)))
                (message (concat "File: " file " was copied to " target)))))
          files)))
like image 100
jhrr Avatar answered Oct 05 '22 07:10

jhrr