comparison lisp/packages/gnuserv.el @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents 56c54cf7c5b6
children c7528f8e288d
comparison
equal deleted inserted replaced
69:804d1389bcd6 70:131b0175ea99
3 ; This file is part of GNU Emacs. 3 ; This file is part of GNU Emacs.
4 ; 4 ;
5 ; Copying is permitted under those conditions described by the GNU 5 ; Copying is permitted under those conditions described by the GNU
6 ; General Public License. 6 ; General Public License.
7 ; 7 ;
8 ; Copyright (C) 1989-1996 Free Software Foundation, Inc. 8 ; Copyright (C) 1989-1994 Free Software Foundation, Inc.
9 ; 9 ;
10 ; Author: Andy Norman (ange@hplb.hpl.hp.com) based on 10 ; Author: Andy Norman (ange@hplb.hpl.hp.com) based on
11 ; 'lisp/server.el' from the 18.52 GNU Emacs distribution. 11 ; 'lisp/server.el' from the 18.52 GNU Emacs distribution.
12 ; 12 ;
13 ; Please mail bugs and suggestions to the author at the above address. 13 ; Please mail bugs and suggestions to the author at the above address.
51 ; Ben Wing <wing@666.com> sometime in 1995 51 ; Ben Wing <wing@666.com> sometime in 1995
52 ; Updated to allow `gnuattach'-type connections to the existing TTY 52 ; Updated to allow `gnuattach'-type connections to the existing TTY
53 ; 53 ;
54 ; Ben Wing <wing@666.com> May/1996 54 ; Ben Wing <wing@666.com> May/1996
55 ; patch to get TTY terminal type correct. 55 ; patch to get TTY terminal type correct.
56 ;
57 ; Jan Vroonhof <vroonhof@math.ethz.ch> July/1996
58 ; ported the server-temp-file-regexp feature from server.el
59 ; ported server hooks from server.el
60 ; ported kill-*-query functions from server.el (and made it optional)
61 ; synced other behaviour with server.el
62 56
63 57
64 58
65 (defconst gnuserv-rcs-header-id "!Header: gnuserv.el,v 2.1 95/02/16 12:00:16 arup alpha !") 59 (defconst gnuserv-rcs-header-id "!Header: gnuserv.el,v 2.1 95/02/16 12:00:16 arup alpha !")
66 60
70 64
71 (if (and (boundp 'server-buffer-clients) 65 (if (and (boundp 'server-buffer-clients)
72 (not (featurep 'gnuserv))) 66 (not (featurep 'gnuserv)))
73 (error "Can't run gnuserv because server.el appears to be loaded already")) 67 (error "Can't run gnuserv because server.el appears to be loaded already"))
74 68
75 ;;;###autoload
76 (defvar gnuserv-frame nil 69 (defvar gnuserv-frame nil
77 "*If non-nil, the frame to be used to display all edited files. 70 "*If non-nil, the frame to be used to display all edited files.
78 If nil, then a new frame is created for each file edited. 71 If nil, then a new frame is created for each file edited.
79 This variable has no effect in XEmacs versions older than 19.9.") 72 This variable has no effect in XEmacs versions older than 19.9.")
80 73
81 (defvar server-done-function 'kill-buffer 74 (defvar server-done-function 'kill-buffer
82 "*A function of one argument, a buffer, which removes the buffer after editing. 75 "*A function of one argument, a buffer, which removes the buffer after editing.
83 Functions such as 'kill-buffer' and 'bury-buffer' are good values. See also 76 Functions such as 'kill-buffer' and 'bury-buffer' are good values.")
84 `server-done-temp-file-function'")
85
86 (defvar server-done-temp-file-function 'kill-buffer
87 "*A function of one argument, a buffer, which removes the buffer after editing a
88 temporary file. Functions such as 'kill-buffer' and 'bury-buffer' are
89 good values. See also `server-done-function'")
90 77
91 (defvar server-program "gnuserv" 78 (defvar server-program "gnuserv"
92 "*The program to use as the edit server") 79 "*The program to use as the edit server")
93 80
94
95 (defvar server-visit-hook nil
96 "*List of hooks to call when visiting a file for the Emacs server.")
97
98 ;; defined by server.el but obsolete?
99 ;; (defvar server-switch-hook nil
100 ;; "*List of hooks to call when switching to a buffer for the Emacs server.")
101
102 (defvar server-done-hook nil
103 "*List of hooks to call when done editing a buffer for the Emacs server.")
104
105
106 (defvar server-process nil 81 (defvar server-process nil
107 "The current server process") 82 "The current server process")
108 83
109 (defvar server-string "" 84 (defvar server-string ""
110 "The last input string from the server") 85 "The last input string from the server")
111
112 (defvar server-kill-last-frame nil
113 "set to t to kill last frame")
114 86
115 (defvar current-client nil 87 (defvar current-client nil
116 "The client we are currently talking to") 88 "The client we are currently talking to")
117 89
118 (defvar server-clients nil 90 (defvar server-clients nil
119 "List of current server clients. 91 "List of current server clients.
120 Each element is (CLIENTID BUFFER...) where CLIENTID is an integer 92 Each element is (CLIENTID BUFFER...) where CLIENTID is an integer
121 that can be given to the server process to identify a client. 93 that can be given to the server process to identify a client.
122 When a buffer is killed, it is removed from this list.") 94 When a buffer is killed, it is removed from this list.")
123 95
124 (defvar server-kill-quietly nil
125 "If this variable is set then don't confirm kills of buffers with
126 clients attached")
127
128
129 (defvar server-buffer-clients nil 96 (defvar server-buffer-clients nil
130 "List of client ids for clients requesting editing of the current buffer.") 97 "List of client ids for clients requesting editing of the current buffer.")
131
132 (defvar server-temp-file-regexp "^/tmp/Re\\|/draft$"
133 "*Regexp which should match filenames of temporary files
134 which are deleted and reused after each edit
135 by the programs that invoke the emacs server.")
136
137 (defvar server-make-temp-file-backup nil
138 "Non-nil makes the server backup temporary files also")
139 98
140 (make-variable-buffer-local 'server-buffer-clients) 99 (make-variable-buffer-local 'server-buffer-clients)
141 (setq-default server-buffer-clients nil) 100 (setq-default server-buffer-clients nil)
142 (or (assq 'server-buffer-clients minor-mode-alist) 101 (or (assq 'server-buffer-clients minor-mode-alist)
143 (setq minor-mode-alist (cons '(server-buffer-clients " Server") 102 (setq minor-mode-alist (cons '(server-buffer-clients " Server")
144 minor-mode-alist))) 103 minor-mode-alist)))
145
146 (defun server-temp-file-p (buffer)
147 "Return non-nil if BUFFER contains a file considered temporary.
148 These are files whose names suggest they are repeatedly
149 reused to pass information to another program.
150
151 The variable `server-temp-file-regexp' controls which filenames
152 are considered temporary."
153 (and (buffer-file-name buffer)
154 (string-match server-temp-file-regexp (buffer-file-name buffer))))
155
156 104
157 (defun server-log (string) 105 (defun server-log (string)
158 "If a *server* buffer exists, write STRING to it for logging purposes." 106 "If a *server* buffer exists, write STRING to it for logging purposes."
159 (if (get-buffer "*server*") 107 (if (get-buffer "*server*")
160 (save-excursion 108 (save-excursion
246 (process-kill-without-query server-process))) 194 (process-kill-without-query server-process)))
247 195
248 ;; make gnuserv-start an alias to server-start, for backward compatibility 196 ;; make gnuserv-start an alias to server-start, for backward compatibility
249 (fset 'server-start (function gnuserv-start)) 197 (fset 'server-start (function gnuserv-start))
250 198
251 ; Can gnuserv handle commands in close succesion? (See server.el line 283) JV 199
252 (defun server-write-to-client (client form) 200 (defun server-write-to-client (client form)
253 "Write the given form to the given client via the server process." 201 "Write the given form to the given client via the server process."
254 (if (and client 202 (if (and client
255 (eq (process-status server-process) 'run)) 203 (eq (process-status server-process) 'run))
256 (let* ((result (format "%s" form)) 204 (let* ((result (format "%s" form))
269 afterwards in order to not keep the client waiting." 217 afterwards in order to not keep the client waiting."
270 (server-write-to-client current-client nil) 218 (server-write-to-client current-client nil)
271 (setq current-client nil) 219 (setq current-client nil)
272 (eval form)) 220 (eval form))
273 221
274
275 (defun server-make-window-visible () 222 (defun server-make-window-visible ()
276 "Try to make this window even more visible." 223 "Try to make this window even more visible."
277 (and (or (and (boundp 'window-system) 224 (cond
278 (boundp 'window-system-version) 225 ;; XEmacs can (in theory) raise any kind of frame
279 (eq window-system 'x) 226 ((fboundp 'raise-frame)
280 (eq window-system-version 11)) 227 (raise-frame (selected-frame)))
281 (and (fboundp 'console-type) 228 ((not (and (boundp 'window-system) window-system))
282 (eq 'x (console-type)))) 229 nil)
283 (cond ((fboundp 'raise-frame) 230 ((fboundp 'deiconify-screen)
284 (raise-frame (selected-frame))) 231 (deiconify-screen (selected-screen))
285 ((fboundp 'deiconify-screen) 232 (raise-screen (selected-screen)))
286 (deiconify-screen (selected-screen)) 233 ((fboundp 'mapraised-screen)
287 (raise-screen (selected-screen))) 234 (mapraised-screen))
288 ((fboundp 'mapraised-screen) 235 ((fboundp 'x-remap-window)
289 (mapraised-screen)) 236 (x-remap-window)
290 ((fboundp 'x-remap-window) 237 ;; give window chance to re-display text
291 (x-remap-window) 238 (accept-process-output))))
292 ;; give window chance to re-display text 239
293 (accept-process-output))))) 240 (defun server-tty-find-file (tty termtype file)
294 241 (let ((device (make-tty-device tty termtype)))
295 (defun server-tty-find-file (tty termtype pid file)
296 (let ((device (make-tty-device tty termtype pid )))
297 (select-frame (make-frame nil device)) 242 (select-frame (make-frame nil device))
298 (if (not file) 243 (if (not file)
299 (switch-to-buffer (get-buffer-create "*scratch*")) 244 (switch-to-buffer (get-buffer-create "*scratch*"))
300 (find-file file))) 245 (find-file file))))
301 (run-hooks 'server-visit-hook))
302 246
303 (defun server-find-file (file) 247 (defun server-find-file (file)
304 "Edit file FILENAME. 248 "Edit file FILENAME.
305 Switch to a buffer visiting file FILENAME, 249 Switch to a buffer visiting file FILENAME,
306 creating one if none already exists." 250 creating one if none already exists."
351 (if (screenp gnuserv-frame) 295 (if (screenp gnuserv-frame)
352 (progn (select-screen gnuserv-frame) 296 (progn (select-screen gnuserv-frame)
353 (find-file file)) 297 (find-file file))
354 (select-screen (create-screen (find-file-noselect file))))) 298 (select-screen (create-screen (find-file-noselect file)))))
355 299
356 (t (find-file file)))) ;; emacs18+ 300 (t (find-file file))))) ;; emacs18+
357 (run-hooks 'server-visit-hook))
358 301
359 302
360 (defun server-edit-files-quickly (list) 303 (defun server-edit-files-quickly (list)
361 "For each (line-number . file) pair in LIST, edit the file at line-number. 304 "For each (line-number . file) pair in LIST, edit the file at line-number.
362 Unlike (server-edit-files), no information is saved about clients waiting on 305 Unlike (server-edit-files), no information is saved about clients waiting on
395 (message (substitute-command-keys 338 (message (substitute-command-keys
396 (if (and (boundp 'infodock-version) window-system) 339 (if (and (boundp 'infodock-version) window-system)
397 "Type {\\[server-edit]} or select Frame/Delete to finish edit." 340 "Type {\\[server-edit]} or select Frame/Delete to finish edit."
398 "When done with a buffer, type \\[server-edit].")))) 341 "When done with a buffer, type \\[server-edit]."))))
399 342
400 (defun server-tty-edit-files (tty termtype pid list) 343 (defun server-tty-edit-files (tty termtype list)
401 "For each (line-number . file) pair in LIST, edit the file at line-number. 344 "For each (line-number . file) pair in LIST, edit the file at line-number.
402 Save enough information for (server-kill-buffer) to inform the client when 345 Save enough information for (server-kill-buffer) to inform the client when
403 the edit is finished." 346 the edit is finished."
404 (or list (setq list '((1 . nil)))) 347 (or list (setq list '((1 . nil))))
405 (while list 348 (while list
406 (let ((line (car (car list))) 349 (let ((line (car (car list)))
407 (path (cdr (car list)))) 350 (path (cdr (car list))))
408 (server-tty-find-file tty termtype pid path) 351 (server-tty-find-file tty termtype path)
409 (server-make-window-visible) 352 (server-make-window-visible)
410 (let ((old-clients (assq current-client server-clients)) 353 (let ((old-clients (assq current-client server-clients))
411 (buffer (current-buffer))) 354 (buffer (current-buffer)))
412 (goto-line line) 355 (goto-line line)
413 (setq server-buffer-clients 356 (setq server-buffer-clients
459 (delq buffer client) 402 (delq buffer client)
460 (if (cdr client) ;pending buffers? 403 (if (cdr client) ;pending buffers?
461 nil ;yep 404 nil ;yep
462 (server-write-to-client (car client) nil) ;nope, tell client 405 (server-write-to-client (car client) nil) ;nope, tell client
463 (setq server-clients (delq client server-clients)))) 406 (setq server-clients (delq client server-clients))))
464 (setq old-clients (cdr old-clients))) 407 (setq old-clients (cdr old-clients))))))))
465 t)))))
466
467
468 ;; Ask before killing a server buffer.
469 ;; It was suggested to release its client instead,
470 ;; but I think that is dangerous--the client would proceed
471 ;; using whatever is on disk in that file. -- rms.
472 (defun server-kill-buffer-query-function ()
473 (or server-kill-quietly
474 (not server-buffer-clients)
475 (yes-or-no-p (format "Buffer `%s' still has clients; kill it? "
476 (buffer-name (current-buffer))))))
477
478 (add-hook 'kill-buffer-query-functions
479 'server-kill-buffer-query-function)
480
481 (defun server-kill-emacs-query-function ()
482 (let (live-client
483 (tail server-clients))
484 ;; See if any clients have any buffers that are still alive.
485 (while tail
486 (if (memq t (mapcar 'stringp (mapcar 'buffer-name (cdr (car tail)))))
487 (setq live-client t))
488 (setq tail (cdr tail)))
489 (or server-kill-quietly
490 (not live-client)
491 (yes-or-no-p "Server buffers still have clients; exit anyway? "))))
492
493 (add-hook 'kill-emacs-query-functions 'server-kill-emacs-query-function)
494 408
495 409
496 (defun server-kill-all-local-variables () 410 (defun server-kill-all-local-variables ()
497 "Eliminate all the buffer-local variable values of the current buffer. 411 "Eliminate all the buffer-local variable values of the current buffer.
498 This buffer will then see the default values of all variables. 412 This buffer will then see the default values of all variables.
518 432
519 (defun server-buffer-done (buffer) 433 (defun server-buffer-done (buffer)
520 "Mark BUFFER as \"done\" for its client(s). 434 "Mark BUFFER as \"done\" for its client(s).
521 Buries the buffer, and returns another server buffer as a suggestion for the 435 Buries the buffer, and returns another server buffer as a suggestion for the
522 new current buffer." 436 new current buffer."
523 ; Note we do NOT return a list with a killed flag, doesn't seem usefull to me. JV
524 (let ((next-buffer nil) 437 (let ((next-buffer nil)
525 (old-clients server-clients)) 438 (old-clients server-clients))
526 (while old-clients 439 (while old-clients
527 (let ((client (car old-clients))) 440 (let ((client (car old-clients)))
528 (or next-buffer 441 (or next-buffer
529 (setq next-buffer (nth 1 (memq buffer client)))) 442 (setq next-buffer (nth 1 (memq buffer client))))
530 (delq buffer client) 443 (delq buffer client)
531 ;; Delete all dead buffers from CLIENT. (Why? JV , copyed from server.el)
532 (let ((tail client))
533 (while tail
534 (and (bufferp (car tail))
535 (null (buffer-name (car tail)))
536 (delq (car tail) client))
537 (setq tail (cdr tail))))
538 ;; If client now has no pending buffers, 444 ;; If client now has no pending buffers,
539 ;; tell it that it is done, and forget it entirely. 445 ;; tell it that it is done, and forget it entirely.
540 (if (cdr client) 446 (if (cdr client)
541 nil 447 nil
542 (if (buffer-name buffer) 448 (server-write-to-client (car client) nil)
543 (save-excursion 449 (setq server-clients (delq client server-clients))))
544 (set-buffer buffer)
545 (setq server-buffer-clients nil)
546 (run-hooks 'server-done-hook)))
547 ; Order is important here --
548 ; server-kill-buffer tries to notify clients that
549 ; they are done, too, but if we try and notify twice,
550 ; we are h0zed -- Hunter Kelly 3/3/97
551 (setq server-clients (delq client server-clients))
552 (if (server-temp-file-p buffer)
553 (funcall server-done-temp-file-function buffer)
554 (funcall server-done-function buffer))
555 (server-write-to-client (car client) nil)))
556 (setq old-clients (cdr old-clients))) 450 (setq old-clients (cdr old-clients)))
451 (if (buffer-name buffer)
452 (save-excursion
453 (set-buffer buffer)
454 (setq server-buffer-clients nil)))
455 (funcall server-done-function buffer)
557 next-buffer)) 456 next-buffer))
558 457
559 458
560 (defun mh-draft-p (buffer) 459 (defun mh-draft-p (buffer)
561 "Return non-nil if this BUFFER is an mh <draft> file. Since MH deletes 460 "Return non-nil if this BUFFER is an mh <draft> file. Since MH deletes
568 "Offer to save current buffer and mark it as \"done\" for clients. 467 "Offer to save current buffer and mark it as \"done\" for clients.
569 Also bury it, and return a suggested new current buffer." 468 Also bury it, and return a suggested new current buffer."
570 (let ((buffer (current-buffer))) 469 (let ((buffer (current-buffer)))
571 (if server-buffer-clients 470 (if server-buffer-clients
572 (progn 471 (progn
573 (if (mh-draft-p buffer);; Does this comflict with temp-file ? JV 472 (if (mh-draft-p buffer)
574 (progn (save-buffer) 473 (progn (save-buffer)
575 (write-region (point-min) (point-max) 474 (write-region (point-min) (point-max)
576 (concat buffer-file-name "~")) 475 (concat buffer-file-name "~"))
577 (kill-buffer buffer)) 476 (kill-buffer buffer))
578 (if (server-temp-file-p buffer) 477 (if (and (buffer-modified-p)
579 ;; For a temp file, save, and do NOT make a non-numeric backup 478 (y-or-n-p (concat "Save file " buffer-file-name "? ")))
580 ;; Why does server.el explicitly back up temporary files? 479 (save-buffer buffer)))
581 (let ((version-control nil)
582 (buffer-backed-up (not server-make-temp-file-backup)))
583 (save-buffer))
584 (if (and (buffer-modified-p)
585 (y-or-n-p (concat "Save file " buffer-file-name "? ")))
586 (save-buffer buffer))))
587 (server-buffer-done buffer))))) 480 (server-buffer-done buffer)))))
588 481
589 482
590 (defun server-edit (&optional arg) 483 (defun server-edit (&optional arg)
591 "Switch to next server editing 484 "Switch to next server editing buffer and mark current one as \"done\".
592 buffer and mark current one as \"done\". If a server buffer is 485 If a server buffer is current, it is marked \"done\" and optionally saved.
593 current, it is marked \"done\" and optionally saved. MH <draft> files 486 MH <draft> files are always saved and backed up, no questions asked.
594 are always saved and backed up, no questions asked. Files that match 487 When all of a client's buffers are marked as \"done\", the client is notified.
595 server-temp-file-regexp are considered temporary and are saved
596 unconditionally and
597 backed up if server-make-temp-file-backup is non-nil. When all of a
598 client's buffers are marked as \"done\", the client is notified.
599 488
600 If invoked with a prefix argument, or if there is no server process running, 489 If invoked with a prefix argument, or if there is no server process running,
601 starts server process and that is all. Invoked by \\[server-edit]. 490 starts server process and that is all. Invoked by \\[server-edit]."
602
603 If `server-kill-last-frame' is t, then the final frame will be killed."
604 (interactive "P") 491 (interactive "P")
605 (if (or arg 492 (if (or arg
606 (not server-process) 493 (not server-process)
607 (memq (process-status server-process) '(signal exit))) 494 (memq (process-status server-process) '(signal exit)))
608 (server-start nil) 495 (server-start nil)
609 (if server-buffer-clients 496 (if server-buffer-clients
610 (progn (server-done-and-switch) 497 (progn (server-switch-buffer (server-done))
611 (cond ((fboundp 'console-type) ;; XEmacs 19.14+ 498 (cond ((fboundp 'console-type) ;; XEmacs 19.14+
612 (or (and (equal (console-type) 'x) 499 (or (and (equal (console-type) 'x)
613 gnuserv-frame 500 gnuserv-frame
614 (frame-live-p gnuserv-frame)) 501 (frame-live-p gnuserv-frame))
615 (condition-case () 502 (condition-case ()
616 (delete-frame (selected-frame) 503 (delete-frame (selected-frame) nil)
617 server-kill-last-frame)
618 (error 504 (error
619 (message "Not deleting last visible frame..."))))) 505 (message "Not deleting last visible frame...")))))
620 ((or (not window-system) 506 ((or (not window-system)
621 (and gnuserv-frame 507 (and gnuserv-frame
622 (or (and (fboundp 'frame-live-p) 508 (or (and (fboundp 'frame-live-p)
632 (delete-screen)))) 518 (delete-screen))))
633 (error 519 (error
634 "(server-edit): Use only on buffers created by external programs.") 520 "(server-edit): Use only on buffers created by external programs.")
635 ))) 521 )))
636 522
637 (defun server-switch-buffer-internal (next-buffer always) 523 (defun server-switch-buffer (next-buffer)
638 "Switch to NEXT-BUFFER if a live buffer, otherwise switch to another buffer 524 "Switch to NEXT-BUFFER if a live buffer, otherwise switch to another buffer
639 with gnuserv clients. If no such buffer is available, we switch to 525 with gnuserv clients. If no such buffer is available, simply choose another
640 another normal buffer if `always' is non-nil!" 526 one."
641 ;; switching
642 (if next-buffer 527 (if next-buffer
643 (if (and (bufferp next-buffer) 528 (if (and (bufferp next-buffer)
644 (buffer-name next-buffer)) 529 (buffer-name next-buffer))
645 (switch-to-buffer next-buffer) 530 (switch-to-buffer next-buffer)
646 ;; If NEXT-BUFFER is a dead buffer, 531 ;; If NEXT-BUFFER is a dead buffer,
647 ;; remove the server records for it 532 ;; remove the server records for it
648 ;; and try the next surviving server buffer. 533 ;; and try the next surviving server buffer.
649 (server-switch-buffer-internal 534 (server-switch-buffer
650 (server-buffer-done next-buffer) always)) 535 (server-buffer-done next-buffer)))
651 (if server-clients 536 (if server-clients
652 (server-switch-buffer-internal (nth 1 (car server-clients)) always) 537 (server-switch-buffer (nth 1 (car server-clients)))
653 (if always 538 (switch-to-buffer (other-buffer)))))
654 (switch-to-buffer (other-buffer))))))
655
656 ;; For compatability
657 (defun server-switch-buffer (next-buffer)
658 (server-switch-buffer-internal next-buffer t))
659
660 ;; The below function calles server-done and switches to the next
661 ;; sensible buffer. This implementation works regardless of the values
662 ;; of server-*-function and doens't need the tail recursion
663 ;; variable passing of server.el. It is more transparant too. JV
664 (defun server-done-and-switch ()
665 "Be done with the current buffer and switch to another server buffer
666 if there is one, otherwise just switch buffer"
667 (let ((old-current (current-buffer)))
668 (server-switch-buffer-internal (server-done) nil)
669 (if (eq old-current (current-buffer))
670 (switch-to-buffer (other-buffer)))))
671 539
672 (global-set-key "\C-x#" 'server-edit) 540 (global-set-key "\C-x#" 'server-edit)
673 541
674 (provide 'gnuserv) 542 (provide 'gnuserv)
675 543
676 ;;; gnuserv.el ends here