How about something like that?
;; 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 (kv) (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 is not exhaustively verified, as I just whipped it in 10 minutes, but it does the job and can process multiple files.
You will need to open the executable buffer in the directory where the files are located and mark each file that you want to copy with "m", then call my-dired-expand-copy , and it will prompt you to specify the destination (in form the keyword from the hash table table that we set) for the file, before finally copying the file to a directory that maps to the target keyword.
This doesn't quite apply to the case of the subdirectories you are talking about, but it should not be too complicated to get a bit more hack there.
UPDATE:
Now you should invite you to go down to subdirectories from the original target; perhaps not the most surprisingly wonderful UX overall, 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-np "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)))
source share