comparison lisp/packages/gnuserv.el @ 151:59463afc5666 r20-3b2

Import from CVS: tag r20-3b2
author cvs
date Mon, 13 Aug 2007 09:37:19 +0200
parents 538048ae2ab8
children 25f70ba0133c
comparison
equal deleted inserted replaced
150:8ebb1c0f0f6f 151:59463afc5666
1 ;;; gnuserv.el --- Lisp interface code between Emacs and gnuserv 1 ;;; gnuserv.el --- Lisp interface code between Emacs and gnuserv
2 ;; Copyright (C) 1989-1997 Free Software Foundation, Inc. 2 ;; Copyright (C) 1989-1997 Free Software Foundation, Inc.
3 3
4 ;; Version: 3.1 4 ;; Version: 3.2
5 ;; Author: Andy Norman (ange@hplb.hpl.hp.com), originally based on server.el 5 ;; Author: Andy Norman (ange@hplb.hpl.hp.com), originally based on server.el
6 ;; Hrvoje Niksic <hniksic@srce.hr> 6 ;; Hrvoje Niksic <hniksic@srce.hr>
7 ;; Keywords: environment, processes, terminals 7 ;; Keywords: environment, processes, terminals
8 8
9 ;; This file is part of XEmacs. 9 ;; This file is part of XEmacs.
75 75
76 76
77 ;;; Code: 77 ;;; Code:
78 78
79 (defconst gnuserv-rcs-version 79 (defconst gnuserv-rcs-version
80 "$Id: gnuserv.el,v 1.8 1997/05/18 03:40:06 steve Exp $") 80 "$Id: gnuserv.el,v 1.9 1997/05/23 01:36:30 steve Exp $")
81 81
82 (defgroup gnuserv nil 82 (defgroup gnuserv nil
83 "The gnuserv suite of programs to talk to Emacs from outside." 83 "The gnuserv suite of programs to talk to Emacs from outside."
84 :group 'environment 84 :group 'environment
85 :group 'processes 85 :group 'processes
152 The hook functions are called after the file has been visited, with the 152 The hook functions are called after the file has been visited, with the
153 current buffer set to the visiting buffer." 153 current buffer set to the visiting buffer."
154 :type 'hook 154 :type 'hook
155 :group 'gnuserv) 155 :group 'gnuserv)
156 156
157 (defcustom gnuserv-init-hook nil
158 "*Hook run after the server is started."
159 :type 'hook
160 :group 'gnuserv)
161
162 (defcustom gnuserv-shutdown-hook nil
163 "*Hook run before the server exits."
164 :type 'hook
165 :group 'gnuserv)
166
157 (defcustom gnuserv-kill-quietly nil 167 (defcustom gnuserv-kill-quietly nil
158 "*Non-nil means to kill buffers with clients attached without requiring confirmation." 168 "*Non-nil means to kill buffers with clients attached without requiring confirmation."
159 :type 'boolean 169 :type 'boolean
160 :group 'gnuserv) 170 :group 'gnuserv)
161 171
228 238
229 ;; We want the client-infested buffers to have some modeline 239 ;; We want the client-infested buffers to have some modeline
230 ;; identification, so we'll make a "minor mode". 240 ;; identification, so we'll make a "minor mode".
231 (defvar gnuserv-minor-mode nil) 241 (defvar gnuserv-minor-mode nil)
232 (make-variable-buffer-local 'gnuserv-mode) 242 (make-variable-buffer-local 'gnuserv-mode)
233 (pushnew '(gnuserv-minor-mode " Server") minor-mode-alist) 243 (pushnew '(gnuserv-minor-mode " Server") minor-mode-alist
244 :test 'equal)
234 245
235 246
236 ;; Sample gnuserv-frame functions 247 ;; Sample gnuserv-frame functions
237 248
238 (defun gnuserv-main-frame-function (type) 249 (defun gnuserv-main-frame-function (type)
261 gnuserv-special-frame) 272 gnuserv-special-frame)
262 273
263 274
264 ;;; Communication functions 275 ;;; Communication functions
265 276
277 ;; We used to restart the server here, but it's too risky -- if
278 ;; something goes awry, it's too easy to wind up in a loop.
266 (defun gnuserv-sentinel (proc msg) 279 (defun gnuserv-sentinel (proc msg)
267 (case (process-status proc) 280 (case (process-status proc)
268 (exit (message "Gnuserv subprocess exited; restarting") 281 (exit
269 ;; This will also kill all the existing clients. 282 (message
270 (gnuserv-start-1)) 283 (substitute-command-keys
271 (closed (message "Gnuserv subprocess closed")) 284 "Gnuserv subprocess exited; restart with `\\[gnuserv-start]'"))
272 (signal (message "Gnuserv subprocess killed")))) 285 (gnuserv-prepare-shutdown))
273 286 (signal
287 (message
288 (substitute-command-keys
289 "Gnuserv subprocess killed; restart with `\\[gnuserv-start]'"))
290 (gnuserv-prepare-shutdown))
291 (closed
292 (message
293 (substitute-command-keys
294 "Gnuserv subprocess closed; restart with `\\[gnuserv-start]'"))
295 (gnuserv-prepare-shutdown))))
296
297 ;; This function reads client requests from our current server. Every
298 ;; client is identified by a unique ID within the server
299 ;; (incidentally, the same ID is the file descriptor the server uses
300 ;; to communicate to client).
301 ;;
302 ;; The request string can arrive in several chunks. As the request
303 ;; ends with \C-d, we check for that character at the end of string.
304 ;; If not found, keep reading, and concatenating to former strings.
305 ;; So, if at first read we receive "5 (gn", that text will be stored
306 ;; to gnuserv-string. If we then receive "us)\C-d", the two will be
307 ;; concatenated, `current-client' will be set to 5, and `(gnus)' form
308 ;; will be evaluated.
309 ;;
310 ;; Server will send the following:
311 ;;
312 ;; "ID <text>\C-d" (no quotes)
313 ;;
314 ;; ID - file descriptor of the given client;
315 ;; <text> - the actual contents of the request.
274 (defun gnuserv-process-filter (proc string) 316 (defun gnuserv-process-filter (proc string)
275 "Process gnuserv client requests to execute Emacs commands." 317 "Process gnuserv client requests to execute Emacs commands."
276 (setq gnuserv-string (concat gnuserv-string string)) 318 (setq gnuserv-string (concat gnuserv-string string))
277 ;; C-d means end of request. 319 ;; C-d means end of request.
278 (when (string-match "\C-d$" gnuserv-string) 320 (when (string-match "\C-d$" gnuserv-string)
296 (setq gnuserv-string ""))) 338 (setq gnuserv-string "")))
297 (t 339 (t
298 (error "%s: invalid response from gnuserv" gnuserv-string) 340 (error "%s: invalid response from gnuserv" gnuserv-string)
299 (setq gnuserv-string ""))))) 341 (setq gnuserv-string "")))))
300 342
343 ;; This function is somewhat of a misnomer. Actually, we write to the
344 ;; server (using `process-send-string' to gnuserv-process), which
345 ;; interprets what we say and forwards it to the client. The
346 ;; incantation server understands is (from gnuserv.c):
347 ;;
348 ;; "FD/LEN:<text>\n" (no quotes)
349 ;; FD - file descriptor of the given client (which we obtained from
350 ;; the server earlier);
351 ;; LEN - length of the stuff we are about to send;
352 ;; <text> - the actual contents of the request.
301 (defun gnuserv-write-to-client (client-id form) 353 (defun gnuserv-write-to-client (client-id form)
302 "Write the given form to the given client via the gnuserv process." 354 "Write the given form to the given client via the gnuserv process."
303 (when (eq (process-status gnuserv-process) 'run) 355 (when (eq (process-status gnuserv-process) 'run)
304 (let* ((result (format "%s" form)) 356 (let* ((result (format "%s" form))
305 (s (format "%s/%d:%s\n" client-id 357 (s (format "%s/%d:%s\n" client-id
306 (length result) result))) 358 (length result) result)))
307 (process-send-string gnuserv-process s)))) 359 (process-send-string gnuserv-process s))))
308 360
309
310 ;; The following two functions are helper functions, used by 361 ;; The following two functions are helper functions, used by
311 ;; gnuclient. 362 ;; gnuclient.
312 363
313 (defun gnuserv-eval (form) 364 (defun gnuserv-eval (form)
314 "Evaluate form and return result to client." 365 "Evaluate form and return result to client."
323 (eval form)) 374 (eval form))
324 375
325 376
326 ;; "Execute" a client connection, called by gnuclient. This is the 377 ;; "Execute" a client connection, called by gnuclient. This is the
327 ;; backbone of gnuserv.el. 378 ;; backbone of gnuserv.el.
328 (defun gnuserv-edit-files (type list &optional flags) 379 (defun gnuserv-edit-files (type list &rest flags)
329 "For each (line-number . file) pair in LIST, edit the file at line-number. 380 "For each (line-number . file) pair in LIST, edit the file at line-number.
330 The visited buffers are memorized, so that when \\[gnuserv-edit] is invoked 381 The visited buffers are memorized, so that when \\[gnuserv-edit] is invoked
331 in such a buffer, or when it is killed, or the client's device deleted, the 382 in such a buffer, or when it is killed, or the client's device deleted, the
332 client will be invoked that the edit is finished. 383 client will be invoked that the edit is finished.
333 384
334 TYPE should either be a (tty TTY TERM PID) list, or (x DISPLAY) list. 385 TYPE should either be a (tty TTY TERM PID) list, or (x DISPLAY) list.
335 If FLAGS is `quick', just edit the files in Emacs. 386 If a flag is `quick', just edit the files in Emacs.
336 If FLAGS is `view', view the files read-only." 387 If a flag is `view', view the files read-only."
337 (or (not flags) 388 (let (quick view)
338 (memq flags '(quick view)) 389 (mapc (lambda (flag)
339 (error "Invalid flag %s" flags)) 390 (case flag
340 (let* ((old-device-num (length (device-list))) 391 (quick (setq quick t))
341 (new-frame nil) 392 (view (setq view t))
342 (dest-frame (if (functionp gnuserv-frame) 393 (t (error "Invalid flag %s" flag))))
343 (funcall gnuserv-frame (car type)) 394 flags)
344 gnuserv-frame)) 395 (let* ((old-device-num (length (device-list)))
345 ;; The gnuserv-frame dependencies are ugly. 396 (new-frame nil)
346 (device (cond ((frame-live-p dest-frame) 397 (dest-frame (if (functionp gnuserv-frame)
347 (frame-device dest-frame)) 398 (funcall gnuserv-frame (car type))
348 ((null dest-frame) 399 gnuserv-frame))
349 (case (car type) 400 ;; The gnuserv-frame dependencies are ugly.
350 (tty (apply 'make-tty-device (cdr type))) 401 (device (cond ((frame-live-p dest-frame)
351 (x (make-x-device (cadr type))) 402 (frame-device dest-frame))
352 (t (error "Invalid device type")))) 403 ((null dest-frame)
353 (t 404 (case (car type)
354 (selected-device)))) 405 (tty (apply 'make-tty-device (cdr type)))
355 (frame (cond ((frame-live-p dest-frame) 406 (x (make-x-device (cadr type)))
356 dest-frame) 407 (t (error "Invalid device type"))))
357 ((null dest-frame) 408 (t
358 (setq new-frame (make-frame nil device)) 409 (selected-device))))
359 new-frame) 410 (frame (cond ((frame-live-p dest-frame)
360 (t (selected-frame)))) 411 dest-frame)
361 (client (make-gnuclient :id gnuserv-current-client 412 ((null dest-frame)
362 :device device 413 (setq new-frame (make-frame nil device))
363 :frame new-frame))) 414 new-frame)
364 (setq gnuserv-current-client nil) 415 (t (selected-frame))))
365 ;; If the device was created by this client, push it to the list. 416 (client (make-gnuclient :id gnuserv-current-client
366 (and (/= old-device-num (length (device-list))) 417 :device device
367 (push device gnuserv-devices)) 418 :frame new-frame)))
368 ;; Visit all the listed files. 419 (setq gnuserv-current-client nil)
369 (while list 420 ;; If the device was created by this client, push it to the list.
370 (let ((line (caar list)) (path (cdar list))) 421 (and (/= old-device-num (length (device-list)))
371 (select-frame frame) 422 (push device gnuserv-devices))
372 ;; Visit the file. 423 (and (frame-iconified-p frame)
373 (funcall (if (eq flags 'view) 424 (deiconify-frame frame))
374 gnuserv-view-file-function 425 ;; Visit all the listed files.
375 gnuserv-find-file-function) 426 (while list
376 path) 427 (let ((line (caar list)) (path (cdar list)))
377 (goto-line line) 428 (select-frame frame)
378 (run-hooks 'gnuserv-visit-hook) 429 ;; Visit the file.
379 ;; Don't memorize the quick and view buffers. 430 (funcall (if view
380 (when (null flags) 431 gnuserv-view-file-function
381 (pushnew (current-buffer) (gnuclient-buffers client)) 432 gnuserv-find-file-function)
382 (setq gnuserv-minor-mode t)) 433 path)
383 (pop list))) 434 (goto-line line)
384 (cond ((and flags (device-on-window-system-p device)) 435 (run-hooks 'gnuserv-visit-hook)
385 ;; Exit if on X device, and quick or view. 436 ;; Don't memorize the quick and view buffers.
386 ;; NOTE: if the client is to finish now, it must absolutely 437 (unless (or quick view)
387 ;; /not/ be included to the list of clients. This way the 438 (pushnew (current-buffer) (gnuclient-buffers client))
388 ;; client-ids should be unique. 439 (setq gnuserv-minor-mode t))
389 (gnuserv-write-to-client (gnuclient-id client) nil)) 440 (pop list)))
390 (t 441 (cond
391 ;; Else, the client gets a vote. 442 ((and (or quick view)
392 (push client gnuserv-clients) 443 (device-on-window-system-p device))
393 ;; Explain buffer exit options. If dest-frame is nil, the 444 ;; Exit if on X device, and quick or view. NOTE: if the
394 ;; user can exit via `delete-frame'. OTOH, if FLAGS are 445 ;; client is to finish now, it must absolutely /not/ be
395 ;; nil and there are some buffers, the user can exit via 446 ;; included to the list of clients. This way the client-ids
396 ;; `gnuserv-edit'. 447 ;; should be unique.
397 (if (and (null flags) 448 (gnuserv-write-to-client (gnuclient-id client) nil))
398 (gnuclient-buffers client)) 449 (t
399 (message (substitute-command-keys 450 ;; Else, the client gets a vote.
400 "Type `\\[gnuserv-edit]' to finish editing")) 451 (push client gnuserv-clients)
401 (or dest-frame 452 ;; Explain buffer exit options. If dest-frame is nil, the
402 (message (substitute-command-keys 453 ;; user can exit via `delete-frame'. OTOH, if FLAGS are nil
403 "Type `\\[delete-frame]' to finish editing")))))))) 454 ;; and there are some buffers, the user can exit via
455 ;; `gnuserv-edit'.
456 (if (and (not (or quick view))
457 (gnuclient-buffers client))
458 (message (substitute-command-keys
459 "Type `\\[gnuserv-edit]' to finish editing"))
460 (or dest-frame
461 (message (substitute-command-keys
462 "Type `\\[delete-frame]' to finish editing")))))))))
404 463
405 464
406 ;;; Functions that hook into Emacs in various way to enable operation 465 ;;; Functions that hook into Emacs in various way to enable operation
407 466
408 ;; Defined later. 467 ;; Defined later.
409 (add-hook 'kill-emacs-hook 'gnuserv-kill-all-clients t) 468 (add-hook 'kill-emacs-hook 'gnuserv-kill-all-clients t)
410 469
411 ;; A helper function; used by others. 470 ;; A helper function; used by others. Try avoiding it whenever
471 ;; possible, because it is slow, and conses a list. Use
472 ;; `gnuserv-buffer-p' when appropriate, for instance.
412 (defun gnuserv-buffer-clients (buffer) 473 (defun gnuserv-buffer-clients (buffer)
413 "Returns a list of clients to which BUFFER belongs." 474 "Returns a list of clients to which BUFFER belongs."
414 (let ((client gnuserv-clients) 475 (let ((client gnuserv-clients)
415 res) 476 res)
416 (while client 477 (while client
417 (if (memq buffer (gnuclient-buffers (car client))) 478 (if (memq buffer (gnuclient-buffers (car client)))
418 (push (car client) res)) 479 (push (car client) res))
419 (pop client)) 480 (pop client))
420 res)) 481 res))
482
483 ;; Like `gnuserv-buffer-clients', but returns a boolean; doesn't
484 ;; collect a list.
485 (defun gnuserv-buffer-p (buffer)
486 (member* buffer gnuserv-clients
487 :test 'memq
488 :key 'gnuclient-buffers))
421 489
422 ;; This function makes sure that a killed buffer is deleted off the 490 ;; This function makes sure that a killed buffer is deleted off the
423 ;; list for the particular client. 491 ;; list for the particular client.
424 ;; 492 ;;
425 ;; This hooks into `kill-buffer-hook'. It is *not* a replacement for 493 ;; This hooks into `kill-buffer-hook'. It is *not* a replacement for
441 509
442 ;; Ask for confirmation before killing a buffer that belongs to a 510 ;; Ask for confirmation before killing a buffer that belongs to a
443 ;; living client. 511 ;; living client.
444 (defun gnuserv-kill-buffer-query-function () 512 (defun gnuserv-kill-buffer-query-function ()
445 (or gnuserv-kill-quietly 513 (or gnuserv-kill-quietly
446 (not (gnuserv-buffer-clients (current-buffer))) 514 (not (gnuserv-buffer-p (current-buffer)))
447 (yes-or-no-p 515 (yes-or-no-p
448 (format "Buffer %s belongs to gnuserv client(s); kill anyway? " 516 (format "Buffer %s belongs to gnuserv client(s); kill anyway? "
449 (current-buffer))))) 517 (current-buffer)))))
450 518
451 (add-hook 'kill-buffer-query-functions 519 (add-hook 'kill-buffer-query-functions
536 604
537 605
538 ;;; Higher-level functions 606 ;;; Higher-level functions
539 607
540 ;; Choose a `next' server buffer, according to several criteria, and 608 ;; Choose a `next' server buffer, according to several criteria, and
541 ;; return it. If none appropriate are found, return nil. 609 ;; return it. If none are found, return nil.
542 (defun gnuserv-next-buffer () 610 (defun gnuserv-next-buffer ()
543 (let* ((frame (selected-frame)) 611 (let* ((frame (selected-frame))
544 (device (selected-device)) 612 (device (selected-device))
545 client) 613 client)
546 (cond 614 (cond
553 ((and 621 ((and
554 (memq (selected-device) gnuserv-devices) 622 (memq (selected-device) gnuserv-devices)
555 (setq client 623 (setq client
556 (car (member* device gnuserv-clients :key 'gnuclient-device)))) 624 (car (member* device gnuserv-clients :key 'gnuclient-device))))
557 (car (gnuclient-buffers client))) 625 (car (gnuclient-buffers client)))
558 ;; Else, try to find just any client, and return its first buffer. 626 ;; Else, try to find any client with at least one buffer, and
559 (gnuserv-clients 627 ;; return its first buffer.
560 (car (gnuclient-buffers (car gnuserv-clients)))) 628 ((setq client
561 ;; Oh, give up. 629 (car (member-if-not 'null gnuserv-clients
630 :key 'gnuserv-buffers)))
631 (car (gnuclient-buffers client)))
632 ;; Oh, give up.
562 (t nil)))) 633 (t nil))))
563 634
564 (defun gnuserv-buffer-done (buffer) 635 (defun gnuserv-buffer-done (buffer)
565 "Mark BUFFER as \"done\" for its client(s). 636 "Mark BUFFER as \"done\" for its client(s).
566 Calls `gnuserv-done-function' and returns another gnuserv buffer as a 637 Does the save/backup queries first, and calls `gnuserv-done-function'."
567 suggestion for the new current buffer."
568 ;; Check whether this is the real thing. 638 ;; Check whether this is the real thing.
569 (unless (gnuserv-buffer-clients buffer) 639 (unless (gnuserv-buffer-p buffer)
570 (error "%s does not belong to a gnuserv client" buffer)) 640 (error "%s does not belong to a gnuserv client" buffer))
571 ;; Backup/ask query. 641 ;; Backup/ask query.
572 (if (gnuserv-temp-file-p buffer) 642 (if (gnuserv-temp-file-p buffer)
573 ;; For a temp file, save, and do NOT make a non-numeric backup 643 ;; For a temp file, save, and do NOT make a non-numeric backup
574 ;; Why does server.el explicitly back up temporary files? 644 ;; Why does server.el explicitly back up temporary files?
576 (buffer-backed-up (not gnuserv-make-temp-file-backup))) 646 (buffer-backed-up (not gnuserv-make-temp-file-backup)))
577 (save-buffer)) 647 (save-buffer))
578 (if (and (buffer-modified-p) 648 (if (and (buffer-modified-p)
579 (y-or-n-p (concat "Save file " buffer-file-name "? "))) 649 (y-or-n-p (concat "Save file " buffer-file-name "? ")))
580 (save-buffer buffer))) 650 (save-buffer buffer)))
581 (gnuserv-buffer-done-1 buffer) 651 (gnuserv-buffer-done-1 buffer))
582 (gnuserv-next-buffer))
583 652
584 ;; Called by `gnuserv-start-1' to clean everything. Hooked into 653 ;; Called by `gnuserv-start-1' to clean everything. Hooked into
585 ;; `kill-emacs-hook', too. 654 ;; `kill-emacs-hook', too.
586 (defun gnuserv-kill-all-clients () 655 (defun gnuserv-kill-all-clients ()
587 "Kill all the gnuserv clients. Ruthlessly." 656 "Kill all the gnuserv clients. Ruthlessly."
588 (mapc 'gnuserv-kill-client gnuserv-clients)) 657 (mapc 'gnuserv-kill-client gnuserv-clients))
589 658
590 ;; Actually start the process. Kills all the clients before-hand. 659 ;; This serves to run the hook and reset
591 (defun gnuserv-start-1 (&optional leave-dead) 660 ;; `allow-deletion-of-last-visible-frame'.
661 (defun gnuserv-prepare-shutdown ()
662 (setq allow-deletion-of-last-visible-frame nil)
663 (run-hooks 'gnuserv-shutdown-hook))
664
665 ;; This is a user-callable function, too.
666 (defun gnuserv-shutdown ()
667 "Shutdown the gnuserv server, if one is currently running.
668 All the clients will be disposed of via the normal methods."
669 (interactive)
592 (gnuserv-kill-all-clients) 670 (gnuserv-kill-all-clients)
593 (when gnuserv-process 671 (when gnuserv-process
594 (set-process-sentinel gnuserv-process nil) 672 (set-process-sentinel gnuserv-process nil)
673 (gnuserv-prepare-shutdown)
595 (condition-case () 674 (condition-case ()
596 (delete-process gnuserv-process) 675 (delete-process gnuserv-process)
597 (error nil))) 676 (error nil))
677 (setq gnuserv-process nil)
678 (message "Killed server")))
679
680 ;; Actually start the process. Kills all the clients before-hand.
681 (defun gnuserv-start-1 (&optional leave-dead)
682 ;; Shutdown the existing server, if any.
683 (gnuserv-shutdown)
598 ;; If we already had a server, clear out associated status. 684 ;; If we already had a server, clear out associated status.
599 (unless leave-dead 685 (unless leave-dead
600 (setq gnuserv-string "") 686 (setq gnuserv-string ""
601 (setq gnuserv-current-client nil) 687 gnuserv-current-client nil)
602 (let ((process-connection-type t)) 688 (let ((process-connection-type t))
603 (setq gnuserv-process 689 (setq gnuserv-process
604 (start-process "gnuserv" nil gnuserv-program))) 690 (start-process "gnuserv" nil gnuserv-program)))
605 (set-process-sentinel gnuserv-process 'gnuserv-sentinel) 691 (set-process-sentinel gnuserv-process 'gnuserv-sentinel)
606 (set-process-filter gnuserv-process 'gnuserv-process-filter) 692 (set-process-filter gnuserv-process 'gnuserv-process-filter)
607 (process-kill-without-query gnuserv-process))) 693 (process-kill-without-query gnuserv-process)
694 (setq allow-deletion-of-last-visible-frame t)
695 (run-hooks 'gnuserv-init-hook)))
608 696
609 697
610 ;;; User-callable functions: 698 ;;; User-callable functions:
699
700 ;;;###autoload
701 (defun gnuserv-running-p ()
702 "Return non-nil if a gnuserv process is running from this XEmacs session."
703 (not (not gnuserv-process)))
611 704
612 ;;;###autoload 705 ;;;###autoload
613 (defun gnuserv-start (&optional leave-dead) 706 (defun gnuserv-start (&optional leave-dead)
614 "Allow this Emacs process to be a server for client processes. 707 "Allow this Emacs process to be a server for client processes.
615 This starts a gnuserv communications subprocess through which 708 This starts a gnuserv communications subprocess through which
616 client \"editors\" (gnuclient and gnudoit) can send editing commands to 709 client \"editors\" (gnuclient and gnudoit) can send editing commands to
617 this Emacs job. See the gnuserv(1) manual page for more details. 710 this Emacs job. See the gnuserv(1) manual page for more details.
618 711
619 Prefix arg means just kill any existing server communications subprocess." 712 Prefix arg means just kill any existing server communications subprocess."
620 (interactive "P") 713 (interactive "P")
621 ;; kill it dead!
622 (and gnuserv-process 714 (and gnuserv-process
623 (not leave-dead) 715 (not leave-dead)
624 (message "Restarting gnuserv")) 716 (message "Restarting gnuserv"))
625 (gnuserv-start-1 leave-dead)) 717 (gnuserv-start-1 leave-dead))
626 718
627 ;;;###autoload 719 (defun gnuserv-edit (&optional count)
628 (defun gnuserv-edit (&optional arg)
629 "Mark the current gnuserv editing buffer as \"done\", and switch to next one. 720 "Mark the current gnuserv editing buffer as \"done\", and switch to next one.
630 721
631 The `gnuserv-done-function' is used to dispose of the buffer after marking it 722 Run with a numeric prefix argument, repeat the operation that number
632 as done; it is `kill-buffer' by default. 723 of times. If given a universal prefix argument, close all the buffers
724 of this buffer's clients.
725
726 The `gnuserv-done-function' (bound to `kill-buffer' by default) is
727 called to dispose of the buffer after marking it as done.
633 728
634 Files that match `gnuserv-temp-file-regexp' are considered temporary and 729 Files that match `gnuserv-temp-file-regexp' are considered temporary and
635 are saved unconditionally and backed up if `gnuserv-make-temp-file-backup' 730 are saved unconditionally and backed up if `gnuserv-make-temp-file-backup'
636 is non-nil. They are disposed of using `gnuserv-done-temp-file-function'. 731 is non-nil. They are disposed of using `gnuserv-done-temp-file-function'
637 732 (also bound to `kill-buffer' by default).
638 When all of a client's buffers are marked as \"done\", the client is notified. 733
639 734 When all of a client's buffers are marked as \"done\", the client is notified."
640 If invoked with a prefix argument, or if there is no gnuserv process
641 running, only starts server process. Invoked with \\[gnuserv-edit]."
642 (interactive "P") 735 (interactive "P")
643 (if (or arg (not gnuserv-process) 736 (when (null count)
644 (memq (process-status gnuserv-process) '(signal exit))) 737 (setq count 1))
645 (gnuserv-start) 738 (cond ((numberp count)
646 (switch-to-buffer (or (gnuserv-buffer-done (current-buffer)) 739 (let (next)
647 (current-buffer))))) 740 (while (natnump (decf count))
648 741 (gnuserv-buffer-done (current-buffer))
649 ;;;###autoload 742 (setq next (gnuserv-next-buffer))
743 (when next
744 (switch-to-buffer next)))))
745 (count
746 (let* ((buf (current-buffer))
747 (clients (gnuserv-buffer-clients buf)))
748 (unless clients
749 (error "%s does not belong to a gnuserv client" buf))
750 (mapc 'gnuserv-kill-client (gnuserv-buffer-clients buf))))))
751
650 (global-set-key "\C-x#" 'gnuserv-edit) 752 (global-set-key "\C-x#" 'gnuserv-edit)
651 753
652 (provide 'gnuserv) 754 (provide 'gnuserv)
653 755
654 ;;; gnuserv.el ends here 756 ;;; gnuserv.el ends here