Mercurial > hg > xemacs-beta
diff lisp/dired/dired-link.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/dired/dired-link.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,135 @@ +;;!emacs +;; +;; FILE: dired-link.el +;; SUMMARY: Properly resolves UNIX (and Apollo variant) links under dired. +;; Works for both classic dired (V18) and tree dired (V19). +;; +;; AUTHOR: Bob Weiner +;; +;; ORIG-DATE: 09-May-89 +;; LAST-MOD: 30-Aug-92 at 19:15:57 by Bob Weiner +;; +;; Copyright (C) 1989, 1991, 1992, Free Software Foundation, Inc. +;; Available for use and distribution under the same terms as GNU Emacs. +;; +;; This file is part of InfoDock. +;; +;; DESCRIPTION: +;; +;; This library is used in conjunction with the Emacs dired facility. +;; To install it, simply load this file or create a +;; dired hook which loads this file. Then use {M-x dired <directory> RTN} +;; or {C-x C-f <directory> RTN} as one normally would. +;; +;; The changes below to 'dired-noselect' assume UNIX shell file +;; abbreviation and UNIX file name conventions. +;; +;; This modified version of the 'dired-noselect' function automatically +;; resolves all recursive links properly and edits the final directory that +;; a link points to, called the link referent. It handles Apollo-isms such +;; as /usr/local -> $(SERVER_LOCAL)/usr/local, /usr/bin -> +;; ../$(SYSTYPE)/usr/bin and /tmp -> `node_data/tmp. It also handles +;; relative links properly as in /usr/local/emacs -> gnu/emacs which must +;; be resolved relative to the '/usr/local' directory. +;; +;; DESCRIP-END. + +;; ************************************************************************ +;; Internal functions +;; ************************************************************************ + +;; Normally, if one performs a dired multiple times on a directory which is a +;; link, a new buffer will be created each time. This is due to the fact +;; that 'dired-find-buffer' is called in 'dired-noselect' before the link is +;; resolved. The following code solves this problem by checking for a +;; previously existing buffer that is performing dired on the directory that +;; the link resolves to. This is also done recursively. If one is found, +;; the dired buffer that shows the link is killed and the previously existing +;; one is used and re-read in. + +(defun dired-link-noselect-classic (dirname) + "Like M-x dired but returns the dired buffer as value, does not select it." + (or dirname (setq dirname default-directory)) + (setq dirname (dired-link-referent (directory-file-name dirname))) + (if (equal dirname "") + nil + (if (= (aref dirname 0) ?~) (setq dirname (expand-file-name dirname))) + (if (file-directory-p dirname) + (setq dirname (file-name-as-directory dirname))) + (let ((buffer (dired-find-buffer dirname))) + (set-buffer buffer) + (dired-readin dirname buffer) + (dired-move-to-filename) + (dired-mode dirname) + buffer))) + +(defun dired-link-noselect-tree (dirname &optional switches) + "Like `dired' but returns the dired buffer as value, does not select it." + (or dirname (setq dirname default-directory)) + (setq dirname (expand-file-name + (dired-link-referent (directory-file-name dirname)))) + (if (file-directory-p dirname) + (setq dirname (file-name-as-directory dirname))) + (dired-internal-noselect dirname switches)) + +;; Overload as appropriate for Classic (V18) or Tree Dired +(fset 'dired-noselect (if (fboundp 'dired-internal-noselect) + 'dired-link-noselect-tree + 'dired-link-noselect-classic)) + +;; +;; Resolves all UNIX links. +;; Works with Apollo's variant and other strange links. Will fail on +;; Apollos if the '../' notation is used to move just above the '/' +;; directory level. This is fairly uncommon and so the problem has not been +;; fixed. +;;; +(defun dired-link-referent (linkname) + "Returns expanded file or directory referent of LINKNAME. +LINKNAME should not end with a directory delimiter. +If LINKNAME is not a string, returns nil. +If LINKNAME is not a link, it is simply expanded and returned." + (if (not (stringp linkname)) + nil + (let ((referent)) + (while (setq referent (file-symlink-p linkname)) + (setq linkname (dired-link-expand + referent (file-name-directory linkname))))) + (dired-link-expand linkname (file-name-directory linkname)))) + +(defun dired-link-expand (referent dirname) + "Expands REFERENT relative to DIRNAME and returns." + (let ((var-link) + (dir dirname)) + (while (string-match "\\$(\\([^\)]*\\))" referent) + (setq var-link (getenv (substring referent (match-beginning 1) + (match-end 1))) + referent (concat (substring referent 0 (match-beginning 0)) + var-link + (substring referent (match-end 0))))) + ;; If referent is not an absolute path + (let ((nd-abbrev (string-match "`node_data" referent))) + (if (and nd-abbrev (= nd-abbrev 0)) + (setq referent (concat + ;; Prepend node name given in dirname, if any + (and (string-match "^//[^/]+" dirname) + (substring dirname 0 (match-end 0))) + "/sys/" (substring referent 1))))) + (while (string-match "\\.\\." referent) + ;; Match to "//.." or "/.." at the start of link referent + (while (string-match "^\\(//\\.\\.\\|/\\.\\.\\)\\(/\\|$\\)" referent) + (setq referent (substring referent (match-end 1)))) + ;; Match to "../" or ".." at the start of link referent + (while (string-match "^\\.\\.\\(/\\|$\\)" referent) + (setq dir (file-name-directory (directory-file-name dir)) + referent (concat dir (substring referent (match-end 0))))) + ;; Match to rest of "../" in link referent + (while (string-match "[^/]+/\\.\\./" referent) + (setq referent (concat (substring referent 0 (match-beginning 0)) + (substring referent (match-end 0)))))) + (and (/= (aref referent 0) ?~) + (/= (aref referent 0) ?/) + (setq referent (concat dirname referent)))) + referent) + +(provide 'dired-link)