;; dired-trns.el - file transformers for dired shell commands. ;; Id: dired-trns.el,v 1.6 1991/07/05 13:36:01 sk RelBeta ;; Code contributed by Hans Chalupsky . ;; Integrated with my dired.el sk@sparc0 11-Jan-1991 14:38. ;; And hacked up a bit. ;; LISPDIR ENTRY for the Elisp Archive =============================== ;; LCD Archive Entry: ;; dired-trns|Hans Chalupsky|hans@cs.Buffalo.EDU ;; |Filename Transformation for Tree Dired Shell Commands ;; |Date: 1991/07/05 13:36:01 |Revision: 1.6 | ;; INSTALLATION ====================================================== ;; Put this file into your load-path and add (load "dired-trns") to ;; your dired-load-hook, e.g. ;; ;; (setq dired-load-hook '(lambda () ;; ;; possibly more statements here ;; (load "dired-trns"))) ;; Transformers are functions that take a file (a string) as an argument ;; and transform it into some other string (e.g., a filename without an ;; extension). ;; ;; Each transformer is associated with a dispatch character. The associations ;; are stored in a keymap for fast and easy lookup. The dispatch character ;; is used to activate the associated transformer function at a particular ;; position in a shell command issued in dired. ;; ;; Transformers can be used to construct complicated shell commands that ;; operate on a large number of files, for example, they allow to create ;; functionality such as "mv *.lsp *.lisp" where each .lsp file is ;; renamed into a a file with same name but new extension .lisp. (defvar dired-trans-map (make-keymap) "Array that associates keys with file transformer functions") (defmacro dired-trans-define (char &rest body) "Macro that assigns the transformer function (lambda (file) BODY) to CHAR (a character or string). BODY must return a string (the transformed file or whatever. This macro allows easy definition of user specific transformation functions." (if (not (stringp char)) (setq char (char-to-string char))) (list 'define-key 'dired-trans-map char (list 'function (append '(lambda (file)) body)))) (defun dired-trans-run (transformers file) "Applies each transformer supplied in the string TRANSFORMERS in sequence to FILE and returns the concatenation of the results." (mapconcat (function (lambda (transformer) (setq transformer (char-to-string transformer)) (funcall (or (lookup-key dired-trans-map transformer) (error "Undefined transfomer: %s" transformer)) file))) transformers nil)) (defvar dired-trans-re-ext "\\.[^.]*\\(\\.\\(\\(g?z\\)\\|Z\\)\\)?$" "The part of a filename matching this regexp will be viewed as extension") (defun dired-trans-init () "Defines a basic set of useful transformers. * is a noop that returns the unmodified filename (equivalent to [dbe]). n returns the Name component of a filename without directory information d returns the Directory component of a filename b returns the Basename of a filename, i.e., the name of the file without directory and extension (see dired-trans-re-ext) A basename with directory component can be obtained by [db]. e returns the Extension of a filename (i.e., whatever dired-trans-re-ext splits off) v returns a file without directory and without ,v suffixes if any. z returns a file without directory and without .Z .z .gz suffixes if any." (dired-trans-define "*" file) (dired-trans-define "n" (or (file-name-nondirectory file) "")) (dired-trans-define "d" (or (file-name-directory file) "")) (dired-trans-define "b" (setq file (dired-trans-run "n" file)) (substring file 0 (string-match dired-trans-re-ext file))) (dired-trans-define "e" (let ((e (string-match dired-trans-re-ext file))) (if e (substring file e) ""))) (dired-trans-define "v" (setq file (dired-trans-run "n" file)) (substring file 0 (string-match ",v$" file))) (dired-trans-define "z" (setq file (dired-trans-run "n" file)) (substring file 0 (string-match "\\.\\(\\(g?z\\)\\|Z\\)$" file))) ) (dired-trans-init) (defun dired-trans-mklist (files &optional transformers) "Takes a list of FILES and applies the sequence of TRANSFORMERS to each of them. The transformed results are concatenated, separated by dired-mark-separator, prefixed by dired-mark-prefix and postfixed by dired-mark-postfix to generate a file list suitable for a particular shell." (if (not (consp files))(setq files (list files))) (if (null transformers) (setq transformers "*")) (let ((file-list (mapconcat (function (lambda (file) (shell-quote (dired-trans-run transformers file)))) files dired-mark-separator))) (if (> (length files) 1) (concat dired-mark-prefix file-list dired-mark-postfix) file-list))) ;; By default, transformations can be specified like this: ;; [db] or [dv] or #z# or #dbe# or #dbe (blank at the end). (defvar dired-trans-starters "[#[]" "User definable set of characters to be used to indicate the start of a transformer sequence") (defvar dired-trans-enders "[]# ]" "User definable set of characters to be used to indicate the end of a transformer sequence") (defun dired-trans-expand (command files) "Takes a shell COMMAND and a list of FILES and substitutes each occurance of a transformer sequence by an accordingly transformed file list. Special characters such as [,] or * can be quoted with a backslash." (let ((quoted nil) (collect-transformers nil) (transformers "")) (mapconcat (function (lambda (char) (setq char (char-to-string char)) (cond (quoted (setq quoted nil) char) ((equal char "\\") (setq quoted t) nil) (collect-transformers (cond ((string-match dired-trans-enders char) (setq collect-transformers nil) (prog1 (dired-trans-mklist files transformers) (setq transformers ""))) (t (setq transformers (concat transformers char)) nil))) ((string-match dired-trans-starters char) (setq collect-transformers t) nil) ;; for compatibility and as a special case that should ;; not be redefinable by the user (used below) ((equal char "*") (dired-trans-mklist files "*")) (t char)))) command nil))) (defun dired-trans-make (command files &optional all-at-once) "Takes a shell COMMAND and a list of FILES and returns a command operating on the list of files (transformed if COMMAND contains transformers). If ALL-AT-ONCE is t the resulting command will be of the form cmd file1 file2 ... fileN otherwise it will be cmd file1; cmd file2; ... cmd fileN; Both examples assume a single reference to the file list." (let (fns expanded-command) (cond (all-at-once (setq expanded-command (dired-trans-expand command files)) (if (equal command expanded-command) (concat command (dired-trans-expand " *" files)) expanded-command)) (t (mapconcat (function (lambda (file) (dired-trans-make command file t))) files ";"))))) ;; Redefine this function from dired.el: (defun dired-shell-stuff-it (command file-list on-each &optional raw-arg) "Make up a shell command line from COMMAND and FILE-LIST. If ON-EACH is t, COMMAND should be applied to each file, else simply concat all files. The list of marked files is appended to the command string unless asterisks `*' or transformer sequences enclosed in `[]' indicate the place(s) where the (transformed) list should go. See documentation of function dired-trans-init for a list of transformers. With a zero argument the resulting command will be of the form cmd file1; cmd file2; ... cmd fileN assuming only one reference to the file list. E.g., to rename all .lsp files into .lisp files mark all the .lsp files and issue the command `mv * [db].lisp' ." (dired-trans-make command file-list (not on-each)))