1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; File: dired-xemacs.el
6 ;; Description: dired functions for XEmacs
7 ;; Author: Mike Sperber <sperber@informatik.uni-tuebingen.de>
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 (provide 'dired-xemacs)
13 (require 'dired-faces)
18 ;;; Variables not meant for user editing
21 (defun dired-demarkify-regexp (re)
22 (if (string-equal (substring re 0 (length dired-re-maybe-mark))
24 (concat "^" (substring re
25 (length dired-re-maybe-mark)
29 (defvar dired-re-raw-dir (dired-demarkify-regexp dired-re-dir))
30 (defvar dired-re-raw-sym (dired-demarkify-regexp dired-re-sym))
31 (defvar dired-re-raw-exe (dired-demarkify-regexp dired-re-exe))
33 (defvar dired-re-raw-boring (dired-omit-regexp)
34 "Regexp to match backup, autosave and otherwise boring files.")
36 (defvar dired-re-raw-socket (concat "^" dired-re-inode-size "s"))
38 (defvar dired-re-raw-setuid
39 (concat "^" dired-re-inode-size
40 "-[-r][-w][Ss][-r][-w][sx][-r][-w][xst]")
41 "setuid plain file (even if not executable)")
43 (defvar dired-re-raw-setgid
44 (concat "^" dired-re-inode-size
45 "-[-r][-w][-x][-r][-w][sS][-r][-w][xst]")
46 "setgid plain file (even if not executable)")
48 (defvar dired-re-pre-permissions "^[^-d]? ?[0-9 ]*[-d]"
49 "Regexp matching the preamble to file permissions part of a dired line.
50 This shouldn't match socket or symbolic link lines (which aren't editable).")
52 (defvar dired-re-permissions "[-r][-w][-Ssx][-r][-w][-Ssx][-r][-w][-xstT]"
53 "Regexp matching the file permissions part of a dired line.")
57 (setq dired-modeline-tracking-cmds '(mouse-track))
62 (defvar dired-subdir-menu nil "The Subdir menu for dired")
63 (defvar dired-mark-menu nil "The Mark menu for dired")
64 (defvar dired-do-menu nil "The Do menu for dired")
65 (defvar dired-regexp-menu nil "The Regexp menu for dired")
66 (defvar dired-look-menu nil "The Look menu for dired")
67 (defvar dired-sort-menu nil "The Sort menu for dired")
68 (defvar dired-help-menu nil "The Help menu for dired")
70 (defvar dired-menubar-menus
71 '(("Subdir" . dired-subdir-menu)
72 ("Mark" . dired-mark-menu)
73 ("Do" . dired-do-menu)
74 ("Regexp" . dired-regexp-menu)
75 ("Look" . dired-look-menu)
76 ("Sort" . dired-sort-menu))
77 "All the dired menus.")
79 (defvar dired-visit-popup-menu nil "The Visit popup for dired")
80 (defvar dired-do-popup-menu nil "The Do popup for dired")
82 (defun dired-setup-menus ()
84 dired-visit-popup-menu
85 '(["Find File" dired-find-file t]
86 ["Find in Other Window" dired-find-file-other-window t]
87 ["Find in Other Frame" dired-find-file-other-frame t]
88 ["View File" dired-view-file t]
89 ["Display in Other Window" dired-display-file t]))
93 '(["Copy to..." dired-do-copy t]
94 ["Rename to..." dired-do-rename t]
95 ["Compress/Uncompress" dired-do-compress t]
96 ["Uuencode/Uudecode" dired-do-uucode t]
97 ["Change Mode..." dired-do-chmod t]
98 ["Change Owner..." dired-do-chown t]
99 ["Change Group..." dired-do-chgrp t]
100 ["Load" dired-do-load t]
101 ["Byte-compile" dired-do-byte-compile t]
102 ["Hardlink to..." dired-do-hardlink t]
103 ["Symlink to..." dired-do-symlink t]
104 ["Shell Command..." dired-do-shell-command t]
105 ["Background Shell Command..." dired-do-background-shell-command t]
106 ["Delete" dired-do-delete t]))
111 ["Next Subdir" dired-next-subdir t]
112 ["Prev Subdir" dired-prev-subdir t]
113 ["Next Dirline" dired-next-dirline t]
114 ["Prev Dirline" dired-prev-dirline t]
115 ["Up Dir" dired-up-directory t]
116 ["Down Dir" dired-down-directory t]
117 ["Insert This Subdir" dired-maybe-insert-subdir t]
118 ["Create Directory..." dired-create-directory t]
119 ["Kill This Subdir" dired-kill-subdir t]
120 "-- Commands on All Files in Subdir --"
121 ["Redisplay Subdir" dired-redisplay-subdir t]
122 ["Mark Files" dired-mark-subdir-files t]
123 ["Flag Files for Deletion" dired-flag-subdir-files t]
124 ["Compress Uncompressed Files" dired-compress-subdir-files t]
125 (vector "Uncompress Compressed Files"
126 '(let ((current-prefix-arg t))
127 (dired-compress-subdir-files))
128 ':keys (dired-key-description 'dired-compress-subdir-files
129 'universal-argument))))
134 ["Next Marked" dired-next-marked-file t]
135 ["Previous Marked" dired-prev-marked-file t]
136 ["Change Marks..." dired-change-marks t]
137 ["Unmark All" dired-unmark-all-files t]
138 (vector "Toggle marks..."
139 '(let ((current-prefix-arg t))
140 (call-interactively 'dired-change-marks))
141 ':keys (dired-key-description 'dired-change-marks
142 'universal-argument))
143 ["Mark Symlinks" dired-mark-symlinks t]
144 ["Mark Directories" dired-mark-directories t]
145 ["Mark Old Backups" dired-clean-directory t]
146 ["Mark Executables" dired-mark-executables t]
147 ["Flag Backup Files" dired-flag-backup-files t]
148 ["Flag Auto-save Files" dired-flag-auto-save-files t]
149 ["Set new marker char" dired-set-marker-char t]
150 ["Restore marker char" dired-restore-marker-char t]
151 ["Marker stack left" dired-marker-stack-left t]
152 ["Marker stack right" dired-marker-stack-right t]
154 ["Mark Files from Other Dired" dired-mark-files-from-other-dired-buffer t]
155 ["Mark Files from Compile Buffer..." dired-mark-files-compilation-buffer t]))
159 '(["Copy to..." dired-do-copy t]
160 ["Rename to..." dired-do-rename t]
161 ["Expunge File Flagged for Deletion" dired-expunge-deletions t]
162 ["Compress/Uncompress" dired-do-compress t]
163 ["Uuencode/Uudecode" dired-do-uucode t]
164 ["Print..." dired-do-print t]
165 ["Change Mode..." dired-do-chmod t]
166 ["Change Owner..." dired-do-chown t]
167 ["Change Group..." dired-do-chgrp t]
168 ["Load" dired-do-load t]
169 ["Byte-compile" dired-do-byte-compile t]
170 ["Hardlink to..." dired-do-hardlink t]
171 ["Symlink to..." dired-do-symlink t]
172 ["Shell Command..." dired-do-shell-command t]
173 ["Background Shell Command..." dired-do-background-shell-command t]
174 ["Delete Marked Files" dired-do-delete t]
175 ["Visit file menu >" dired-visit-popup-menu-internal t]
176 ["Operate on file menu >" dired-do-popup-menu-internal t]))
181 ["Mark..." dired-mark-files-regexp t]
182 ["Mark Files with Extension..." dired-mark-extension t]
183 ["Flag..." dired-flag-files-regexp t]
184 ["Flag Files with Extension..." dired-flag-extension t]
185 ["Downcase" dired-downcase t]
186 ["Upcase" dired-upcase t]
187 ["Copy..." dired-do-copy-regexp t]
188 ["Rename..." dired-do-rename-regexp t]
189 ["Hardlink..." dired-do-hardlink-regexp t]
190 ["Symlink..." dired-do-symlink-regexp t]
191 ["Relative Symlink..." dired-do-relsymlink-regexp t]
193 ["Add Omit Regex..." dired-add-omit-regexp t]
194 (vector "Remove Omit Regex..."
195 '(let ((current-prefix-arg 1))
196 (call-interactively 'dired-add-omit-regexp))
197 ':keys (dired-key-description 'dired-add-omit-regexp 1))
198 (vector "Add Omit Extension..."
199 '(let ((current-prefix-arg '(4)))
200 (call-interactively 'dired-add-omit-regexp))
201 ':keys (dired-key-description 'dired-add-omit-regexp 'universal-argument))
202 (vector "Remove Omit Extension..."
203 '(let ((current-prefix-arg '(16)))
204 (call-interactively 'dired-add-omit-regexp))
205 ':keys (dired-key-description 'dired-add-omit-regexp
206 'universal-argument 'universal-argument))
207 (vector "Show Omit Regex"
208 '(let ((current-prefix-arg 0))
209 (call-interactively 'dired-add-omit-regexp))
210 ':keys (dired-key-description 'dired-add-omit-regexp 0))))
214 '(["Grep for..." dired-do-grep t]
215 ["Tags Search for..." dired-do-tags-search t]
216 ["Tags Query Replace..." dired-do-tags-query-replace t]
218 ["Diff File..." dired-diff t]
219 ["Diff with Backup" dired-backup-diff t]
220 ["Merge Files..." dired-emerge t]
221 ["Merge Files Having Common Ancestor..." dired-emerge-with-ancestor t]
222 ["Ediff Files..." dired-ediff t]
223 ["Patch File" dired-epatch t]))
228 ["Toggle Current Subdir by Name/Date" dired-sort-toggle-or-edit t]
229 (vector "Show Current Switches"
230 '(dired-sort-toggle-or-edit 0)
231 ':keys (dired-key-description 'dired-sort-toggle-or-edit 0))
232 (vector "Edit Switches for Current Subdir..."
233 '(dired-sort-toggle-or-edit 1)
234 ':keys (dired-key-description 'dired-sort-toggle-or-edit 1))
235 (vector "Edit Default Switches for Inserted Subdirs..."
236 '(dired-sort-toggle-or-edit 2)
237 ':keys (dired-key-description 'dired-sort-toggle-or-edit 2))
238 (vector "Sort Entire Buffer by Date"
239 '(dired-sort-toggle-or-edit 'date)
240 ':keys (dired-key-description 'dired-sort-toggle-or-edit
241 'universal-argument))
242 (vector "Sort Entire Buffer by Name"
243 '(dired-sort-toggle-or-edit 'name)
244 ':keys (dired-key-description 'dired-sort-toggle-or-edit
245 'universal-argument))
246 (vector "Edit Switches for Entire Buffer..."
247 '(dired-sort-toggle-or-edit '(16))
248 ':keys (dired-key-description 'dired-sort-toggle-or-edit
249 'universal-argument))
251 ["Hide All Subdirs" dired-hide-all t]
252 ["Hide Subdir" dired-hide-subdir t]
253 ["Toggle Omit" dired-omit-toggle t]
254 ["Kill Marked Lines" dired-do-kill-file-lines t]
255 (vector "Redisplay Killed Lines"
256 '(dired-do-kill-file-lines 0)
257 ':keys (dired-key-description 'dired-do-kill-file-lines "0"))))
261 ["Dired Summary Help" dired-summary t]
262 ["Describe Dired" dired-describe-mode t]
263 (vector "Dired Info Manual"
264 '(dired-describe-mode t)
265 ':keys (dired-key-description 'dired-describe-mode
266 'universal-argument))
267 ["Dired Command Apropos" dired-apropos t]
268 (vector "Dired Variable Apropos"
269 '(let ((current-prefix-arg t))
270 (call-interactively 'dired-apropos))
271 ':keys (dired-key-description 'dired-apropos 'universal-argument))
272 ["Report Dired Bug" dired-report-bug t])))
274 (defun dired-install-menubar ()
275 "Installs the Dired menu at the menubar."
276 (if (null dired-help-menu)
278 (if (and (featurep 'menubar) current-menubar)
280 (let ((buffer-menubar (copy-sequence current-menubar)))
281 (set-buffer-menubar buffer-menubar)
285 (let ((name (car pair))
286 (menu (symbol-value (cdr pair))))
287 (add-submenu nil (cons name menu)))))
288 dired-menubar-menus))
290 (car (find-menu-item current-menubar '("Help" "Dired")))
291 (add-menu-button '("Help") "--:shadowEtchedIn")
292 (add-submenu '("Help") (cons "Dired" dired-help-menu))))))
294 (add-hook 'dired-mode-hook 'dired-install-menubar)
298 (defun dired-mouse-file-action (event fun)
299 "In dired, apply function FUN to the file or directory name you click on."
301 (set-buffer (window-buffer (event-window event)))
302 (if dired-subdir-alist
304 (goto-char (event-point event))
307 (concat "dired-subdir-alist seems to be mangled. "
308 (substitute-command-keys
309 "\\<dired-mode-map>Try dired-revert (\\[dired-revert])."))))))
311 (defun dired-mouse-find-file (event)
312 "In dired, visit the file or directory name you click on."
314 (dired-mouse-file-action event 'dired-find-file))
316 (defun dired-mouse-display-file (event)
317 "In dired, display the file or directory name you click on."
319 (dired-mouse-file-action event 'dired-display-file))
321 (defun dired-mouse-find-file-other-window (event)
322 "In dired, visit the file or directory name you click on in another window."
324 (dired-mouse-file-action event 'dired-find-file-other-window))
326 (defun dired-mouse-find-file-other-frame (event)
327 "In dired, visit the file or directory name you click on in another frame."
329 (dired-mouse-file-action event 'dired-find-file-other-frame))
331 (defun dired-mouse-mark (event)
332 "In dired, mark the file name that you click on.
333 If the file name is already marked, this unmarks it."
336 (set-buffer (window-buffer (event-window event)))
337 (if dired-subdir-alist
339 (goto-char (event-point event))
341 (if (looking-at dired-re-mark)
345 (concat "dired-subdir-alist seems to be mangled. "
346 (substitute-command-keys
347 "\\<dired-mode-map>Try dired-revert (\\[dired-revert])."))))))
349 (defun dired-mouse-flag (event)
350 "In dired, flag for deletion the file name that you click on.
351 If the file name is already flag, this unflags it."
354 (set-buffer (window-buffer (event-window event)))
355 (if dired-subdir-alist
357 (goto-char (event-point event))
359 (if (char-equal (char-after (point)) dired-del-marker)
361 (dired-flag-file-deletion 1)))
363 (concat "dired-subdir-alist seems to be mangled. "
364 (substitute-command-keys
365 "\\<dired-mode-map>Try dired-revert (\\[dired-revert])."))))))
367 (defun dired-mouse-get-target (event)
368 "In dired, put a copy of the selected directory in the active minibuffer."
370 (let ((obuff (current-buffer))
372 (set-buffer (window-buffer (event-window event)))
373 (if (and dired-subdir-alist (setq mb (dired-get-active-minibuffer-window)))
375 (goto-char (event-point event))
376 (setq dir (dired-current-directory))
378 (set-buffer (window-buffer mb))
383 (error "No directory specified")
384 (error "No active minibuffer")))))
386 (defun dired-visit-popup-menu (event)
387 "Popup a menu to visit the moused file."
390 (set-buffer (window-buffer (event-window event)))
392 (goto-char (event-point event))
393 (dired-visit-popup-menu-internal event))))
395 (defun dired-visit-popup-menu-internal (event)
397 (let ((fn (dired-get-filename 'no-dir)))
399 (cons (concat "Visit " fn " with") dired-visit-popup-menu))
400 ;; this looks like a kludge to me ...
402 (dispatch-event (next-event)))))
404 (defun dired-do-popup-menu (event)
405 "Pop up a menu to do an operation on the moused file."
407 (let ((obuff (current-buffer)))
410 (set-buffer (window-buffer (event-window event)))
411 (dired-save-excursion
412 (goto-char (event-point event))
413 (dired-do-popup-menu-internal event)))
414 (set-buffer obuff))))
416 (defun dired-do-popup-menu-internal (event)
418 (let ((fn (dired-get-filename 'no-dir))
419 (current-prefix-arg 1))
421 (cons (concat "Do operation on " fn) dired-do-popup-menu))
423 (dispatch-event (next-event)))))
425 (defvar dired-filename-local-map
426 (let ((map (make-sparse-keymap)))
427 (set-keymap-name map 'dired-filename-local-map)
428 (define-key map [button2] 'dired-mouse-find-file)
429 (define-key map [(shift button2)] 'dired-mouse-display-file)
430 (define-key map [(meta button2)] 'dired-mouse-find-file-other-frame)
431 (define-key map [button3] 'dired-visit-popup-menu)
432 (define-key map [(control button2)] 'dired-do-popup-menu)
433 (define-key map [(shift button1)] 'dired-mouse-mark)
434 (define-key map [(control shift button1)] 'dired-mouse-flag)
436 "Keymap used to activate actions on files in dired.")
438 ;; Make this defined everywhere in the dired buffer.
439 (define-key dired-mode-map '(meta button3) 'dired-mouse-get-target)
442 (define-key dired-mode-map [(home)] (function (lambda ()
445 (when dired-do-interactive-permissions
446 (dired-move-to-permissions ?u 1)))))
448 (define-key dired-mode-map [(end)] (function (lambda ()
451 (dired-move-to-filename))))
455 (defun dired-maybe-filename-start (start end)
456 "Return start of filename if indicated by 'dired-file-name extent.
457 Presumably, this extent was inserted by `insert-directory'."
458 (let ((extents (dired-filename-extents start end)))
460 (extent-start-position (car extents)))))
462 (defun dired-maybe-filename-end (start end)
463 "Return end of filename if indicated by 'dired-file-name extent.
464 Presumably, this extent was inserted by `insert-directory'."
465 (let ((extents (dired-filename-extents start end)))
467 (extent-end-position (car extents)))))
469 (defun dired-filename-extents (start end)
470 "Returns extents with DIRED-FILE-NAME property.
471 START and END say where."
473 (map-extents #'(lambda (extent _)
474 (if (extent-property extent 'dired-file-name)
475 (setq extents (cons extent extents)))
481 (defun dired-set-extent-text-properties (extent face)
482 (set-extent-face extent face)
483 (set-extent-property extent 'keymap dired-filename-local-map)
484 (set-extent-property extent 'highlight t)
488 "button2 finds, button3 visits, "
489 "C-button2 file ops, [C-]shift-button1 marks/flags.")))
491 (defun dired-set-text-properties (start end &optional face)
493 (let ((extents (dired-filename-extents start end)))
496 (let ((extent (make-extent start end)))
497 (set-extent-property extent 'dired-file-name t)
498 (set-extent-property extent 'start-open t)
499 (set-extent-property extent 'end-open t)
501 (dired-set-extent-text-properties extent (or face 'default))
504 (defun dired-insert-set-properties (beg end)
505 ;; Sets the extents for the file names and their properties
509 (let ((eol (save-excursion (end-of-line) (point)))
512 (while (< (point) end)
513 (setq eol (save-excursion (end-of-line) (point)))
515 (if dired-do-interactive-permissions
516 (dired-make-permissions-interactive (point)))
518 (if (dired-manual-move-to-filename nil bol eol)
521 (dired-manual-move-to-end-of-filename nil bol eol)
522 (dired-set-text-properties
528 ((null dired-do-highlighting) nil)
529 ((looking-at dired-re-raw-dir) 'dired-face-directory)
530 ((looking-at dired-re-raw-sym) 'dired-face-symlink)
531 ((or (looking-at dired-re-raw-setuid)
532 (looking-at dired-re-raw-setgid)) 'dired-face-setuid)
533 ((looking-at dired-re-raw-exe) 'dired-face-executable)
534 ((looking-at dired-re-raw-socket) 'dired-face-socket)
538 (narrow-to-region (point) eol)
539 (re-search-forward dired-re-raw-boring eol t)))
540 'dired-face-boring))))))
545 (defun dired-remove-text-properties (start end)
546 ;; Removes text properties. Called in popup buffers.
549 (lambda (extent maparg)
550 (delete-extent extent)
552 nil start end nil nil 'dired-file-name))
554 (defun dired-highlight-filename-mark (extent)
557 (skip-chars-backward "^\n\r")
558 (char-after (point))))
559 (face (extent-face extent)))
560 (if (char-equal mark ?\ )
562 (set-extent-face extent (cadr face)))
565 ((char-equal dired-default-marker mark)
567 ((char-equal dired-del-marker mark)
573 (list new-face (cadr face))
574 (list new-face face)))))))
576 (defun dired-move-to-filename (&optional raise-error bol eol)
577 (or bol (setq bol (save-excursion
578 (skip-chars-backward "^\n\r")
580 (or eol (setq eol (save-excursion
581 (skip-chars-forward "^\n\r")
587 (lambda (extent maparg)
588 (if (extent-property extent 'dired-file-name)
594 (if dired-do-highlighting
595 (dired-highlight-filename-mark extent))
596 (goto-char (extent-start-position extent)))
598 (error "No file on this line")
602 (defun dired-move-to-end-of-filename (&optional no-error bol eol)
603 ;; Assumes point is at beginning of filename,
604 ;; thus the rwx bit re-search-backward below will succeed in *this*
605 ;; line if at all. So, it should be called only after
606 ;; (dired-move-to-filename t).
607 ;; On failure, signals an error (with non-nil NO-ERROR just returns nil).
608 (or eol (setq eol (save-excursion (skip-chars-forward "^\r\n") (point))))
612 (or bol (setq bol (save-excursion (skip-chars-backward "^\r\n") (point))))
613 (eq (char-after (1- bol)) ?\r)
615 ((dired-subdir-hidden-p (dired-current-directory))
617 (substitute-command-keys
618 "File line is hidden. Type \\[dired-hide-subdir] to unhide.")))
620 (substitute-command-keys
621 "File line is omitted. Type \\[dired-omit-toggle] to un-omit.")))))
622 (let ((filename-extent (map-extents
624 (lambda (e p) (and (extent-property e p) e)))
625 (current-buffer) bol eol 'dired-file-name)))
627 (goto-char (extent-end-position filename-extent))
628 (and (null no-error) (error "No file on this line")))))
630 (defun dired-move-to-permissions (domain direction)
631 (skip-chars-backward "^\r\n")
633 (while (not (setq extent (map-extents (function
636 (char-equal domain (extent-property e p))
641 (skip-chars-forward "^\r\n")
643 'dired-permissions)))
644 (forward-line direction))
645 (goto-char (extent-start-position extent))))
647 ;;; Interactive chmod
648 ;;; (based on ideas from Russell Ritchie's dired-chmod.el)
650 (defun dired-do-interactive-chmod (new-attribute)
651 (let* ((file (dired-get-filename))
652 (operation (concat "chmod " new-attribute " " file))
653 (failure (apply (function dired-check-process)
655 "chmod" new-attribute (list file))))
658 (dired-log-summary (buffer-name (current-buffer))
659 (format "%s: error" operation) nil))))
661 (defun dired-chmod-popup-menu (event menu)
663 (set-buffer (window-buffer (event-window event)))
665 (goto-char (event-point event))
667 ;; this looks like a kludge to me ...
669 (dispatch-event (next-event))))))
671 ;; This is probably overdoing it.
672 ;; Someone give me lexical scoping here ...
674 (defun dired-setup-chmod-keymap (domain id keys &optional toggle-keys)
679 (let ((name (intern (concat "dired-"
680 (list domain ?- key)))))
684 (dired-do-interactive-chmod ,(concat (list domain ?+ key)))
688 (prefix (concat "dired-" (list domain) "-" (list id)))
689 (remove-name (intern (concat prefix "-remove")))
690 (toggle-name (intern (concat prefix "-toggle")))
691 (mouse-toggle-name (intern (concat prefix "-mouse-toggle")))
692 (mouse-menu-name (intern (concat prefix "-menu"))))
695 `(defun ,remove-name ()
697 (cond ,@(mapcar (function
699 `((looking-at ,(regexp-quote (char-to-string key)))
700 (dired-do-interactive-chmod
701 ,(concat (list domain ?- key))))))
706 `(defun ,toggle-name ()
708 (cond ((looking-at "-") (dired-do-interactive-chmod
709 ,(concat (list domain ?+ (car keys)))))
710 ,@(let ((l (or toggle-keys keys))
715 `((looking-at (regexp-quote (char-to-string ,(car l))))
716 (dired-do-interactive-chmod
718 (concat (list domain ?- (car l)))
719 (concat (list domain ?+ (cadr l))))))
723 (t (dired-do-interactive-chmod
724 ,(concat (list domain ?+ (car keys))))))
728 `(defun ,mouse-toggle-name (event)
731 (set-buffer (window-buffer (event-window event)))
733 (goto-char (event-point event))
741 (cons (vector (concat (list ?+ (car loop-keys)))
745 (setq loop-keys (cdr loop-keys)
746 loop-names (cdr loop-names)))
747 (setq menu (append menu (list (vector "Toggle" toggle-name t)
748 (vector "Clear" remove-name t))))
749 (setq menu (cons (char-to-string domain) menu))
752 `(defun ,mouse-menu-name (event)
754 (dired-chmod-popup-menu event ',menu))))
756 (let ((keymap (make-sparse-keymap)))
757 (let ((loop-keys (cons ?. (cons ?- keys)))
758 (loop-names (cons toggle-name (cons remove-name names))))
760 (define-key keymap (car loop-keys) (car loop-names))
761 (setq loop-keys (cdr loop-keys)
762 loop-names (cdr loop-names))))
764 (define-key keymap 'button2 mouse-toggle-name)
765 (define-key keymap 'button3 mouse-menu-name)
766 (define-key keymap [(control ?p)] (function (lambda ()
768 (dired-permissions-arrow-move -1))))
769 (define-key keymap [(up)] (function (lambda ()
771 (dired-permissions-arrow-move -1))))
772 (define-key keymap [(control ?n)] (function (lambda ()
774 (dired-permissions-arrow-move 1))))
775 (define-key keymap [(down)] (function (lambda ()
777 (dired-permissions-arrow-move 1))))
778 (set-keymap-name keymap (char-to-string domain))
781 (defun dired-permissions-arrow-move (direction)
782 (let ((domain (extent-property
783 (extent-at (point) nil 'dired-permissions)
786 (forward-line direction)
787 ;; /etc/rcN.d is ".", "..", and the rest all symlinks.
788 (if (catch 'found-one
791 ;; Cannot modify symlink permissions.
792 ((looking-at dired-re-sym) (forward-line direction))
793 ((looking-at "^. [ \t0-9]*[^l][r-][w-]") (throw 'found-one t))
794 (t (throw 'found-one nil)))))
795 (dired-move-to-permissions domain direction)
798 (forward-line direction)
799 (looking-at dired-re-sym))
801 (forward-line direction)
802 (dired-move-to-filename))
803 (dired-move-to-permissions domain direction)
804 (when signal-error-on-buffer-boundary
805 ;; it'll do for now...
806 (ding nil 'buffer-bound))))))
808 (defvar dired-u-r-keymap nil "internal keymap for dired")
809 (defvar dired-u-w-keymap nil "internal keymap for dired")
810 (defvar dired-u-x-keymap nil "internal keymap for dired")
811 (defvar dired-g-r-keymap nil "internal keymap for dired")
812 (defvar dired-g-w-keymap nil "internal keymap for dired")
813 (defvar dired-g-x-keymap nil "internal keymap for dired")
814 (defvar dired-o-r-keymap nil "internal keymap for dired")
815 (defvar dired-o-w-keymap nil "internal keymap for dired")
816 (defvar dired-o-x-keymap nil "internal keymap for dired")
819 (defun dired-setup-chmod-keymaps ()
821 dired-u-r-keymap (dired-setup-chmod-keymap ?u ?r '(?r))
822 dired-u-w-keymap (dired-setup-chmod-keymap ?u ?w '(?w))
823 dired-u-x-keymap (dired-setup-chmod-keymap ?u ?x '(?x ?s) '(?x))
824 dired-g-r-keymap (dired-setup-chmod-keymap ?g ?r '(?r))
825 dired-g-w-keymap (dired-setup-chmod-keymap ?g ?w '(?w))
826 dired-g-x-keymap (dired-setup-chmod-keymap ?g ?x '(?x ?s) '(?x))
827 dired-o-r-keymap (dired-setup-chmod-keymap ?o ?r '(?r))
828 dired-o-w-keymap (dired-setup-chmod-keymap ?o ?w '(?w))
829 dired-o-x-keymap (dired-setup-chmod-keymap ?o ?x '(?x ?s ?t) '(?x))))
831 (defun dired-make-permissions-interactive (beg)
834 (buffer-substring (point) (save-excursion (end-of-line) (point)))
835 (if (and (re-search-forward dired-re-pre-permissions
836 (save-excursion (end-of-line) (point))
838 (looking-at dired-re-permissions))
840 (dired-activate-permissions (make-extent p (+ 1 p)) dired-u-r-keymap)
841 (dired-activate-permissions (make-extent (+ 1 p) (+ 2 p)) dired-u-w-keymap)
842 (dired-activate-permissions (make-extent (+ 2 p) (+ 3 p)) dired-u-x-keymap)
843 (dired-activate-permissions (make-extent (+ 3 p) (+ 4 p)) dired-g-r-keymap)
844 (dired-activate-permissions (make-extent (+ 4 p) (+ 5 p)) dired-g-w-keymap)
845 (dired-activate-permissions (make-extent (+ 5 p) (+ 6 p)) dired-g-x-keymap)
846 (dired-activate-permissions (make-extent (+ 6 p) (+ 7 p)) dired-o-r-keymap)
847 (dired-activate-permissions (make-extent (+ 7 p) (+ 8 p)) dired-o-w-keymap)
848 (dired-activate-permissions (make-extent (+ 8 p) (+ 9 p)) dired-o-x-keymap)))))
850 (defun dired-activate-permissions (extent keymap)
851 (set-extent-face extent 'dired-face-permissions)
852 (set-extent-property extent 'keymap keymap)
853 (set-extent-property extent 'highlight t)
854 (set-extent-property extent 'dired-permissions (string-to-char (keymap-name keymap)))
855 (set-extent-property extent 'help-echo
856 "button2 toggles, button3 changes otherwise."))
858 (dired-setup-chmod-keymaps)
861 ;;; Popup header supports
862 (defun dired-insert-set-headerline-properties ()
863 ;; Sets the extents for the current directory header line
864 (let ((position (dired-get-headerline)))
865 (dired-insert-set-headerline-properties-internal (car position)
868 (defun dired-get-headerline ()
869 ;; Get the bufffer position of the current directory header line
873 (re-search-forward " *\\(.*\\):$" nil t)
874 ;; Return begin and end pair
875 (cons (match-beginning 1) (match-end 1)))))
877 (defun dired-insert-set-headerline-properties-internal (b e)
878 (let ((extent (make-extent b e)))
879 (set-extent-face extent 'dired-face-header)
880 (set-extent-property extent 'keymap dired-headerline-local-map)
881 (set-extent-property extent 'highlight t)
884 "button2 do dired this window.")))
886 (defvar dired-headerline-local-map
887 (let ((map (make-sparse-keymap)))
888 (set-keymap-name map 'dired-headerline-local-map)
889 (define-key map [button2] 'dired-headerline-dired)
890 (define-key map [(shift button2)] 'dired-headerline-dired-other-window)
891 (define-key map [(meta button2)] 'dired-headerline-dired-other-frame)
893 (define-key map "f" 'dired-headerline-dired-by-key)
894 (define-key map "o" 'dired-headerline-dired-other-window-by-key)
895 (define-key map "w" 'dired-headerline-dired-frame-window-by-key)
897 "Keymap used to activate actions on the header line in dired directory.")
899 (defun dired-split-headerline (dir)
900 ;; (dired-split-headerline "/")
903 ;; (dired-split-headerline "/a/b/c")
904 ;; => (list "/" "/a" "/a/b" "/a/b/c")
906 ;; (dired-split-headerline "/masat-y@foo:/a")
907 ;; => (list "/" "/masat-y@foo:/" "/masat-y@foo:/a")
909 ;; (dired-split-headerline "/masat-y@foo:/")
910 ;; => (list "/" "/masat-y@foo:/")
912 (let ((dirlist (cons dir nil))
913 (lastdir dir)) ; To check double entry item
914 (setq dir (directory-file-name
915 (file-name-directory dir)))
916 (while (not (string= dir lastdir))
917 (setq dirlist (cons dir dirlist)
919 dir (directory-file-name
920 (file-name-directory dir))))
921 ;; Add "/" if it is not in `dirlist'.
922 (if (not (string= (car dirlist) "/"))
923 (setq dirlist (cons "/" dirlist)))
927 (defun dired-headerline-dired (event)
928 "On the header line in dired, visit the parent directory."
930 (dired-headerline-dired-internal event 'dired "Dired"))
932 (defun dired-headerline-dired-other-window (event)
933 "On the header line in dired, visit the parent directory in another window."
935 (dired-headerline-dired-internal event
937 "Dired in Other Window"))
939 (defun dired-headerline-dired-other-frame (event)
940 "On the header line in dired, visit the parent directory in another frame."
942 (dired-headerline-dired-internal event
944 "Dired in Other Frame"))
946 (defun dired-headerline-dired-internal (event func title)
948 ;; Header line: /a/b/c
960 ;; Get directory list
962 (let (points basedir)
964 (set-buffer (window-buffer (event-window event)))
966 (goto-char (event-point event))
967 (setq points (dired-get-headerline)
968 dirlist (dired-split-headerline
969 (buffer-substring (car points) (cdr points)))))))
971 ;; Create menu and popup it
975 (setq dir (car dirlist)
976 dirlist (cdr dirlist)
978 (aset v 0 dir) (aset v 1 (list func dir)) (aset v 2 t)
979 (setq items (cons v items)))
980 (popup-menu (cons title items)))))
983 (defun dired-headerline-dired-by-key (p)
984 "On the header line in dired, visit the parent directory under ther cursor."
986 (dired-headerline-dired-by-key-internal p 'dired))
988 (defun dired-headerline-dired-other-window-by-key (p)
989 "On the header line in dired, visit the parent directory under ther cursor on another window."
991 (dired-headerline-dired-by-key-internal p 'dired-other-window))
993 (defun dired-headerline-dired-other-frame-by-key (p)
994 "On the header line in dired, visit the parent directory under ther cursor on another frame."
996 (dired-headerline-dired-by-key-internal p 'dired-other-frame))
998 (defun dired-headerline-dired-by-key-internal (p func)
999 (let ((points (dired-get-headerline))
1004 ;; A function that checks the headerline shows remote directry.
1005 (fset 'check-remote (lambda (str)
1006 (save-match-data (string-match "/.*@.*:/" str))))
1008 ;; Calculate position in headerline
1009 (setq p (- p (car points)))
1011 ;; Get directory list
1012 (setq basedir (buffer-substring (car points) (cdr points)))
1013 (setq dirlist (dired-split-headerline basedir))
1015 ;; Which directory 'p' in on...
1019 ;; P points out Root directory?
1024 (setq dirlist (cdr dirlist)))
1026 ;; P points out remote host name field.
1029 (apply 'check-remote (list (car dirlist))))
1030 ;; P points out remote host field in headerline?
1031 (if (< p (length (car dirlist)))
1032 (throw 'found (car dirlist))
1033 ;; P points out remote directory not remote host field.
1034 (setq dirlist (cdr dirlist))))
1036 ;; Find p from directory list
1040 (setq tmpdir (car dirlist))
1041 (if (<= p (length tmpdir))
1042 (throw 'found tmpdir)
1043 (setq dirlist (cdr dirlist))))
1049 (if (string= dir basedir)
1051 (funcall func dir))))
1053 ;;; end of dired-xemacs.el