comparison lisp/efs/emacs-19.el @ 22:8fc7fe29b841 r19-15b94

Import from CVS: tag r19-15b94
author cvs
date Mon, 13 Aug 2007 08:50:29 +0200
parents
children
comparison
equal deleted inserted replaced
21:b88636d63495 22:8fc7fe29b841
1 ;;;; Emacs 19 compatibility functions for use in Emacs 18.
2 ;;;; Based on: $Id: emacs-19.el,v 1.1 1997/02/11 05:05:14 steve Exp $
3 ;;;;
4 ;;;; Rewritten by sandy@ibm550.sissa.it after gnu emacs 19 was
5 ;;;; released to make it closer to V19.
6 ;;;; Last modified: Sun Jun 12 00:06:06 1994 by sandy on ibm550
7
8 ;;; This program is free software; you can redistribute it and/or modify
9 ;;; it under the terms of the GNU General Public License as published by
10 ;;; the Free Software Foundation; either version 1, or (at your option)
11 ;;; any later version.
12 ;;;
13 ;;; This program is distributed in the hope that it will be useful,
14 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;;; GNU General Public License for more details.
17 ;;;
18 ;;; A copy of the GNU General Public License can be obtained from this
19 ;;; program's author (send electronic mail to roland@ai.mit.edu) or from
20 ;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
21 ;;; 02139, USA.
22
23 ;; These functions are used in dired.el, but are also of general
24 ;; interest, so you may want to add this to your .emacs:
25 ;;
26 ;; (autoload 'make-directory "emacs-19" "Make a directory." t)
27 ;; (autoload 'delete-directory "emacs-19" "Remove a directory." t)
28 ;; (autoload 'member "emacs-19" "Like memq, but uses `equal' instead of `eq'.")
29 ;; (autoload 'compiled-function-p "emacs-19" "Emacs 18 doesn't have these.")
30
31 (provide 'emacs-19)
32
33 ;;; Variables
34
35 (defvar insert-directory-program "ls"
36 "Absolute or relative name of the `ls' program used by `insert-directory'.")
37
38 (defvar bv-length) ; make the byte compiler a happy camper
39
40 (defconst directory-abbrev-alist
41 nil
42 "*Alist of abbreviations for file directories.
43 A list of elements of the form (FROM . TO), each meaning to replace
44 FROM with TO when it appears in a directory name. This replacement is
45 done when setting up the default directory of a newly visited file.
46 *Every* FROM string should start with `^'.
47
48 Use this feature when you have directories which you normally refer to
49 via absolute symbolic links. Make TO the name of the link, and FROM
50 the name it is linked to.")
51
52 (defconst automount-dir-prefix "^/tmp_mnt/"
53 "Regexp to match the automounter prefix in a directory name.")
54
55 (defvar abbreviated-home-dir nil
56 "The the user's homedir abbreviated according to `directory-abbrev-list'.")
57
58 ;;; Autoloads
59
60 (autoload 'diff "diff" "Diff two files." t)
61 (autoload 'diff-backup "diff" "Diff a file with its most recent backup.")
62
63 ;;; Functions which are subroutines in Emacs 19.
64
65 ;; Provide a non-working version of find-file-name-handler.
66 ;; If you want it to work, require 'fn-handler.
67
68 (or (fboundp 'find-file-name-handler) (fset 'find-file-name-handler 'ignore))
69 (or (boundp 'file-name-handler-alist) (defvar file-name-handler-alist nil))
70
71 ;; The name of buffer-flush-undo has changed in V19.
72 (fset 'buffer-disable-undo 'buffer-flush-undo)
73
74 (defun current-time ()
75 "Returns the number of seconds since midnight.
76 A poor man's version of the the function `current-time' in emacs 19."
77 (let ((string (current-time-string)))
78 (list
79 0
80 (+ (* 3600 (string-to-int (substring string 11 13)))
81 (* 60 (string-to-int (substring string 14 16)))
82 (string-to-int (substring string 17 19)))
83 0)))
84
85 ;; call-process below may lose if filename starts with a `-', but I
86 ;; fear not all mkdir or rmdir implementations understand `--'.
87
88 (defun delete-directory (fn)
89 "Delete a directory.
90 This is a subr in Emacs 19."
91 (interactive
92 (list (read-file-name "Delete directory: " nil nil 'confirm)))
93 (setq fn (expand-file-name fn))
94 (if (file-directory-p fn)
95 (call-process "rmdir" nil nil nil fn)
96 (error "Not a directory: %s" fn))
97 (if (file-exists-p fn)
98 (error "Could not remove directory %s" fn)))
99
100 (defun make-directory (dir &optional parents)
101 "Create the directory DIR and any nonexistent parent dirs."
102 (interactive "FMake directory: \nP")
103 (if (not parents)
104 (make-directory-internal dir)
105 (let ((dir (directory-file-name (expand-file-name dir)))
106 create-list)
107 (while (not (file-exists-p dir))
108 (setq create-list (cons dir create-list)
109 dir (directory-file-name (file-name-directory dir))))
110 (while create-list
111 (make-directory-internal (car create-list))
112 (setq create-list (cdr create-list))))))
113
114 (defun make-directory-internal (fn)
115 ;; This is a subroutine in emacs 19.
116 (let* ((fn (expand-file-name fn))
117 (handler (find-file-name-handler fn 'make-directory-internal)))
118 (if handler
119 (funcall handler 'make-directory-internal fn)
120 (setq fn (directory-file-name fn))
121 (if (file-exists-p fn)
122 (error "Cannot make directory %s: file already exists" fn)
123 (call-process "mkdir" nil nil nil fn))
124 (or (file-directory-p fn)
125 (error "Could not make directory %s" fn)))))
126
127 (defun kill-new (string)
128 "Save STRING as if killed in a buffer."
129 (setq kill-ring (cons string kill-ring))
130 (if (> (length kill-ring) kill-ring-max)
131 (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
132 (setq kill-ring-yank-pointer kill-ring))
133
134 (defun insert-directory (file switches &optional wildcard full-directory-p)
135 "Insert directory listing for FILE, formatted according to SWITCHES.
136 Leaves point after the inserted text.
137 SWITCHES may be a string of options, or a list of strings.
138 Optional third arg WILDCARD means treat FILE as shell wildcard.
139 Optional fourth arg FULL-DIRECTORY-P means file is a directory and
140 switches do not contain `d', so that a full listing is expected.
141
142 This works by running a directory listing program
143 whose name is in the variable `insert-directory-program'.
144 If WILDCARD, it also runs the shell specified by `shell-file-name'."
145 ;; We need the directory in order to find the right handler.
146 (let ((handler (find-file-name-handler (expand-file-name file)
147 'insert-directory)))
148 (if handler
149 (funcall handler 'insert-directory file switches
150 wildcard full-directory-p)
151 (if (eq system-type 'vax-vms)
152 (vms-read-directory file switches (current-buffer))
153 (if wildcard
154 ;; Run ls in the directory of the file pattern we asked for.
155 (let ((default-directory
156 (if (file-name-absolute-p file)
157 (file-name-directory file)
158 (file-name-directory (expand-file-name file))))
159 (pattern (file-name-nondirectory file))
160 (beg 0))
161 ;; Quote some characters that have special meanings in shells;
162 ;; but don't quote the wildcards--we want them to be special.
163 ;; We also currently don't quote the quoting characters
164 ;; in case people want to use them explicitly to quote
165 ;; wildcard characters.
166 (while (string-match "[ \t\n;<>&|()#$]" pattern beg)
167 (setq pattern
168 (concat (substring pattern 0 (match-beginning 0))
169 "\\"
170 (substring pattern (match-beginning 0)))
171 beg (1+ (match-end 0))))
172 (call-process shell-file-name nil t nil
173 "-c" (concat insert-directory-program
174 " -d "
175 (if (stringp switches)
176 switches
177 (mapconcat 'identity switches " "))
178 " "
179 pattern)))
180 ;; SunOS 4.1.3, SVr4 and others need the "." to list the
181 ;; directory if FILE is a symbolic link.
182 (apply 'call-process
183 insert-directory-program nil t nil
184 (let (list)
185 (if (listp switches)
186 (setq list switches)
187 (if (not (equal switches ""))
188 (progn
189 ;; Split the switches at any spaces
190 ;; so we can pass separate options as separate args.
191 (while (string-match " " switches)
192 (setq list (cons (substring switches 0
193 (match-beginning 0))
194 list)
195 switches (substring switches
196 (match-end 0))))
197 (setq list (cons switches list)))))
198 (append list
199 (list
200 (if full-directory-p
201 (concat (file-name-as-directory file) ".")
202 file))))))))))
203
204 (defun file-local-copy (file)
205 "Copy the file FILE into a temporary file on this machine.
206 Returns the name of the local copy, or nil, if FILE is directly
207 accessible."
208 (let* ((file (expand-file-name file))
209 (handler (find-file-name-handler file 'file-local-copy)))
210 ;; Does nothing, if no handler.
211 (if handler
212 (funcall handler 'file-local-copy file))))
213
214 (defun file-truename (filename)
215 "Return the truename of FILENAME, which should be absolute.
216 The truename of a file name is found by chasing symbolic links
217 both at the level of the file and at the level of the directories
218 containing it, until no links are left at any level."
219 (if (or (string= filename "~")
220 (and (string= (substring filename 0 1) "~")
221 (string-match "~[^/]*" filename)))
222 (progn
223 (setq filename (expand-file-name filename))
224 (if (string= filename "")
225 (setq filename "/"))))
226 (let ((handler (find-file-name-handler filename 'file-truename)))
227 ;; For file name that has a special handler, call handler.
228 ;; This is so that ange-ftp can save time by doing a no-op.
229 (if handler
230 (funcall handler 'file-truename filename)
231 (let ((dir (file-name-directory filename))
232 target dirfile file-name-handler-alist)
233 ;; Get the truename of the directory.
234 (setq dirfile (directory-file-name dir))
235 ;; If these are equal, we have the (or a) root directory.
236 (or (string= dir dirfile)
237 (setq dir (file-name-as-directory (file-truename dirfile))))
238 (if (equal ".." (file-name-nondirectory filename))
239 (directory-file-name (file-name-directory
240 (directory-file-name dir)))
241 (if (equal "." (file-name-nondirectory filename))
242 (directory-file-name dir)
243 ;; Put it back on the file name.
244 (setq filename (concat dir (file-name-nondirectory filename)))
245 ;; Is the file name the name of a link?
246 (setq target (file-symlink-p filename))
247 (if target
248 ;; Yes => chase that link, then start all over
249 ;; since the link may point to a directory name that uses links.
250 ;; We can't safely use expand-file-name here
251 ;; since target might look like foo/../bar where foo
252 ;; is itself a link. Instead, we handle . and .. above.
253 (if (file-name-absolute-p target)
254 (file-truename target)
255 (file-truename (concat dir target)))
256 ;; No, we are done!
257 filename)))))))
258
259 (defun generate-new-buffer-name (name)
260 "Return a string which is the name of no existing buffer based on
261 NAME. If there is no live buffer named NAME, return NAME. Otherwise,
262 modify name by appending `<NUMBER>', incrementing NUMBER until an
263 unused name is found. Return that name."
264 (if (get-buffer name)
265 (let ((num 2)
266 attempt)
267 (while (progn
268 (setq attempt (concat name "<" (int-to-string num) ">"))
269 (get-buffer attempt))
270 (setq num (1+ num)))
271 attempt)
272 name))
273
274 (defun abbreviate-file-name (filename)
275 "Return a version of FILENAME shortened using `directory-abbrev-alist'.
276 This also substitutes \"~\" for the user's home directory.
277 Type \\[describe-variable] directory-abbrev-alist RET for more information."
278 ;; Get rid of the prefixes added by the automounter.
279 (if (and (string-match automount-dir-prefix filename)
280 (file-exists-p (file-name-directory
281 (substring filename (1- (match-end 0))))))
282 (setq filename (substring filename (1- (match-end 0)))))
283 (let ((tail directory-abbrev-alist))
284 ;; If any elt of directory-abbrev-alist matches this name,
285 ;; abbreviate accordingly.
286 (while tail
287 (if (string-match (car (car tail)) filename)
288 (setq filename
289 (concat (cdr (car tail)) (substring filename (match-end 0)))))
290 (setq tail (cdr tail)))
291 ;; Compute and save the abbreviated homedir name.
292 ;; We defer computing this until the first time it's needed, to
293 ;; give time for directory-abbrev-alist to be set properly.
294 (or abbreviated-home-dir
295 (setq abbreviated-home-dir
296 (let ((abbreviated-home-dir "$foo"))
297 (concat "^" (abbreviate-file-name (expand-file-name "~"))))))
298 ;; If FILENAME starts with the abbreviated homedir,
299 ;; make it start with `~' instead.
300 (if (string-match abbreviated-home-dir filename)
301 (setq filename
302 (concat "~"
303 ;; If abbreviated-home-dir ends with a slash,
304 ;; don't remove the corresponding slash from
305 ;; filename. On MS-DOS and OS/2, you can have
306 ;; home directories like "g:/", in which it is
307 ;; important not to remove the slash. And what
308 ;; about poor root on Unix systems?
309 (if (eq ?/ (aref abbreviated-home-dir
310 (1- (length abbreviated-home-dir))))
311 "/"
312 "")
313 (substring filename (match-end 0)))))
314 filename))
315
316 (defun file-newest-backup (filename)
317 "Return most recent backup file for FILENAME or nil if no backups exist."
318 (let* ((filename (expand-file-name filename))
319 (file (file-name-nondirectory filename))
320 (dir (file-name-directory filename))
321 (comp (file-name-all-completions file dir))
322 newest)
323 (while comp
324 (setq file (concat dir (car comp))
325 comp (cdr comp))
326 (if (and (backup-file-name-p file)
327 (or (null newest) (file-newer-than-file-p file newest)))
328 (setq newest file)))
329 newest))
330
331 ;; This is used in various files.
332 ;; The usage of bv-length is not very clean,
333 ;; but I can't see a good alternative,
334 ;; so as of now I am leaving it alone.
335 (defun backup-extract-version (fn)
336 "Given the name of a numeric backup file, return the backup number.
337 Uses the free variable `bv-length', whose value should be
338 the index in the name where the version number begins."
339 (if (and (string-match "[0-9]+~$" fn bv-length)
340 (= (match-beginning 0) bv-length))
341 (string-to-int (substring fn bv-length -1))
342 0))
343
344 ;; The standard V18 version of this function doesn't support
345 ;; the arg KEEP-BACKUP-VERSION
346 (defun file-name-sans-versions (name &optional keep-backup-version)
347 "Return FILENAME sans backup versions or strings.
348 This is a separate procedure so your site-init or startup file can
349 redefine it.
350 If the optional argument KEEP-BACKUP-VERSION is non-nil,
351 we do not remove backup version numbers, only true file version numbers."
352 (let ((handler (find-file-name-handler name 'file-name-sans-versions)))
353 (if handler
354 (funcall handler 'file-name-sans-versions name keep-backup-version)
355 (substring name 0
356 (if (eq system-type 'vax-vms)
357 ;; VMS version number is (a) semicolon, optional
358 ;; sign, zero or more digits or (b) period, option
359 ;; sign, zero or more digits, provided this is the
360 ;; second period encountered outside of the
361 ;; device/directory part of the file name.
362 (or (string-match ";[-+]?[0-9]*\\'" name)
363 (if (string-match "\\.[^]>:]*\\(\\.[-+]?[0-9]*\\)\\'"
364 name)
365 (match-beginning 1))
366 (length name))
367 (if keep-backup-version
368 (length name)
369 (or (string-match "\\.~[0-9]+~\\'" name)
370 (string-match "~\\'" name)
371 (length name))))))))
372
373 (defun member (x y)
374 "Like memq, but uses `equal' for comparison.
375 This is a subr in Emacs 19."
376 (while (and y (not (equal x (car y))))
377 (setq y (cdr y)))
378 y)
379
380 (defun compiled-function-p (x)
381 "Emacs 18 doesn't have these."
382 nil)
383
384 ;; punt -- this will at least allow handlers to work for this.
385 (defun set-visited-file-modtime (&optional time)
386 (error "set-visited-file-modtime not defined in emacs 18."))
387
388 (defun add-hook (hook function &optional append)
389 "Add to the value of HOOK the function FUNCTION.
390 FUNCTION is not added if already present.
391 FUNCTION is added (if necessary) at the beginning of the hook list
392 unless the optional argument APPEND is non-nil, in which case
393 FUNCTION is added at the end.
394
395 HOOK should be a symbol, and FUNCTION may be any valid function. If
396 HOOK is void, it is first set to nil. If HOOK's value is a single
397 function, it is changed to a list of functions."
398 (or (boundp hook) (set hook nil))
399 ;; If the hook value is a single function, turn it into a list.
400 (let ((old (symbol-value hook)))
401 (if (or (not (listp old)) (eq (car old) 'lambda))
402 (set hook (list old))))
403 (or (if (consp function)
404 ;; Clever way to tell whether a given lambda-expression
405 ;; is equal to anything in the hook.
406 (let ((tail (assoc (cdr function) (symbol-value hook))))
407 (equal function tail))
408 (memq function (symbol-value hook)))
409 (set hook
410 (if append
411 (nconc (symbol-value hook) (list function))
412 (cons function (symbol-value hook))))))
413
414 ;;; after-save.el (Now part of files.el in Gnu Emacs V19)
415
416 ;;; Copyright (C) 1990 Roland McGrath
417 ;;;
418
419 (or (fboundp 'real-save-buffer)
420 (fset 'real-save-buffer (symbol-function 'save-buffer)))
421
422 (defvar after-save-hook nil
423 "A function or list of functions to be run after saving the current buffer.")
424
425 (defun save-buffer (&optional args)
426 "Save the current buffer, and then run `after-save-buffer-hook'.
427 The hooks are only run if the buffer was actually written.
428 For more documentation, do \\[describe-function] real-save-buffer RET."
429 (interactive "p")
430 (let ((modp (buffer-modified-p)))
431 (real-save-buffer args)
432 (if modp
433 (run-hooks 'after-save-hook))))
434
435 ;;; end of after-save
436
437 ;;;;
438 ;;;; Correcting for V18 bugs, and hacking around stupidities.
439 ;;;;
440
441 ;; The 18.57 version has a bug that causes C-x C-v RET (which usually
442 ;; re-visits the current buffer) to fail on dired buffers.
443 ;; Only the last statement was changed to avoid killing the current
444 ;; buffer.
445 (defun find-alternate-file (filename)
446 "Find file FILENAME, select its buffer, kill previous buffer.
447 If the current buffer now contains an empty file that you just visited
448 \(presumably by mistake), use this command to visit the file you really want."
449 (interactive "FFind alternate file: ")
450 (and (buffer-modified-p)
451 (not buffer-read-only)
452 (not (yes-or-no-p (format "Buffer %s is modified; kill anyway? "
453 (buffer-name))))
454 (error "Aborted"))
455 (let ((obuf (current-buffer))
456 (ofile buffer-file-name)
457 (oname (buffer-name)))
458 (rename-buffer " **lose**")
459 (setq buffer-file-name nil)
460 (unwind-protect
461 (progn
462 (unlock-buffer)
463 (find-file filename))
464 (cond ((eq obuf (current-buffer))
465 (setq buffer-file-name ofile)
466 (lock-buffer)
467 (rename-buffer oname))))
468 (or (eq (current-buffer) obuf)
469 (kill-buffer obuf))))
470
471 ;; At least in Emacs 18.55 this defvar has been forgotten to be copied
472 ;; from lpr.el into loaddefs.el
473
474 (defvar lpr-command (if (eq system-type 'usg-unix-v)
475 "lp" "lpr")
476 "Shell command for printing a file")
477
478
479 ;; buffer-disable-undo used to be called buffer-flush-undo in Emacs
480 ;; 18.55:
481 (or (fboundp 'buffer-disable-undo)
482 (fset 'buffer-disable-undo 'buffer-flush-undo))
483
484 ;;; end of emacs-19.el