[comp.emacs] GNUemacs server/client mode

gnb@bby.oz (Gregory N. Bond) (03/07/89)

[I have previously posted this to an aus distribution and got no reply]

I am looking for pointers or information on the clisent/server mode of
GNUemacs.  I have found the client and server programs but can't work
out how they are suppoed to be used, and can't find anything in the FM.

My understanding is that this will allow me to use one emacs process
(which is quite large) as a server and several clients as the editor
for MH/rn/4GL and other "call editors within an application" uses,
without continual creating/destroying emacs processes.

My environment:  GNU emacs 18.52, SunOs 3.5 under both SunView and
yukko 80x25 terminals.

Thanks for your help.

Greg.
--
Gregory Bond, Burdett Buckeridge & Young Ltd, Melbourne, Australia
Internet: gnb@melba.bby.oz.au    non-MX: gnb%melba.bby.oz@uunet.uu.net
Uucp: {uunet,mnetor,pyramid,ubc-vision,ukc,mcvax,...}!munnari!melba.bby.oz!gnb

neilc@natmlab.dms.oz (Neil Crellin) (03/08/89)

In article <GNB.89Mar7151044@melba.bby.oz>, gnb@bby (Gregory N. Bond) writes:
>[I have previously posted this to an aus distribution and got no reply]
Sorry Greg, I saw it there but was snowed under.

>I am looking for pointers or information on the client/server mode of
>GNUemacs.  I have found the client and server programs but can't work
>out how they are suppoed to be used, and can't find anything in the FM.

In etc/NEWS we find the following: (Try also C-h f server-start and look
                                                         at lisp/server.el)

* Existing Emacs usable as a server.

Programs such as mailers that invoke "the editor" as an inferior
to edit some text can now be told to use an existing Emacs process
instead of creating a new editor.

To do this, you must have an Emacs process running and capable of
doing terminal I/O at the time you want to invoke it.  This means that
either you are using a window system and give Emacs a separate window
or you run the other programs as inferiors of Emacs (such as, using
M-x shell).

First prepare the existing Emacs process by loading the `server'
library and executing M-x server-start.  (Your .emacs can do this
automatically.)

Now tell the other programs to use, as "the editor", the Emacs client
program (etc/emacsclient, located in the same directory as this file).
This can be done by setting the environment variable EDITOR.

When another program invokes the emacsclient as "the editor", the
client actually transfers the file names to be edited to the existing
Emacs, which automatically visits the files.

When you are done editing a buffer for a client, do C-x # (server-edit).
This marks that buffer as done, and selects the next buffer that the client
asked for.  When all the buffers requested by a client are marked in this
way, Emacs tells the client program to exit, so that the program that
invoked "the editor" will resume execution.

You can only have one server Emacs at a time, but multiple client programs
can put in requests at the same time.

The client/server work only on Berkeley Unix, since they use the Berkeley
sockets mechanism for their communication.

>My understanding is that this will allow me to use one emacs process
>(which is quite large) as a server and several clients as the editor
>for MH/rn/4GL and other "call editors within an application" uses,
>without continual creating/destroying emacs processes.

Sounds that way. Have fun.

--
Neil Crellin, CSIRO Maths and Stats, Sydney, Australia. (neilc@natmlab.oz.au)
PO Box 218, Lindfield, NSW 2070.  (ph) +61 2 467 6721 (fax) +61 2 416 9317

karl@triceratops.cis.ohio-state.edu (Karl Kleinpaste) (03/08/89)

In your .emacs, put this line:
	(server-edit)
and thereafter, you can run `emacsclient /some/file/name' to edit
files.  It'll open a connection to the existing emacs, tell it what
file to edit, and emacs will go get that file.  Edit a while, and when
you're done, type
	C-x #
which will tell the (waiting) emacsclient that you're done.  It is in
your best interest to
	setenv EDITOR /usr/local/bin/emacsclient
and so forth, so that programs which invoke editors on their own will
do it The Right Way.  (Of course, since you're a GNUS user, this may
not matter much to you.)

From emacs/lisp/server.el:

