1 ;;; tinydired.el --- Dired enchancements. Backgroud Ange ftp support
3 ;; This file is not part of Emacs
7 ;; Copyright (C) 1996-2007 Jari Aalto
8 ;; Keywords: extensions
10 ;; Maintainer: Jari Aalto
12 ;; To get information on this program use ident(1) or call M-x
13 ;; tinydired-version. Look at code with folding.el
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with program; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30 ;; Boston, MA 02110-1301, USA.
32 ;; Visit <http://www.gnu.org/copyleft/gpl.html> for more information
37 ;; ....................................................... &t-install ...
38 ;; Put this file on your Emacs-Lisp load path, add following into your
39 ;; ~/.emacs startup file.
41 ;; ;; Make sure the keys will be defined.
42 ;; (setq tinydired-:force-add-keys-flag 'override)
44 ;; (autoload 'tinydired-hook-control "tinydired" "" t)
45 ;; (autoload 'tinydired-switch-to-some-ange-ftp-buffer "tinydired" "" t)
46 ;; (add-hook 'tinydired-:load-hook 'tinydired-hook-control)
47 ;; (add-hook 'dired-mode-hook '(lambda () (require 'tinydired) nil))
49 ;; For more personal setup, you have to look at the calls in function
50 ;; `tinydired-hook-control' and put your own initializations into
51 ;; `dired-mode-hook' and `dired-after-readin-hook'.
53 ;; To select/kill ange buffers, use these bindings
55 ;; (global-set-key "\C-cab" 'tinydired-switch-to-some-ange-ftp-buffer)
56 ;; (global-set-key "\C-cak" 'tinydired-kill-all-ange-buffers)
57 ;; (global-set-key "\C-caK" 'tinydired-kill-all-ange-and-dired-buffers)
59 ;; If you don't want default keybindings, modify variable
61 ;; tinydired-:bind-hook
63 ;; Help about keys - do this in dired buffer after you've loaded this file
65 ;; t C-h enchanced "tiny" dired commands
66 ;; a C-h enchanced "ange-ftp" commands
68 ;; If you have any questions, always use function
70 ;; M-x tinydired-submit-bug-report
74 ;; ..................................................... &t-commentary ...
81 ;; This package started evolving, when there was need for something
82 ;; more from ange-ftp, like background file loading. Ange-ftp also had
83 ;; nasty habbit of putting user to just downloaded .zip or .tar.gz
84 ;; buffer. That not what was usually wanted, but to download the files
85 ;; somewhere other than inside emacs. There was need for ability to
86 ;; *mark* files for download and get them all at once to a download
87 ;; directory. With standard `ange-ftp' you would have to load them one
88 ;; by one. Sometimes you may want to go associated `ange-ftp' buffer
89 ;; and give commands directly there, so a command to switch between
90 ;; ange-ftp and dired buffers would be handy.
92 ;; Now you can do this with standard `ange-ftp' and Emacs dired.
94 ;; Note: This paskage is just extension to `ange-ftp', consider
95 ;; getting next generation ange-ftp, the `EFS', if you want
96 ;; overall better and more complete interface. Use this package if
97 ;; you only need features like batch put/get at backround.
98 ;; (Further note: EFS was later installed to XEmacs and it does not work
99 ;; any more with Emacs.)
101 ;; Overview of features
103 ;; o Few enchancements to dired mode. Eg. keep only one
104 ;; dired buffer when ascending to directory. Shorten symlinks.
105 ;; o User can mark and put files into STORE and start a backgroud
106 ;; ange-ftp session to get STORED files into download directory
107 ;; o Easy switching between ange-ftp session buffer and dired buffer
108 ;; o Dealing with ange ftp buffers in general
109 ;; (x) killing all ange buffers at once
110 ;; (x) killing all ange + dired ange buffers at once.
111 ;; (x) switching to ange buffers with completion
112 ;; o Run "!" on ange ftp dired buffer (operate on local copy)
113 ;; o customizable backup file flagging.
114 ;; o other handy dired commands, like "pop to this file in emacs."
115 ;; "find all marked files"...
119 ;; The dired and ange-ftp implementation (nowadays efs) is
120 ;; completely differen than in Emacs
122 ;; ** THIS PACKAGE IS FOR Emacs ONLY **
124 ;; General dired additions
126 ;; In simplest form. This module installs some functions in your
127 ;; dired hooks. Their purpose is
129 ;; o To keep your dired buffer sorted so that directories are
131 ;; o Delete unwanted files from dired buffer automatically.
132 ;; o Shorten the symlink references, so that they don't spread
133 ;; multiple lines and ruin your view.
135 ;; It also changes one dired function with `defadvice', so that you
136 ;; can control if you want to have only one dired buffer when
137 ;; ascending to another directory. See variable:
139 ;; tinydired-:use-only-one-buffer-flag
141 ;; Dired and ange-ftp additions
143 ;; When you want to start ftp session in emacs you just do
145 ;; C-x C-f /login@site:/dir/dir/file
147 ;; Let's take an example: To see what new things has arrived
148 ;; to GNU site, you'd do this:
150 ;; C-x C-f /ftp@prep.ai.mit.edu:/pub/gnu/
152 ;; After that you are put into the dired listing, where you
153 ;; can mark files with dired-mark command
157 ;; Now you have files ready. Next put files into batch STORAGE.
158 ;; There is "a" prefix for ange-ftp related commands.
160 ;; a S Big S put selected files into storage
161 ;; a q To check what files you have batched
162 ;; a c To clear the batch storage
164 ;; Now start ftp'ding the files in background. You're prompted
165 ;; for the download directory.
167 ;; a g Get marked file(s)
169 ;; If you want to operate on the associated ftp buffer
170 ;; directly, there is command
172 ;; a b For "buffer change"
174 ;; that puts you into ftp, where the dired buffer refers. When
175 ;; you're in the ftp buffer you have some keybinding available.
177 ;; C-c f insert stored files on the line
178 ;; C-c d insert directory name
179 ;; C-c b back to dired window
181 ;; It's sometimes handy that you can give direct ftp commands.
183 ;; Setting up ange ftp
185 ;; Here is my settings, which you can use as a reference so that you
186 ;; get the ange running. For more details, see the ange-ftp.el's
187 ;; source code. These settings include firewall "ftpgw.example.com"
189 ;; ;; (setq ange-ftp-generate-anonymous-password t)
190 ;; (setq ange-ftp-dumb-unix-host-regexp "tntpc") ;PC hosts
191 ;; (setq ange-ftp-gateway-host "ftpgw.example.com")
192 ;; (setq ange-ftp-smart-gateway t)
193 ;; (setq ange-ftp-local-host-regexp "\\.myhost\\.\\(com|fi\\)|^[^.]*$")
194 ;; ;; Always use binary
195 ;; (setq ange-ftp-binary-file-name-regexp ".")
196 ;; (autoload 'ange-ftp-set-passwd "ange-ftp" t t)
197 ;; (setq ange-ftp-generate-anonymous-password "jdoe@example.com")
199 ;; How to use this module 3 -- special vc
201 ;; There are some extra commands that you may take a look at.
202 ;; See source code of bind function
204 ;; tinydired-default-other-bindings
206 ;; What additional commands you get when loading this module.
208 ;; The VC special commands were programmed, because I felt that the
209 ;; C-x v v in dired mode didn't quite do what I wanted. I wanted
210 ;; simple ci/co/revert commands for files that were in VC control.
211 ;; And I wanted to handle them individually, expecially when ci'ing.
212 ;; (written for Emacs 19.28).
214 ;; This VC part of the package is highly experimental.
215 ;; I'm not sure if I support it in further releases.
217 ;; Important ange-ftp interface note
219 ;; The ange ftp batch interface used here may cause unpredictable
220 ;; problems. Sometimes the `get' or `put' process doesn't start at all
221 ;; although you see message saying it started the job. I have had
222 ;; several occurrances where `lcd' cmd succeeded, but then nothing
223 ;; happened. Repeating the `put' or `get' command cleared the problem
226 ;; So, never trust the message `completed', unless you saw that the
227 ;; download percentage count started running. If you're downloading
228 ;; important file, double check the real ftp buffer for correct response.
229 ;; Try again if ftp wasn't started. Another way to clear the problem: kill
230 ;; the ange ftp buffer and try the command from dired again. It
231 ;; automatically opens session to the site.
233 ;; Advertise -- other useful packages
235 ;; There are exellent dired extensions around, please consider getting
238 ;; o dired-sort.el (requires date-parse.el)
241 ;; Note: Slow autoload
243 ;; When you have added the autoloads into your .emacs, the first time
244 ;; you bring up dired buffer may be quite slow. This is normal, Emacs
245 ;; just need to load some additional files that this package uses.
247 ;; Note: Refreshing the view takes long time / point isn't exatly the same
249 ;; This is normal, dired is just slow and program has to do lot of
250 ;; work to maintain the "view". Eg. save view, save marks, delete
251 ;; marks, revert, sort, restore marks... Only the current line
252 ;; position is preserved where user was, not point.
256 ;; Emacs ships with package `dired-x.el', which seems to offer some
257 ;; more goodies to dired. Currently, if the `dired-x' is detected the
258 ;; appropriate functions in this package are diabled, to prevent
259 ;; overlapping behavior. However, if the function behaves differently
260 ;; than the one in some dired extension package, then the function
261 ;; isn't disabled. Eg. see `tinydired-load-all-marked-files', which can turn
272 ;;; ......................................................... &require ...
281 (autoload 'dired-do-shell-command "dired-x" "" t)
283 ;; We really don't need to load full packages, so use these..
284 (defvar vc-dired-mode)
285 (autoload 'vc-dired-mode "vc")
286 (autoload 'vc-finish-logentry "vc")
287 (autoload 'vc-next-action-on-file "vc")
288 (autoload 'vc-workfile-unchanged-p "vc")
290 ;; Too bad that can't autoload this one...
291 (defvar vc-dired-mode nil)
292 (autoload 'vc-registered "vc-hooks")
294 ;; The ange interface in this package is based on Emacs only
296 (autoload 'ange-ftp-ftp-name "ange-ftp"))
298 (autoload 'dired-bunch-files "dired-aux")
299 (autoload 'dired-run-shell-command "dired-aux")
300 (autoload 'dired-shell-stuff-it "dired-aux")
302 (defvar diff-switches) ;; in diff.el
303 (autoload 'ediff-files "ediff" "" t))
306 (ti::package-use-dynamic-compilation)
309 ** tinydired.el: This package is for Emacs only.\n\
310 Dired and ange-ftp interfaces are incompatible between\n\
312 If you see XEmacs byte compiler error:
313 evaluating (< nil 0): (wrong-type-argument..
314 you can ignore it safely. The problem is in
315 dired.el::dired-map-over-marks"))
317 (unless (boundp 'dired-move-to-filename-regexp)
319 ** tinydired.el: Error, this Emacs did not define dired-move-to-filename-regexp"))
320 (defvar dired-move-to-filename-regexp))
322 (ti::package-defgroup-tiny TinyDired tinydired-: extensions
323 "Dired enchancements. Backgroud Ange ftp support.
326 o Few enchancements to dired mode. Eg. keep only one
327 dired buffer when ascending to directory. Shorten symlinks.
328 o User can mark and put files into STORE and start a backgroud
329 ange-ftp session to get STORED files into download directory
330 o Easy switching between ange-ftp session buffer and dired buffer
331 o Dealing with ange ftp buffers in general
332 (x) killing all ange buffers at once
333 (x) killing all ange + dired ange buffers at once.
334 (x) switching to ange buffers with completion
335 o Run ! on ange ftp dired buffer (operate on local copy)
336 o customizable backup file flagging.
337 o other handy dired commands, like: pop to this file in emacs.
338 find all marked files ...")
343 ;;; .......................................................... &v-bind ...
344 ;;; handle extra keybindings.
346 (defcustom tinydired-:bind-hook
347 '(tinydired-default-ange-bindings
348 tinydired-default-other-bindings)
349 "*Single function or list of functions to bind keys.
350 These are installed to `dired-mode-hook' automatically when this package
355 ;;; ......................................................... &v-hooks ...
357 (defcustom tinydired-:readin-hook
362 ;; Includes variable ls-lisp-dirs-first
363 (message "TinyDired: `ls-lisp-dirs-first' set to t, DO NOT CHANGE.")
364 (setq ls-lisp-dirs-first t)
367 'tinydired-sort-dir))
368 'tinydired-kill-files
369 'tinydired-shorten-links))
370 "*List of functions to run after dired read.
371 These are inserted into `dired-after-readin-hook' when package
372 installs itself. Do not remove 'tinydired-sort-dir' or
373 it paralyzes package, because it relies on seeing directories first
374 in the dired listing."
378 (defcustom tinydired-:load-hook nil
379 "*Hook run when package has been loaded."
383 ;;; ....................................................... &v-private ...
385 (defvar tinydired-:file-store nil
386 "Private. Storage of filenames.")
387 (make-variable-buffer-local 'tinydired-:file-store)
389 (defvar tinydired-:directory nil
390 "Private. Directory name.")
392 (defvar tinydired-:mark-list nil
393 "Private. Saved filename mark list.")
395 (defvar tinydired-:mput-last-ftp nil
396 "Private. Last ftp mput site string.")
397 (make-variable-buffer-local 'tinydired-:mput-last-ftp)
399 (defvar tinydired-:mput-history nil
400 "Private. History variable.")
402 (defvar tinydired-:previous-buffer nil
403 "Private. Recorded buffer, before leaping in another.")
405 (defvar tinydired-:dir-copy-buffer "*tinydired-dir*"
406 "Private. Copy of current directory. Created every time when needed.")
408 (defvar tinydired-:dired-directory-ange-regexp "[@:]"
409 "Regexp to match `dired-directory' to find ange-ftp buffers.")
412 ;;{{{ setup: User vars
414 ;;; ........................................................ &v-public ...
415 ;;; User configurable
417 (defcustom tinydired-:tmp-dir
418 (dolist (dir '("~/tmp/dired/"
421 (when (file-directory-p dir)
423 "*Temporary directory where to store ange ftp files.
424 This should be user's private directory, and _must_not_ not be
425 /tmp, because someone else may be running tinydired too and using
430 (defcustom tinydired-:download-dir
431 (dolist (dir '("~/tmp/ftp"
435 (when (file-directory-p dir)
437 "*Directory where to down load selected files in dired listing."
441 (defcustom tinydired-:force-add-keys-flag 'overrride
442 "*Non-nil means to install and override default keys to dired.
443 Normally the keys are defined _only_ if the prefix key is in state
448 (defcustom tinydired-:use-only-one-buffer-flag t
449 "*Non-nil means the previous dired buffer is killed when ascending to next.
450 This makes sure you have only one dired buffer for each dired session.
451 This feature is not used if dired-x is present."
455 (defcustom tinydired-:page-step 10
456 "*Page Up step size in lines."
460 (defcustom tinydired-:unwanted-files-regexp
461 "\\.o$\\|~$\\|\\.class\\|\\.pyc"
462 "*Regexp to match files that should not be shown in dired buffer.
463 Set to nil, if you want to see all files.
464 This feature is not used if dired-x is present."
465 :type '(string :tag "Regexp")
468 (defcustom tinydired-:backup-file-regexp
469 ;; Like files from CVS: .#ChangeLog.1.3288
470 "\\(\\.bak\\|\\.backup\\|[~#]\\)\\|\\.#$"
471 "*Backup filename regexp, used by advised `dired-flag-backup-files'."
472 :type '(string :tag "Regexp")
475 (defcustom tinydired-:mput-sites nil
476 "*List of ange-ftp style site location strings, where user can upload files.
478 Format '(\"ANGE-FTP-REF\" ..), ange-ftp-ref is like /login@site:dir/dir/"
479 :type '(repeat (string :tag "Ange-Ftp"))
482 (defcustom tinydired-:tmp-dir-function 'tinydired-create-tmp-dir
483 "*Create directory for `tinydired-:tmp-dir'."
487 (defcustom tinydired-:show-storage-function
490 (message "%d: %s" (length args) (ti::list-to-string args))))
491 "*How to show the storage to user. Default is to use `message' function.
492 The function is called with list of files in storage."
499 ;;; ....................................................... &v-version ...
502 (ti::macrof-version-bug-report
505 tinydired-:version-id
506 "$Id: tinydired.el,v 2.49 2007/05/06 23:15:19 jaalto Exp $"
507 '(tinydired-:version-id
509 tinydired-:readin-hook
511 tinydired-:file-store
513 tinydired-:mput-last-ftp
514 tinydired-:mput-last-ftp
515 tinydired-:previous-buffer
516 tinydired-:dir-copy-buffer
518 tinydired-:tmp-dir-function
519 tinydired-:force-add-keys-flag
520 tinydired-:use-only-one-buffer-flag
521 tinydired-:unwanted-files-regexp
522 tinydired-:download-dir
523 tinydired-:mput-sites
524 tinydired-:show-storage-function
526 ;; This tells if used has dired-x loaded
531 ;;; ########################################################### &Funcs ###
533 ;;{{{ code: install, bind, hook control
535 ;;; ----------------------------------------------------------------------
537 (defun tinydired-default-ange-bindings (&optional force)
538 "Add Extra dired bindings. Optionally FORCE adding bindings."
540 ;; "a" for Ange ftp related commands, since the file information
541 ;; stored is best used in *ftp* buffer itself.
542 (when (or tinydired-:force-add-keys-flag
544 (eq 'undefined (lookup-key dired-mode-map "a")))
545 ;; clear this only it the map is not in our use.
546 (if (not (keymapp (lookup-key dired-mode-map "a")))
547 (define-key dired-mode-map "a" nil))
548 ;; "b" for buffer handling
549 (define-key dired-mode-map "abb" 'tinydired-switch-to-ange-ftp-buffer)
550 (define-key dired-mode-map "abp" 'tinydired-switch-to-mput-ange-ftp-buffer)
551 (define-key dired-mode-map "abk" 'tinydired-kill-dired-and-ange-session)
552 ;; Redefine key "q" too. Was 'dired-delete-and-exit'
553 (define-key dired-mode-map "q" 'tinydired-kill-dired-and-ange-session)
554 (when (ti::emacs-p) ;XEmacs has EFS, these don't work
555 (define-key dired-mode-map "as" 'tinydired-store-filename)
556 (define-key dired-mode-map "ad" 'tinydired-store-delete-filename)
557 (define-key dired-mode-map "aS" 'tinydired-store-add-marked)
558 (define-key dired-mode-map "ar" 'tinydired-store-remove-file)
559 (define-key dired-mode-map "aR" 'tinydired-store-delete-marked)
560 (define-key dired-mode-map "ac" 'tinydired-store-clear)
561 ;; the "q" is just close to "a" key, no other particular logic used.
562 (define-key dired-mode-map "aq" 'tinydired-store-show)
564 (define-key dired-mode-map "ag" 'tinydired-store-ftp-mget)
565 (define-key dired-mode-map "ap" 'tinydired-store-ftp-mput)))
568 ;;; ----------------------------------------------------------------------
570 (defun tinydired-default-other-bindings (&optional force)
571 "Add extra dired bindings. Optionally FORCE adding bindings."
572 (when (or tinydired-:force-add-keys-flag
574 (eq 'undefined (lookup-key dired-mode-map "t")))
575 ;; make prefix key available for us.
576 (ti::use-prefix-key dired-mode-map "t")
577 ;; You propably want to do also
578 ;; (define-key dired-mode-map "!" 'tinydired-dired-do-shell-command)
579 (define-key dired-mode-map "t!" 'tinydired-dired-do-shell-command)
580 (define-key dired-mode-map "t-" 'tinydired-one-dir-up)
581 ;; "f" for find-file related
582 (ti::use-prefix-key dired-mode-map "tf")
583 (define-key dired-mode-map "tff" 'tinydired-load-all-marked-files)
584 (define-key dired-mode-map "tfr" 'tinydired-marked-revert-files)
585 (define-key dired-mode-map "tg" 'tinydired-refresh-view)
586 (define-key dired-mode-map "tG" 'tinydired-read-dir-as-is)
587 (ti::use-prefix-key dired-mode-map "tk")
588 (define-key dired-mode-map "tkk" 'tinydired-kill-lines)
589 (define-key dired-mode-map "tkm" 'tinydired-kill-marked-lines)
590 (define-key dired-mode-map "tkM" 'tinydired-kill-unmarked-lines)
591 (define-key dired-mode-map "tl" 'tinydired-leave-only-lines)
592 (define-key dired-mode-map "tp" 'tinydired-pop-to-buffer)
593 (define-key dired-mode-map "te" 'tinydired-ediff)
594 (define-key dired-mode-map "t<" 'tinydired-shorten-links)
595 (define-key dired-mode-map "t>" 'tinydired-lenghten-links)
596 ;; Mark related commands in "m" map
597 (ti::use-prefix-key dired-mode-map "tf")
598 (define-key dired-mode-map "tme" 'tinydired-mark-files-in-Emacs)
599 (define-key dired-mode-map "tmd" 'tinydired-mark-today-files)
600 (define-key dired-mode-map "tmo" 'tinydired-mark-opposite-toggle)
601 (define-key dired-mode-map "tmr" 'tinydired-mark-read-only-files)
602 (define-key dired-mode-map "tms" 'tinydired-marks-save)
603 (define-key dired-mode-map "tmS" 'tinydired-marks-restore)
604 (define-key dired-mode-map "tmw" 'tinydired-mark-writable-files)
605 (ti::use-prefix-key dired-mode-map "tmv")
606 (define-key dired-mode-map "tmvv" 'tinydired-mark-vc-files-in-Emacs)
607 (define-key dired-mode-map "tmvd" 'tinydired-mark-vc-has-diffs)
608 ;; some special VC functions for marked files in "v" map
609 (ti::use-prefix-key dired-mode-map "tv")
610 (define-key dired-mode-map "tvi" 'tinydired-marked-vc-ci)
611 (define-key dired-mode-map "tvo" 'tinydired-marked-vc-co)
612 (define-key dired-mode-map "tvu" 'tinydired-marked-vc-revert)
613 ;; Override some Emacs default bindings to better follow
614 ;; this buffer's content.
615 (define-key dired-mode-map "\M-<" 'tinydired-first-line)
616 (define-key dired-mode-map "\M->" 'tinydired-last-file)
617 (define-key dired-mode-map [(home)] 'tinydired-first-file)
618 (define-key dired-mode-map [(end)] 'tinydired-last-file)
619 (define-key dired-mode-map [(select)] 'tinydired-last-file) ;; 'end' key
620 (define-key dired-mode-map [(prior)] 'tinydired-pgup)
621 (define-key dired-mode-map [(next)] 'tinydired-pgdown))
624 ;;; ----------------------------------------------------------------------
625 ;;; - If user has relocated some keys...well, we don't handle those.
627 (defun tinydired-remove-bindings ()
628 "Remove bindings from this dired session.
629 User must be in dired buffer. Makes the `dired-mode-map'
630 local to current buffer."
633 '("abb" "abp" "as" "aS" "ar" "aR" "ac" "aq" "ag" "ap"
634 "t!" "tf" "tg" "tk" "tl" "tp" "t<" "t>"
635 "tmd" "tml" "tms" "tmS" "tmv"
637 (when (and (memq major-mode '(dired-mode))
639 (make-local-variable 'dired-mode-map)
641 (define-key dired-mode-map elt 'tinydired-ignore))
643 (define-key dired-mode-map "\M-<" 'beginning-of-buffer)
644 (define-key dired-mode-map "\M->" 'end-of-buffer)
645 (define-key dired-mode-map [(home)] 'beginning-of-buffer)
646 (define-key dired-mode-map [(end)] 'end-of-buffer))))
648 ;;; ----------------------------------------------------------------------
651 (defun tinydired-hook-control (&optional remove)
652 "Add hooks to dired mode. Optional REMOVE all hooks inserted by package."
654 (let* ((list (ti::list-make tinydired-:bind-hook)))
657 (ti::add-hooks 'dired-after-readin-hook tinydired-:readin-hook 'remove)
658 (ti::add-hooks 'dired-mode-hook tinydired-:bind-hook 'remove))
660 ;; Now, install the package
661 (ti::add-hooks 'dired-after-readin-hook tinydired-:readin-hook)
662 (dolist (x list) ;bind the keys
663 (add-hook 'dired-mode-hook x)
664 ;; This is due to autoload: while the package is beeing loaded,
665 ;; it should also set the bindings immediately
666 (if (boundp 'dired-mode-map)
670 ;;; ----------------------------------------------------------------------
672 (defun tinydired-install (&optional remove)
673 "Install package. Optionally REMOVE."
677 (tinydired-hook-control remove)
678 (tinydired-advice-control remove))
680 (tinydired-hook-control)
681 (tinydired-advice-control)
682 (tinydired-xemacs-note))))
685 ;;{{{ XEmacs compatibility
687 ;;; ----------------------------------------------------------------------
688 ;;; Some functions are not found from XEmacs, mimic them
690 (defun tinydired-dired-unmark-all-files-no-query ()
691 "XEmacs compatibility."
692 (if (fboundp 'dired-unmark-all-files-no-query)
693 (ti::funcall 'dired-unmark-all-files-no-query)
694 (ti::save-line-column-macro nil nil
695 (tinydired-first-line)
696 (while (or (not (eobp))
697 (not (looking-at "^[ \t]*$")))
698 ;; Just use brute force for all lines.
701 ;;; ----------------------------------------------------------------------
703 (defun tinydired-xemacs-note ()
704 "Warn that tinydired.el may work improperly in XEmacs."
705 (when (and (ti::xemacs-p)
707 "You know that TinyDired's features won't work in XEmacs?")))
708 (tinydired-advice-control 'disable)
712 ;;{{{ code: ange-ftp.el
714 ;;; ----------------------------------------------------------------------
716 (defun tinydired-advice-control-old (&optional disable verb)
717 "Activate all advises. Use extra argument to DISABLE all. VERB."
726 (y-or-n-p (format "advices %s: No mistake here? "
727 (if disable "off" "on")))))
731 (ad-disable-regexp re) ;only sets flag
732 (setq msg "All advices deactivated"))
734 (ad-enable-regexp re) ;only sets flag
735 (setq msg "All advices activated")))
736 (ad-update-regexp re)
740 ;;; ----------------------------------------------------------------------
742 (defun tinydired-advice-control (&optional disable)
743 "Activate or DISABLE advices in this package."
746 '(ange-ftp-set-binary-mode
747 dired-move-to-end-of-filename
749 ange-ftp-expand-file-name
750 ange-ftp-get-file-entry
751 dired-flag-backup-files
756 "TinyDired advices "))
758 ;;; ----------------------------------------------------------------------
760 (defadvice ange-ftp-set-binary-mode (before tinydired-error-prevent-fix dis)
761 "Sometimes you can get error:
764 `ange-ftp-set-binary-mode'(\"ftp.uit.no\" \"ftp\")
766 Which is due to missing variables
768 `ange-ftp-ascii-hash-mark-size'
769 `ange-ftp-binary-hash-mark-size'
771 This advice resets them to some default values, so that you don't get
774 (set-buffer (ange-ftp-ftp-process-buffer host user))
775 (if (null ange-ftp-ascii-hash-mark-size)
776 (setq ange-ftp-ascii-hash-mark-size 1024))
777 (if (null ange-ftp-binary-hash-mark-size)
778 (setq ange-ftp-binary-hash-mark-size 1024))))
783 ;;; ----------------------------------------------------------------------
784 ;;; - See dired-repeat-over-lines
786 (defmacro tinydired-map-over-regexp (re &rest body)
787 "If '(looking-at RE)' then do BODY over all lines matching.
788 Start from current point. The point is positioned at the beginning of line.
789 Buffer read-only is removed.
791 The BODY should move the pointer to next file and bol, until eob reached."
793 (let* ((end (tinydired-last-file-point))
796 (while (and (not (eobp))
799 (if (looking-at (, re))
802 (forward-line 1))))))
804 ;;; ----------------------------------------------------------------------
806 (put 'tinydired-map-over-files 'lisp-indent-function 0)
807 (defmacro tinydired-map-over-files (&rest body)
808 "Map over files. No No dirs are included.
809 You must advance the cursor in the BODY. See `tinydired-map-over-regexp'."
812 (tinydired-first-file)
813 (tinydired-map-over-regexp "^. +[^d]" (,@ body)))))
815 ;;; ----------------------------------------------------------------------
817 (put 'tinydired-map-over-unmarked 'lisp-indent-function 0)
818 (defmacro tinydired-map-over-unmarked (&rest body)
819 "Map over unmarked lines and execute BODY at the beginning of line.
820 The calling BODY should position the cursor for next search so
821 that current line is skipped when BODY finishes.
823 The buffer is writable during mapping."
825 (let* (buffer-read-only
826 (ReGexp (dired-marker-regexp)))
828 (tinydired-map-over-files
829 (if (looking-at ReGexp)
834 ;;; ----------------------------------------------------------------------
836 (defmacro tinydired-remember-marks (var-sym &optional beg end)
837 "Save mark list to variable VAR-SYM between points BEG and END.
838 START and END defaults to all files"
841 (dired-remember-marks
843 (tinydired-first-line-point))
845 (tinydired-last-file-point))))))
847 ;;; ----------------------------------------------------------------------
849 (defun tinydired-ignore ()
852 (message "TinyDired: Function is not available in this dired buffer."))
854 ;;; ----------------------------------------------------------------------
856 (defun tinydired-create-tmp-dir ()
857 "Create directory `tinydired-:tmp-dir' if possible."
858 (make-directory (expand-file-name tinydired-:tmp-dir)))
860 ;;; ----------------------------------------------------------------------
862 (defun tinydired-get-tmp-dir ()
863 "Return temp directory with slash at the end."
864 (let* ((dir tinydired-:tmp-dir)
865 (func tinydired-:tmp-dir-function))
866 (unless (not (file-exists-p dir))
867 (setq dir (funcall func)))
868 (setq dir (expand-file-name dir))
869 (unless (file-exists-p dir)
870 (error "TinyDired: Directory not exist %s" dir))
871 (file-name-as-directory dir)))
873 ;;; ----------------------------------------------------------------------
875 (defsubst tinydired-get-filename ()
876 "Return only filename without directory."
877 ;; The (dired-get-filename t) almos does the same, but it _may_
878 ;; contains slahes.. docs say so.
879 (ti::string-match "\\([^/]+\\)$" 1 (dired-get-filename)))
881 ;;; ----------------------------------------------------------------------
883 (defsubst tinydired-get-mark ()
884 "Return first char to the left. Point is not preserved."
888 ;;; ----------------------------------------------------------------------
890 (defsubst tinydired-get-marked-files ()
892 (ignore-errors (dired-get-marked-files)))
894 ;;; ----------------------------------------------------------------------
896 (defun tinydired-get-marked-files-no-dir ()
897 "Return LIST of marked files."
898 ;; #todo: See this code via macroexpand And you'll find test
900 ;; (if (< nil 0) (nreverse results) results))
902 ;; Which flags an compile error in XEmacs.
904 (dired-map-over-marks
905 (tinydired-get-filename)
908 ;;; ----------------------------------------------------------------------
910 (defsubst tinydired-first-line-point ()
911 "Return first file point."
913 (tinydired-first-line)
914 (line-beginning-position)))
916 ;;; ----------------------------------------------------------------------
918 (defsubst tinydired-last-file-point ()
919 "Return last file point."
920 (save-excursion (tinydired-last-file) (line-end-position)))
922 ;;; ----------------------------------------------------------------------
924 (defsubst tinydired-mark-re (re &optional unmark)
925 "Mark files matching RE. Give prefix argument to UNMARK."
928 (while (re-search-forward re nil t)
933 ;;; ----------------------------------------------------------------------
935 (defsubst tinydired-mark-file-list (list &optional unmark)
936 "Mark files in LIST. Give prefix argument to UNMARK."
937 (dolist (elt (ti::list-make list))
938 (tinydired-mark-re (concat (regexp-quote elt) "$") unmark)))
940 ;;; ----------------------------------------------------------------------
942 (defun tinydired-feature-p (arg)
943 "Check if we already have this functionality in dired. See ARG from code."
944 ;; Emacs with with `dired-x', which I just noticed had some of
945 ;; the same functionality. We don't use TDD if those
946 ;; are present in some cases.
948 ((eq arg 'auto-delete)
949 ;; see dired-omit-files-p
950 (and (featurep 'dired-x)
951 (> emacs-minor-version 27)))
955 ;;; ----------------------------------------------------------------------
958 (defun tinydired-normal-buffer-p ()
959 "Check if buffer's first line look like dired."
961 (and (not (ti::buffer-narrowed-p))
964 (and (looking-at "^[ \t]+\\([a-z]:\\)?/")
965 ;;; In VAX these don't exist.
968 ;;; (looking-at "^[ \t]+total[ \t]+[0-9]")
971 ;;; ----------------------------------------------------------------------
973 (defun tinydired-kill-files ()
974 "After each dired read, remove unwanted files."
975 (let* ((re tinydired-:unwanted-files-regexp)
977 (unless (tinydired-feature-p 'auto-delete)
978 ;; Is this new directory buffer ..
979 (if (and (eq major-mode 'dired-mode)
981 (flush-lines re)) ;don't wanna see these
984 ;;; ----------------------------------------------------------------------
986 (defun tinydired-file-list (&optional arg mode)
987 "Gets all files/dir entries in the view.
988 The ARG is `dired-get-filename' parameter.
992 ARG If non-nil, no absolute names
993 MODE if 're then make regexp out of files.
994 if 'files then return just filenames
998 (re re ..) If mode is 're
999 (file file ...) If mode is 'plain
1000 ((mark file) ..) default
1002 The `mark' is first character in the left for file or dir."
1007 (setq last-point (tinydired-last-file-point))
1008 (tinydired-first-line)
1009 (if (setq file (ignore-errors (dired-get-filename arg)))
1013 (if (looking-at dired-re-sym)
1014 (push (concat (regexp-quote file) " +->") list)
1015 (push (format " %s$" (regexp-quote file)) list)))
1019 (push (list (tinydired-get-mark) file) list))))
1020 (while (< (point) last-point)
1022 (if (setq file (ignore-errors (dired-get-filename arg)))
1026 (if (looking-at dired-re-sym)
1027 (push (concat (regexp-quote file) " +->") list)
1028 (push (format " %s$" (regexp-quote file)) list)))
1032 (push (list (tinydired-get-mark) file) list))))))
1035 ;;; ----------------------------------------------------------------------
1037 (defun tinydired-sort-dir ()
1038 "Put directories first in dired listing."
1039 (let (buffer-read-only
1043 ;; - Buffer gets narrowed in some dired internal operations, like
1044 ;; pressing "l", dired-do-redisplay
1045 ;; - We do nothing in these cases
1047 ;; - We have to save position, because e.g. pressing "Z" to
1048 ;; compress file, causes reading the whole dir --> point moved.
1050 (when (tinydired-normal-buffer-p)
1051 (ti::save-with-marker-macro
1052 (tinydired-first-line)
1053 (tinydired-remember-marks marks (point))
1054 (tinydired-dired-unmark-all-files-no-query) ; sort goes nuts otherwise
1055 (message "") ; stupid message from dired-un...
1057 ;; 19 Nov 1995, sof@dcs.glasgow.ac.uk (Sigbjorn Finne), comp.Emacs
1059 (tinydired-first-line) (beginning-of-line)
1060 (sort-regexp-fields t "^.*$" "[ ]*." (point) (point-max))
1061 ;; now, We prefer to have dirs first, and then links, allthough
1062 ;; some links may be dirs (we can't know anything about links)
1065 (when (re-search-forward "^[ \t]+lr" nil t)
1066 (setq p1 (line-beginning-position))
1067 ;; We know that dirs are after links, because the listing is
1070 (re-search-forward "^[ \t]+d" nil t)
1071 (setq p2 (line-beginning-position))
1072 (setq region (buffer-substring p1 p2))
1073 (delete-region p1 p2)
1074 (re-search-forward "^[ \t]+-" nil t) ;go after dirs
1077 (dired-mark-remembered marks)
1078 (set-buffer-modified-p nil)))))
1080 ;;; ----------------------------------------------------------------------
1082 (defun tinydired-dir-original (dir &optional buffer)
1083 "Do same as `dired-insert-directory'.
1084 Insert DIR to BUFFER, which defaults to `tinydired-:dir-copy-buffer'"
1086 ;; See dired.el dired-readin-insert
1087 (ti::temp-buffer (or buffer tinydired-:dir-copy-buffer) 'clear)
1088 (set-buffer (or buffer tinydired-:dir-copy-buffer))
1089 (insert-directory (expand-file-name dir)
1090 dired-listing-switches nil t)))
1092 ;;; ----------------------------------------------------------------------
1094 (defun tinydired-dir-original-get-line (file)
1095 "Return original line for FILE.
1096 Be sure you have called `tinydired-dir-original' first.
1097 Signal no error. Use `regexp-quote' for FILE if it contains unusual characters.
1101 nil ,no line was found"
1103 (set-buffer tinydired-:dir-copy-buffer)
1106 (if (re-search-forward (concat " " file) nil t)
1107 (ti::read-current-line))))
1110 ;;{{{ code: interactive
1112 ;;; ----------------------------------------------------------------------
1115 (defun tinydired-ediff (file &optional switches)
1116 "Compare file at point with file FILE using `ediff'.
1117 FILE defaults to the file at the mark.
1118 The prompted-for file is the first file given to `ediff'.
1119 With prefix arg, prompt for second argument SWITCHES,
1120 which is options for `diff'."
1122 (let ((default (if (mark t)
1123 (save-excursion (goto-char (mark t))
1124 (dired-get-filename t t)))))
1126 (read-file-name ;ARG 1
1127 (format "Ediff %s with: %s"
1128 (dired-get-filename t)
1130 (concat "(default " default ") ")
1132 (dired-current-directory) default t)
1133 (if current-prefix-arg ;ARG 2
1135 "Options for diff: "
1136 (if (stringp diff-switches)
1138 (mapconcat 'identity diff-switches " ")))))))
1139 ;; Interactive part end
1141 (dired-get-filename t) switches))
1143 ;;; ----------------------------------------------------------------------
1146 (defun tinydired-read-dir-as-is ()
1147 "Read the directory without any filtering."
1149 (let* (dired-after-readin-hook)
1152 ;;; ----------------------------------------------------------------------
1155 (defun tinydired-mark-files-in-Emacs ()
1156 "Mark all files in current directory that are in Emacs."
1158 (let* ((dir (expand-file-name dired-directory)) ;get rid of "~"
1159 (list (ti::dolist-buffer-list
1160 (and (buffer-file-name)
1161 (string-match (regexp-quote dir) (buffer-file-name))))))
1163 (setq dir dir)) ;Shut up byteCompiler
1166 (tinydired-first-file)
1167 (if (re-search-forward elt nil t)
1170 ;;; ----------------------------------------------------------------------
1173 (defun tinydired-marked-revert-files (&optional arg)
1174 "Revert ie. replace files in Emacs with true copies in directory.
1175 If ARG is non-nil, remove any marks if file was loaded.
1178 Only reload files in Emacs whose modify flag is non-nil.
1179 If file does not exist in Emacs, do nothing."
1181 (let* ((list (tinydired-get-marked-files))
1184 (when (setq buffer (get-file-buffer file))
1185 (with-current-buffer buffer
1186 (unless (buffer-modified-p)
1187 (revert-buffer nil t) ;no confirmation
1188 (setq buffer 'done) )))
1189 (when (and arg (eq 'done buffer))
1191 (regexp-quote (file-name-nondirectory file)) 'unmark)))))
1193 ;;; ----------------------------------------------------------------------
1194 ;;; - It's lot faster to use direct command, than search the buffer
1195 ;;; for ".." and use "f" or click mouse over it.
1198 (defun tinydired-one-dir-up ()
1199 "Go up one directory."
1201 (find-file (concat dired-directory "..")))
1203 ;;; ----------------------------------------------------------------------
1206 (defun tinydired-dired-do-shell-command (command &optional arg)
1207 "Like `dired-do-shell-command', but run running command in dired ange-ftp.
1208 This is not remote shell, but instead it
1209 transfers the file to your local system and then executes the dired
1210 command on the file.
1212 Remember: Every time you run this command this files are copied _blindly_
1213 to your local directory. No file cache information is kept.
1222 `tinydired-:tmp-dir'"
1225 (dired-read-shell-command
1229 (dired-get-marked-files
1230 t current-prefix-arg))
1231 current-prefix-arg))
1232 (let* ((to-dir (tinydired-get-tmp-dir))
1233 (ange (ange-ftp-ftp-name dired-directory))
1234 (on-each (not (string-match "\\*" command)))
1240 ;; Simple local dired.
1241 (dired-do-shell-command command arg))
1243 (setq host (nth 0 ange)
1246 (setq file-list (dired-get-marked-files t))
1247 (ti::file-ange-file-handle 'get user host dir to-dir file-list 'foreground)
1248 (dolist (file file-list) ; All directory to every filename
1249 (push (concat to-dir file) list))
1250 (setq file-list list)
1251 ;; ......................................... copy from dired-aux ...
1254 (- 10000 (length command))
1256 (lambda (&rest files)
1257 (dired-run-shell-command
1258 (dired-shell-stuff-it command files t arg))))
1261 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... .. then ...
1262 ;; execute the shell command
1263 (dired-run-shell-command
1264 (dired-shell-stuff-it command file-list nil arg)))))))
1266 ;;; ----------------------------------------------------------------------
1269 (defun tinydired-lenghten-links ()
1270 "Opposite to `tinydired-shorten-links'.
1271 This may take a while, because the whole directory structure must
1274 (let* ((line (ti::current-line-number))
1278 (when (tinydired-normal-buffer-p)
1279 ;; Now create copy of original directory.
1280 (tinydired-dir-original dired-directory)
1281 (tinydired-remember-marks marks)
1282 (tinydired-dired-unmark-all-files-no-query)
1284 (dired-mark-symlinks nil)
1285 ;; This didn't update full line, only the data part, not the
1286 ;; linked name portion "->"
1287 ;; (dired-do-redisplay)
1288 (dired-map-over-marks
1290 (setq file (dired-get-filename 'no-dir))
1291 (setq line (tinydired-dir-original-get-line (regexp-quote file)))
1292 ;; now, delete line and relace it with original entry.
1295 (re-search-forward " l")
1297 (delete-region (point) (line-end-position))
1300 (dired-mark-symlinks 'unmark)
1302 (dired-mark-remembered marks))
1303 (set-buffer-modified-p nil))))
1305 ;;; ----------------------------------------------------------------------
1306 ;;; - It's awfull to see 30 linked files whyen they don't fit on one line...
1309 (defun tinydired-shorten-links ()
1310 "Shortens all linked files. The link part is removed."
1312 (let* ((line (ti::current-line-number))
1314 (when (tinydired-normal-buffer-p)
1317 (if (looking-at ".* +->\\([^\n]+\\)")
1318 (ti::replace-match 1))
1321 (dired-move-to-filename))))
1323 ;;; ----------------------------------------------------------------------
1326 (defun tinydired-marks-save ()
1327 "Save mark list to private storage.
1328 Use this function if you know next operation will remove the marks.
1329 You can get the marks back with `tinydired-marks-restore'."
1331 (save-excursion ;due to next command
1332 (tinydired-remember-marks tinydired-:mark-list)
1333 (message "TinyDired: Marks saved.")))
1335 ;;; ----------------------------------------------------------------------
1338 (defun tinydired-marks-restore ()
1339 "Restore mark list saved by `tinydired-marks-save'."
1341 (if (null tinydired-:mark-list)
1343 (substitute-command-keys
1344 "No marks saved. Use '\\[tinydired-marks-save]' first."))
1345 (dired-mark-remembered tinydired-:mark-list)))
1347 ;;; ----------------------------------------------------------------------
1350 (defun tinydired-pgup ()
1351 "Move cursor to _last_ file in dired mode."
1353 (dired-next-line (- tinydired-:page-step))
1355 (tinydired-first-line)))
1357 ;;; ----------------------------------------------------------------------
1360 (defun tinydired-pgdown ()
1363 (dired-next-line tinydired-:page-step)
1365 (tinydired-last-file)))
1367 ;;; ----------------------------------------------------------------------
1370 (defun tinydired-first-line ()
1371 "Move to first _line_ in dired."
1377 (when (looking-at "^ .*[rwx]")
1378 (dired-move-to-filename)
1379 (setq point (point))))
1382 ;; Then, it's some strange non-unix propably ...
1385 ;;; ----------------------------------------------------------------------
1386 ;;; - Supposing the directory is in order...dirs first then files...
1389 (defun tinydired-first-file ()
1390 "Move to first file in dired."
1395 (while (and (null point)
1398 (dired-move-to-filename)
1399 (unless (eq 0 (current-column))
1400 (setq point (point))) ))
1403 ;; Then, it's some strange non-unix propably ...
1406 ;;; ----------------------------------------------------------------------
1409 (defun tinydired-last-file ()
1410 "Move to last file in dired."
1415 (while (and (null point)
1418 (dired-move-to-filename)
1419 (unless (eq 0 (current-column))
1420 (setq point (point))) ))
1423 ;; Then, it's some strange non-unix propably ...
1426 ;;; ----------------------------------------------------------------------
1428 (defun tinydired-kill-marked-lines ()
1429 "Remove lines that are unmarked."
1431 (let (buffer-read-only
1433 (dired-map-over-marks
1434 (push (regexp-quote (ti::read-current-line)) list)
1438 (if (re-search-forward re nil t)
1439 (ti::buffer-kill-line)))))
1441 ;;; ----------------------------------------------------------------------
1444 (defun tinydired-kill-unmarked-lines ()
1445 "Remove unmarked lines. Ignore directories and symlinks."
1447 (tinydired-map-over-unmarked
1449 ;; We're at the beginning of line, suppose std unix 'ls'
1451 (setq char (buffer-substring (+ 2 (point)) (+ 3 (point))))
1452 (if (not (or (string= char "d")
1453 (string= char "l")))
1454 (ti::buffer-kill-line)
1457 (tinydired-first-file))
1459 ;;; ----------------------------------------------------------------------
1462 (defun tinydired-kill-lines (re)
1463 "Delete lines matching RE."
1464 (interactive "sKill files re: ")
1465 (let* (buffer-read-only)
1466 (unless (ti::nil-p re)
1467 (ti::save-line-column-macro (tinydired-first-file) (dired-move-to-filename)
1468 (tinydired-first-file) ;; do this in ti::save-line-column-macro
1469 (flush-lines re)))))
1471 ;;; ----------------------------------------------------------------------
1474 (defun tinydired-leave-only-lines (re)
1475 "Leave only lines matching RE. Directory lines are skipped.
1476 You can easily undo this with reverting the buffer (dired \"g\")."
1477 (interactive "sLeave regexp: ")
1478 (unless (ti::nil-p re)
1480 (tinydired-map-over-files
1481 (if (string-match re (ti::read-current-line))
1483 (ti::buffer-kill-line)))
1484 (tinydired-first-file)))
1486 ;;; ----------------------------------------------------------------------
1489 (defun tinydired-pop-to-buffer ()
1490 "Pop to buffer if it exists in Emacs."
1492 (let* ((file (ignore-errors (dired-get-filename)))
1495 ((and (stringp file)
1496 (setq buffer (get-file-buffer file)))
1497 (pop-to-buffer buffer))
1499 (message (format "TinyDired: Can't pop ... Not in Emacs. [%s]"
1502 ;;; ----------------------------------------------------------------------
1503 ;;; - This behaves differently than dired-x.el dired-do-find-marked-files
1506 (defun tinydired-mark-today-files ()
1507 "Mark all files, not dirs, that are created today.
1508 Point sits on first today file. If no today's files are found, point stays
1509 on current filename."
1511 (let* ((list (ti::date-time-elements))
1512 (line (ti::current-line-number))
1514 (re (concat ".*[0-9] " (nth 5 list) " +"
1515 (int-to-string (nth 0 list))
1517 ;; This year's file have time in this field
1519 (tinydired-map-over-files
1520 (if (not (looking-at re))
1523 (tinydired-first-file)
1524 (if (re-search-forward re nil t)
1525 (dired-move-to-filename)
1527 (dired-move-to-filename))))
1529 ;;; ----------------------------------------------------------------------
1531 (defun tinydired-mark-writable-files ()
1532 "Mark Your files that have writable flag set."
1534 (let* ((re ".*.w..[-w]..[-w]. "))
1535 (tinydired-map-over-files
1536 (if (not (looking-at re))
1540 ;;; ----------------------------------------------------------------------
1542 (defun tinydired-mark-read-only-files ()
1543 "Mark Your files that have writable flag set."
1545 (let* ((re ".*r-.[-r]..[-r].. "))
1546 (tinydired-map-over-files
1547 (if (not (looking-at re))
1551 ;;; ----------------------------------------------------------------------
1553 (defun tinydired-mark-opposite-toggle ()
1554 "Mark opposite files.
1555 Ie. if you have marked some files, unmark those and mark all other files."
1557 (let* ((re (dired-marker-regexp)))
1558 (ti::save-line-column-macro nil nil
1559 (tinydired-map-over-files
1565 ;;; ----------------------------------------------------------------------
1566 ;;; - This behaves differently than dired-x.el dired-do-find-marked-files
1569 (defun tinydired-mark-vc-files-in-Emacs (&optional unmark verb)
1570 "Mark all files in the current _view_ that are in Emacs _and_ in VC control.
1571 Optionally UNMARK. VERB."
1573 (let* ((dir (expand-file-name dired-directory))
1580 (setq dir dir)) ;Shut up XEmacs 19.14 ByteComp
1582 (ti::dolist-buffer-list
1583 (and buffer-file-name
1584 (string-match dir buffer-file-name)
1585 (vc-registered buffer-file-name))))
1589 ((and (null list) verb)
1590 (message "Tinydired: No VC files of this dir in Emacs."))
1592 (tinydired-mark-file-list list unmark)
1594 (message (concat msg "Done")))))))
1596 ;;; ----------------------------------------------------------------------
1599 (defun tinydired-refresh-view (&optional verb)
1600 "Refresh current dired view.
1601 If you have used `tinydired-leave-only-lines' and have done some changes to
1602 the files. You can use this function to re-read the current view.
1604 The dired \"g\" will load full view back. This instead caches the
1605 current view, executes read, and deletes lines that weren't in the
1606 cache --> you get refreshed view. All this may take a while...
1610 VERB Verbose messages
1617 (let* ((cache (tinydired-file-list 'no-path-names 're))
1618 (line (ti::current-line-number)) ;save user position
1620 buffer-read-only ;allow write
1625 (setq re (mapconcat 'concat cache "\\|"))
1627 (dired-remember-marks
1628 (tinydired-first-line-point)
1629 (tinydired-last-file-point)))
1630 ;; sort goes nuts otherwise
1631 (tinydired-dired-unmark-all-files-no-query)
1632 (message "") ; stupid message from dired-un...
1635 (forward-line 2) ;leave headers
1636 (tinydired-first-file)
1638 (let ((case-fold-search nil)) ;case sensitive
1639 (delete-non-matching-lines re))
1640 (dired-mark-remembered marks)
1642 (dired-move-to-filename)
1644 (message "TinyDired: Refresh done."))
1648 (message "TinyDired: Can't cache view."))
1651 ;;; ----------------------------------------------------------------------
1652 ;;; - This behaves differently than dired-x.el dired-do-find-marked-files
1655 (defun tinydired-load-all-marked-files (&optional arg verb)
1656 "Load all marked files into Emacs.
1657 Does not load files which are already in Emacs.
1658 If ARG is non-nil, remove mark if file was loaded. VERB."
1660 (let* ((files (tinydired-get-marked-files))
1666 ((and verb (null files))
1667 (message "Tinydired: No marked files."))
1668 ((y-or-n-p "Tinydired: Load all marked files, No kidding? ")
1669 (dolist (file files)
1671 (if (get-file-buffer file)
1674 (find-file-noselect file))
1676 (save-excursion (dired-unmark 1))))))
1679 ((eq all not-loaded)
1680 (message "Hmm, all files are in Emacs already.."))
1682 (message "Tinydired: %s files loaded." loaded))))))
1685 ;;{{{ code: vc special
1687 ;;; ----------------------------------------------------------------------
1689 (defun tinydired-mark-vc-has-diffs (&optional arg)
1690 "Leave mark to files: VC controlled, have diffs and are in Emacs.
1691 If ARG is non-nil, examine file whether it was in Emacs or not.
1694 Please be patient, taking diffs may be slow per file."
1696 (let* ((list (tinydired-get-marked-files))
1702 (setq fn (file-name-nondirectory file)
1703 buffer (get-file-buffer file)
1704 vc-reg-stat (vc-registered file))
1706 ((or (not vc-reg-stat)
1707 ;; Not exist in Emacs, do not bother looking
1708 (and (null arg) (null buffer)))
1709 (tinydired-mark-re (regexp-quote fn) 'unmark))
1711 (setq diff-no-stat (vc-workfile-unchanged-p file 'get-diffs))
1713 (tinydired-mark-re (regexp-quote fn) 'unmark)))))))
1715 ;;; ----------------------------------------------------------------------
1717 (defun tinydired-marked-vc-revert (&optional arg verb)
1718 "Revert all version controlled/no changed/marked files. Ignore ARG. VERB."
1720 (let* ((list (tinydired-get-marked-files))
1721 (display (if list t))
1722 (vc-dired-mode nil) ;turn mode off
1731 (setq buffer (get-file-buffer file)
1732 vc-reg-stat (vc-registered file)
1736 ;; ... ... ... ... ... ... ... ... ... ... ... ... possible load . .
1737 (when (and (null buffer)
1738 (file-writable-p file)
1740 (setq buffer (find-file-noselect file)
1743 (setq diff-no-stat (vc-workfile-unchanged-p file 'get-diffs)))
1744 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... .. handle . .
1747 nil) ;no file, no vc controlled
1750 (save-window-excursion
1751 (vc-next-action-on-file file 'verbose)
1753 (kill-buffer buffer))))))
1755 (dired-do-redisplay))
1757 (message "Tinydired: VC revert: %s/%s handled " handled count))))
1759 ;;; ----------------------------------------------------------------------
1761 (defun tinydired-marked-vc-co (&optional arg)
1762 "Check Out all marked files and load them inside Emacs.
1763 Do some checking, before doing co.
1764 o if file is writable, skip over.
1765 o if file is not in RCS, skip over.
1767 Optional ARG skips all load confirmations.
1769 Marks are left only to files which were loaded into Emacs."
1771 (let* ((list (tinydired-get-marked-files))
1772 (dired-vc-mode nil) ;turn mode off
1783 (setq dired-vc-mode nil)) ;ByteComp silencer
1785 (setq fn (file-name-nondirectory file)
1786 buffer (get-file-buffer file)
1787 vc-reg-stat (vc-registered file)
1789 (if buffer ;read stat only if it's in Emacs
1792 (setq modify-stat (buffer-modified-p)
1793 read-stat buffer-read-only)))
1795 ;; ... ... ... ... ... ... ... ... ... ... ... ... possible load . .
1798 vc-reg-stat ;; in VC
1799 (not (file-writable-p file)) ;; -r--r--r--
1802 (concat "file " fn " not in Emacs. Load? " ))))
1804 (setq buffer (find-file-noselect file)
1806 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... .. handle . .
1811 ((and buffer ;; in Emacs, be extra carefull
1812 vc-reg-stat ;; in VC
1813 (not (file-writable-p file)) ;; -r--
1814 (null modify-stat) ;; %*
1816 ;; --> no-op, valid state
1818 (t ;; User has modified it!
1819 ;; This situation may occur very easily
1820 ;; - You load -r-- file in Emacs that's in VC
1821 ;; - you want to temporary play with it, like changing one
1822 ;; flag in .mak temporarily
1823 ;; - you go and M-x toggle-read-only, change it, C-x C-s
1825 ;; Now you have modified the read-only file !
1829 ;; 18 15:09 test3.txt
1830 (tinydired-mark-re (concat "[0-9] +" fn) 'unmark)
1833 (save-window-excursion
1835 (vc-next-action-on-file file 'verbose)))))
1836 (if (not (eq 0 handled))
1837 (dired-do-redisplay))
1838 (message (format "Tinydired: VC co: %s/%s handled, loaded %s"
1839 handled count loaded))))
1841 ;;; ----------------------------------------------------------------------
1842 ;;; - This is vastly different than C-x v v in dired mode
1844 (defun tinydired-marked-vc-ci (&optional arg &optional verb)
1845 "Check In all marked files and load them inside Emacs. Ignore ARG.
1846 Do some heavy checking, before doing ci.
1847 o if file is not writable, skip over
1848 o if file is not in Emacs, load it first
1849 o if file is in Emacs, but read only, suppose no diffs
1850 o if file is in Emacs, check rcsdiff, --> do nothing if no diffs
1851 o if file is in Emacs, check rcsdiff, if file not saved, offer save
1853 Notice, that this function enters `recursive-edit' if it thinks file should
1854 be Checked In. Use \\[exit-recursive-edit] to get back to this function
1855 and continue with rest of the files.
1857 Recursive edit is shown with those [ ] marks in the modeline.
1858 VERB print verbose messages.
1862 There is plenty of messages for each file in marked, because
1863 used should know if the marked file couldn't be processed with ci.
1865 Marks are removed from handled files.
1869 This function automatically removes marks from files where user has
1870 used recursive edit. If user didn't ci the file, this program
1873 Anyway, the mark is gone."
1875 (let* ((list (tinydired-get-marked-files))
1887 (if (and (null vc-dired-mode)
1888 (y-or-n-p "Buffer must be in VC dired mode. Turn it on? "))
1892 (setq fn (file-name-nondirectory file)
1893 buffer (get-file-buffer file)
1894 vc-reg-stat (vc-registered file)
1897 ;; ... ... ... ... ... ... ... ... ... ... ... ... possible load . .
1901 (file-writable-p file) ; "-r--r--r--" , not ci'able file
1902 (y-or-n-p (concat "file " fn " not in Emacs. Load? " )))
1903 (setq buffer (find-file-noselect file)
1906 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... stat . .
1908 ((setq buffer (get-file-buffer file))
1911 (setq modify-stat (buffer-modified-p)
1912 read-stat buffer-read-only)
1913 ;; Can't ask stat if not in VC control
1916 (vc-workfile-unchanged-p file 'get-diffs))))))
1917 ;; ... ... ... ... ... ... ... ... ... ... ... ... set diff stat . .
1922 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1924 read-stat) ;is file in CheckOut state ?
1925 (ti::read-char-safe-until
1926 (concat fn " in VC, but _buffer_ is read-only. (ok)" ))
1928 (y-or-n-p (concat "Unload " fn " ? "))
1929 (kill-buffer buffer)
1931 ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1937 (ti::read-char-safe-until
1938 (concat fn " contains NO changes. (ok) "))
1939 (if (y-or-n-p (concat fn " contains NO changes, unload NOW? "))
1940 (kill-buffer buffer))))
1945 (save-window-excursion
1948 (tinydired-mark-re (concat "[0-9] +" file) 'unmark)
1949 (pop-to-buffer buffer)
1950 (call-interactively 'vc-next-action)
1952 (ad-enable-advice 'vc-finish-logentry
1953 'after 'tinydired-recursive-edit)
1954 (ad-activate 'vc-finish-logentry)
1957 (substitute-command-keys
1959 "Use \\[exit-recursive-edit] to abort action."
1962 (ad-disable-advice 'vc-finish-logentry
1963 'after 'tinydired-recursive-edit)
1964 (ad-activate 'vc-finish-logentry))))
1965 (ti::pmin) ;remove file after VC
1966 (if (re-search-forward fn nil t)
1968 ;; ........................................................ loop ...
1971 (message (format "VC ci: %s/%s handled, loaded %s"
1972 handled count loaded)))))
1977 ;;; ----------------------------------------------------------------------
1978 ;;; - Until someone fixes dired to honor the backup-file-name-p
1979 ;;; this stays replaced...
1980 ;;; - This is copy from 19.30 dired.el
1982 (defadvice dired-flag-backup-files (around tdd dis)
1983 "Replace original function.
1984 This function honours the `backup-file-name-p' function and
1985 additionally flag files that match regexp `tinydired-:backup-file-regexp'."
1986 (let ((dired-marker-char (if unflag-p ?\040 dired-del-marker))
1987 (re tinydired-:backup-file-regexp)
1992 (when (not (looking-at dired-re-dir))
1993 (setq file (dired-get-filename t t))
1995 (or (backup-file-name-p file)
1997 (string-match re file))))))
2000 ;;; ----------------------------------------------------------------------
2002 (defadvice vc-finish-logentry (after tinydired-recursive-edit dis)
2003 "When this advice is enabled, it call `exit-recursive-edit'.
2004 Only if f recursive edit is in effect.
2006 This advice is controlled by function `tinydired-marked-vc-ci' and it is never
2007 enabled outside of that function."
2008 (ignore-errors (exit-recursive-edit)))
2010 ;;; ----------------------------------------------------------------------
2011 ;;; - When using "f" it loads directory to same buffer.
2012 ;;; - only kills the Dired buffer if a prefix arg is given
2014 (defadvice dired-find-file (around tinydired-kill-dired-buffer last dis)
2015 "If a prefix argument is given, kill the Dired buffer.
2017 If you have loaded dired-x and it contains variable
2018 `dired-find-subdir', this advice does nothing."
2019 (let* ((dired-buffer (current-buffer)))
2022 (if (and (eq major-mode 'dired-mode)
2023 (not (eq (current-buffer) dired-buffer))
2024 (or current-prefix-arg
2025 tinydired-:use-only-one-buffer-flag)
2026 (or (not (featurep 'dired-x)) ;not loaded
2027 (and (featurep 'dired-x) ;is loaded, but this var not exist
2028 (not (boundp 'dired-find-subdir)))))
2029 (kill-buffer dired-buffer)))))
2034 ;;; ----------------------------------------------------------------------
2036 (defsubst tinydired-store-get-string ()
2037 "Return content of storage as string."
2038 (ti::list-to-string tinydired-:file-store))
2040 ;;; ----------------------------------------------------------------------
2042 (defun tinydired-store-show ()
2043 "Show filenames in storage."
2045 (if (null tinydired-:file-store)
2046 (message "Tinydired: Store is empty.")
2047 (funcall tinydired-:show-storage-function tinydired-:file-store)))
2049 ;;; ----------------------------------------------------------------------
2051 (defun tinydired-store-filename ()
2052 "Save current filename into variable."
2054 (let* ((file (tinydired-get-filename)))
2055 (if (member file tinydired-:file-store)
2056 (message "TinyDireds: %s already in storage." file)
2057 (push file tinydired-:file-store) file)
2059 (tinydired-store-show))))
2061 ;;; ----------------------------------------------------------------------
2063 (defun tinydired-store-delete-filename ()
2064 "Remove filename from store."
2066 (let* ((file (tinydired-get-filename)))
2067 (setq tinydired-:file-store (delete file tinydired-:file-store))
2069 (message "Tinydired: %s" (ti::list-to-string tinydired-:file-store)))))
2071 ;;; ----------------------------------------------------------------------
2073 (defun tinydired-store-clear ()
2074 "Clear variable holding files."
2076 (setq tinydired-:file-store nil)
2078 (message "Tinydired: Storage cleared.")))
2080 ;;; ----------------------------------------------------------------------
2082 (defun tinydired-store-remove-file ()
2083 "Delete current filename from storage."
2085 (let* ((file (tinydired-get-filename))
2086 (verb (interactive-p))
2087 (store tinydired-:file-store)
2090 (if verb (message "Tinydired: Storage is empty."))
2092 (if (not (string= x file))
2094 (setq tinydired-:file-store list)
2096 (tinydired-store-show)))))
2098 ;;; ----------------------------------------------------------------------
2100 (defun tinydired-store-delete-marked ()
2101 "Delete marked files from store."
2103 (tinydired-store-add-marked 'delete (interactive-p)))
2105 ;;; ----------------------------------------------------------------------
2107 (defun tinydired-store-add-marked (&optional delete verb)
2108 "Add marked files into store. No duplicates are inserted.
2109 If parameter DELETE is non-nil, removes marked files from store. VERB."
2111 (let* ((list tinydired-:file-store)
2112 (marked (tinydired-get-marked-files-no-dir)))
2116 (if (not (member x list))
2117 (push x tinydired-:file-store)))
2120 (setq tinydired-:file-store
2121 (delete x tinydired-:file-store)))))
2123 (tinydired-store-show))))
2126 ;;{{{ code: ange ftp
2128 ;;; ----------------------------------------------------------------------
2130 (defun tinydired-store-ftp-message (&rest args)
2131 "Show Message from ange ftp after finishing the mget. Ange ARGS."
2132 (message "Tinydired: Store, ftp completed.") (sleep-for 1))
2134 ;;; ----------------------------------------------------------------------
2136 (defun tinydired-back-to-dired-buffer ()
2137 "Switch back to dired buffer, which is associated with ange-ftp buffer.
2138 If no such buffer is found, do nothing."
2140 (let* ((buffer (ti::buffer-find-ange-to-dired-buffer)))
2142 (pop-to-buffer (car buffer))
2143 (message "Tinydired: No dired buffer found."))))
2145 ;;; ----------------------------------------------------------------------
2146 ;;; - If I have 2-3 dired ftp sessions and I want to close the current
2147 ;;; one, this is a handy command.
2150 (defun tinydired-kill-dired-and-ange-session (&optional verb)
2151 "Kill the current dired buffer and possible ange-ftp buffer. VERB.
2152 This is like `dired-delete-and-exit'."
2154 (let* ((buffer (tinydired-ange-ftp-buffer-for-this-dired)))
2157 (kill-buffer buffer))
2158 (kill-buffer (current-buffer))
2162 "Ange buffer killed too."
2163 "No ange buffer associated with dired.")))))
2165 ;;; ----------------------------------------------------------------------
2168 (defun tinydired-kill-all-ange-and-dired-buffers (&optional verb)
2169 "Kill all ange-ftp buffers _and_ all remote dired buffers. VERB."
2171 (let* ((ange (ti::buffer-get-ange-buffer-list))
2172 (dired (ti::dolist-buffer-list
2173 (and (eq major-mode 'dired-mode)
2174 (string-match tinydired-:dired-directory-ange-regexp
2186 (message "Tinydired: Killed %s ange, %s dired buffers."
2187 ange-count dired-count))))
2189 ;;; ----------------------------------------------------------------------
2192 (defun tinydired-kill-all-ange-buffers ()
2193 "Kill all ange-ftp process buffers.
2194 If you want to kill one buffer at a time, use
2195 `tinydired-switch-to-some-ange-ftp-buffer' to switch to individual buffer
2196 and use \\[kill-buffer] to kill session.
2198 This function is primarily used for cleanups. After a while
2199 you may end up with many ftp session and it's nice if
2200 you can get rid of them fast.
2202 Don't worry about the dired buffers, Ange will automatically
2203 create connection, if you use \"g\" -- rever-buffer, in a dired
2204 that is associated with ange-ftp."
2206 (let* ((list (ti::buffer-get-ange-buffer-list))
2209 (incf i) (kill-buffer elt))
2211 (message (concat "Tinydired: Ange buffers killed: " i))
2212 (message "Tinydired: No ange buffers found."))))
2214 ;;; ----------------------------------------------------------------------
2217 (defun tinydired-switch-to-some-ange-ftp-buffer ()
2218 "Gather all ange FTP buffers and offer completion menu.
2219 If there is only one Ange buffer, switches to it without asking."
2221 (let* ((list (ti::buffer-get-ange-buffer-list))
2225 (message "no Ange-ftp sessions at the moment.")
2226 (if (eq 1 (length list))
2227 (setq buffer (car list))
2229 (completing-read "go ange: " (ti::list-to-assoc-menu list))))
2230 (if (setq go (get-buffer buffer))
2231 (switch-to-buffer go)
2232 (message (concat "No ange buffer: " buffer))))))
2234 ;;; ----------------------------------------------------------------------
2235 ;;; - This is handy, when you want to check that the mput went ok.
2237 (defun tinydired-switch-to-mput-ange-ftp-buffer ()
2238 "Switch to ange buffer where last mput was made.
2239 Does nothing if no mput were recorded or such ange buffer does not exist.
2241 Binds local keys to ftp buffer
2243 C - c b switch back to previous buffer
2247 `tinydired-:previous-buffer'
2248 `tinydired-:mput-last-ftp'
2252 nil no action taken.
2255 (let* ((file tinydired-:mput-last-ftp)
2256 (buffer (current-buffer))
2261 ((null tinydired-:mput-last-ftp)
2262 (message "Tinydired: Sorry, No mput information."))
2263 ((not (string-match "/.*@.*:" file))
2264 (message "Tinydired: Sorry, No ange reference in `tinydired-:mput-last-ft'p"))
2266 ;; This return 3 member list: SITE LOGIN DIRECTORY/FILE
2267 (setq list (ange-ftp-ftp-name file)
2269 (setq tinydired-:previous-buffer buffer)
2270 ;; Try to find buffer , ange uses SITE name for buffer names
2274 (setq buffer (car (ti::dolist-buffer-list
2276 (concat "[*]ftp.*" (regexp-quote host))
2279 (switch-to-buffer-other-window buffer)
2281 ;; Switching back to previous (b)uffer
2282 (local-set-key "\C-cb"
2285 "TinyDired: mput ange, back to previous buffer"
2287 (pop-to-buffer tinydired-:previous-buffer))))
2291 "Tinydired: Sorry, can't find ange buffer for `%s'" host)))))
2294 ;;; ----------------------------------------------------------------------
2296 (defun tinydired-ange-ftp-buffer-for-this-dired (&optional file)
2297 "Return ange ftp buffer-name-string for current dired or FILE, or nil."
2301 (setq file (or file (dired-get-filename)))
2302 ;; This return 3 member list: SITE LOGIN DIRECTORY/FILE
2303 (setq list (ange-ftp-ftp-name file)
2305 (when list ;This dired is not in remote site
2306 ;; Remove that ange-ftp site information from the string.
2307 (setq tinydired-:directory
2308 (ti::string-index-substring dired-directory ?: nil 'right))
2309 ;; Try to find buffer , ange uses SITE name for buffer names
2313 (car (ti::dolist-buffer-list
2315 (concat "[*]ftp.*" (regexp-quote host))
2318 (unless (get-buffer buffer)
2319 (setq buffer nil))))
2322 ;;; ----------------------------------------------------------------------
2324 (defun tinydired-switch-to-ange-ftp-buffer (&optional verb)
2325 "If the dired is ange ftp buffer, switch to the real ftp buffer. VERB.
2328 `tinydired-:directory' filename for current line
2330 Binds local keys in ftp buffer
2332 C - c af insert files stored in current point
2333 C - c ad insert directory name
2334 C - c ab switch back to dired buffer"
2339 ;; 1. try normal ange ftp
2340 ;; 2. did user used 'put' to remove site ?
2342 (setq buffer (tinydired-ange-ftp-buffer-for-this-dired))
2345 tinydired-:file-store
2346 tinydired-:mput-last-ftp
2347 (null (tinydired-switch-to-mput-ange-ftp-buffer)))
2349 (message "Tinydired: can't locate associated ftp buffer.")))
2352 (message "Tinydired: can't locate associated ftp buffer.")))
2354 (switch-to-buffer-other-window buffer)
2355 (set (make-local-variable 'tinydired-:directory) dir)
2357 ;; "f" for file information
2361 (lambda (&optional arg)
2362 "TinyDired: Inserts file storage string."
2364 (setq arg (tinydired-store-get-string))
2366 (message "Tinydired: No files in storage.")
2367 (insert (tinydired-store-get-string))))))
2368 ;; "d" for directory information
2373 "TinyDired: Inserts dired's directory string."
2375 (insert tinydired-:directory))))
2376 ;; Switching back to dired (b)uffer
2381 "TinyDired: Back to dired buffer"
2383 (tinydired-back-to-dired-buffer))))))))
2385 ;;; ----------------------------------------------------------------------
2386 ;;; mget = multiple get
2388 (defun tinydired-store-ftp-mget ()
2389 "Send command to ange to fetch all files in store."
2391 (let* ((files tinydired-:file-store)
2392 (down tinydired-:download-dir)
2393 (store (tinydired-store-get-string))
2394 (ange (ange-ftp-ftp-name dired-directory))
2401 (message "Tinydired: Can't find ftp process. Start one first."))
2403 (message "Tinydired: No files in store."))
2406 (y-or-n-p (concat "Tinydired: really get: "
2408 (if (> (length store) 50)
2409 (concat (substring store 0 50 )
2411 (concat store " ")))))
2414 ;; Hack to read directory easily
2415 (let ((default-directory down))
2419 (interactive "Ddownload dir: ")
2421 (message "Tinydired: Cancelled.")
2422 ;; ................................................. then part ...
2423 ;; - First update the value, so that user gets the old selection
2424 (setq tinydired-:download-dir to-dir)
2425 ;; Next, get all needed parameters
2426 (setq host (nth 0 ange)
2429 to-dir (expand-file-name to-dir))
2430 (ti::file-ange-file-handle
2431 'get user host dir to-dir files))))))
2433 ;;; ----------------------------------------------------------------------
2434 ;;; - remember to be in DIRED before you call this
2435 ;;; mput = multiple put
2437 (defun tinydired-store-ftp-mput (ange-ref-to)
2438 "Send all files in store to remote site ANGE-REF-TO."
2443 (ti::list-to-assoc-menu tinydired-:mput-sites)
2444 nil nil tinydired-:mput-last-ftp
2445 'tinydired-:mput-history)))
2446 (if (null dired-directory)
2447 (error "Tinydired: Must execute command in dired buffer."))
2448 ;; Record the site name where the mput was made
2449 (setq tinydired-:mput-last-ftp ange-ref-to)
2450 (let* ((files tinydired-:file-store)
2451 (store (tinydired-store-get-string))
2452 (dir dired-directory)
2457 ;; If user is in remote dired buffer, signal error
2458 ;; We don't support this. At least not now.
2460 (if (string-match "@" dired-directory)
2461 (error "Tinydired: sorry, load files first to your site."))
2462 (if (not (ti::nil-p ange-ref-to))
2463 (setq ange (ange-ftp-ftp-name ange-ref-to) ;crack it
2466 to-dir (nth 2 ange)))
2468 ((ti::nil-p ange-ref-to)
2469 (message "Tinydired: No site given"))
2471 (message "Tinydired: No files in store."))
2473 (message "Tinydired: No destination download directory given"))
2475 (if (not (y-or-n-p (concat "Put " host ": "
2477 (if (> (length store) 50)
2478 (concat (substring store 0 50)
2480 (concat store " ")))))
2481 (message "Tinydired: Cancelled.")
2482 ;; ................................................. then part ...
2483 ;; (mode user host dir lcd file-list &optional not-bg msg-func)
2484 (ti::file-ange-file-handle 'put user host to-dir dir files))))))
2488 (provide 'tinydired)
2491 (run-hooks 'tinydired-:load-hook)
2493 ;;; tinydired.el ends here