home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / gnu / emacs / sources / 883 < prev    next >
Encoding:
Text File  |  1992-12-17  |  15.3 KB  |  388 lines

  1. Newsgroups: gnu.emacs.sources
  2. Path: sparky!uunet!mcsun!sunic!kth.se!News.kth.se!aho
  3. From: aho@thalamus.sans.kth.se (Anders Holst)
  4. Subject: tree-dired-aho.el
  5. Message-ID: <AHO.92Dec17212118@thalamus.sans.kth.se>
  6. Sender: usenet@kth.se (Usenet)
  7. Nntp-Posting-Host: thalamus.sans.kth.se
  8. Organization: /home/aho/.organization
  9. Date: Thu, 17 Dec 1992 20:21:18 GMT
  10. Lines: 376
  11.  
  12. This is my modifications of tree-dired. See the discussion in the
  13. previous article, or the documentation below for details.
  14.  
  15. ;;
  16. ;;  File: aho-tree-dired.el
  17. ;; 
  18. ;;  Author: Anders Holst (aho@sans.kth.se)
  19. ;;
  20. ;;  Last change: 12 December 1992
  21. ;;
  22. ;;  Copyright (C) Anders Holst
  23. ;;
  24. ;;  ----------------------------------------------------------------------
  25. ;;  This program is free software; you can redistribute it and/or modify
  26. ;;  it under the terms of the GNU General Public License as published by
  27. ;;  the Free Software Foundation; either version 1, or (at your option)
  28. ;;  any later version.
  29. ;; 
  30. ;;  This program is distributed in the hope that it will be useful,
  31. ;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
  32. ;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  33. ;;  GNU General Public License for more details.
  34. ;; 
  35. ;;  You should have received a copy of the GNU General Public License
  36. ;;  along with your copy of Emacs; if not, write to the Free Software
  37. ;;  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  38. ;;  ----------------------------------------------------------------------
  39. ;;
  40. ;;  
  41. ;;  INSTALLATION
  42. ;;
  43. ;;  The easiest way to install this, is to put the file in your load-path, 
  44. ;;  and add the following to 'dired-load-hook':
  45. ;;
  46. ;;    (load "aho-tree-dired")
  47. ;;    (define-key dired-mode-map "q" 'dired-back)
  48. ;;    (define-key dired-mode-map "Q" 'dired-quit)
  49. ;;
  50. ;;
  51. ;;  DESCRIPTION
  52. ;;
  53. ;;  This file implements the following modifications to tree dired:
  54. ;;
  55. ;;  * More extensive "window" defaulting in Copy/Rename/Link (searches
  56. ;;    all windows for a dired-buffer), together with defaulting to
  57. ;;    last directory used (if "window" defaulting fails).
  58. ;;  * Sorting in alphabetically of new files/links (if the current sort
  59. ;;    order is alphabetical).
  60. ;;  * More emphasized tree-structure between the different dired-buffers.
  61. ;;    'f' and 'v' climbs (as before) down to a sub-directory, 'q' climbs
  62. ;;    back up again. (All dired-buffers in the "dired-buffer-tree" are
  63. ;;    kept buried, except the current.) 'Q' jumps out of the entire
  64. ;;    "dired-buffer-tree". 
  65. ;;
  66. ;;  Comments on the modifications:
  67. ;;
  68. ;;  * Regarding "window" defaulting: I don't know how the changes will
  69. ;;    work with for example Epoch, or Emacs 19, since I have never
  70. ;;    used Epoch myself. But if every buffer gets a window of it's own
  71. ;;    (or have I missunderstood something ?) that might mean that all
  72. ;;    dired-buffers have windows, and the defaulting will be
  73. ;;    completely useless (i.e. always come up with something, and
  74. ;;    probably wrong).
  75. ;;  * The defaulting to last used directory works as a second
  76. ;;    alternative, when there are no other dired-window to default to.
  77. ;;    It is currently activated only together with this window
  78. ;;    defaulting, i.e. when the variable 'dired-dwim-target' is non-nil.
  79. ;;    Perhaps it should have a variable of its own ?
  80. ;;  * Sorting in of new files are done only when sort order is
  81. ;;    alphabetical, since that was most easy to do. Perhaps it should
  82. ;;    be done also for other sort orders. On the other hand, it might
  83. ;;    slow things down a bit to sort (but I havn't noticed anything
  84. ;;    such yet). Also on some places there is a local language
  85. ;;    sort order which string-lessp follows, instead of the normal
  86. ;;    ascii-order which ls uses. I had to work around this in a way
  87. ;;    that may make sorting more slow.
  88. ;;  * 'q' is not the same as '^'. For example when following a link
  89. ;;    '^' goes up one directory on "the other side", but 'q' returns
  90. ;;    to the dired-buffer you came from. Also, when in the first
  91. ;;    dired-buffer of such a dired-buffer-tree, 'q' quits the tree,
  92. ;;    whereas '^' climbs further up ('q' will after such use of '^'
  93. ;;    climb back down instead).
  94. ;;
  95. ;;  NOTE: The modifications in this file has only been tested with
  96. ;;  version 6.0 of tree-dired. I don't know how much tree-dired will
  97. ;;  change, but at least some of my modifications deals with small
  98. ;;  inconveniences in tree-dired, which hopefully might dissapear in
  99. ;;  later versions.
  100. ;;  These modifications should also work reasonably together with
  101. ;;  dired-nstd.el, some strange things of which I have tried to
  102. ;;  mitigate. 
  103. ;;  
  104.  
  105.  
  106. (defvar father-buffer nil)
  107. (make-variable-buffer-local 'father-buffer)
  108.  
  109. (defun dired-up-directory ()
  110.   "Run dired on parent directory of current directory.
  111. Find the parent directory either in this buffer or another buffer.
  112. Creates a buffer if necessary."
  113.   (interactive)
  114.   (let* ((dir (dired-current-directory))
  115.      (up (file-name-directory (directory-file-name dir))))
  116.     (or (dired-goto-file (directory-file-name dir))
  117.     (dired-goto-subdir up)
  118.     (let ((buf (current-buffer))
  119.           (father father-buffer))
  120.       (bury-buffer)
  121.       (dired up)
  122.       (dired-goto-file dir)
  123.       (if (not (equal father (current-buffer)))
  124.           (setq father-buffer buf))))))
  125.  
  126. (defun dired-view-file ()
  127.   "In dired, examine a file in view mode, returning to dired when done.
  128. When file is a directory, show it in this buffer if it is inserted;
  129. otherwise, display it in another buffer."
  130.   (interactive)
  131.   (let ((file (dired-get-filename)))
  132.     (if (file-directory-p file)
  133.     (or (dired-goto-subdir file)
  134.         (let ((buf (current-buffer))
  135.           (father father-buffer))
  136.           (bury-buffer)
  137.           (dired file)
  138.           (if (not (equal father (current-buffer)))
  139.           (setq father-buffer buf))))
  140.     (view-file file))))
  141.  
  142. (defun dired-find-file ()
  143.   "In dired, visit the file or directory named on this line."
  144.   (interactive)
  145.   (let ((file (dired-get-filename)))
  146.     (if (file-directory-p file)
  147.     (or (dired-goto-subdir file)
  148.         (let ((buf (current-buffer))
  149.           (father father-buffer))
  150.           (bury-buffer)
  151.           (dired file)
  152.           (if (not (equal father (current-buffer)))
  153.           (setq father-buffer buf))))
  154.     (find-file file))))
  155.  
  156. (defun dired-back ()
  157.   "Return to the dired-buffer this buffer was invoked from.
  158. If none, just bury this buffer"
  159.   (interactive)
  160.   (let ((buf father-buffer))
  161.     (bury-buffer)
  162.     (if (and (bufferp buf)
  163.          (buffer-name buf))
  164.     (if (get-buffer-window buf)
  165.         (select-window (get-buffer-window buf))
  166.         (switch-to-buffer buf)))))
  167.  
  168. (defun dired-quit ()
  169.   "Bury the current dired buffer."
  170.   (interactive)
  171.   (bury-buffer))
  172.  
  173. (defvar dired-last-used-directory () 
  174.     "Default directory in copy/rename/link file")
  175. (make-variable-buffer-local 'dired-last-used-directory)
  176.  
  177. (defun dired-default-target-directory ()
  178.   ;; Try to guess which target directory the user may want.
  179.   ;; If there is a dired buffer displayed in the next window, use
  180.   ;; its current subdir, else last used diredctory if any, else
  181.   ;; use current subdir of this dired buffer.
  182.   (let ((this-dir (and (eq major-mode 'dired-mode)
  183.                (dired-current-directory))))
  184.     (if dired-dwim-target
  185.     (let* ((this-window (selected-window))
  186.            (other-window (next-window this-window))
  187.            other-dir)
  188.       (while (not (or (equal this-window other-window)
  189.               other-dir))
  190.         (set-buffer (window-buffer other-window))
  191.         (setq other-dir (and (eq major-mode 'dired-mode)
  192.                  (dired-current-directory)))
  193.         (setq other-window (next-window other-window)))
  194.       (set-buffer (window-buffer this-window))
  195.       (or other-dir dired-last-used-directory this-dir))
  196.       this-dir)))
  197.  
  198. (defun dired-do-create-files (op-symbol file-creator operation arg
  199.                          &optional marker-char op1
  200.                          how-to)
  201.   ;; Create a new file for each marked file.
  202.   ;; Prompts user for target, which is a directory in which to create
  203.   ;;   the new files.  Target may be a plain file if only one marked
  204.   ;;   file exists.
  205.   ;; OP-SYMBOL is the symbol for the operation.  Function `dired-mark-pop-up'
  206.   ;;   will determine wether pop-ups are appropriate for this OP-SYMBOL.
  207.   ;; FILE-CREATOR and OPERATION as in dired-create-files.
  208.   ;; ARG as in dired-mark-get-files.
  209.   ;; Optional arg OP1 is an alternate form for OPERATION if there is
  210.   ;;   only one file.
  211.   ;; Optional arg MARKER-CHAR as in dired-create-files.
  212.   ;; Optional arg HOW-TO determines how to treat target:
  213.   ;;   If HOW-TO is not given (or nil), and target is a directory, the
  214.   ;;     file(s) are created inside the target directory.  If target
  215.   ;;     is not a directory, there must be exactly one marked file,
  216.   ;;     else error.
  217.   ;;   If HOW-TO is t, then target is not modified.  There must be
  218.   ;;     exactly one marked file, else error.
  219.   ;; Else HOW-TO is assumed to be a function of one argument, target,
  220.   ;;     that looks at target and returns a value for the into-dir
  221.   ;;     variable.  The function dired-into-dir-with-symlinks is provided
  222.   ;;     for the case (common when creating symlinks) that symbolic
  223.   ;;     links to directories are not to be considered as directories
  224.   ;;     (as file-directory-p would if HOW-TO had been nil).
  225.   (or op1 (setq op1 operation))
  226.   (let* ((fn-list (dired-mark-get-files nil arg))
  227.      (fn-count (length fn-list))
  228.      (target (expand-file-name
  229.            (dired-mark-read-file-name
  230.             (concat (if (= 1 fn-count) op1 operation) " %s to: ")
  231.             (dired-default-target-directory)
  232.             op-symbol arg (mapcar (function dired-make-relative) fn-list))))
  233.      (into-dir (cond ((null how-to) (file-directory-p target))
  234.              ((eq how-to t) nil)
  235.              (t (funcall how-to target)))))
  236.     (if (and (> fn-count 1)
  237.          (not into-dir))
  238.     (error "Marked %s: target must be a directory: %s" operation target))
  239.     ;; rename-file bombs when moving directories unless we do this:
  240.     (or into-dir (setq target (directory-file-name target)))
  241.     (setq dired-last-used-directory (if into-dir
  242.                     (file-name-as-directory target)
  243.                     (file-name-directory target)))
  244.     (dired-create-files
  245.      file-creator operation fn-list
  246.      (if into-dir            ; target is a directory
  247.      ;; This function uses fluid vars into-dir and target when called
  248.      ;; inside dired-create-files:
  249.      (function (lambda (from)
  250.              (expand-file-name (file-name-nondirectory from) target)))
  251.        (function (lambda (from) target)))
  252.      marker-char)))
  253.  
  254. (defun dired-create-directory (directory)
  255.   "Create a directory called DIRECTORY."
  256.   (interactive
  257.    (list (read-file-name "Create directory: " (dired-current-directory))))
  258.   (let ((expanded (directory-file-name (expand-file-name directory))))
  259.     (make-directory expanded)
  260.     (setq dired-last-used-directory (file-name-as-directory expanded))
  261.     (dired-add-file expanded)
  262.     (dired-move-to-filename)))
  263.  
  264. (defun dired-add-entry (filename &optional marker-char)
  265.   ;; Add a new entry for FILENAME, optionally marking it
  266.   ;; with MARKER-CHAR (a character, else dired-marker-char is used).
  267.   ;; Note that this adds the entry `out of order' if files sorted by
  268.   ;; time, etc.
  269.   ;; At least this version inserts in the right subdirectory (if present).
  270.   ;; And it skips "." or ".." (see `dired-trivial-filenames').
  271.   ;; Hidden subdirs are exposed if a file is added there.
  272.   (setq filename (directory-file-name filename))
  273.   ;; Entry is always for files, even if they happen to also be directories
  274.   (let ((opoint (point))
  275.     (cur-dir (dired-current-directory))
  276.     (directory (file-name-directory filename))
  277.     reason)
  278.     (setq filename (file-name-nondirectory filename)
  279.       reason
  280.       (catch 'not-found
  281.         (if (string= directory cur-dir)
  282.         (progn
  283.           (if (dired-subdir-hidden-p cur-dir)
  284.               (dired-unhide-subdir))
  285.           ;; We are already where we should be, except when
  286.           ;; point is before the subdir line or its total line.
  287.           (dired-goto-the-right-place filename))
  288.           ;; else try to find correct place to insert
  289.           (if (dired-goto-subdir directory)
  290.           (progn;; unhide if necessary
  291.             (if (looking-at "\r");; point is at end of subdir line
  292.             (dired-unhide-subdir))
  293.             ;; found - skip subdir and `total' line
  294.             ;; and uninteresting files like . and ..
  295.             ;; This better not moves into the next subdir!
  296.             (dired-goto-the-right-place filename))
  297.         ;; not found
  298.         (throw 'not-found "Subdir not found")))
  299.         ;; found and point is at The Right Place:
  300.         (let ((buffer-read-only ())
  301.           (at-beg (bolp)))
  302.           (beginning-of-line)
  303.           (if at-beg
  304.           (progn
  305.             (backward-char 1)
  306.             (insert-char 10 1)))
  307.           (dired-add-entry-do-indentation marker-char)
  308.           (dired-ls (dired-make-absolute filename directory)
  309.                                                   ;; don't expand `.' !
  310.             (concat dired-actual-switches "d"))
  311.           (if at-beg
  312.           (delete-char 1))
  313.           (forward-line -1)
  314.           ;; We want to have the non-directory part, only:
  315.           (let* ((beg (dired-move-to-filename t)) ; error for strange output
  316.              (end (dired-move-to-end-of-filename)))
  317.         (setq filename (buffer-substring beg end))
  318.         (delete-region beg end)
  319.         (insert (file-name-nondirectory filename)))
  320.           (if dired-after-readin-hook;; the subdir-alist is not affected...
  321.           (save-excursion;; ...so we can run it right now:
  322.             (save-restriction
  323.               (beginning-of-line)
  324.               (narrow-to-region (point) (save-excursion
  325.                           (forward-line 1) (point)))
  326.               (run-hooks 'dired-after-readin-hook))))
  327.           (dired-move-to-filename))
  328.         ;; return nil if all went well
  329.         nil))
  330.     (if reason                ; don't move away on failure
  331.     (goto-char opoint))
  332.     (not reason)))            ; return t on succes, nil else
  333.  
  334. ;;  Ridiculous that this should be needed just because someone tries to be
  335. ;;  smart and makes string-lessp sort according to LOCALE, which is wrong 
  336. ;;  here since ls doesn't care about that. I dont want to think about how
  337. ;;  much extra time this might take:
  338. (if (or (getenv "LANG") (getenv "LC_LOCALE"))
  339.  
  340.     (defun my-string-lessp (str1 str2)
  341.       (let ((maxlen (min (length str1) (length str2)))
  342.         (i 0))
  343.     (while (and (< i maxlen)
  344.             (= (string-to-char (substring str1 i)) 
  345.                (string-to-char (substring str2 i))))
  346.       (setq i (1+ i)))
  347.     (< (string-to-char (substring str1 i))
  348.        (string-to-char (substring str2 i)))))
  349.  
  350.     (fset 'my-string-lessp 'string-lessp))
  351.  
  352. (defun dired-goto-the-right-place (filename)
  353.   (if (string-match dired-sort-by-name-regexp dired-actual-switches)
  354.       ;;sort in alphabetically
  355.       (let ((max (dired-subdir-max)))
  356.     (goto-char (dired-after-subdir-garbage (dired-current-directory)))
  357.     (while (and (< (point) max) 
  358.             (my-string-lessp (file-name-nondirectory
  359.                       (or (dired-get-filename nil t) "\377"))
  360.                      filename))
  361.       (dired-next-file-same-dir)))
  362.     (dired-goto-next-nontrivial-file)))
  363.  
  364. (defun dired-goto-next-nontrivial-file ()
  365.   ;; Position point on first nontrivial file after point.
  366.   (dired-goto-next-file);; so there is a file to compare with
  367.   (if (stringp dired-trivial-filenames)
  368.       (while (and (not (eobp))
  369.           (string-match dired-trivial-filenames
  370.                 (file-name-nondirectory
  371.                  (or (dired-get-filename nil t) ""))))
  372.     (dired-next-file-same-dir))))
  373.  
  374. ;;  Actually, all the interface to how the buffer looks, and where
  375. ;;  to move, should be done through functions like this, to make the
  376. ;;  change to alternative formats, as e.g. dired-nstd.el, more
  377. ;;  transparent. In that case this could also be done more efficient.
  378. (defun dired-next-file-same-dir ()
  379.   (let ((dir (dired-current-directory))
  380.     (max (dired-subdir-max)))
  381.     (dired-next-line 1)
  382.     (while (and (< (point) max)
  383.         (not (equal (dired-current-directory) dir)))
  384.       (dired-next-line 1))
  385.     (if (not (equal (dired-current-directory) dir))
  386.     (beginning-of-line))))
  387.     
  388.