;;; Load this library and do M-x server-edit to enable Emacs as a server.
;;; Emacs runs the program ../etc/server as a subprocess
;;; for communication with clients.  If there are no client buffers to edit, 
;;; server-edit acts like (switch-to-buffer (other-buffer))

;;; When some other program runs "the editor" to edit a file,
;;; "the editor" can be the Emacs client program ../etc/emacsclient.
;;; This program transmits the file names to Emacs through
;;; the server subprocess, and Emacs visits them and lets you edit them.

;;; Note that any number of clients may dispatch files to emacs to be edited.

;;; When you finish editing a Server buffer, again call server-edit
;;; to mark that buffer as done for the client and switch to the next 
;;; Server buffer.  When all the buffers for a client have been edited 
;;; and exited with server-edit, the client "editor" will return
;;; to the program that invoked it.  

--Karl

tale@pawl.rpi.edu (David C Lawrence) (03/08/89)

In article <KARL.89Mar8083603@triceratops.cis.ohio-state.edu>
karl@triceratops.cis.ohio-state.edu (Karl Kleinpaste) writes:
Karl> In your .emacs, put this line:
Karl> 	(server-edit)

That's peculiar.  I have to do server-start, not -edit, it GNU Emacs
18.50.2.   What version is server-edit from?  Regardless, Joe Wells
posted something useful a few moths ago.  It seems as though there is
a problem with changing the mode of a file you are editing via the
server.   kill-all-local-variables, called by most major modes,
trashes server-buffer-clients, making the C-x # effectively disabled.
In order to circumvent this problem, kill-all-local-variables was
slightly modified to preserve variables which have a "preserved"
property. 

After you start the server you should immediately execute:
(put 'server-buffer-clients 'preserved t)
and add have the following short segment of code loaded however you
like, probably in your .emacs.  Good luck with it.

Dave
--- Cutline ---
;; Enhancement to kill-all-local-variables, author Joe Wells
;; jbw%bucsf.bu.edu@bu-it.bu.edu (school year)
;; joew%uswest@boulder.colorado.edu (summer)

