
(defconst gnuserv-rcs-header-id "$Header: /afs/sipb.mit.edu/project/sipbsrc/src/lib/elisp/gnuserv/RCS/gnuserv.el,v 1.1 92/05/24 02:13:46 ckclark Exp $")

(provide (quote gnuserv))

(defvar server-program "/usr/sipb/etc/gnuserv" "\
*The program to use as the edit server")

(defvar server-process nil "\
the current server process")

(defvar server-string "" "\
the last input string from the server")

(defvar current-client nil "\
the client we are currently talking to")

(defvar server-clients nil "\
List of current server clients.
Each element is (CLIENTID BUFFER...) where CLIENTID is an integer
that can be given to the server process to identify a client.
When a buffer is killed, it is removed from this list.")

(defvar server-buffer-clients nil "\
List of clientids for clients requesting editing of current buffer.")

(make-variable-buffer-local (quote server-buffer-clients))

(setq-default server-buffer-clients nil)

(or (assq (quote server-buffer-clients) minor-mode-alist) (setq minor-mode-alist (cons (quote (server-buffer-clients " Server")) minor-mode-alist)))

(defun server-log (string) "\
If a *server* buffer exists, write STRING to it for logging purposes." (byte-code "! qdbcn  )" [string get-buffer "*server*" newline] 3))

(defun server-sentinel (proc msg) (byte-code "!= !! != !!" [proc process-status exit server-log message "Server subprocess exited" signal "Server subprocess killed"] 7))

(defun server-process-display-error (string) "\
When an error has been reported from the server, display the error in a
pop-up window." (byte-code " !! `\"!!*" [cur pop-up-windows t string selected-window pop-to-buffer get-buffer-create "*server*" set-window-start server-log select-window] 8))

(defun server-process-filter (proc string) "\
Process incoming requests from the server for GNU Emacs to do some actions." (byte-code "	P\"4 \"- !!
@ˏ̉)4 !̉" [server-string string header current-client string-match "
$" "^[0-9]+" server-log read-from-string oops (byte-code "	A\"@!" [server-string header eval read-from-string] 4) ((error (byte-code "ĉ	
\"É
@
A\"" [server-string current-client oops nil "" server-write-to-client signal] 4)) (quit (byte-code "ĉ	
\"É\"" [server-string current-client oops nil "" server-write-to-client signal quit] 4))) "" server-process-display-error] 7))

(defun server-release-outstanding-buffers nil "\
Release all buffers that have clients waiting for them to be finished." (interactive) (byte-code " @8	!) " [server-clients buffer nil 1 server-buffer-done] 3))

(defun server-start (&optional leave-dead) "\
Allow this Emacs process to be a server for client processes.
This starts a server communications subprocess through which
client \"editors\" can send editing commands to this Emacs job.

Prefix arg means just kill any existing server communications subprocess." (interactive "P") (byte-code "  \"ˏ
 F $ !!ω#)\"\"!" [server-process nil leave-dead server-string current-client process-connection-type t server-program server-release-outstanding-buffers set-process-sentinel (byte-code "!" [server-process delete-process] 2) ((error (byte-code "" [nil] 1))) server-log message "Restarting server" "" start-process "server" server-sentinel set-process-filter server-process-filter process-kill-without-query] 9))

(defun server-write-to-client (client form) "\
Write the given form to the given client via the server process." (byte-code "	 	!= #	
\"
!)" [client server-process s form process-status run format "%s:%s
" send-string server-log] 5))

(defun server-eval (form) "\
Evaluate form and return result to client." (byte-code "	!\"" [current-client form nil server-write-to-client eval] 4))

(defun server-eval-quickly (form) "\
Let client know that we've received the request, but eval the form
afterwards in order to not keep the client waiting." (byte-code "\"
!" [current-client nil form server-write-to-client eval] 3))

(defun server-make-window-visible nil "\
Try to make this window even more visible." (byte-code "! ! = 	= !#   " [window-system window-system-version boundp x 11 fboundp x-remap-window accept-process-output] 6))

(defun server-find-file (file) "\
Edit file FILENAME.
Switch to a buffer visiting file FILENAME,
creating one if none already exists." (byte-code "	!
 q6 	!' !? !$ \"3 	Q!3 	!: 	!q)p!" [obuf file t nil get-file-buffer file-exists-p verify-visited-file-modtime buffer-modified-p revert-buffer y-or-n-p "File no longer exists: " ", write buffer to file? " write-file find-file-noselect switch-to-buffer] 10))

(defun server-edit-files-quickly (l) "\
For each (lineno . file) pair in the given list, edit the file and goto the
given line number. Note that unlike server-edit-files, no information is saved
about clients waiting for this buffer to be killed." (byte-code "\" 
) 
@@
@A!!*
A " [current-client nil l line path server-write-to-client server-make-window-visible server-find-file goto-line] 7))

(defun server-edit-files (l) "\
For each (lineno . file) pair in the given list, edit the given file for the
client and save enough information such that server-kill-buffer can let the client
know when the buffer has been finished with." (byte-code " G @@@A
!\"p	!B4 C\"< DB**A !!" [l line path old-clients current-client server-clients buffer server-buffer-clients server-make-window-visible server-find-file assq goto-line nconc message substitute-command-keys "When done with a buffer, type \\[server-edit]."] 8))

(defun server-get-buffer (buffer) "\
One arg, a string or a buffer. Return either a buffer object or
throw an error if the buffer named was not a buffer." (byte-code "?	 p& !	?$ ; \"! !% 	)" [buffer buf get-buffer error "No buffer named %s" "Invalid buffer argument"] 4))

(defun server-kill-buffer (buffer) "\
One arg, a string or a buffer.  Get rid of the specified buffer.
NOTE: This function has been enhanced to allow for remote editing
in the following way:

If the buffer is waited upon by one or more clients, and a client is
not waiting for other buffers to be killed, then the client is told
that the buffer has been killed." (interactive "bKill buffer ") (byte-code "È!!O q
!!\" ÂM 	M 	@\"A7 ÂC @\"
\")	A\" ))" [buffer old-clients server-clients nil client server-get-buffer buffer-name server-real-kill-buffer delq server-write-to-client] 10))

(defun server-kill-all-local-variables nil "\
Eliminate all the buffer-local variable values of the current buffer.
This buffer will then see the default values of all variables.
NOTE: This function has been modified to ignore the variable 
server-buffer-clients." (byte-code "	  )" [clients server-buffer-clients server-real-kill-all-local-variables] 3))

(or (fboundp (quote server-real-kill-buffer)) (fset (quote server-real-kill-buffer) (symbol-function (quote kill-buffer))))

(fset (quote kill-buffer) (quote server-kill-buffer))

(or (fboundp (quote server-real-kill-all-local-variables)) (fset (quote server-real-kill-all-local-variables) (symbol-function (quote kill-all-local-variables))))

(fset (quote kill-all-local-variables) (quote server-kill-all-local-variables))

(defun server-buffer-done (buffer) "\
Mark BUFFER as \"done\" for its client(s).
Buries the buffer, and returns another server buffer
as a suggestion for what to select next." (byte-code "
; 
@ >8\"A% 1 @\"\")
A !K q)!*" [next-buffer nil old-clients server-clients client buffer server-buffer-clients 1 delq server-write-to-client buffer-name bury-buffer] 6))

(defun mh-draft-p (buffer) "\
Return non-nil if this BUFFER is an mh <draft> file.
Since MH deletes draft *BEFORE* it is edited, the server treats them specially." (byte-code "!\"" [buffer string= buffer-name "draft"] 4))

(defun server-done nil "\
Offer to save current buffer, mark it as \"done\" for clients,
bury it, and return a suggested buffer to select next." (byte-code "p	2 !  ed
P#!.  ( 
Q!. !!)" [buffer server-buffer-clients buffer-file-name mh-draft-p save-buffer write-region "~" kill-buffer buffer-modified-p y-or-n-p "Save file " "? " server-buffer-done] 9))

(defun server-edit (&optional arg) "\
Switch to next server editing buffer; say \"Done\" for current buffer.
If a server buffer is current, it is marked \"done\" and optionally saved.
MH <draft> files are always saved and backed up, no questions asked.
When all of a client's buffers are marked as \"done\", the client is notified.

If invoked with a prefix argument, or if there is no server process running, 
starts server process and that is all.  Invoked by \\[server-edit]." (interactive "P") (byte-code " 	? 	!> !  !" [arg server-process nil process-status (signal exit) server-start server-switch-buffer server-done] 5))

(defun server-switch-buffer (next-buffer) "\
Switch to another buffer, preferably one that has a client.
Arg NEXT-BUFFER is a suggestion; if it is a live buffer, use it." (byte-code " ! ! ! !!/ 	+ 	@8!/  !" [next-buffer server-clients bufferp buffer-name switch-to-buffer server-switch-buffer server-buffer-done 1 other-buffer] 9))

(global-set-key "#" (quote server-edit))
