Mercurial > hg > xemacs-beta
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 |