home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / msdos / demacs / edired / dired.el < prev    next >
Encoding:
Text File  |  1991-11-21  |  88.9 KB  |  2,377 lines

  1. ;; DIRED commands for Emacs.  $Revision: 4.53 $
  2. ;; Copyright (C) 1985, 1986, 1990 Free Software Foundation, Inc.
  3.  
  4. ;; This file is part of GNU Emacs.
  5.  
  6. ;; GNU Emacs is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation; either version 1, or (at your option)
  9. ;; any later version.
  10.  
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;; GNU General Public License for more details.
  15.  
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  18. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. ;; Enhanced from 18.55 dired by Sebastian Kremer.
  21. ;; Send bug reports to <sk@thp.uni-koeln.de>.
  22.  
  23. (provide 'dired)
  24.  
  25. (defconst dired-version (substring "$Revision: 4.53 $" 11 -2)
  26.   "The revision number of dired (as string).  The complete RCS id is:
  27.  
  28.   $Id: dired.el,v 4.53 90/12/21 12:09:56 sk Exp $
  29.  
  30. Don't forget to mention this when reporting bugs.")
  31.  
  32. ;; compatibility package when using Emacs 18.55
  33. (require 'emacs-19)
  34.  
  35. ;; can now contain even `F', but still not `i'.
  36. ;In loaddefs.el
  37. ;(defvar dired-listing-switches "-al"
  38. ;  "Switches passed to ls for dired. MUST contain the `l' option.
  39. ;CANNOT contain the `F' option.")
  40.  
  41. ;;; patched by Manabu Higashida for demacs-1.1 91/10/28
  42. (defvar dired-chmod-program
  43.   "chmod"
  44.   "Pathname of chmod command.")
  45.  
  46. (defvar dired-chgrp-program
  47.   "chgrp"
  48.   "Pathname of chgrp command.")
  49. ;;; end of patch
  50.  
  51. (defvar dired-chown-program
  52.   (if (memq system-type '(hpux usg-unix-v)) "/bin/chown" "/etc/chown")
  53.   "Pathname of chown command.")
  54.  
  55. (defvar dired-ls-program "ls"
  56.   ;; GNU ls has no way to suppress the group, so one might prefer /bin/ls.
  57.   "*Absolute or relative name of the ls program used by dired.")
  58.  
  59. (defvar dired-ls-F-marks-symlinks nil
  60.   "*Set this to t if dired-ls-program with -lF marks the symbolic link
  61. itself with a trailing @ (usually the case under Ultrix).
  62.  
  63. Example: if `ln -s foo bar; ls -F bar' gives `bar -> foo', set it to
  64. nil (the default), if it gives `bar@ -> foo', set it to t.
  65.  
  66. Dired checks if there is really a @ appended.  Thus, if you have a
  67. marking ls program on one host and a non-marking on another host, and
  68. don't care about symbolic links which really contain a trailing @, you
  69. can always set this variable to t.")
  70.  
  71. (defvar dired-directory nil
  72.   "The directory name or shell wildcard passed as argument to ls.
  73. Local to each dired buffer.")
  74.  
  75. (defvar dired-actual-switches nil
  76.   "The actual (buffer-local) value of dired-listing-switches.")
  77.  
  78. ;; This makes matches rather slow - perhaps -is should be forbidden.
  79. ;; If you don't use -is, you can set this to "".
  80. (defvar dired-re-inode-size ;;"\\(\\s *[0-9]*\\s *[0-9]* \\)?"
  81.   "\\s *[0-9]*\\s *[0-9]* ?" ; this seems to be slightly faster
  82.   ;;"Regexp for optional initial inode and file size as produced
  83.   ;;by ls' -i and -s flags."
  84. )
  85.  
  86. ;; These regexps must be tested at beginning-of-line, but are also
  87. ;; used to search for next matches, so omitting "^" won't do.
  88. ;; Replacing "^" by "\n" might be faster, but fails on the first line,
  89. ;; thus excluding the possibility to mark subdir lines.
  90.  
  91. (defconst dired-re-mark "^[^ \n]")
  92. ;; "Regexp matching a marked line.
  93. ;; Important: the match ends just after the marker."
  94. ;; "\n[^ \n]" 
  95. (defconst dired-re-maybe-mark "^. ")
  96. ;;; patched by Manabu Higashida for demacs-1.1 91/10/28 
  97. ;;; original lines are
  98. ;(defconst dired-re-dir (concat dired-re-maybe-mark dired-re-inode-size "d"))
  99. ;(defconst dired-re-sym (concat dired-re-maybe-mark dired-re-inode-size "l"))
  100. ;;; and new lines are
  101. (defconst dired-re-dir (concat dired-re-maybe-mark dired-re-inode-size "d[-r]"))
  102. (defconst dired-re-sym (concat dired-re-maybe-mark dired-re-inode-size "l[-r]"))
  103. ;;; end of patch
  104. (defconst dired-re-exe
  105.   (mapconcat (function
  106.           (lambda (x)
  107.         (concat dired-re-maybe-mark dired-re-inode-size x)))
  108.          '("-[-r][-w][xs][-r][-w].[-r][-w]." 
  109.            "-[-r][-w].[-r][-w][xs][-r][-w]."
  110.            "-[-r][-w].[-r][-w].[-r][-w][xst]")
  111.          "\\|"))
  112. (defconst dired-re-dot "^.* \\.\\.?$")
  113.  
  114. ;;; Customizable variables:
  115.  
  116. ;; Might use {,} for bash or csh:
  117. (defvar dired-mark-prefix "" "*Prepended to marked files.")
  118. (defvar dired-mark-postfix "" "*Appended to marked files.")
  119. (defvar dired-mark-separator " " "*Separates marked files.")
  120.  
  121. ;; User might like the shorter "! on %s: " and "& on %s: " to save screen space:
  122. (defvar dired-background-prompt "Background shell command on %s: "
  123.   "*Format string for \\[dired-mark-background-shell-command] prompt.")
  124.  
  125. (defvar dired-shell-prompt "Shell command on %s: "
  126.   "*Format string for \\[dired-mark-shell-command] prompt.")
  127.  
  128. (defvar shell-maximum-command-length 10000
  129.   ;; 10K is a reasonable length to give the user a chance for second
  130.   ;; thoughts.
  131.   ;; SunOS 4.1 csh(1) mentions
  132.   ;;     1048576 as system limit on argument lists (that's a meg!)
  133.   ;;    max. 1706 arguments to a command using file name expansion
  134.   ;;     1024 as maximum word length
  135.   ;; Assuming 10 chars per filename, about 17000 should be OK.
  136.   "*If non-nil, maximum number of bytes a dired shell command can have
  137. before the user is asked for confirmation.")
  138.  
  139. (defvar dired-print-command "print %s"
  140.   "Format string for shell command to print files in dired.
  141. Can actually be used for any special purpose shell command to be run
  142. by \\[dired-mark-print].")
  143.  
  144. (defvar dired-trivial-filenames "^\\.\\.?$\\|^#"
  145.   "*Regexp of files to skip when moving point to the first file of a
  146. new directory listing.
  147. Nil means move to the subdir line, t means move to first file.")
  148.  
  149. (defvar dired-basename-regexp "\\(.+\\)\\.\\(.+\\)$")
  150.  
  151. ;; user might prefer 'y-or-n-p or even 'identity, in effect disabling
  152. ;; all confirmation upon deletion. 
  153. (or (fboundp 'dired-yes)
  154.     (fset 'dired-yes 'yes-or-no-p))
  155.  
  156. ;;; Hook variables
  157.  
  158. (defvar dired-load-hook nil
  159.   "Run after loading dired.
  160. You can customize key bindings or load extensions with this.")
  161.  
  162. (defvar dired-mode-hook nil
  163.   "Run in each new dired buffer.")
  164.  
  165. (defvar dired-readin-hook nil
  166.   "After each listing of a file or directory, this hook is run
  167. with the buffer narrowed to the listing.")
  168.  
  169. ;; An example filter to squeeze spaces:
  170. ;(setq dired-readin-hook
  171. ;      '(lambda () (goto-char (point-min))
  172. ;     (while (re-search-forward " +" nil t) (replace-match " "))))
  173. ;
  174. ;  See dired-extra.el for an example on how to use it for sorting on
  175. ;  file size.   It also supports use of several different markers
  176. ;  (other than `D' and `*') in parallel and a minibuffer history for
  177. ;  shell commands.  Email if you want to try it.  It is about 20K.
  178.  
  179. ;;; Global internal variables
  180.  
  181. ;; next two used by function dired-mark-prompt
  182. (defvar dired-mark-count 0
  183.   "Count of marked files as determined by the last dired-mark-get-files.")
  184. (defvar dired-mark-files nil
  185.   "List of marked files as determined by the last dired-mark-get-files.")
  186.  
  187. (defvar dired-flagging-regexp nil
  188.   "Last regexp used in flagging files.")
  189.  
  190. ;;; Macros must be defined before they are used - for the byte compiler.
  191.  
  192. (defmacro dired-count-up ()
  193.   ;; Increment variable dired-mark-count.
  194.   '(setq dired-mark-count (1+ dired-mark-count)))
  195.  
  196. (defun dired-plural-s ()
  197.   (if (= 1 dired-mark-count) "" "s"))
  198.  
  199. (defmacro dired-mark-if (predicate msg)
  200.   (` (let ((buffer-read-only nil))
  201.        (save-excursion
  202.      (setq dired-mark-count 0)
  203.      (message "0 %ss..." (, msg))
  204.      (goto-char (point-min))
  205.      (while (not (eobp))
  206.        (if (, predicate)
  207.            (progn
  208.          (delete-char 1)
  209.          (insert dired-marker-char)
  210.          (setq dired-mark-count (1+ dired-mark-count))))
  211.        (forward-line 1))
  212.      (message "%s %s%s %s%s."
  213.           dired-mark-count
  214.           (, msg)
  215.           (dired-plural-s)
  216.           (if (eq dired-marker-char ?\ ) "un" "")
  217.           (if (eq dired-marker-char ?D) "flagged" "marked"))))))
  218.  
  219. (defmacro dired-mark-map (body arg)
  220. ;  "Macro: Perform BODY with point on each marked line and
  221. ;mark it again (so BODY can call dired-redisplay without losing markers).
  222. ;If no file was marked, execute BODY on the current line.
  223. ;If ARG is non-nil, use current file instead."
  224.   ;; BODY should not be too long as it is expanded three times.
  225.   (` (let (buffer-read-only found)
  226.        (if arg
  227.        (, body)
  228.      (let (opoint (regexp (dired-marker-regexp)))
  229.        (save-excursion
  230.          (goto-char (point-min))
  231.          (while (re-search-forward regexp nil t)
  232.            ;; If body contains dired-redisplay, the deletion (and
  233.            ;; new insertion) of the line confuses save-excursion.
  234.            (setq opoint (point))    ; column 1 stays, however
  235.            (, body)
  236.            (goto-char opoint)
  237.            (setq found t))))
  238.      (or found (, body))))))
  239.  
  240. ;; The following functions are redefinable for VMS or ange-ftp
  241. ;; - or for customization.
  242.  
  243. (defun dired-ls (file &optional switches wildcard full-directory-p)
  244. ;  "Insert ls output of FILE, optionally formatted with SWITCHES.
  245. ;Optional third arg WILDCARD means treat FILE as shell wildcard.
  246. ;Optional fourth arg FULL-DIRECTORY-P means file is a directory and
  247. ;switches do not contain `d'.
  248. ;
  249. ;SWITCHES default to dired-listing-switches.
  250. ;Uses dired-ls-program and maybe shell-file-name to do the work."
  251.   (if (not dired-ls-program)
  252.       (dos-dired-ls file switches wildcard full-directory-p)
  253.     (progn
  254.       (or switches (setq switches dired-listing-switches))
  255.       (if wildcard
  256.       (let ((default-directory (file-name-directory file)))
  257.         (call-process shell-file-name nil t nil
  258.               (if (eq system-type 'ms-dos) "\/c" "-c")
  259.               (concat dired-ls-program " -d " switches " "
  260.                   (file-name-nondirectory file))))
  261.     (call-process dired-ls-program nil t nil switches
  262.               (if (eq system-type 'ms-dos)
  263.               (directory-file-name file)
  264.             file))))))
  265.  
  266. (defun dired-call-process (program discard &rest arguments)
  267. ;  "Run PROGRAM with output to current buffer unless DISCARD is t.
  268. ;Remaining arguments are strings passed as command arguments to PROGRAM."
  269. ;;; patched by Manabu Higashida for demacs-1.1 91/10/28
  270. ;;; original line is
  271. ;  (apply 'call-process program nil (not discard) nil arguments))
  272. ;;; and new lines are
  273.   (if (file-exists-p program)
  274.       (apply 'call-process program nil (not discard) nil arguments)
  275.     (and (not discard)
  276.      (insert "Command not found."))))
  277. ;;; end of patch
  278.  
  279. ;; A "why" command (`W'?) could pop-up this:
  280. (defconst dired-log-buf "*Dired log*")
  281.  
  282. (defun dired-why ()
  283.   "Pop up a buffer with error log output from Dired's last subprocesses."
  284.   (interactive)
  285.   (pop-to-buffer dired-log-buf))
  286.  
  287. (defun dired-check-process-handler ()
  288.   ;;"Run from function dired-check-process if there is output.
  289.   ;; Insert output in a log buffer and returns nil."
  290.   ;;- Old version raised error and aborted:
  291.   ;;-(progn (display-buffer err-buffer) (error "%s... error!" msg))
  292.   ;; Could cons up a list of failed args as with deleted files.
  293.   (let ((log-buf dired-log-buf))
  294.     (save-excursion
  295.       (set-buffer (get-buffer-create log-buf))
  296.       (goto-char (point-max))
  297.       (insert "\n\t" (current-time-string) "\t("  program ")\n")
  298.       (insert-buffer err-buffer))
  299.     (message "%s... error - type W or see buffer %s" msg log-buf)
  300.     ;;(ding t)                ; annoying
  301.     (sit-for 1)
  302.     nil))
  303.  
  304. (defun dired-check-process (program msg &rest arguments)
  305. ;  "Run PROGRAM, display MSG while running, and check for output.
  306. ;Remaining arguments are strings passed as command arguments to PROGRAM.
  307. ;If dired-check-process-checker returns t, call
  308. ;dired-check-process-handler and return its value.
  309. ;Else returns t for success."
  310.   (let (err-buffer err)
  311.     (message "%s..." msg)
  312.     (save-excursion
  313.       ;; Get a clean buffer for error output:
  314.       (setq err-buffer (get-buffer-create " *dired-check-process output*"))
  315.       (set-buffer err-buffer)
  316.       (erase-buffer)
  317.       (apply 'dired-call-process program nil arguments)
  318.       ;; In Emacs 19 the exit status should be checked instead.
  319.       ;; The following is not The Right Thing as some compress
  320.       ;; programs are verbose by default
  321.       (setq err (/= 0 (buffer-size))))
  322.     ;; Check for errors and display them:
  323.     (if err
  324.     (dired-check-process-handler)
  325.       (kill-buffer err-buffer)
  326.       (message "%s... done." msg)
  327.       t)))
  328.  
  329. (defun dired-insert-headerline (dir)
  330.   ;; No trailing slash, like ls does:
  331.   (insert "  " (directory-file-name dir) ":")
  332.   ;; put cursor on root subdir line:
  333.   (save-excursion (insert "\n")))
  334.  
  335. (defun dired-readin (dirname buffer)
  336.   (save-excursion
  337.     (message "Reading directory %s..." dirname)
  338.     (set-buffer buffer)
  339.     (let ((buffer-read-only nil))
  340.       (widen)
  341.       (erase-buffer)
  342.       (setq dirname (expand-file-name dirname))
  343.       (if (eq system-type 'vax-vms)
  344.       (vms-read-directory dirname dired-actual-switches buffer)
  345.     (if (file-directory-p dirname)
  346.         (dired-ls dirname dired-actual-switches nil t)
  347.       (if (not (file-readable-p
  348.             (directory-file-name (file-name-directory dirname))))
  349.           (insert "Directory " dirname " inaccessible or nonexistent.\n")
  350.         ;; else assume it contains wildcards:
  351.         (dired-ls dirname dired-actual-switches t))))
  352.       (goto-char (point-min))
  353.       (indent-rigidly (point-min) (point-max) 2)
  354.       (run-hooks 'dired-readin-hook)
  355.       ;; We need this to make the root dir have a header line as all
  356.       ;; other subdirs have:
  357.       (goto-char (point-min))
  358.       (dired-insert-headerline default-directory))
  359.     (set-buffer-modified-p nil)
  360.     (message "Reading directory %s...done" dirname)))
  361.  
  362. ;; This differs from dired-buffers in that it does not consider
  363. ;; subdirs of default-directory and searches for the _first_ match
  364. (defun dired-find-buffer (dirname)
  365.   (let ((blist (buffer-list))
  366.     found)
  367.     (while blist
  368.       (save-excursion
  369.         (set-buffer (car blist))
  370.     (if (and (eq major-mode 'dired-mode)
  371.          (equal dired-directory dirname))
  372.         (setq found (car blist)
  373.           blist nil)
  374.       (setq blist (cdr blist)))))
  375.     (or found
  376.     (create-file-buffer (directory-file-name dirname)))))
  377.  
  378. (defun dired-read-dir-and-switches (str)
  379.   ;; For use in interactive.
  380.   (list
  381.    (read-file-name (format "Dired %s (directory): " str)
  382.            nil default-directory nil)
  383.    (if current-prefix-arg 
  384.        (read-string "Dired listing switches: "
  385.             dired-listing-switches))))
  386.  
  387. (defun dired (dirname &optional switches)
  388.   "`Edit' directory DIRNAME--delete, rename, print, etc. some files in it.
  389. Prefix arg lets you change the buffer local value of dired-actual-switches.
  390. Dired displays a list of files in DIRNAME (which may also have
  391.   shell wildcards appended to select certain files).
  392. You can move around in it with the usual commands.
  393. You can flag files for deletion with C-d and then delete them by
  394.   typing `x'. 
  395. Type `h' after entering dired for more info."
  396.   ;; Cannot use (interactive "D") because of wildcards.
  397.   (interactive (dired-read-dir-and-switches ""))
  398.   (switch-to-buffer (dired-noselect dirname switches)))
  399.  
  400. (defun dired-other-window (dirname &optional switches)
  401.   "`Edit' directory DIRNAME.  Like M-x dired but selects in another window."
  402.   (interactive (dired-read-dir-and-switches "in other window "))
  403.   (switch-to-buffer-other-window (dired-noselect dirname switches)))
  404.  
  405. (defun dired-noselect (dirname &optional switches)
  406.   ;; Like M-x dired but returns the dired buffer as value, does not
  407.   ;; select it.
  408.   (or dirname (setq dirname default-directory))
  409.   ;; This loses the distinction between "/foo/*/" and "/foo/*" that
  410.   ;; some shells make:
  411.   (setq dirname (expand-file-name (directory-file-name dirname)))
  412.   (if (file-directory-p dirname)
  413.       (setq dirname (file-name-as-directory dirname)))
  414.   (dired-internal-noselect dirname switches))
  415.  
  416. (defun dired-internal-noselect (dirname &optional switches)
  417.   (let ((buffer (dired-find-buffer dirname))
  418.     (old-buf (current-buffer)))
  419.     (or switches (setq switches dired-listing-switches))
  420.     (save-excursion
  421.       (set-buffer buffer)
  422.       ;; must be set before dired-readin inserts the root line:
  423.       (setq default-directory (if (file-directory-p dirname)
  424.                   dirname (file-name-directory dirname)))
  425.       (let ((dired-actual-switches switches))
  426.     (dired-readin dirname buffer))
  427.       (dired-mode dirname switches))
  428.     ;; changing point inside a save-excursion is rather pointless... 
  429.     (unwind-protect
  430.     (progn            
  431.       (set-buffer buffer)
  432.       (goto-char (point-min))
  433.       (dired-initial-position))
  434.       (set-buffer old-buf))
  435.     buffer))
  436.  
  437. (defun dired-remember-marks ()
  438.   ;; Return alist of files and their marks, from point to eob.
  439.   (let (fil chr alist)
  440.     (while (re-search-forward dired-re-mark nil t)
  441.       (if (setq fil (dired-get-filename nil t))
  442.       (setq chr (preceding-char)
  443.         alist (cons (cons fil chr) alist))))
  444.     alist))
  445.  
  446. (defun dired-mark-remembered (alist)
  447.   ;; Mark all files remembered in ALIST.
  448.   (let (elt fil chr)
  449.     (while alist
  450.       (setq elt (car alist)
  451.         alist (cdr alist)
  452.         fil (car elt)
  453.         chr (cdr elt))
  454.       (if (dired-goto-file fil)
  455.       (save-excursion
  456.         (beginning-of-line)
  457.         (delete-char 1)
  458.         (insert chr))))))
  459.  
  460. (defun dired-revert (&optional arg noconfirm)
  461.   ;; Reread the dired buffer.  Should not fail even on completely
  462.   ;; garbaged buffers.
  463.   ;; All marks/flags are preserved.
  464.   (let ((opoint (point))
  465.     (ofile (dired-get-filename nil t))
  466.     (mark-alist nil)        ; save marked files
  467.     ;; Save old alist except default-directory:
  468.     (old-subdir-alist (cdr (reverse dired-subdir-alist)))
  469.     (buffer-read-only nil))
  470.     ;; Remember all marks/flags.  Must unhide to make this work.
  471.     (if selective-display
  472.     (subst-char-in-region (point-min) (point-max) ?\r ?\n))
  473.     (goto-char 1)
  474.     (setq mark-alist (dired-remember-marks))
  475.     (dired-readin dired-directory (current-buffer))
  476.     (dired-advertise)            ; no harm if already called
  477.     (setq dired-used-F            ; ls switches may have changed
  478.       (string-match "F" dired-actual-switches))
  479.     (dired-build-subdir-alist)        ; moving/retrieval cmds work now
  480.  
  481.     ;; Try to insert all subdirs that were displayed before
  482.     (or (string-match "R" dired-actual-switches)
  483.     (let (elt dir)
  484.       (while old-subdir-alist
  485.         (setq elt (car old-subdir-alist)
  486.           old-subdir-alist (cdr old-subdir-alist)
  487.           dir (car elt))
  488.         (condition-case ()
  489.         (dired-insert-subdir dir)
  490.           (error nil)))))
  491.  
  492.     ;; Mark files that were marked before
  493.     (dired-mark-remembered mark-alist)
  494.  
  495.     ;; Move cursor to where it was before
  496.     (or (and ofile (dired-goto-file ofile))
  497.     (goto-char opoint))
  498.     (dired-move-to-filename))
  499.  
  500.   ;; outside of the let scope:
  501.   (setq buffer-read-only t)        ; gets sometimes out of sync
  502. )
  503.  
  504. (defvar dired-mode-map nil "Local keymap for dired-mode buffers.")
  505. (if dired-mode-map
  506.     nil
  507.   (setq dired-mode-map (make-keymap))
  508.   (suppress-keymap dired-mode-map)
  509.   (define-key dired-mode-map " "  'dired-next-line)
  510.   (define-key dired-mode-map "!" 'dired-mark-shell-command)
  511.   (define-key dired-mode-map "#" 'dired-flag-auto-save-files)
  512.   (define-key dired-mode-map "$" 'dired-hide-subdir)
  513.   (define-key dired-mode-map "&" 'dired-mark-background-shell-command)
  514.   (define-key dired-mode-map "*" 'dired-mark-executables)
  515.   (define-key dired-mode-map "+" 'dired-create-directory)
  516.   (define-key dired-mode-map "." 'dired-clean-directory)
  517.   (define-key dired-mode-map "/" 'dired-mark-dirlines)
  518.   (define-key dired-mode-map "<" 'dired-prev-dirline)
  519.   (define-key dired-mode-map "=" 'dired-hide-all)
  520.   (define-key dired-mode-map ">" 'dired-next-dirline)
  521.   (define-key dired-mode-map "?" 'dired-summary)
  522.   (define-key dired-mode-map "@" 'dired-mark-symlinks)
  523.   (define-key dired-mode-map "B" 'dired-mark-byte-recompile)
  524.   (define-key dired-mode-map "C" 'dired-mark-compress)
  525.   (define-key dired-mode-map "D" 'dired-diff)
  526.   (define-key dired-mode-map "F" 'dired-flag-regexp-files)
  527.   (define-key dired-mode-map "G" 'dired-mark-chgrp)
  528.   (define-key dired-mode-map "K" 'dired-kill-subdir)
  529.   (define-key dired-mode-map "L" 'dired-mark-load)
  530.   (define-key dired-mode-map "M" 'dired-mark-chmod)
  531.   (define-key dired-mode-map "O" 'dired-mark-chown)
  532.   (define-key dired-mode-map "P" 'dired-mark-print)
  533.   (define-key dired-mode-map "R" 'dired-rename-regexp)
  534.   (define-key dired-mode-map "S" 'dired-sort-other)
  535.   (define-key dired-mode-map "U" 'dired-mark-uncompress)
  536.   (define-key dired-mode-map "W" 'dired-why)
  537.   (define-key dired-mode-map "X" 'dired-mark-delete)
  538.   (define-key dired-mode-map "\177" 'dired-backup-unflag)
  539.   (define-key dired-mode-map "\C-_" 'dired-undo)
  540.   (define-key dired-mode-map "\C-d" 'dired-flag-file-deleted)
  541.   (define-key dired-mode-map "\C-n" 'dired-next-line)
  542.   (define-key dired-mode-map "\C-p" 'dired-previous-line)
  543.   (define-key dired-mode-map "\C-xu" 'dired-undo)
  544.   (define-key dired-mode-map "\M-\C-?" 'dired-unflag-all-files)
  545.   (define-key dired-mode-map "\M-g" 'dired-goto-file)
  546.   (define-key dired-mode-map "\M-d" 'dired-down-subdir)
  547.   (define-key dired-mode-map "\M-G" 'dired-goto-subdir)
  548.   (define-key dired-mode-map "\M-k" 'dired-mark-kill)
  549.   (define-key dired-mode-map "\M-m" 'dired-mark-files)
  550.   (define-key dired-mode-map "\M-n" 'dired-next-subdir)
  551.   (define-key dired-mode-map "\M-p" 'dired-prev-subdir)
  552.   (define-key dired-mode-map "\M-u" 'dired-up-subdir)
  553.   (define-key dired-mode-map "\M-~" 'dired-backup-diff)
  554.   (define-key dired-mode-map "^" 'dired-up-directory)
  555.   (define-key dired-mode-map "c" 'dired-mark-copy)
  556.   (define-key dired-mode-map "d" 'dired-flag-file-deleted)
  557.   (define-key dired-mode-map "e" 'dired-find-file)
  558.   (define-key dired-mode-map "f" 'dired-find-file)
  559.   (define-key dired-mode-map "g" 'revert-buffer)
  560.   (define-key dired-mode-map "h" 'describe-mode)
  561.   (define-key dired-mode-map "i" 'dired-insert-subdir)
  562.   (define-key dired-mode-map "k" 'dired-kill-line)
  563.   (define-key dired-mode-map "l" 'dired-mark-redisplay)
  564. ;  (define-key dired-mode-map "m" 'dired-mark-file)
  565.   (define-key dired-mode-map "m" 'dired-mark-subdir-or-file)
  566.   (define-key dired-mode-map "n" 'dired-next-line)
  567.   (define-key dired-mode-map "o" 'dired-find-file-other-window)
  568.   (define-key dired-mode-map "p" 'dired-previous-line)
  569.   (define-key dired-mode-map "q" 'kill-buffer)
  570.   (define-key dired-mode-map "r" 'dired-mark-move)
  571.   (define-key dired-mode-map "s" 'dired-sort-toggle)
  572.   (define-key dired-mode-map "u" 'dired-unflag)
  573.   (define-key dired-mode-map "v" 'dired-view-file)
  574.   (define-key dired-mode-map "w" 'dired-copy-filename-as-kill)
  575.   (define-key dired-mode-map "x" 'dired-do-deletions)
  576.   (define-key dired-mode-map "z" 'bury-buffer)
  577.   (define-key dired-mode-map "~" 'dired-flag-backup-files)
  578. )
  579.  
  580.  
  581. ;; Dired mode is suitable only for specially formatted data.
  582. (put 'dired-mode 'mode-class 'special)
  583.  
  584. (defun dired-mode (&optional dirname switches)
  585.   "Mode for `editing' directory listings.
  586. In dired, you are `editing' a list of the files in a directory and
  587. \(optionally) its subdirectories.
  588. You can move using the usual cursor motion commands.
  589. Letters no longer insert themselves.  Digits are prefix arguments.
  590. Instead, type d to flag a file for Deletion.
  591. Type m to mark a file or subdirectory for later commands.
  592.   Most commands operate on the marked files and use the current file
  593.   if no files are marked (or a prefix argument is given).
  594. Type u to Unflag a file (remove its D flag or any mark).
  595.   Type DEL to back up one line and unflag.
  596. Type x to eXecute the deletions requested.
  597. Type f to Find the current line's file
  598.   (or dired it in another buffer, if it is a directory).
  599. Type i to dired a subdirectory In situ and K to kill it again or ^ to
  600.   go back.  Type v to view a file or its in situ subdirectory.
  601. Type ^ to go to the parent directory.
  602. Type < and > to move to file lines that are directories.
  603. Type M-n, M-p, M-u, M-d to move to in situ subdirectory headerlines.
  604. Type M-g to go to a file's line, M-G to go to a subdir headerline.
  605. Type o to find file or dired directory in Other window.
  606. Type # to flag temporary files (names beginning with #) for deletion.
  607. Type ~ to flag backup files (names ending with ~) for deletion.
  608. Type . to flag numerical backups for deletion.
  609.   (Spares dired-kept-versions (or prefix argument) recent versions.)
  610. Type + to create a new directory.
  611. Type r to Rename a file or move the marked files to another directory.
  612. Type c to Copy files.
  613. Type D to Diff a file, M-~ to diff it with its backup.
  614. Type l to reList files or subdirectories.
  615. Type s to toggle sorting by name/date, S to set dired-actual-switches.
  616. Type g to read all directories again.  This retains all marks.
  617. Space and Rubout can be used to move down and up by lines.
  618. Also:
  619.  C      -- compress files          U -- uncompress files
  620.  !      -- run shell command on files    & -- background shell command
  621.  M, G, O -- change mode, group or owner of files
  622.  L, B      -- load or byte-compile emacs lisp files
  623.  F, M-m  -- flag (`D') or mark (`*') files matching a regexp
  624.  *, @, / -- (un)mark executables, symbolic links, directories
  625.  $, =      -- (un)hide this or all subdirectories
  626.  X       -- delete marked files
  627.  
  628. If dired ever gets confused, you can either type \\[dired-revert] \
  629. to read the
  630. directories again, type \\[dired-mark-redisplay] \
  631. to relist a single file or subdirectory, or
  632. type \\[dired-build-subdir-alist] to parse the buffer again for the
  633. directory tree.
  634.  
  635. Hooks: dired-load-hook, dired-mode-hook, dired-readin-hook (q.v.)
  636.  
  637. \\{dired-mode-map}"
  638.   (interactive)
  639.   (kill-all-local-variables)
  640.   (make-local-variable 'revert-buffer-function)
  641.   (setq revert-buffer-function 'dired-revert)
  642.   (setq major-mode 'dired-mode)
  643.   (setq mode-name "Dired")
  644.   (make-local-variable 'dired-directory)
  645.   (setq dired-directory (or dirname default-directory))
  646.   (make-local-variable 'list-buffers-directory)
  647.   (setq list-buffers-directory dired-directory)    ; never used!?
  648.   (make-local-variable 'dired-actual-switches)
  649.   (setq dired-actual-switches (or switches
  650.                   dired-listing-switches))
  651.   (set (make-local-variable 'dired-used-F)
  652.        (string-match "F" dired-actual-switches))
  653.   (setq mode-line-buffer-identification
  654.     (list (concat "Dired " dired-version " (beta): %17b")))
  655.   (setq case-fold-search nil)
  656.   (setq buffer-read-only t)
  657.   (use-local-map dired-mode-map)
  658.   (make-local-variable 'minor-mode-alist)
  659.   (setq selective-display t)        ; for subdirectory hiding
  660.   (dired-advertise)
  661.   (make-local-variable 'dired-subdir-alist)
  662.   (setq dired-subdir-alist nil)
  663.   (dired-build-subdir-alist)
  664.   (make-local-variable 'dired-sort-mode)
  665.   (dired-sort-mode)
  666.   (setq minor-mode-alist
  667.     (cons '(dired-sort-mode dired-sort-mode)
  668.           minor-mode-alist))
  669.   (run-hooks 'dired-mode-hook))
  670.  
  671.  
  672. (defun dired-repeat-over-lines (arg function)
  673.   ;; This version skips non-file lines.
  674.   (beginning-of-line)
  675.   (while (and (> arg 0) (not (eobp)))
  676.     (setq arg (1- arg))
  677.     (beginning-of-line)
  678.     (while (and (not (eobp)) (dired-between-files)) (forward-line 1))
  679.     (save-excursion (funcall function))
  680.     (forward-line 1)
  681.     (dired-move-to-filename))
  682.   (while (and (< arg 0) (not (bobp)))
  683.     (setq arg (1+ arg))
  684.     (forward-line -1)
  685.     (while (and (not (bobp)) (dired-between-files)) (forward-line -1))
  686.     (beginning-of-line)
  687.     (save-excursion (funcall function))
  688.     (dired-move-to-filename)))
  689.  
  690. (defun dired-flag-file-deleted (arg)
  691.   "In dired, flag the current line's file for deletion.
  692. With arg, repeat over several lines."
  693.   (interactive "p")
  694.   (dired-repeat-over-lines arg
  695.     '(lambda ()
  696.        (let ((buffer-read-only nil))
  697.      (delete-char 1)
  698.      (insert "D")
  699.      nil))))
  700.  
  701. (defun dired-read-regexp (prompt)
  702. ;; This is an extra function so that gmhist can redefine it.
  703.   (setq dired-flagging-regexp
  704.     (read-string prompt dired-flagging-regexp)))
  705.  
  706. (defun dired-flag-regexp-files (regexp &optional arg marker-char)
  707.   "In dired, flag all files containing the specified REGEXP for deletion.
  708. Use `^' and `$' if the match should span the whole (non-directory
  709.   part) of the filename.   Exclude subdirs by hiding them.
  710. Directories are not flagged unless a prefix argument is given."
  711.   (interactive (list (dired-read-regexp "Flagging regexp: ")
  712.              current-prefix-arg))
  713.   (let ((dired-marker-char (or marker-char ?D)))
  714.     (dired-mark-if
  715.      (and (or arg (not (looking-at dired-re-dir)))
  716.       (not (eolp))
  717.       (dired-this-file-matches regexp))
  718.      "matching file")))
  719.  
  720. (defun dired-summary ()
  721.   (interactive)
  722.   ;>> this should check the key-bindings and use substitute-command-keys if non-standard
  723.   (message
  724.    ;;"d-elete, u-ndelete, x-ecute, f-ind, o-ther window, r-ename, c-opy, v-iew"
  725.    "d-elete, u-ndelete, x-ecute, f-ind, o-ther window, r-ename, c-opy, h-elp"
  726.    ;;"m-ark, u-nmark, d-elete, f-ind, o-ther window, r-ename, c-opy, h-elp"
  727. ))
  728.  
  729. (defun dired-unflag (arg)
  730.   "In dired, remove the current line's delete flag then move to next line."
  731.   (interactive "p")
  732.   (dired-repeat-over-lines arg
  733.     '(lambda ()
  734.        (let ((buffer-read-only nil))
  735.      (delete-char 1)
  736.      (insert " ")
  737.      (forward-char -1)
  738.      nil))))
  739.  
  740. (defun dired-backup-unflag (arg)
  741.   "In dired, move up a line and remove deletion flag there."
  742.   (interactive "p")
  743.   (dired-unflag (- arg)))
  744.  
  745. (defun dired-next-line (arg)
  746.   "Move down ARG lines then position at filename."
  747.   (interactive "p")
  748.   (next-line arg)
  749.   (dired-move-to-filename))
  750.  
  751. (defun dired-previous-line (arg)
  752.   "Move up ARG lines then position at filename."
  753.   (interactive "p")
  754.   (previous-line arg)
  755.   (dired-move-to-filename))
  756.  
  757. (defun dired-up-directory ()
  758.   "Dired parent directory.  Tries first to find it in this buffer."
  759.   (interactive)
  760.   (let ((fn "..")
  761.     (dir (dired-current-directory)))
  762.     (setq fn (file-name-as-directory (expand-file-name fn dir)))
  763.     (or (dired-goto-file (directory-file-name dir))
  764.     (dired (expand-file-name    ; give user a chance to abort
  765.         (read-file-name "Dired: " fn fn t))))))
  766.  
  767. (defun dired-find-file ()
  768.   "In dired, visit the file or directory named on this line."
  769.   (interactive)
  770.   (find-file (dired-get-filename)))
  771.  
  772. (defun dired-view-file ()
  773.   "In dired, examine a file in view mode, returning to dired when done.
  774. When file is a directory, tries to go to its in situ subdirectory."
  775.   (interactive)
  776.   (if (file-directory-p (dired-get-filename))
  777.       (or (dired-goto-subdir (dired-get-filename))
  778.       (message "Directory %s not inserted - type i to insert or f to dired."
  779.            (dired-get-filename t)))
  780.     (view-file (dired-get-filename))))
  781.  
  782. (defun dired-find-file-other-window ()
  783.   "In dired, visit this file or directory in another window."
  784.   (interactive)
  785.   (find-file-other-window (dired-get-filename)))
  786.  
  787. ; Now that there is dired-move-to-end-of-filename,
  788. ; use it in dired-get-filename.
  789. (defun dired-get-filename (&optional localp no-error-if-not-filep)
  790.   "In dired, return name of file mentioned on this line.
  791. Value returned normally includes the directory name.
  792. A non-nil 1st argument means use path name relative to
  793.   default-directory, which may contain slashes if in a subdirectory.
  794. A non-nil 2nd argument says return nil if no filename on this line,
  795.   otherwise an error occurs."
  796.   (let ((case-fold-search nil) file p1 p2)
  797.     (save-excursion
  798.       (if (setq p1 (dired-move-to-filename (not no-error-if-not-filep)))
  799.       (setq p2 (dired-move-to-end-of-filename no-error-if-not-filep))))
  800.     ;; nil if no file on this line, but no-error-if-not-filep is t:
  801.     (setq file (and p1 p2 (buffer-substring p1 p2)))
  802.     (and file (dired-make-absolute file (dired-current-directory localp)))))
  803.  
  804. (defun dired-move-to-filename (&optional raise-error eol)
  805.   "In dired, move to first char of filename on this line.
  806. Returns position (point) or nil if no filename on this line."
  807.   (or eol (setq eol (progn (end-of-line) (point))))
  808.   (beginning-of-line)
  809.   (if (eq system-type 'vax-vms)
  810.       (if (re-search-forward ". [][.A-Z-0-9_$;<>]" eol t)
  811.       (backward-char 1)
  812.     (if raise-error
  813.         (error "No file on this line.")
  814.       nil))
  815.     ;; Unix case
  816.     (if (re-search-forward
  817.      "\\(Jan\\|Feb\\|Mar\\|Apr\\|May\\|Jun\\|Jul\\|Aug\\|Sep\\|Oct\\|Nov\\|Dec\\)[ ]+[0-9]+"
  818.      eol t)
  819.     (progn
  820.       (skip-chars-forward " ")    ; there is one SPC after day of month
  821.       (skip-chars-forward "^ " eol)    ; move after time of day (or year)
  822.       (skip-chars-forward " " eol)    ; there is one SPC before the file name
  823.       (point))
  824.       (if raise-error
  825.       (error "No file on this line.")
  826.     nil))))
  827.  
  828. (defun dired-move-to-end-of-filename (&optional no-error eol)
  829.   ;; Assumes point is at beginning of filename,
  830.   ;; thus the rwx bit re-search-backward below will succeed in *this* line.
  831.   ;; So, it should be called only after (dired-move-to-filename t).
  832.   ;; case-fold-search must be nil, at least for VMS.
  833.   ;; On failure, signals an error or returns nil.
  834.   (let (opoint flag ex sym hidden)
  835.     (setq opoint (point))
  836.     (or eol (setq eol (save-excursion (end-of-line) (point))))
  837.     (setq hidden (and selective-display
  838.               (save-excursion (search-forward "\r" eol t))))
  839.     (if hidden
  840.     nil
  841.       (if (eq system-type 'vax-vms)
  842.       ;; Non-filename lines don't match
  843.       ;; because they have lower case letters.
  844.       (re-search-forward "[][.A-Z-0-9_$;<>]+" eol t)
  845.     ;; Unix case
  846.     (save-excursion
  847.       (or (re-search-backward
  848.            "\\(.\\)[-r][-w]\\(.\\)[-r][-w]\\(.\\)[-r][-w]\\(.\\)"
  849.            nil t)
  850.           no-error
  851.           (error "No file on this line."))
  852.       (setq flag (buffer-substring (match-beginning 1) (match-end 1))
  853.         sym (string= flag "l")
  854.         ;; ex is actually only needed when dired-used-F is t.
  855.         ex (string-match
  856.             "[xst]";; execute bit set anywhere?
  857.             (concat
  858.              (buffer-substring (match-beginning 2) (match-end 2))
  859.              (buffer-substring (match-beginning 3) (match-end 3))
  860.              (buffer-substring (match-beginning 4) (match-end 4))))))
  861.     (if sym
  862.         (if (re-search-forward " ->" eol t)
  863.         (progn
  864.           (forward-char -3)
  865.           ;; we check that ls -lF really marks the link
  866.           (if (and dired-ls-F-marks-symlinks (eq (preceding-char) ?@))
  867.               (forward-char -1))))
  868.       (goto-char eol))
  869.     (if (and dired-used-F
  870.          (or (string= flag "d")
  871.              (string= flag "s")
  872.              (and (not sym) ex))) ; ls -lF ignores x bits on symlinks
  873.         (forward-char -1))))
  874.     (or no-error
  875.     (not (eq opoint (point)))
  876.     (error (if hidden
  877.            "File line is hidden, type $ to unhide."
  878.          "No file on this line.")))
  879.     (if (eq opoint (point))
  880.     nil
  881.       (point))))
  882.  
  883. (defun dired-map-dired-file-lines (fn)
  884.   ;; perform fn with point at the end of each non-directory line:
  885.   ;; arguments are the short and long filename
  886.   (save-excursion
  887.     (let (filename longfilename (buffer-read-only nil))
  888.       (goto-char (point-min))
  889.       (while (not (eobp))
  890.     (save-excursion
  891.       (and (not (looking-at dired-re-dir))
  892.            (not (eolp))
  893.            (setq filename (dired-get-filename t t)
  894.              longfilename (dired-get-filename nil t))
  895.            (progn (end-of-line)
  896.               (funcall fn filename longfilename))))
  897.     (forward-line 1)))))
  898.  
  899. ;; Perhaps something could be done to handle VMS' own backups.
  900.  
  901. (defun dired-clean-directory (keep)
  902.   "Flag numerical backups for deletion.
  903. Spares dired-kept-versions latest versions, and kept-old-versions oldest.
  904. Positive numeric arg overrides dired-kept-versions;
  905. negative numeric arg overrides kept-old-versions with minus the arg.
  906.  
  907. To clear the flags on these files, you can use \\[dired-flag-backup-files]
  908. with a prefix argument."
  909.   (interactive "P")
  910.   (setq keep (if keep (prefix-numeric-value keep) dired-kept-versions))
  911.   (let ((early-retention (if (< keep 0) (- keep) kept-old-versions))
  912.     (late-retention (if (<= keep 0) dired-kept-versions keep))
  913.     (file-version-assoc-list ()))
  914.     ;; Look at each file.
  915.     ;; If the file has numeric backup versions,
  916.     ;; put on file-version-assoc-list an element of the form
  917.     ;; (FILENAME . VERSION-NUMBER-LIST)
  918.     (dired-map-dired-file-lines 'dired-collect-file-versions)
  919.     ;; Sort each VERSION-NUMBER-LIST,
  920.     ;; and remove the versions not to be deleted.
  921.     (let ((fval file-version-assoc-list))
  922.       (while fval
  923.     (let* ((sorted-v-list (cons 'q (sort (cdr (car fval)) '<)))
  924.            (v-count (length sorted-v-list)))
  925.       (if (> v-count (+ early-retention late-retention))
  926.           (rplacd (nthcdr early-retention sorted-v-list)
  927.               (nthcdr (- v-count late-retention)
  928.                   sorted-v-list)))
  929.       (rplacd (car fval)
  930.           (cdr sorted-v-list)))
  931.     (setq fval (cdr fval))))
  932.     ;; Look at each file.  If it is a numeric backup file,
  933.     ;; find it in a VERSION-NUMBER-LIST and maybe flag it for deletion.
  934.     (dired-map-dired-file-lines 'dired-trample-file-versions)))
  935.  
  936. (defun dired-collect-file-versions (ignore fn)
  937.   ;; If it looks like fn has versions, we make a list of the versions.
  938.   ;; We may want to flag some for deletion.
  939.     (let* ((base-versions
  940.         (concat (file-name-nondirectory fn) ".~"))
  941.        (bv-length (length base-versions))
  942.        (possibilities (file-name-all-completions
  943.                base-versions
  944.                (file-name-directory fn)))
  945.        (versions (mapcar 'backup-extract-version possibilities)))
  946.       (if versions
  947.       (setq file-version-assoc-list (cons (cons fn versions)
  948.                           file-version-assoc-list)))))
  949.  
  950. (defun dired-trample-file-versions (ignore fn)
  951.   (let* ((start-vn (string-match "\\.~[0-9]+~$" fn))
  952.      base-version-list)
  953.     (and start-vn
  954.      (setq base-version-list    ; there was a base version to which
  955.            (assoc (substring fn 0 start-vn)    ; this looks like a
  956.               file-version-assoc-list))    ; subversion
  957.      (not (memq (string-to-int (substring fn (+ 2 start-vn)))
  958.             base-version-list))    ; this one doesn't make the cut
  959.      (progn (beginning-of-line)
  960.         (delete-char 1)
  961.         (insert "D")))))
  962.  
  963. (defun dired-flag-backup-and-auto-save-files ()
  964.   "Flag all backup and temporary files for deletion.
  965. Backup files have names ending in `~'.  Auto save file names usually
  966. start with `#'."
  967.   (interactive)
  968.   (dired-flag-backup-files)
  969.   (dired-flag-auto-save-files))
  970.  
  971. (defun dired-create-directory (directory)
  972.   "Create a directory called DIRECTORY"
  973.   (interactive
  974.    (list (read-file-name "Create directory: " (dired-current-directory))))
  975.   (let ((expanded (directory-file-name (expand-file-name directory))))
  976.     (make-directory expanded)
  977.     (dired-add-entry-all-buffers (file-name-directory expanded)
  978.                  (file-name-nondirectory expanded))
  979.   (dired-next-line 1)))
  980.  
  981.  
  982. (defun dired-buffers (dir)
  983. ;; Return a list of buffers that dired DIR (possibly as subdir).
  984. ;; As a side effect, killed dired buffers for DIR are removed from
  985. ;; dired-buffers.
  986.   (setq dir (file-name-as-directory dir))
  987.   (let ((alist dired-buffers) result elt)
  988.     (while alist
  989.       (setq elt (car alist))
  990.       (if (dired-in-this-tree dir (car elt))
  991.       (let ((buf (cdr elt)))
  992.         (if (buffer-name buf)
  993.         (setq result (cons buf result))
  994.           ;; else buffer is killed - clean up:
  995.           (setq dired-buffers (delq elt dired-buffers)))))
  996.       (setq alist (cdr alist)))
  997.     result))
  998.  
  999. (defun dired-fun-in-all-buffers (directory fun)
  1000.   ;; In all buffers dired'ing DIRECTORY, run FUN.
  1001.   ;; FUN returns t for success, nil else.
  1002.   (let ((buf-list (dired-buffers directory)) buf success-list)
  1003.     (while buf-list
  1004.       (setq buf (car buf-list)
  1005.         buf-list (cdr buf-list))
  1006.       (save-excursion
  1007.     (set-buffer buf)
  1008.     (if (funcall fun)
  1009.         (setq success-list (cons (buffer-name buf) success-list)))))
  1010.     success-list))
  1011.  
  1012. (defun dired-add-entry-all-buffers (directory filename)
  1013.   (dired-fun-in-all-buffers
  1014.    directory
  1015.    (function (lambda () (dired-add-entry directory filename)))))
  1016.    
  1017. (defun dired-add-entry (directory filename)
  1018.   ;; Note that this adds the entry `out of order' if files sorted by
  1019.   ;; time, etc.
  1020.   ;; At least this version tries to insert in the right subdirectory.
  1021.   ;; And it skips "." or ".." (dired-trivial-filenames).
  1022.   ;; Hidden subdirs are exposed if a file is added there.
  1023.   (setq directory (file-name-as-directory directory))
  1024.   (let*
  1025.       ((opoint (point))
  1026.        (cur-dir (dired-current-directory))
  1027.        (reason
  1028.     (catch 'not-found
  1029.       (if (string= directory cur-dir)
  1030.           (progn;; unhide if necessary
  1031.         (if (dired-subdir-hidden-p cur-dir) (dired-unhide-subdir))
  1032.         ;; We are already where we should be, except in one case:
  1033.         ;; If point is before the *root* subdir line or its
  1034.         ;; total line, inserting there is ugly.
  1035.         ;; (Everything *before* the rootline is considered as
  1036.         ;; belonging to the root dir, too - in contrast to other
  1037.         ;; subdirs)
  1038.         (if (string= default-directory cur-dir)
  1039.             (let ((p (save-excursion
  1040.                    (dired-goto-next-file)
  1041.                    (point))))
  1042.               (if (<= (point) p)
  1043.               (goto-char p)))))
  1044.         ;; else try to find correct place to insert
  1045.         (if (dired-goto-subdir directory)
  1046.         (progn;; unhide if necessary
  1047.           (if (looking-at "\r");; point is at end of subdir line
  1048.               (dired-unhide-subdir))
  1049.           ;; found - skip subdir and `total' line
  1050.           ;; and uninteresting files like . and ..
  1051.           (dired-goto-next-nontrivial-file))
  1052.           ;; not found
  1053.           (throw 'not-found "Subdir not found")))
  1054.       ;; found and point is at The Right Place:
  1055.       (let ((buffer-read-only nil))
  1056.         (beginning-of-line)
  1057.         (insert "  ")
  1058.         (dired-ls (dired-make-absolute filename directory)
  1059.               (concat dired-actual-switches "d"))
  1060.         (forward-line -1)
  1061.         (dired-move-to-filename t)    ; raise an error if ls output
  1062.                     ; is strange
  1063.         (let* ((beg (point))
  1064.            (end (progn (dired-move-to-end-of-filename) (point))))
  1065.           (setq filename (buffer-substring beg end))
  1066.           (delete-region beg end)
  1067.           (insert (file-name-nondirectory filename)))
  1068.         (beginning-of-line)
  1069.         (if dired-readin-hook
  1070.         (save-restriction
  1071.           (narrow-to-region (point)
  1072.                     (save-excursion (forward-line 1) (point)))
  1073.           (run-hooks 'dired-readin-hook)))
  1074.         )
  1075.       ;; return nil if all went well
  1076.       nil)))
  1077.     (if reason
  1078.     (progn
  1079.       (goto-char opoint)        ; don't move away on failure
  1080.       ;;-(message "Couldn't add %s%s: %s" directory filename reason)
  1081.       ))
  1082.     (not reason)            ; return t on succes, nil else
  1083.     ))
  1084.  
  1085. (defun dired-remove-entry-all-buffers (file)
  1086.   (dired-fun-in-all-buffers
  1087.    (file-name-directory file)
  1088.    (function (lambda () (dired-remove-entry file)))))
  1089.  
  1090. (defun dired-remove-entry (file)
  1091.   (save-excursion
  1092.     (and (dired-goto-file file)
  1093.      (let ((buffer-read-only nil))
  1094.        (delete-region (progn (beginning-of-line) (point))
  1095.               (save-excursion (forward-line 1) (point)))))))
  1096.  
  1097.  
  1098. (defun dired-diff (file)
  1099.   "Compare this file with another (default: file at mark), by running `diff'.
  1100. The other file is the first file given to `diff'.
  1101. See the command `diff'."
  1102.   (interactive
  1103.    (let ((default (if (mark)
  1104.               (save-excursion (goto-char (mark))
  1105.                       (dired-get-filename t)))))
  1106.      (list (read-file-name (format "Diff %s with: %s"
  1107.                    (dired-get-filename t)
  1108.                    (if default
  1109.                        (concat "(default " default ") ")
  1110.                      ""))
  1111.                (dired-current-directory) default t))))
  1112.   (diff file (dired-get-filename t)))
  1113.  
  1114. (defun dired-backup-diff ()
  1115.   "Diff this file with its backup file.
  1116. Uses the latest backup, if there are several numerical backups.
  1117. If this file is a backup, diff it with its original.
  1118. The backup file is the first file given to `diff'."
  1119.   (interactive)
  1120.   (let (bak ori (file (dired-get-filename)))
  1121.     (if (backup-file-name-p file)
  1122.     (setq bak file
  1123.           ori (file-name-sans-versions file))
  1124.       (setq bak (latest-backup-file file)
  1125.         ori file))
  1126.     (diff bak ori)))
  1127.  
  1128. ;; This function is missing in files.el:
  1129. (defun latest-backup-file (fn)
  1130.   "Return the latest existing backup of FILE, or nil."
  1131.   ;; First try simple backup, then the highest numbered of the
  1132.   ;; numbered backups.
  1133.   ;; Ignore the value of version-control because we look for existing
  1134.   ;; backups, which maybe were made earlier with another value of
  1135.   ;; version-control.
  1136.   (or
  1137.    (let ((bak (make-backup-file-name fn)))
  1138.      (if (file-exists-p bak) bak))
  1139.    (let* ((base-versions (concat (file-name-nondirectory fn) ".~"))
  1140.       (bv-length (length base-versions)))
  1141.      (car (sort
  1142.        (file-name-all-completions base-versions (file-name-directory fn))
  1143.        ;; bv-length is a fluid var for backup-extract-version:
  1144.        (function
  1145.         (lambda (fn1 fn2)
  1146.           (> (backup-extract-version fn1)
  1147.          (backup-extract-version fn2)))))))))
  1148.  
  1149. (defun dired-compress ()
  1150.   (let* ((buffer-read-only nil)
  1151.      (from-file (dired-get-filename))
  1152.      (to-file (concat from-file ".Z")))
  1153.     (if (dired-check-process
  1154. ;;; patched by Manabu Higashida for demacs-1.1 91/10/29
  1155. ;;; original line is
  1156. ;     "compress" (format "Compressing %s" from-file) "-f" from-file)
  1157. ;;; and new line is
  1158.      dired-compress-program (format "Compressing %s" from-file) "-f" from-file)
  1159. ;;; end of patch     
  1160.     (dired-redisplay to-file))))
  1161.  
  1162. (defun dired-uncompress ()
  1163.   (let* ((buffer-read-only nil)
  1164.      (from-file (dired-get-filename))
  1165.      (to-file (substring from-file 0 -2)))
  1166.     (if (dired-check-process
  1167. ;;; patched by Manabu Higashida for demacs-1.1 91/10/29
  1168. ;;; original line is
  1169. ;     "uncompress" (format "Uncompressing %s" from-file) from-file)
  1170. ;;; and new line is
  1171.      dired-uncompress-program (format "Uncompressing %s" from-file) from-file)
  1172. ;;; end of patch
  1173.     (dired-redisplay to-file))))
  1174.  
  1175. ; The (un)compress functions are just mapped over all marked files
  1176. ; It is not very effective to call many processes if one would suffice,
  1177. ; but you can use dired-mark-shell-command if necessary,
  1178. ; This version has the advantage of redisplaying after each
  1179. ; (un)compress the corresponding (different!) filename.
  1180. ; And it does not stop if a single file cannot be compressed.
  1181.  
  1182. (defun dired-mark-compress (&optional arg)
  1183.   "Compress marked files
  1184. \(or this file if none are marked or a prefix argument is given)."
  1185.   (interactive "P")
  1186.   (dired-mark-map (dired-compress) arg))
  1187.  
  1188. (defun dired-mark-uncompress (&optional arg)
  1189.   "Uncompress marked files
  1190. \(or this file if none are marked or a prefix argument is given)."
  1191.   (interactive "P")
  1192.   (dired-mark-map (dired-uncompress) arg))
  1193.  
  1194. ;; Elisp commands on files
  1195.  
  1196. (defun dired-byte-recompile ()
  1197.   (let* ((buffer-read-only nil)
  1198.      (from-file (dired-get-filename))
  1199.      (new-file (concat from-file "c")))
  1200.     (if (not (string-match "\\.el$" from-file))
  1201.     (message "%s is no .el file!" from-file)
  1202.       (byte-compile-file from-file)
  1203.       (dired-remove-entry-all-buffers new-file)
  1204.       (dired-add-entry-all-buffers (file-name-directory new-file)
  1205.                    (file-name-nondirectory new-file)))))
  1206.  
  1207. (defun dired-mark-byte-recompile (&optional arg)
  1208.   "Byte recompile marked Emacs lisp files
  1209. \(or this file if none are marked or a prefix argument is given)."
  1210.   (interactive "P")
  1211.   (dired-mark-map (dired-byte-recompile) arg))
  1212.  
  1213. (defun dired-mark-load (&optional arg)
  1214.   "Load the marked Emacs lisp files
  1215. \(or this file if none are marked or a prefix argument is given)."
  1216.   (interactive "P")
  1217.   (dired-mark-map (load (dired-get-filename)) arg))
  1218.  
  1219. ;; Change file modes.
  1220.  
  1221. ; Don't use absolute path for ch{mod,grp} as /bin should be in
  1222. ; any PATH.  However, chown is special: dired-chown-program.
  1223.  
  1224. (defun dired-mark-chmod (&optional arg)
  1225.   "Change mode of marked files
  1226. \(or this file if none are marked or a prefix argument is given)."
  1227.   (interactive "P")
  1228.   (let* ((files (dired-mark-get-files nil t arg))
  1229.       (mode (read-string (format "Change %s to Mode: "
  1230.                      (dired-mark-prompt)))) )
  1231. ;;; patched by Manabu Higashida for demacs-1.1 91/10/29
  1232. ;;; original line is
  1233. ;    (apply 'dired-check-process "chmod"
  1234. ;;; and new line is
  1235.     (apply 'dired-check-process dired-chmod-program
  1236. ;;; end of patch
  1237.         (format "chmod %s " mode) mode files)
  1238.     (dired-mark-redisplay arg)))
  1239.  
  1240. (defun dired-mark-chgrp (&optional arg)
  1241.   "Change group of marked files
  1242. \(or this file if none are marked or a prefix argument is given)."
  1243.   (interactive "P")
  1244.   (let* ((files (dired-mark-get-files nil t arg))
  1245.      (group (read-string (format "Change %s to Group: "
  1246.                     (dired-mark-prompt)))) )
  1247. ;;; patched by Manabu Higashida for demacs-1.1 91/10/29
  1248. ;;; original line is
  1249. ;    (apply 'dired-check-process "chgrp"
  1250. ;;; and new line is
  1251.     (apply 'dired-check-process dired-chgrp-program
  1252. ;;; end if patch
  1253.        (format "chgrp %s " group) group files)
  1254.     (dired-mark-redisplay arg)))
  1255.  
  1256. (defun dired-mark-chown (&optional arg)
  1257.   "Change owner of marked files
  1258. \(or this file if none are marked or a prefix argument is given)."
  1259.   (interactive "P")
  1260.   (let* ((files (dired-mark-get-files nil t arg))
  1261.      (owner (read-string (format "Change %s to Owner: "
  1262.                     (dired-mark-prompt)))) )
  1263.     (apply 'dired-check-process dired-chown-program
  1264.        (format "chown %s " owner) owner files)
  1265.     (dired-mark-redisplay arg)))
  1266.  
  1267. (defun dired-redisplay (file)
  1268.   ;; Redisplay the file on this line.
  1269.   ;; Keeps any marks that may be present in column one.
  1270.   ;; Does not bother to update other dired buffers.
  1271.   (beginning-of-line)
  1272.   (let ((char (following-char)) (opoint (point)))
  1273.     (delete-region (point) (progn (forward-line 1) (point)))
  1274.     (if file
  1275.     (progn
  1276.       (dired-add-entry (file-name-directory    file)
  1277.                (file-name-nondirectory file))
  1278.       ;; Replace space by old marker without moving point.
  1279.       ;; Faster than goto+insdel inside a save-excursion?
  1280.       (subst-char-in-region opoint (1+ opoint) ?\040 char))))
  1281.   (dired-move-to-filename))
  1282.  
  1283. (defun dired-mark-redisplay (&optional arg)
  1284.   "Redisplay all marked files
  1285. \(or this file if none are marked or a prefix argument is given).
  1286. If on a subdir line, redisplay that subdirectory."
  1287.   (interactive "P")
  1288.   (if (dired-get-subdir)
  1289.       (dired-insert-subdir (dired-get-subdir))
  1290.     (message "Redisplaying ...")
  1291.     (dired-mark-map (dired-redisplay (dired-get-filename)) arg)
  1292.     (dired-move-to-filename)
  1293.     (message "Redisplaying ... done.")))
  1294.  
  1295. (defun dired-mark-delete ()
  1296.   "Delete all files marked with the current marker char."
  1297.   (interactive)
  1298.   (dired-do-deletions t))
  1299.  
  1300. (defun dired-mark-kill (&optional arg)
  1301.   "Kill all marked lines (not files).
  1302. With a prefix arg, kill all lines not marked or flagged."
  1303.   (interactive "P")
  1304.   (save-excursion
  1305.     (goto-char (point-min))
  1306.     (let ((buffer-read-only nil))
  1307.       (if (not arg)
  1308.       (flush-lines (dired-marker-regexp))
  1309.     (while (not (eobp))
  1310.       (if (or (dired-between-files)
  1311.           (not (looking-at "^  ")))
  1312.           (forward-line 1)
  1313.         (delete-region (point) (save-excursion
  1314.                      (forward-line 1)
  1315.                      (point)))))))))
  1316.  
  1317. (defun dired-do-deletions (&optional marked)
  1318.   "In dired, delete the files flagged for deletion."
  1319.   ;; Optional arg MARKED means delete marked instead flagged files.
  1320.   (interactive)
  1321.   (let ((regexp (if marked (dired-marker-regexp) "^D"))
  1322.     delete-list answer)
  1323.     (save-excursion
  1324.       (goto-char 1)
  1325.       (while (re-search-forward regexp nil t)
  1326.     (setq delete-list
  1327.           (cons (cons (dired-get-filename t) (1- (point)))
  1328.             delete-list))))
  1329.     (if (null delete-list)
  1330.     (message "(No deletions requested)")
  1331.       ;; Make the `dx' idiom less painful:
  1332.       (if (= (length delete-list) 1)
  1333.       (setq answer
  1334.         (dired-yes (format "Delete '%s'? " (car (car delete-list)))))
  1335.     (save-window-excursion
  1336.       (set-buffer (get-buffer-create " *Deletions*"))
  1337.       (funcall (if (> (length delete-list) (* (window-height) 2))
  1338.                'switch-to-buffer 'switch-to-buffer-other-window)
  1339.            (current-buffer))
  1340.       (erase-buffer)
  1341.       (setq fill-column 70)
  1342.       (let ((l (reverse delete-list)))
  1343.         ;; Files should be in forward order for this loop.
  1344.         (while l
  1345.           (if (> (current-column) 59)
  1346.           (insert ?\n)
  1347.         (or (bobp)
  1348.             (indent-to (* (/ (+ (current-column) 19) 20) 20) 1)))
  1349.           (insert (car (car l)))
  1350.           (setq l (cdr l))))
  1351.       ;; let window shrink to fit:
  1352.       (let* ((window (selected-window))
  1353.          (start (window-start window))
  1354.          (window-lines (window-height window)))
  1355.         (goto-char (point-min))
  1356.         (enlarge-window (- (max (+ 2 (vertical-motion window-lines))
  1357.                     window-min-height)
  1358.                    window-lines))
  1359.         (set-window-start (selected-window) start))
  1360.       (setq answer (dired-yes "Delete these files? "))))
  1361.       (if answer
  1362.       (save-excursion
  1363.         (let ((l delete-list)
  1364.           failures)
  1365.           ;; Files better be in reverse order for this loop!
  1366.           ;; That way as changes are made in the buffer
  1367.           ;; they do not shift the lines still to be changed.
  1368.           (while l
  1369.         (goto-char (cdr (car l)))
  1370.         (let ((buffer-read-only nil))
  1371.           (condition-case ()
  1372.               (let ((fn (dired-make-absolute (car (car l))
  1373.                              default-directory)))
  1374.             (if (and (file-directory-p fn)
  1375.                  (not (file-symlink-p fn)))
  1376.                 (remove-directory fn)
  1377.               (delete-file fn))
  1378.             (delete-region (point)
  1379.                        (progn (forward-line 1) (point)))
  1380.             (save-excursion
  1381.               (if (dired-goto-subdir fn)
  1382.                   (dired-kill-subdir))))
  1383.             (error (delete-char 1)
  1384.                (insert " ")
  1385.                (setq failures (cons (car (car l)) failures)))))
  1386.         (setq l (cdr l)))
  1387.           (if failures
  1388.           (message "Deletions failed: %s"
  1389.                (prin1-to-string failures)))))))))
  1390.  
  1391.  
  1392. (defun dired-replace-in-string (regexp to string)
  1393.   ;; Replace REGEXP with TO in STRING and return result.
  1394.   ;; No \\DIGIT escapes will be recognized in TO.
  1395.   (let ((result "") (start 0) mb me)
  1396.     (while (string-match regexp string start)
  1397.       (setq mb (match-beginning 0)
  1398.         me (match-end 0)
  1399.         result (concat result (substring string start mb) to)
  1400.         start me))
  1401.     (concat result (substring string start))))
  1402.  
  1403. (defun dired-next-dirline (arg)
  1404.   "Goto ARG'th next directory file line."
  1405.   (interactive "p")
  1406.   (if (if (> arg 0)
  1407.       (re-search-forward dired-re-dir nil t arg)
  1408.     (re-search-backward dired-re-dir nil t
  1409.                 (if (save-excursion (beginning-of-line)
  1410.                         (looking-at dired-re-dir))
  1411.                 (- 1 arg)
  1412.                   (- arg))))
  1413.       (dired-move-to-filename)        ; user may type `i' or `f'
  1414.     (error "No more subdirectories.")))
  1415.  
  1416. (defun dired-prev-dirline (arg)
  1417.   "Goto ARG'th previous directory file line."
  1418.   (interactive "p")
  1419.   (dired-next-dirline (- arg)))
  1420.  
  1421. (defun dired-unflag-all-files (flag)
  1422.   "Remove a specific or all flags from every file."
  1423.   (interactive "sRemove flag: (default: all flags) ")
  1424.   (let ((count 0)
  1425.     (re (if (zerop (length flag)) dired-re-mark
  1426.           (concat "^" (regexp-quote flag)))))
  1427.     (save-excursion
  1428.       (let ((buffer-read-only nil))
  1429.     (goto-char (point-min))
  1430.     (while (re-search-forward re nil t)
  1431.       (progn (delete-char -1) (insert " ") (setq count (1+ count)))
  1432.       (forward-line 1))))
  1433.     (message (format "All flags removed: %d %s" count flag) )))
  1434.  
  1435.  
  1436. (defun dired-kill-line (arg)
  1437.   "Kill this line (but not this file).
  1438. If file is displayed as in situ subdir, kill that as well, unless a
  1439. prefix arg is given."
  1440.   (interactive "P")
  1441.   (let ((buffer-read-only nil) (file (dired-get-filename nil t)))
  1442.     (delete-region (progn (beginning-of-line) (point))
  1443.            (progn (forward-line 1) (point)))
  1444.     (and (not arg)
  1445.      file
  1446.      (dired-goto-subdir file)
  1447.      (dired-kill-subdir))))
  1448.  
  1449. ;; This function is missing in simple.el:
  1450. (defun copy-string-as-kill (string)
  1451.   "Save STRING as if killed in a buffer."
  1452.   (setq kill-ring (cons string kill-ring))
  1453.   (if (> (length kill-ring) kill-ring-max)
  1454.     (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
  1455.   (setq kill-ring-yank-pointer kill-ring))
  1456.  
  1457. (defun dired-copy-filename-as-kill (&optional arg)
  1458.   "Copy this file (or subdir) name into the kill ring.
  1459. With a prefix arg, use the complete pathname of file.
  1460. Subdirs are always complete pathnames."
  1461.   (interactive "P")
  1462.   (copy-string-as-kill
  1463.    (or (dired-get-subdir)
  1464.        (if arg;; dired-get-filename's localp is not what we usually
  1465.        (dired-get-filename);; want, esp. deep in a tree
  1466.      (file-name-nondirectory (dired-get-filename)))))
  1467.   (message "%s" (car kill-ring)))
  1468.  
  1469. ;; file marking
  1470.  
  1471. (defconst dired-marker-char ?*
  1472.   ;; so that you can write things like
  1473.   ;; (let ((dired-marker-char ?X))
  1474.   ;;    ;; great code using X markers ...
  1475.   ;;    )
  1476.   ;; For example, commands operating on two sets of files, A and B.
  1477.   ;; Or marking files with digits 0-9.  This could implicate
  1478.   ;; concentric sets or an order for the marked files.
  1479.   "In dired, character used to mark files for later commands.")
  1480.  
  1481. (defun dired-marker-regexp ()
  1482.   (concat "^" (regexp-quote (char-to-string dired-marker-char))))
  1483.  
  1484. (defun dired-mark-file (arg)
  1485.   "In dired, mark the current line's file for later commands.
  1486. With arg, repeat over several lines.
  1487. Use \\[dired-unflag-all-files] to remove all flags."
  1488.   (interactive "p")
  1489.   (let ((buffer-read-only nil))
  1490.     (dired-repeat-over-lines
  1491.      arg
  1492.      (function (lambda () (delete-char 1) (insert dired-marker-char))))))
  1493.  
  1494. (defun dired-mark-files (regexp &optional arg)
  1495.   "Mark all files matching REGEXP for use in later commands.
  1496. Directories are not marked unless a prefix argument is given.
  1497.  
  1498. This is an Emacs regexp, not a shell wildcard.    E.g., use \\.o$ for
  1499. object files - just .o will mark more than you might think.
  1500.  
  1501. An empty string will match all files except directories."
  1502.   (interactive
  1503.    (list (dired-read-regexp "Mark files (regexp): ")
  1504.      current-prefix-arg))
  1505.   (dired-flag-regexp-files regexp arg dired-marker-char))
  1506.  
  1507. (defun dired-mark-symlinks (unflag-p)
  1508.   "Mark all symbolic links.
  1509. With prefix argument, unflag all those files."
  1510.   (interactive "P")
  1511.   (let ((dired-marker-char (if unflag-p ?\  dired-marker-char)))
  1512.     (dired-mark-if (looking-at dired-re-sym) "symbolic link")))
  1513.  
  1514. (defun dired-mark-dirlines (unflag-p)
  1515.   "Mark all directory file lines except `.' and `..'.
  1516. With prefix argument, unflag all those files."
  1517.   (interactive "P")
  1518.   (let ((dired-marker-char (if unflag-p ?\  dired-marker-char)))
  1519.     (dired-mark-if (and (looking-at dired-re-dir)
  1520.             (not (looking-at dired-re-dot)))
  1521.            "directory file")))
  1522.  
  1523. (defun dired-mark-executables (unflag-p)
  1524.   "Mark all executable files.
  1525. With prefix argument, unflag all those files."
  1526.   (interactive "P")
  1527.   (let ((dired-marker-char (if unflag-p ?\  dired-marker-char)))
  1528.     (dired-mark-if (looking-at dired-re-exe) "executable file")))
  1529.  
  1530. (defun dired-flag-auto-save-files (&optional unflag-p)
  1531.   "Flag for deletion files whose names suggest they are auto save files.
  1532. A prefix argument says to unflag those files instead."
  1533.   (interactive "P")
  1534.   (let ((dired-marker-char (if unflag-p ?\  ?D))
  1535.     (bound (fboundp 'auto-save-file-name-p)))
  1536.     (dired-mark-if
  1537.        (and (not (looking-at dired-re-dir))
  1538.         (if bound
  1539.         (let ((fn (dired-get-filename t t)))
  1540.           (if fn (auto-save-file-name-p fn)))
  1541.           (if (save-excursion
  1542.             (dired-move-to-filename)
  1543.             (looking-at "#")))))
  1544.        "auto save file")))
  1545.  
  1546. (defun dired-flag-backup-files (&optional unflag-p)
  1547.   "Flag all backup files (names ending with `~') for deletion.
  1548. With prefix argument, unflag all those files."
  1549.   (interactive "P")
  1550.   (let ((dired-marker-char (if unflag-p ?\  ?D))
  1551.     (bound (fboundp 'backup-file-name-p)))
  1552.     (dired-mark-if
  1553.      (and (not (looking-at dired-re-dir))
  1554.       (if bound
  1555.           (let ((fn (dired-get-filename t t)))
  1556.         (if fn (backup-file-name-p fn)))
  1557.         (save-excursion
  1558.           (end-of-line)        ; symlinks are never backups
  1559.           (forward-char -1)
  1560.           (looking-at "~"))))
  1561.      "backup file")))
  1562.  
  1563. (defun dired-mark-get-files (&optional localp defaultp this-file)
  1564.   "Return the marked files as list of strings.
  1565. Values returned normally do include the directory name.
  1566. A non-nil first argument LOCALP means do not include it.
  1567. A non-nil second argument DEFAULTP means default to list with current
  1568.   file as single element if none are marked.  If this happens,
  1569.   dired-mark-defaulted is set to t.
  1570. A non-nil third argument THIS-FILE forces to use the current file.
  1571. Sets the global variables  dired-mark-count and  dired-mark-files."
  1572.   (setq dired-mark-defaulted nil)
  1573.   (if this-file
  1574.       (setq dired-mark-count 1
  1575.         dired-mark-files (list (dired-get-filename localp)))
  1576.     (let (the-list (regexp (dired-marker-regexp)))
  1577.       (save-excursion
  1578.     (setq dired-mark-count 0)
  1579.     (goto-char (point-max))        ; make list same order
  1580.     (while (re-search-backward regexp nil t) ; as in buffer
  1581.       (setq the-list (cons (dired-get-filename localp) the-list))
  1582.       (dired-count-up)))
  1583.       (setq dired-mark-defaulted (and defaultp (not the-list))
  1584.         dired-mark-count (if the-list dired-mark-count (if defaultp 1 0))
  1585.         dired-mark-files
  1586.         (or the-list (if defaultp (list (dired-get-filename localp)) nil))))))
  1587.  
  1588. (defun dired-rename-regexp (regexp newname)
  1589.   "Rename all marked files containing REGEXP to NEWNAME.
  1590. See dired-flag-regexp-files for more info on REGEXP.
  1591. NEWNAME may contain \\N or \\& as in replace-match (q.v.).
  1592. REGEXP defaults to the last regexp used, but with a prefix arg
  1593. dired-basename-regexp is provided.  This makes the basename as \\1 and
  1594. the extension as \\2 available in NEWNAME."
  1595.   (interactive
  1596.    (let ((a1 (read-string "Rename from (regexp): "
  1597.               (if current-prefix-arg
  1598.                   dired-basename-regexp
  1599.                 dired-flagging-regexp))))
  1600.      (list a1 (read-string (format "Rename %s to: " a1)))))
  1601.   (save-excursion
  1602.       (goto-char (point-min))
  1603.       (let ((buffer-read-only nil)
  1604.         (dired-mark-count 0)
  1605.         (re (dired-marker-regexp))
  1606.         old new) 
  1607.     (while (and (re-search-forward re nil t)
  1608.             (setq old (dired-get-filename)))
  1609.       (if (dired-this-file-matches regexp)
  1610.           (progn
  1611.         (replace-match newname t)
  1612.         (setq new (dired-get-filename))
  1613.         (rename-file old new)
  1614.         (dired-count-up))))
  1615.       (message "%d file%s renamed." dired-mark-count (dired-plural-s)))))
  1616.  
  1617. (defun dired-this-file-matches (regexp)
  1618. ;      (let ((fn (dired-get-filename t t)))
  1619. ;        (if fn (string-match regexp fn)))
  1620. ; fails in subdirs.
  1621. ; But much worse, we can not use (replace-match) for renaming by
  1622. ; regexp unless the match was in a buffer (not a string)
  1623.   (save-excursion
  1624.     (let ((beg (dired-move-to-filename)) end)
  1625.       (and beg
  1626.        (setq end (dired-move-to-end-of-filename t))
  1627.       (save-restriction            ; so that "^" in the
  1628.     (narrow-to-region beg end)    ; regexp works.
  1629.     (goto-char beg)
  1630.     ;; search is better than looking-at because then it is easy to
  1631.     ;; replace "frizzle" by "frozzle" anywhere in a name.
  1632.     ;; "^" and "$" can still be used to constrain a match.
  1633.     (re-search-forward regexp end t))))))
  1634.  
  1635. ;;; Shell commands
  1636.  
  1637. (defun shell-quote (filename)
  1638.   ;; Quote everything except POSIX filename characters.
  1639.   ;; This should be safe enough even for really wierd shells.
  1640.   (let ((result "") (start 0) end)
  1641.     (while (string-match "[^---0-9a-zA-Z_./]" filename start)
  1642.       (setq end (match-beginning 0)
  1643.         result (concat result (substring filename start end)
  1644.                "\\" (substring filename end (1+ end)))
  1645.         start (1+ end)))
  1646.     (concat result (substring filename start))))
  1647.  
  1648. (defun dired-read-shell-command (prompt)
  1649.   "Read a dired shell command prompting with PROMPT (using read-string).
  1650. This is an extra function so that you can redefine it, e.g., to use gmhist."
  1651.   (read-string prompt))
  1652.  
  1653. (defun dired-mark-prompt ()
  1654.   ;; Either the current file name or the marker and a count of marked
  1655.   ;; files for use in a prompt.
  1656.   (if (eq dired-mark-count 1)
  1657.       (file-name-nondirectory (car dired-mark-files))
  1658.     ;; more than 1 file:
  1659.     (format "%c [%d files]" dired-marker-char dired-mark-count)))
  1660.  
  1661. (defun dired-mark-background-shell-command (&optional arg)
  1662.   "Like \\[dired-mark-shell-command], but starts command in background.
  1663. This requires background.el to work."
  1664.   (interactive "P")
  1665.   (require 'background)
  1666.   (dired-mark-shell-command arg t))
  1667.  
  1668. (defun dired-mark-shell-command (&optional arg in-background)
  1669.   "Run a shell command on the marked files.
  1670. If there is output, it goes to a separate buffer.
  1671. The list of marked files is appended to the command string unless asterisks
  1672.   `*' indicate the place(s) where the list should go.  See variables
  1673.   dired-mark-prefix, -separator, -postfix.  If you have a curly brace
  1674.   expanding shell, you may want to set these to \"{\",\",\" and \"}\"
  1675.   to make commands like `mv *~ bak; compress bak/*~' work.
  1676. If no files are marked or a prefix arg is given, uses file on the
  1677.   current line. The prompt mentions the file or the marker, as
  1678.   appropriate.  See variables dired-shell-prompt, dired-background-prompt.
  1679. No automatic redisplay is attempted, as the file names may have
  1680.   changed.  Type \\[dired-mark-redisplay] to redisplay the marked files.
  1681.  
  1682. Function dired-run-shell-command does the actual work and can be
  1683. redefined for customization."
  1684.   ;; Bug: There is no way to quote a *
  1685.   (interactive "P")
  1686.   (let (result command fns
  1687.            (prompt (if in-background dired-background-prompt
  1688.              dired-shell-prompt)))
  1689.     (setq fns (mapconcat (function shell-quote)
  1690.              (dired-mark-get-files t t arg)
  1691.              dired-mark-separator))
  1692.     (if (> dired-mark-count 1)
  1693.     (setq fns (concat dired-mark-prefix fns dired-mark-postfix)))
  1694.     ;; Want to give feedback whether this file or marked files are used.
  1695.     (setq command (dired-read-shell-command (format prompt
  1696.                             (dired-mark-prompt))))
  1697.     (setq result (if (string-match "\\*" command)
  1698.              (dired-replace-in-string "\\*" fns command)
  1699.            (concat command " " fns)))
  1700.     ;; execute the shell command
  1701.     (dired-run-shell-command result in-background)))
  1702.  
  1703. ;; This is an extra function so that it can be redefined for remote
  1704. ;; shells or whatever.
  1705. (defun dired-run-shell-command (command &optional in-background)
  1706.   "Run shell COMMAND, optionally IN-BACKGROUND.
  1707. If COMMAND is longer than shell-maximum-command-length, you are asked
  1708. for confirmation."
  1709.   (if in-background
  1710.       (setq command (concat "cd " default-directory "; " command)))
  1711.   (if (or (and shell-maximum-command-length
  1712.            (< (length command) shell-maximum-command-length))
  1713.       (yes-or-no-p
  1714.        (format
  1715.         "Dired shell command is %d bytes long - execute anyway? "
  1716.         (length command))))
  1717.       (if in-background
  1718.       (background command)
  1719.     (shell-command command))))
  1720.  
  1721. (defun dired-mark-print (&optional arg)
  1722.   "Print the marked files
  1723. \(or this file if none are marked or a prefix argument is given).
  1724. Uses the shell command in variable dired-print-command as default."
  1725.   (interactive "P")
  1726.   (let* ((files (mapconcat (function shell-quote)
  1727.                (dired-mark-get-files t t arg)
  1728.                " "))
  1729.      (command (read-string (format "Print %s with cmd: "
  1730.                        (dired-mark-prompt))
  1731.                    dired-print-command)))
  1732.     (setq dired-print-command command)
  1733.     (dired-run-shell-command (format command files))))
  1734.    
  1735.  
  1736. ;;; Copy, move and rename
  1737.  
  1738. (defun dired-rename-visited (filename to-file)
  1739.   ;; Optionally rename the visited file of any buffer visiting this file.
  1740.   (and (get-file-buffer filename)
  1741.      (y-or-n-p (message "Change visited file name of buffer %s too? "
  1742.                 (buffer-name (get-file-buffer filename))))
  1743.      (save-excursion
  1744.        (set-buffer (get-file-buffer filename))
  1745.        (let ((modflag (buffer-modified-p)))
  1746.          (set-visited-file-name to-file)
  1747.          (set-buffer-modified-p modflag)))))
  1748.  
  1749. (defun dired-mark-cp-or-mv (fun fun2 msg msg1 &optional arg)
  1750.   (let* ((fn-list (dired-mark-get-files nil t arg))
  1751.      ;; this depends on dired-mark-get-files to be run first:
  1752.      (target (expand-file-name
  1753.           (read-file-name
  1754.            (format "%s %s to: "
  1755.                (if (= 1 dired-mark-count) msg1 msg)
  1756.                (dired-mark-prompt))
  1757.            (dired-current-directory))))
  1758.      (is-dir (file-directory-p target)))
  1759.     (if (and (> dired-mark-count 1)
  1760.          (not is-dir))
  1761.     (error "Marked %s: target must be a directory: %s" msg target))
  1762.     (let (to overwrite (buffer-read-only nil))
  1763.       (or is-dir (setq to target))
  1764.       (or is-dir            ; paranoid
  1765.       (= 1 (length fn-list))
  1766.       (error "Internal error: non-dir and more than 1 file: %s" fn-list))
  1767.       (mapcar
  1768.        (function
  1769.     (lambda (from)
  1770.       (if is-dir            ; else to = target
  1771.           (setq to (expand-file-name
  1772.             (file-name-nondirectory from) target)))
  1773.       (setq overwrite (file-exists-p to))
  1774.       (funcall fun from to 0)
  1775.       (and fun2 (funcall fun2 from to))
  1776.       (if overwrite;; if we get here, fun hasn't been aborted
  1777.           ;; and the old entry has to be deleted
  1778.           ;; before adding the new entry
  1779.           (dired-remove-entry-all-buffers to))
  1780.       (dired-add-entry-all-buffers (file-name-directory to)
  1781.                        (file-name-nondirectory to))))
  1782.        fn-list)))
  1783.   (dired-move-to-filename))
  1784.  
  1785. (defun dired-mark-copy (&optional arg)
  1786.  "Copy all marked files (or this file if none are marked or prefix given)."
  1787.   (interactive "P")
  1788.   (dired-mark-cp-or-mv 'copy-file nil "Copy" "Copy" arg))
  1789.  
  1790. (defun dired-mark-move (&optional arg)
  1791.   "Move all marked files into a directory
  1792. \(or rename this file if none are marked or prefix given)."
  1793.   (interactive "P")
  1794.   (dired-mark-cp-or-mv
  1795.    'rename-file
  1796.    (function (lambda (from to)
  1797.            (dired-remove-entry-all-buffers from)
  1798.            (dired-rename-visited from to)))
  1799.    "Move" "Rename" arg))
  1800.  
  1801. ;; tree dired
  1802.  
  1803. ;;---------------------------------------------------------------------
  1804.  
  1805. (defvar dired-buffers nil
  1806.   ;; Enlarged/modified by dired-mode and dired-revert
  1807.   ;; Queried by function dired-buffers. When this detects a
  1808.   ;; killed buffer, it is removed from this list.
  1809.   "Alist of directories and their associated dired buffers.")
  1810.  
  1811. ;;---------------------------------------------------------------------
  1812.  
  1813. ;;; utility functions
  1814.  
  1815. (defconst dired-subdir-regexp "^. \\([^ ]*\\)\\(:\\)[\n\r]"
  1816.   "Regexp matching a maybe hidden subdirectory line in ls -lR output.
  1817. Subexpression 1 is subdirectory proper, no trailing slash.
  1818. The match starts at the beginning of the line and ends after the end
  1819. of the line (\\n or \\r).
  1820. Subexpression 2 must end right before the \\n or \\r.")
  1821.  
  1822. (defun dired-relative-path-p (file)
  1823.   ;;"Return t iff FILE is a relative path name.
  1824.   ;;Dired uses dired-make-absolute to convert it to an absolute pathname."
  1825.   ;; Only used in dired-normalize-subdir, but might perhaps be
  1826.   ;; redefined (for VMS?)
  1827.   (not (file-name-absolute-p file)))
  1828.  
  1829. (defun dired-make-absolute (file dir)
  1830.   ;;"Convert FILE (a pathname relative to DIR) to an absolute pathname."
  1831.   ;; This should be good enough for ange-ftp, but might easily be
  1832.   ;; redefined (for VMS?).
  1833.   ;; It should be reasonably fast, though, as it is called in
  1834.   ;; dired-get-filename.
  1835.   (concat dir file))
  1836.  
  1837. (defun dired-make-relative (file dir)
  1838.   ;;"Convert FILE (an absolute pathname) to a pathname relative to DIR.
  1839.   ;;Else error."
  1840.   ;; DIR must be file-name-as-directory, as with all directory args in
  1841.   ;; elisp code. 
  1842.   (if (string-match (concat "^" (regexp-quote dir)) file)
  1843.       (substring file (match-end 0))
  1844.     (error  "%s: not in directory tree growing at %s." file dir)))
  1845.  
  1846. (defun dired-in-this-tree (file dir)
  1847.   ;;"Is FILE part of the directory tree starting at DIR?"
  1848.   (string-match (concat "^" (regexp-quote dir)) file))
  1849.  
  1850. (defun dired-normalize-subdir (dir)
  1851.   ;; prepend default-directory if relative path name
  1852.   ;; and make sure it ends in a slash, like default-directory does
  1853.   ;; Make this "end in a slash or a colon" for ange-ftp.  The point is
  1854.   ;; that dired-make-absolute (i.e. concat) must suffice in
  1855.   ;; dired-get-filename to make a valid filename from a file and its
  1856.   ;; directory.
  1857.   (file-name-as-directory
  1858.    (if (dired-relative-path-p dir)
  1859.        (dired-make-absolute dir default-directory)
  1860.      dir)))
  1861.  
  1862. (defun dired-between-files ()
  1863.   ;; Point must be at beginning of line
  1864.   ;; Should be equivalent to (save-excursion (not (dired-move-to-filename)))
  1865.   ;; but faster.
  1866.   (or (looking-at "^$")
  1867.       (looking-at "^. *$")        ; should not be marked
  1868.       (looking-at "^. total")        ; but may be
  1869.       (looking-at dired-subdir-regexp)))
  1870.  
  1871. (defun dired-get-subdir ()
  1872.   ;;"Return the subdir name on this line, or nil."
  1873.   (save-excursion
  1874.     (beginning-of-line)
  1875.     (if (looking-at dired-subdir-regexp)
  1876.     (file-name-as-directory
  1877.      (buffer-substring (match-beginning 1)
  1878.                (match-end 1))))))
  1879.  
  1880. ;;; We use an alist of directories for speed.
  1881.  
  1882. (defconst dired-subdir-alist nil
  1883.   "Association list of subdirectories and their buffer positions:
  1884.  
  1885.   \((lastdir . lastmarker) ... (default-directory . firstmarker)).
  1886.  
  1887. The markers point right at the end of the line, so that the cursor
  1888. looks at either \\n or \\r, the latter for a hidden subdir.") 
  1889.  
  1890. (defun dired-clear-alist ()
  1891.   (while dired-subdir-alist
  1892.     (set-marker (cdr (car dired-subdir-alist)) nil)
  1893.     (setq dired-subdir-alist (cdr dired-subdir-alist))))
  1894.  
  1895. (defun dired-build-subdir-alist ()
  1896.   "Build dired-subdir-alist anew and return it's new value."
  1897.   (interactive)
  1898.   (dired-clear-alist)
  1899.   (save-excursion
  1900.     (let ((count 0))
  1901.       (goto-char (point-min))
  1902.       (setq dired-subdir-alist nil)
  1903.       (while (re-search-forward dired-subdir-regexp nil t)
  1904.     (setq count (1+ count))
  1905.     (message "%d" count)
  1906.     (dired-alist-add (buffer-substring (match-beginning 1)
  1907.                        (match-end 1))
  1908.              (progn
  1909.                (goto-char (match-end 2))
  1910.                (point-marker))))
  1911.       (message "%d director%s." count (if (= 1 count) "y" "ies"))
  1912.       ;; return new alist:
  1913.       dired-subdir-alist)))
  1914.  
  1915. (defun dired-alist-add (dir new-marker)
  1916.   ;; Add new DIR at NEW-MARKER (at end of buffer, but beginning of alist!)
  1917.   ;; Should perhaps use setcar for speed?
  1918.   (setq dired-subdir-alist
  1919.     (cons (cons (dired-normalize-subdir dir) new-marker)
  1920.           dired-subdir-alist)))
  1921.  
  1922. (defun dired-unsubdir (dir)
  1923.   ;; Remove DIR from the alist
  1924.   (setq dired-subdir-alist
  1925.     (delq (assoc dir dired-subdir-alist) dired-subdir-alist)))
  1926.  
  1927. (defun dired-goto-next-nontrivial-file ()
  1928.   ;; Position point on first nontrivial file after point.
  1929.   (dired-goto-next-file);; so there is a file to compare with
  1930.   (if (stringp dired-trivial-filenames)
  1931.       (while (and (not (eobp))
  1932.           (string-match dired-trivial-filenames
  1933.                 (file-name-nondirectory
  1934.                  (or (dired-get-filename nil t) ""))))
  1935.     (forward-line 1)
  1936.     (dired-move-to-filename))))
  1937.  
  1938. (defun dired-goto-next-file ()
  1939.   (while (and (not (dired-move-to-filename)) (not (eobp)))
  1940.     (forward-line 1)))
  1941.  
  1942. (defun dired-goto-subdir (dir)
  1943.   "Goto header line of DIR in this dired buffer."
  1944.   ;; Search for DIR (an absolute pathname) in alist and move to it.
  1945.   ;; Return buffer position on success, otherwise return nil.
  1946.   (interactive (list (expand-file-name
  1947.               ;;(read-file-name "Goto directory: ")
  1948.               (completing-read "Goto directory: " ; prompt
  1949.                        dired-subdir-alist ; table
  1950.                        nil ; predicate
  1951.                        t ; require-match
  1952.                        (dired-current-directory)))))
  1953.   (let ((elt (assoc (file-name-as-directory dir) dired-subdir-alist)))
  1954.     (and elt (goto-char (cdr elt)))))
  1955.  
  1956. (defun dired-goto-file (file)
  1957.   "Goto file line of FILE in this dired buffer."
  1958.   (interactive (list (expand-file-name
  1959.               (read-file-name "Goto file: "
  1960.                       (dired-current-directory)))))
  1961.   (setq file (directory-file-name file)) ; does no harm if no directory
  1962.   (let (found)
  1963.     (save-excursion
  1964.       (if (dired-goto-subdir (file-name-directory file))
  1965.       (let ((keep-going t)
  1966.         (match nil)
  1967.         (string (file-name-nondirectory file))
  1968.         (boundary (dired-subdir-max)))
  1969.         (while keep-going
  1970.           (setq keep-going
  1971.             (and (< (point) boundary)
  1972.              (setq match (search-forward string nil 'move))))
  1973.           (if (and match (equal file (dired-get-filename nil t)))
  1974.           (setq found (point) keep-going nil)))
  1975.         )))
  1976.     (and found (goto-char found))))
  1977.  
  1978. (defun dired-initial-position ()
  1979.   ;; Where point should go in new listings.
  1980.   ;; Point assumed at beginning of new subdir line.
  1981.   (end-of-line)
  1982.   (if dired-trivial-filenames (dired-goto-next-nontrivial-file)))
  1983.  
  1984. ;;; moving by subdirectories
  1985.  
  1986. (defun dired-subdir-index (dir)
  1987.   ;; Return an index into alist for use with nth
  1988.   ;; for the sake of subdir moving commands.
  1989.   (let (found (index 0) (alist dired-subdir-alist))
  1990.     (while alist
  1991.       (if (string= dir (car (car alist)))
  1992.       (setq alist nil found t)
  1993.     (setq alist (cdr alist) index (1+ index))))
  1994.     ;; (message "%s %s" dir (nth index dired-subdir-alist))
  1995.     (if found index nil)))
  1996.  
  1997. (defun dired-next-subdir (arg &optional no-error-if-not-found)
  1998.   "Go to next subdirectory, regardless of level.
  1999. Use 0 prefix argument to go to this directory's header line."
  2000.   (interactive "p")
  2001.   (let ((this-dir (dired-current-directory))
  2002.     pos index)
  2003.     ;; nth with negative arg does not return nil but the first element
  2004.     (setq index (- (dired-subdir-index this-dir) arg))
  2005.     (setq pos (if (>= index 0) (cdr (nth index dired-subdir-alist)) nil))
  2006.     (if pos
  2007.     (goto-char pos)            ; exit with non-nil return value
  2008.       (if no-error-if-not-found
  2009.       nil                ; return nil if not found
  2010.     (error "No more directories.")))))
  2011.  
  2012. (defun dired-prev-subdir (arg &optional no-error-if-not-found)
  2013.   "Go to previous subdirectory, regardless of level.
  2014. When called interactively and not on a subdir line, go to subdir line."
  2015.   (interactive
  2016.    (list (if current-prefix-arg
  2017.          (prefix-numeric-value current-prefix-arg)
  2018.        (if (and (dired-get-subdir) (not (bolp))) 1 0))))
  2019.   (dired-next-subdir (- arg) no-error-if-not-found))
  2020.  
  2021. (defun dired-up-subdir (arg)
  2022.   "Go up ARG levels in the dired tree."
  2023.   (interactive "p")
  2024.   (let ((dir (concat (dired-current-directory) "..")))
  2025.     (while (> arg 1) (setq arg (1- arg) dir (concat dir "/..")))
  2026.     (setq dir (expand-file-name dir))
  2027.     (or (dired-goto-subdir dir)
  2028.     (error "Cannot go up to %s - not in this tree." dir))))
  2029.  
  2030. (defun dired-down-subdir (arg)
  2031.   "Go down ARG levels in the dired tree."
  2032.   (interactive "p")
  2033.   (let ((dir (dired-current-directory)) ; has slash
  2034.     (tail "[^/]+"))            ; at least one more path name component
  2035.     (while (> arg 1) (setq arg (1- arg) tail (concat tail "/[^/]+")))
  2036.     (if (re-search-forward        ; can't use $ searches when
  2037.      (concat "^. " dir tail ":[\n\r]") nil t) ; dir is hidden
  2038.     (backward-char 1)
  2039.       (error "At the bottom."))))
  2040.  
  2041. ;;; hiding
  2042.  
  2043. (defun dired-subdir-hidden-p (dir)
  2044.   (save-excursion
  2045.     (and selective-display
  2046.      (dired-goto-subdir dir)
  2047.      (looking-at "\r"))))
  2048.  
  2049. (defun dired-unhide-subdir ()
  2050.   (let ((buffer-read-only nil))
  2051.     (subst-char-in-region (dired-subdir-min) (dired-subdir-max) ?\r ?\n)))
  2052.  
  2053. (defun dired-hide-check ()
  2054.   (or selective-display
  2055.       (error "selective-display must be t for subdir hiding to work!")))
  2056.  
  2057. (defun dired-hide-subdir (arg)
  2058.   "Hide or unhide the current subdirectory and move to next directory.
  2059. Optional prefix arg is a repeat factor.
  2060. Use \\[dired-hide-all] to (un)hide all directories."
  2061.   (interactive "p")
  2062.   (dired-hide-check)
  2063.   (let (from-char to-char end-pos (buffer-read-only nil))
  2064.     (dired-next-subdir 0)    ; to end of subdir line
  2065.     (while (> arg 0)
  2066.       (setq arg (1- arg))
  2067.       (if (looking-at "\n")
  2068.       (setq from-char ?\n to-char ?\r) ; hide
  2069.     (setq to-char ?\n from-char ?\r)) ; unhide
  2070.       (subst-char-in-region
  2071.        (point)
  2072.        (save-excursion
  2073.      (or (setq end-pos (dired-next-subdir 1 t))
  2074.          (goto-char (point-max)))
  2075.      ;;(forward-line -1) does work only with \n, not \r
  2076.      ;; search backward for \n or \r:
  2077.      (skip-chars-backward (concat "^" (char-to-string from-char)))
  2078.      ;; this is necessary, else blank lines will be deleted:
  2079.      (if (= from-char ?\n) (backward-char 1))
  2080.      (point))
  2081.        from-char to-char)
  2082.       (if end-pos (goto-char end-pos)))))
  2083.  
  2084. (defun dired-hide-all (arg)
  2085.   "Hide all subdirectories, leaving only their header lines.
  2086. If there is already something hidden, make everything visible again.
  2087. Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
  2088.   (interactive "P")
  2089.   (dired-hide-check)
  2090.   (let ((buffer-read-only nil))
  2091.     (if (save-excursion
  2092.       (goto-char (point-min))
  2093.       (search-forward "\r" nil t))
  2094.     ;; unhide - bombs on \r in filenames
  2095.     (subst-char-in-region (point-min) (point-max) ?\r ?\n)
  2096.       ;; hide
  2097.       (let ((pos (point-max))        ; pos of end of last directory
  2098.         (alist dired-subdir-alist))
  2099.     (while alist            ; while there are dirs before pos
  2100.       (subst-char-in-region (cdr (car alist)) ; pos of prev dir
  2101.                 (save-excursion
  2102.                   (goto-char pos) ; current dir
  2103.                   (forward-line -1)
  2104.                   (point))
  2105.                 ?\n ?\r)
  2106.       (setq pos (cdr (car alist)))    ; prev dir gets current dir
  2107.       (setq alist (cdr alist)))))))
  2108.  
  2109. (defun dired-undo ()
  2110.   "Undo in a dired buffer.
  2111. This doesn't recover lost files, it is just normal undo with temporarily
  2112. writeable buffer.  You can use it to recover killed lines or subdirs.
  2113. You might have to do \\[dired-build-subdir-alist] to parse the buffer again."
  2114.   (interactive)
  2115.   (let ((buffer-read-only nil))
  2116.     (undo)))
  2117.  
  2118. (defun dired-advertise ()
  2119.   "Advertise in  dired-buffers  what directory we dired."
  2120.   (if (memq (current-buffer) (dired-buffers default-directory))
  2121.       t                    ; we have already advertised ourselves
  2122.     (setq dired-buffers
  2123.       (cons (cons default-directory (current-buffer))
  2124.         dired-buffers))))
  2125.  
  2126. ; unused:
  2127. ;(defun dired-unadvertise (dir)
  2128. ;  ;; Remove DIR from the buffer alist in variable dired-buffers.
  2129. ;  (setq dired-buffers
  2130. ;      (delq (assoc dir dired-buffers) dired-buffers)))
  2131.  
  2132. ;; This function is the heart of tree dired
  2133. (defun dired-current-directory (&optional relative)
  2134.   "Get the subdirectory to which this line belongs.
  2135. This returns a string with trailing slash, like default-directory.
  2136. Optional argument means return a name relative to default-directory."
  2137.   (let (elt
  2138.     dir
  2139.     (here (point))
  2140.     ;; Under strange circumstances, when dired-revert calls
  2141.     ;; dired-get-filename and thus this function, the alist is not
  2142.     ;; defined.  I don't understand how this can happen.
  2143.     (alist (or dired-subdir-alist (dired-build-subdir-alist))))
  2144.     (while alist
  2145.       (setq elt (car alist)
  2146.         dir (car elt))
  2147.       (if (<= (cdr elt) here)        ; subdir line is part of subdir
  2148.       ;; found - exit while
  2149.       (setq alist nil)
  2150.     ;; else have to loop once more
  2151.     (setq alist (cdr alist))))
  2152.     (if relative
  2153.     (dired-make-relative dir default-directory)
  2154.       dir)))
  2155.  
  2156. (defun dired-subdir-min ()
  2157.   (save-excursion
  2158.     (if (not (dired-prev-subdir 0 t))
  2159.     (error "Not in a subdir!")
  2160.       (beginning-of-line)
  2161.       (point))))
  2162.  
  2163. (defun dired-subdir-max ()
  2164.   (save-excursion
  2165.     (if (not (dired-next-subdir 1 t))
  2166.     (point-max)
  2167.       (beginning-of-line)
  2168.       (point))))
  2169.  
  2170. (defun dired-kill-subdir (&optional no-build)
  2171.   "Remove all lines of current subdirectory.
  2172. Lower levels are unaffected."
  2173.   (interactive)
  2174.   (let ((buffer-read-only nil))
  2175.     ;;(end-of-line);;  necessary if on a subdir line
  2176.     (if (and (interactive-p)
  2177.          (equal (dired-current-directory) default-directory))
  2178.     (error "Cannot kill top level directory."))
  2179.     (delete-region (dired-subdir-min) (dired-subdir-max))
  2180.     ;; leave one blank line when between directories:
  2181.     (skip-chars-backward " \n")
  2182.     (or (eobp) (forward-char 1))
  2183.     (while (and (not (eobp))
  2184.         (looking-at "[ \n]"))
  2185.       (delete-char 1))
  2186.     ;;(insert "\n")
  2187.     (or (eobp) (insert "\n  "))
  2188.     (or no-build (dired-unsubdir (dired-current-directory)))))
  2189.  
  2190. (defun dired-mark-files-in-region (start end &optional arg)
  2191.   (let ((buffer-read-only nil))
  2192.     (if (> start end)
  2193.     (error "start > end"))
  2194.     (goto-char start)            ; assumed at beginning of line
  2195.     (while (< (point) end)
  2196.       ;; Skip subdir line and following garbage like the `total' line:
  2197.       (while (and (< (point) end) (dired-between-files))
  2198.     (forward-line 1))
  2199.       (if (and (or arg (not (looking-at dired-re-dir)))
  2200.            (dired-get-filename nil t))
  2201.       (progn
  2202.         (delete-char 1)
  2203.         (insert dired-marker-char)))
  2204.       (forward-line 1))))
  2205.  
  2206. (defun dired-mark-subdir-files (&optional arg)
  2207.   "Mark all files except directories in this subdir.
  2208. With prefix arg, mark even directories."
  2209.   (interactive "P")
  2210.   (let ((buffer-read-only nil)
  2211.     (p-min (dired-subdir-min)))
  2212.     (dired-mark-files-in-region p-min (dired-subdir-max) arg)
  2213.     ;; This only makes sense if marking also works when subdir is hidden.
  2214.     ;; But should it work on hidden files?
  2215. ;    (save-excursion
  2216. ;      (goto-char p-min)
  2217. ;      (delete-char 1)
  2218. ;      (insert dired-marker-char))
  2219.     ))
  2220.  
  2221. (defun dired-mark-subdir-or-file (arg)
  2222.   "If looking at a subdir, mark all its files, else like dired-mark-file."
  2223.   (interactive "P")
  2224.   (if (dired-get-subdir)
  2225.       (save-excursion
  2226.     (end-of-line)
  2227.     (dired-mark-subdir-files arg))
  2228.     (dired-mark-file (prefix-numeric-value arg))))
  2229.  
  2230. (defun dired-insert-subdir (dirname &optional switches)
  2231.   "Insert this subdirectory into the same dired buffer.
  2232. If subdirectory is already present, overwrites previous entry, else
  2233. appends at end of buffer.
  2234. With a prefix arg, you may edit the ls switches used for this listing."
  2235.   ;; This function takes some pains to conform to ls -lR output.
  2236.   (interactive
  2237.    (list (dired-get-filename)
  2238.      (if current-prefix-arg
  2239.          (read-string "Switches for listing: " dired-actual-switches))))
  2240.   (setq dirname (file-name-as-directory (expand-file-name dirname)))
  2241.   (dired-make-relative dirname default-directory) ; error on failure
  2242.   (let (beg end index old-marker new-marker mark-alist (buffer-read-only nil)) 
  2243.     (or (file-directory-p dirname) (error  "Not a directory: %s" dirname))
  2244.     (if (setq index (dired-subdir-index dirname))
  2245.     (progn
  2246.       (setq old-marker (cdr (nth index dired-subdir-alist)))
  2247.       (goto-char old-marker)
  2248.       (forward-line -1)
  2249.       (setq beg (point))
  2250.       (goto-char old-marker)
  2251.       (setq end (dired-subdir-max))
  2252.       (save-restriction
  2253.         (narrow-to-region old-marker end)
  2254.         ;; Must unhide to make remembering work:
  2255.         (subst-char-in-region (point-min) (point-max) ?\r ?\n)
  2256.         (setq mark-alist (dired-remember-marks)))
  2257.       (delete-region beg end)
  2258.       ;; must make an empty line to
  2259.       ;; separate it from next subdir (if any)
  2260.       (if (not (eobp))
  2261.           (save-excursion (insert "\n"))))
  2262.       (goto-char (point-max)))
  2263.     (or (bobp) (insert "\n"))
  2264.     (setq beg (point))
  2265.     (message "Reading directory %s..." dirname)
  2266.     (dired-ls dirname
  2267.           (or switches
  2268.           (dired-replace-in-string "R" "" dired-actual-switches))
  2269.           nil t)
  2270.     (message "Reading directory %s...done" dirname)
  2271.     (indent-rigidly beg (point) 2)
  2272.     (if dired-readin-hook
  2273.     (save-restriction
  2274.       (narrow-to-region beg (point))
  2275.       (run-hooks 'dired-readin-hook)))
  2276.     ;;  call dired-insert-headerline afterwards, as under VMS dired-ls
  2277.     ;;  does insert the headerline itself and the insert function just
  2278.     ;;  moves point.
  2279.     (goto-char beg)
  2280.     (dired-insert-headerline dirname)    ; must put point where
  2281.     (setq new-marker (point-marker))    ; dired-build-subdir-alist
  2282.                     ; would
  2283.     (if index (set-marker old-marker new-marker))
  2284.  
  2285.     (if index                ; if already present,
  2286.     (set-marker new-marker nil)    ; new-marker is unused
  2287.       (dired-alist-add dirname new-marker))
  2288.     (if (and switches (string-match "R" switches))
  2289.     (dired-build-subdir-alist))
  2290.     (dired-initial-position)
  2291.     (save-excursion
  2292.       (goto-char beg)
  2293.       (dired-mark-remembered mark-alist))))
  2294.  
  2295. ;; sorting
  2296.  
  2297. (defvar dired-sort-by-date-regexp "^-altR?$"
  2298.   "Regexp recognized by dired-sort-mode to set by date mode.")
  2299.  
  2300. (defvar dired-sort-by-name-regexp "^-alR?$"
  2301.   "Regexp recognized by dired-sort-mode to set by name mode.")
  2302.  
  2303. (defun dired-sort-mode ()
  2304.   "Set dired-sort-mode according to dired-actual-switches."
  2305.   (cond ((string-match dired-sort-by-date-regexp dired-actual-switches)
  2306.      (dired-sort-by-date))
  2307.     ((string-match dired-sort-by-name-regexp dired-actual-switches)
  2308.      (dired-sort-by-name))
  2309.     (t (dired-sort-other dired-actual-switches t))))
  2310.  
  2311. (defun dired-sort-toggle ()
  2312.   "Toggle between sort by date/name."
  2313.   (interactive)
  2314.   (if (string-match dired-sort-by-date-regexp dired-actual-switches)
  2315.       (dired-sort-by-name)
  2316.     (dired-sort-by-date))
  2317.   (revert-buffer))
  2318.  
  2319. ;; We can't preserve arbitrary ls switches because they may override
  2320. ;; the presence or absence of the `t' option.
  2321. ;; And we have to make sure to set dired-actual-switches to a legal
  2322. ;; value.
  2323. ;; And when displaying `by name' or `by date' in the modeline, this
  2324. ;; should correspond to a definite listing format.
  2325.  
  2326. (defun dired-sort-by-date ()
  2327.   ;; Force sort by date, but preserve `R' and `a' ls switches.
  2328.   (setq dired-actual-switches
  2329.     (concat "-" (if (string-match "a" dired-actual-switches) "a" "")
  2330.         "lt" (if (string-match "R" dired-actual-switches) "R" "")))
  2331.   (setq dired-sort-mode " by date")
  2332.   (set-buffer-modified-p (buffer-modified-p))) ;No-op, but updates mode line.
  2333.  
  2334. (defun dired-sort-by-name ()
  2335.   ;; Force sort by name, but preserve `R' and `a' ls switches.
  2336.   (setq dired-actual-switches
  2337.     (concat "-" (if (string-match "a" dired-actual-switches) "a" "")
  2338.         "l" (if (string-match "R" dired-actual-switches) "R" "")))
  2339.   (setq dired-sort-mode " by name")
  2340.   (set-buffer-modified-p (buffer-modified-p))) ;No-op, but updates mode line.
  2341.  
  2342. (defun dired-sort-other (switches &optional no-revert)
  2343.   "Specify dired-actual-switches for dired-mode.
  2344. Values matching dired-sort-by-date-regexp or dired-sort-by-name-regexp
  2345. set the minor mode accordingly, others appear literally in the mode line.
  2346. With prefix arg, don't revert the buffer afterwards."
  2347.   (interactive
  2348.    (list (read-string "ls switches (must contain -l): "
  2349.               dired-actual-switches)
  2350.      current-prefix-arg))
  2351.   (setq dired-actual-switches switches)
  2352.   (setq dired-sort-mode (concat " " dired-actual-switches))
  2353.   ;; might really be by name or by date
  2354.   (if (string-match dired-sort-by-date-regexp dired-actual-switches)
  2355.       (dired-sort-by-date)
  2356.     (if (string-match dired-sort-by-name-regexp dired-actual-switches)
  2357.     (dired-sort-by-name)))
  2358.   (set-buffer-modified-p (buffer-modified-p)) ;No-op, but updates mode line.
  2359.   (or no-revert (revert-buffer)))
  2360.  
  2361. (if (eq system-type 'vax-vms)
  2362.     (load "dired-vms"))
  2363.  
  2364. ;;; patched by Manabu Higashida for demacs-1.1 91/10/28
  2365. (if (eq system-type 'ms-dos)
  2366.     (load "direddos"))
  2367.  
  2368. (run-hooks 'dired-load-hook)        ; for your customizations
  2369.  
  2370. ;;; debugging:
  2371.  
  2372. (defun dired-log (fmt &rest args)
  2373.   (save-excursion
  2374.     (set-buffer (get-buffer-create "*Dired Log*"))
  2375.     (goto-char (point-max))
  2376.     (insert "\n" (apply 'format fmt args))))
  2377.