;; save the original subr function definition of kill-all-local-variables
(or (fboundp 'original-kill-all-local-variables)
    (fset 'original-kill-all-local-variables
	  (symbol-function 'kill-all-local-variables)))

(defun kill-all-local-variables ()
  "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
buffer-local variables whose preserved property is non-nil."
  (let ((oldvars (buffer-local-variables)))
    (original-kill-all-local-variables)
    (while oldvars
      (let ((var (car (car oldvars))))
	(cond ((get var 'preserved)
	       (make-local-variable var)
	       (set var (cdr (car oldvars))))))
      (setq oldvars (cdr oldvars)))))
--- CUtline ---
--
      tale@rpitsmts.bitnet, tale%mts@rpitsgw.rpi.edu, tale@pawl.rpi.edu

gaynor@porthos.rutgers.edu (Silver) (03/11/89)

neilc@natmlab.dms.oz writes:
> To do this [the emacs server/client thing], you must have an Emacs process
> running and capable of doing terminal I/O at the time you want to invoke it.
> This means that either you are using a window system and give Emacs a
> separate window or you run the other programs as inferiors of Emacs (such as,
> using M-x shell).

I've had experience otherwise.

server = emacs -f server-start
client = .../etc/emacsclient
foo    = a program that invokes the value of the envariable EDITOR

On Pyramids, Celerities, and Suns, I have had no problem
1. starting then suspending server
2. running foo, which in turn invokes client
3. suspending foo invoking client, and continuing server
4. completing the editing session in server
5. resuming foo invoking client
6. Done

This is not a convenient sequence of steps, though...

Regards, [Ag] gaynor@rutgers.edu

tale@pawl.rpi.edu (David C Lawrence) (03/11/89)

In e-mail, Peter Baer Galvin <galvin-peter@YALE.ARPA> asked the following:

> This is probably a dumb question (which is why I'm mailing it to you
> rather than posting it to the new group :-).  I'd like to set a couple
> of things automatically in each buffer created by a emacsclient
> program.  I'd like auto-fill mode set and a special fill-prefix too.
> I tried
> (setq fundamental-mode-hook 'turn-on-auto-fill)
> (setq fill-prefix "		")

> but the fundamental mode buffer started by emacsclient isn't in text
> mode and has no fill prefix.  If I get this working I'll be very
> happy.  Of course I'd be happied if emacsclient could talk to a remote
> host (since it uses sockets anyway) so I could have one emacs on one
> system and have all other editor-invocations from other systems talk
> to it.  Maybe in the next release, hey :-).

Well, since the answer is non-obvious as near as I can tell (and not
dumb at all), I'll accept the responsibility for bothering the group
with it.  

What Peter has encountered here are two problems: a) the server
provides no hook of it's own for server buffers and b) fundamental
mode calls no hook (that I can find) in and of itself.  Additionally,
if the server visited a file in something other than findamental mode,
your hook wouldn't run anyway (kind of moot, though).

One way around this is to note that server-visit-files is called by
the server process filter to find the buffers for client files.
find-file-hooks is going to be run in it by find-file-noselect so
configuring your find-file-hooks to deal with the server should do
what you want.  The variable client-record is bound in the let
statement which makes up the body of server-visit-files, so the
following should work:

(setq find-file-hooks '(lambda ()
                         (if (boundp 'client-record)
                             (progn
                                (turn-on-auto-fill)
                                (set-fill-prefix "             ")))
                         ;; here you should put whatever else is a 
                         ;; part of your find-file-hooks
                         ))

Through non-rigorous testing on a couple of files here that seems to
do the trick.  Hope it at least points you in the right direction.

Dave

--
      tale@rpitsmts.bitnet, tale%mts@rpitsgw.rpi.edu, tale@pawl.rpi.edu

billo@cadnetix.COM (Bill Oakley) (03/13/89)

On the subject of GNUemacs server/client mode, I have a tool that invokes
$EDITOR with the command:

        $EDITOR +<line number> <filename>.

If EDITOR is set to "emacs" this works fine, but is kind of wasteful.  It
would be better to set EDITOR to "emacsclient", as has been discussed here.
If I do this, however, I first get a buffer/new file of the name
+<line number>, and when I C-# out of it I get the buffer containing
<filename>, with the cursor positioned at line one.  Ideally, I'd like emacs
to recognize the +<line number>, save it, switch to the buffer containing
<filename>, and then execute a goto-line to <line number>.  As a second
choice, I'd like emacs to just ignore the +<line number>.  (I realize this
might screw up filenames beginning with '+', but that's ok.)  Anyway, I've
looked at server.el a little bit, and this seems to be the place to make the
changes, but before I jumped in and tried my hand at it I thought I would see
if anyone has already done something like this.

By the way, I'm running 18.44 (and wishing the systems people would
upgrade to 18.52) on a Sun3 OS3 (soon to be OS4) machine.

Thanks for your help.

Bill Oakley            billo@cadnetix.com
Cadnetix Corporation   ...!{uunet,sunpeaks,boulder}!cadnetix!billo
                       (303) 444-8075 x489

les@chinet.chi.il.us (Leslie Mikesell) (03/13/89)

In article <5132@natmlab.dms.oz> neilc@natmlab.dms.oz (Neil Crellin) writes:

>The client/server work only on Berkeley Unix, since they use the Berkeley
>sockets mechanism for their communication.

At least versions 18.5[12] will work under sysV with FIFOs if you
define HAVE_SVIPC.  You still need a windowing system but it will
work (for example) on the AT&T 3b1 console windows. You can start
the server in one full-screen window, suspend it and go to anther
session where you invoke "emacsclient file(s).  Then you jump back
to the server session where the file will already be open for you.
The same technique should work on other machines that have multiple
virtual consoles or real windowing systems.

Les Mikesell

sft@ihlpa.ihlpa (Scott Thompson) (03/14/89)

The emacs client/server mode does work on SYSV IPC as well.
--
--
  Scott Thompson (IHP 2A-428), AT&T Bell Labs, Naperville, Il. 60566

       VOICE: (312)-416-4236     UUCP: ...!att!ihlpa!sft

scott@cdp.UUCP (03/17/89)

Is it possible to use emacs server/client mode with shl in
System V Release 3?  I'd like to have an emacs in one shell
layer, and access it with emacsclient in the other layers.
I tried to use SYSVIPC and emacsclient hung waiting to
talk to emacs (if I remember correctly).  I'm using 18.52
on release 3.0 for the '386.

-scott
{hplabs,pyramid,arisia.xerox.com}!cdp!scott

les@chinet.chi.il.us (Leslie Mikesell) (03/21/89)

In article <132500001@cdp> scott@cdp.UUCP writes:
>
>Is it possible to use emacs server/client mode with shl in
>System V Release 3?  I'd like to have an emacs in one shell
>layer, and access it with emacsclient in the other layers.
>I tried to use SYSVIPC and emacsclient hung waiting to
>talk to emacs (if I remember correctly).  I'm using 18.52
>on release 3.0 for the '386.

I tried this but could not switch out of the emacs layer.  Emacs
seems to disable the switch character and intercept ^Z to run
a non-interactive subshell.  You can start an interactive shell
and invoke emacsclient there, then emacs will just switch buffers
and load the file in the new buffer.  When you type ctl-x# you
are switched back to the shell buffer and the emacsclient will
exit.  The IPC mechanism should work with shl if you could persuade
emacs to leave the switch character alone (but then you have to
pick a control character to steal from the emacs commands).

msb@ho5cad (Mike Balenger) (03/22/89)

>On the subject of GNUemacs server/client mode, I have a tool that invokes
>$EDITOR with the command:
>
>        $EDITOR +<line number> <filename>.

We got the following code from the net somewhere.  We have it in
server_num.el.  It should replace server.el.  Most of the code is the
same in server.el and server_num.el.  Here's the section from my
.gnuemacs.el:

;; ================================================================
;; client/server set-up
;;
(autoload 'server-edit "server_num" "emacs-client stuff" t)
(autoload 'server-start "server_num" "emacs-client stuff" t)
(global-set-key "\C-x#" 'server-edit)
(server-start)


It works for the above example, but if you try to do the following:

	$EDITOR +1 file1 +2 file2 +3 file3

you effectively get

	$EDITOR +3 file1 +3 file2 +3 file3

Does anyone more versed in lisp have any idea why ALL files whould be
edited at the line number specified for the LAST file?  

I've looked through the sections of code that put the linenumbers and
filenames together in the list, and the sections that take them out of
the list.  They look like the car's and cdr's are correct.  Is the
linenumber variable somehow getting declared as global, thereby
getting overwritten on the last assignment?  (Look in
server-process-filter and server-visit-files for the modifications to
accomodate linenum/filename pairs.)

----------------------------------------------------------------------
<cute quote>            Michael S. Balenger             (201) 949-8789
<cute disclaimer>       AT&T Bell Labs
                        Room 1L-405
msb@ho5cad.att.com      Crawfords Corner Road
att!ho5cad!msb          Holmdel, NJ   07733


cut here
================================================================
================================================================
================================================================
;; server.el     (emacsclient +number filename)
;;

;; Lisp code for GNU Emacs running as server process.
;; Copyright (C) 1986, 1987 Free Software Foundation, Inc.
;; Author William Sommerfeld, wesommer@athena.mit.edu.
;; Changes by peck@sun.com and by rms.

;; This file is part of GNU Emacs.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY.  No author or distributor
;; accepts responsibility to anyone for the consequences of using it
;; or for whether it serves any particular purpose or works at all,
;; unless he says so in writing.  Refer to the GNU Emacs General Public
;; License for full details.

;; Everyone is granted permission to copy, modify and redistribute
;; GNU Emacs, but only under the conditions described in the
;; GNU Emacs General Public License.   A copy of this license is
;; supposed to have been given to you along with GNU Emacs so you
;; can know your rights and responsibilities.  It should be in a
;; file named COPYING.  Among other things, the copyright notice
;; and this notice must be preserved on all copies.


;;; This Lisp code is run in Emacs when it is to operate as
;;; a server for other processes.

;;; Load this library and do M-x server-edit to enable Emacs as a server.
;;; Emacs runs the program ../etc/server as a subprocess
;;; for communication with clients.  If there are no client buffers to edit, 
;;; server-edit acts like (switch-to-buffer (other-buffer))

;;; When some other program runs "the editor" to edit a file,
;;; "the editor" can be the Emacs client program ../etc/emacsclient.
;;; This program transmits the file names to Emacs through
;;; the server subprocess, and Emacs visits them and lets you edit them.

;;; Note that any number of clients may dispatch files to emacs to be edited.

;;; When you finish editing a Server buffer, again call server-edit
;;; to mark that buffer as done for the client and switch to the next 
;;; Server buffer.  When all the buffers for a client have been edited 
;;; and exited with server-edit, the client "editor" will return
;;; to the program that invoked it.  

;;; Your editing commands and Emacs's display output go to and from
;;; the terminal in the usual way.  Thus, server operation is possible
;;; only when Emacs can talk to the terminal at the time you invoke
;;; the client.  This is possible in two cases:

;;; 1. On a window system, where Emacs runs in one window and the
;;; program that wants to use "the editor" runs in another.

;;; 2. When the program that wants to use "the editor" is running
;;; as a subprocess of Emacs.

;;; The buffer local variable "server-buffer-clients" lists 
;;; the clients who are waiting for this buffer to be edited.  
;;; The global variable "server-clients" lists all the waiting clients,
;;; and which files are yet to be edited for each.

(defvar server-program "server"
  "*The program to use as the edit server")

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

(defvar server-clients nil
  "List of current server clients.
Each element is (CLIENTID FILES...) where CLIENTID is a string
that can be given to the server process to identify a client.
When a buffer is marked as \"done\", 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 'server-buffer-clients)
(setq-default server-buffer-clients nil)
(or (assq 'server-buffer-clients minor-mode-alist)
    (setq minor-mode-alist (cons '(server-buffer-clients " Server") minor-mode-alist)))

;; If a *server* buffer exists,
;; write STRING to it for logging purposes.
(defun server-log (string)
  (if (get-buffer "*server*")
      (save-excursion
	(set-buffer "*server*")
	(goto-char (point-max))
	(insert string)
	(or (bobp) (newline)))))

(defun server-sentinel (proc msg)
  (cond ((eq (process-status proc) 'exit)
	 (server-log (message "Server subprocess exited")))
	((eq (process-status proc) 'signal)
	 (server-log (message "Server subprocess killed")))))

(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 your editing commands to this Emacs job.
To use the server, set up the program `etc/emacsclient' in the
Emacs distribution as your standard \"editor\".

Prefix arg means just kill any existing server communications subprocess."
  (interactive "P")
  ;; kill it dead!
  (if server-process
      (progn
	(set-process-sentinel server-process nil)
	(condition-case () (delete-process server-process) (error nil))))
  (condition-case () (delete-file "~/.emacs_server") (error nil))
  ;; If we already had a server, clear out associated status.
  (while server-clients
    (let ((buffer (nth 1 (car server-clients))))
      (server-buffer-done buffer)))
  (if leave-dead
      nil
    (server-log (message "Restarting server"))
    (setq server-process (start-process "server" nil server-program))
    (set-process-sentinel server-process 'server-sentinel)
    (set-process-filter server-process 'server-process-filter)
    (process-kill-without-query server-process)))

;Process a request from the server to edit some files.
;Format of STRING is "Client: CLIENTID PATH PATH PATH... \n"
(defun server-process-filter (proc string)
  (server-log string)
  (if (not (eq 0 (string-match "Client: " string)))
      nil
    (setq string (substring string (match-end 0)))
    (let ((client (list (substring string 0 (string-match " " string))))
	  (filenames nil)
	  (filename nil)
	  (lineno nil))
      (setq string (substring string (match-end 0)))
      (while (string-match "[^ ]+ " string)
	(setq filename
	      (substring string (match-beginning 0) (1- (match-end 0))))
	(if (string-match "/\\(\\+[0-9]+\\)" filename)
	    (progn
	      (setq lineno
		    (string-to-int (substring filename (match-beginning 1))))
	      (string-match "[^ ]* \\([^ ]+\\) " string)
	      (setq filename (substring string
					(match-beginning 1)
					(match-end 1))))
	  (setq lineno 1))
	(setq filenames
	      (cons (list filename lineno)
		    filenames))
	(setq string (substring string (match-end 0))))
      (server-visit-files filenames client)
      ;; CLIENT is now a list (CLIENTNUM BUFFERS...)
      (setq server-clients (cons client server-clients))
      (switch-to-buffer (nth 1 client))
      (message (substitute-command-keys
		"When done with a buffer, type \\[server-edit].")))))

(defun server-visit-files (filenames client)
  "Finds FILES and returns the list CLIENT with the buffers nconc'd."
  (let (client-record)
    (while filenames
      (save-excursion
	;; If there is an existing buffer that's not modified, revert it.
	;; If there is an existing buffer with deleted file, offer to write it.
 	(let* ((filename (car (car filenames)))
	       (lineno (car (cdr (car filenames))))
	       (obuf (get-file-buffer filename)))
 	  (if (and obuf (set-buffer obuf))
 	      (if (file-exists-p filename)
 		  (if (buffer-modified-p obuf) nil
 		    (revert-buffer t nil))
 		(if (y-or-n-p
 		     (concat "File no longer exists: "
 			     filename
 			     ", write buffer to file? "))
 		    (write-file filename)))
	    (set-buffer (find-file-noselect filename))))
	  (goto-line lineno)
  	(setq server-buffer-clients (cons (car client) server-buffer-clients))
  	(setq client-record (cons (current-buffer) client-record)))
        (setq filenames (cdr filenames)))
    (nconc client client-record)))

(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."
  (let ((running (eq (process-status server-process) 'run))
	(next-buffer nil)
	(old-clients server-clients))
    (while old-clients
      (let ((client (car old-clients)))
	(or next-buffer 
	    (setq next-buffer (nth 1 (memq buffer client))))
	(delq buffer client)
	;; If client now has no pending buffers,
	;; tell it that it is done, and forget it entirely.
	(if (cdr client) nil
	  (if running
	      (progn
		(send-string server-process 
			     (format "Close: %s Done\n" (car client)))
		(server-log (format "Close: %s Done\n" (car client)))))
	  (setq server-clients (delq client server-clients))))
      (setq old-clients (cdr old-clients)))
    (if (buffer-name buffer)
	(save-excursion
	  (set-buffer buffer)
	  (setq server-buffer-clients nil)))
    (bury-buffer buffer)
    next-buffer))

(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."
 ;; This may not be appropriately robust for all cases.
  (string= (buffer-name buffer) "draft"))

(defun server-done ()
  "Offer to save current buffer, mark it as \"done\" for clients,
bury it, and return a suggested buffer to select next."
  (let ((buffer (current-buffer)))
    (if server-buffer-clients
	(progn
 	  (if (mh-draft-p buffer)
 	      (progn (save-buffer)
		     (write-region (point-min) (point-max)
				   (concat buffer-file-name "~"))
		     (kill-buffer buffer))
	    (if (and (buffer-modified-p)
		     (y-or-n-p (concat "Save file" buffer-file-name "? ")))
		(save-buffer buffer)))
	  (server-buffer-done buffer)))))

(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")
  (if (or arg
	  (not server-process)
	  (memq (process-status server-process) '(signal exit)))
      (server-start nil)
    (server-switch-buffer (server-done))))

(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."
  (if next-buffer
      (if (and (bufferp next-buffer)
	       (buffer-name next-buffer))
	  (switch-to-buffer next-buffer)
	;; If NEXT-BUFFER is a dead buffer,
	;; remove the server records for it
	;; and try the next surviving server buffer.
	(server-switch-buffer
	 (server-buffer-done next-buffer)))
    (if server-clients
	(server-switch-buffer (nth 1 (car server-clients)))
      (switch-to-buffer (other-buffer)))))

(global-set-key "\C-x#" 'server-edit)
================================================================
================================================================
================================================================