server.el 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. ;; Lisp code for GNU Emacs running as server process.
  2. ;; Copyright (C) 1986, 1987 Free Software Foundation, Inc.
  3. ;; Author William Sommerfeld, wesommer@athena.mit.edu.
  4. ;; Changes by peck@sun.com and by rms.
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is distributed in the hope that it will be useful,
  7. ;; but WITHOUT ANY WARRANTY. No author or distributor
  8. ;; accepts responsibility to anyone for the consequences of using it
  9. ;; or for whether it serves any particular purpose or works at all,
  10. ;; unless he says so in writing. Refer to the GNU Emacs General Public
  11. ;; License for full details.
  12. ;; Everyone is granted permission to copy, modify and redistribute
  13. ;; GNU Emacs, but only under the conditions described in the
  14. ;; GNU Emacs General Public License. A copy of this license is
  15. ;; supposed to have been given to you along with GNU Emacs so you
  16. ;; can know your rights and responsibilities. It should be in a
  17. ;; file named COPYING. Among other things, the copyright notice
  18. ;; and this notice must be preserved on all copies.
  19. ;;; This Lisp code is run in Emacs when it is to operate as
  20. ;;; a server for other processes.
  21. ;;; Load this library and do M-x server-edit to enable Emacs as a server.
  22. ;;; Emacs runs the program ../etc/server as a subprocess
  23. ;;; for communication with clients. If there are no client buffers to edit,
  24. ;;; server-edit acts like (switch-to-buffer (other-buffer))
  25. ;;; When some other program runs "the editor" to edit a file,
  26. ;;; "the editor" can be the Emacs client program ../etc/emacsclient.
  27. ;;; This program transmits the file names to Emacs through
  28. ;;; the server subprocess, and Emacs visits them and lets you edit them.
  29. ;;; Note that any number of clients may dispatch files to emacs to be edited.
  30. ;;; When you finish editing a Server buffer, again call server-edit
  31. ;;; to mark that buffer as done for the client and switch to the next
  32. ;;; Server buffer. When all the buffers for a client have been edited
  33. ;;; and exited with server-edit, the client "editor" will return
  34. ;;; to the program that invoked it.
  35. ;;; Your editing commands and Emacs's display output go to and from
  36. ;;; the terminal in the usual way. Thus, server operation is possible
  37. ;;; only when Emacs can talk to the terminal at the time you invoke
  38. ;;; the client. This is possible in two cases:
  39. ;;; 1. On a window system, where Emacs runs in one window and the
  40. ;;; program that wants to use "the editor" runs in another.
  41. ;;; 2. When the program that wants to use "the editor" is running
  42. ;;; as a subprocess of Emacs.
  43. ;;; The buffer local variable "client-list" lists the clients who are waiting
  44. ;;; for this buffer to be edited. The global variable "server-clients" lists
  45. ;;; all the waiting clients, and which files are yet to be edited for each.
  46. (defvar server-program "server"
  47. "*The program to use as the edit server")
  48. (defvar server-process nil
  49. "the current server process")
  50. (defvar server-clients nil
  51. "List of current server clients.
  52. Each element is (CLIENTID FILES...) where CLIENTID is a string
  53. that can be given to the server process to identify a client.
  54. When a buffer is marked as \"done\", it is removed from this list.")
  55. (defvar server-buffer-clients nil
  56. "List of clientids for clients requesting editing of current buffer.")
  57. (make-variable-buffer-local 'server-buffer-clients)
  58. (setq-default server-buffer-clients nil)
  59. (or (assq 'server-buffer-clients minor-mode-alist)
  60. (setq minor-mode-alist (cons '(server-buffer-clients " Server") minor-mode-alist)))
  61. ;; If a *server* buffer exists,
  62. ;; write STRING to it for logging purposes.
  63. (defun server-log (string)
  64. (if (get-buffer "*server*")
  65. (save-excursion
  66. (set-buffer "*server*")
  67. (goto-char (point-max))
  68. (insert string)
  69. (or (bobp) (newline)))))
  70. (defun server-sentinel (proc msg)
  71. (cond ((eq (process-status proc) 'exit)
  72. (server-log (message "Server subprocess exited")))
  73. ((eq (process-status proc) 'signal)
  74. (server-log (message "Server subprocess killed")))))
  75. (defun server-start (leave-dead)
  76. "Start a server process, killing any existing server first.
  77. Prefix arg means just kill any existing server."
  78. (interactive "P")
  79. ;; kill it dead!
  80. (if server-process
  81. (progn
  82. (set-process-sentinel server-process nil)
  83. (condition-case () (delete-process server-process) (error nil))))
  84. (condition-case () (delete-file "~/.emacs_server") (error nil))
  85. ;; If we already had a server, clear out associated status.
  86. (while server-clients
  87. (let ((buffer (nth 1 (car server-clients))))
  88. (server-buffer-done buffer)))
  89. (if leave-dead nil
  90. (setq server-process (start-process "server" nil server-program))
  91. (set-process-sentinel server-process 'server-sentinel)
  92. (set-process-filter server-process 'server-process-filter)
  93. (process-kill-without-query server-process)
  94. (server-log "Starting server")))
  95. ;Process a request from the server to edit some files.
  96. ;Format of STRING is "Client: CLIENTID PATH PATH PATH... \n"
  97. (defun server-process-filter (proc string)
  98. (server-log string)
  99. (if (not (eq 0 (string-match "Client: " string)))
  100. nil
  101. (setq string (substring string (match-end 0)))
  102. (let ((client (list (substring string 0 (string-match " " string))))
  103. (filenames nil))
  104. (setq string (substring string (match-end 0)))
  105. (while (string-match "[^ ]+ " string)
  106. (setq filenames
  107. (cons (substring string (match-beginning 0) (1- (match-end 0)))
  108. filenames))
  109. (setq string (substring string (match-end 0))))
  110. (server-visit-files filenames client)
  111. ;; CLIENT is now a list (CLIENTNUM BUFFERS...)
  112. (setq server-clients (cons client server-clients))
  113. (switch-to-buffer (nth 1 client))
  114. (message (substitute-command-keys
  115. "When done with a buffer, type \\[server-edit].")))))
  116. (defun server-visit-files (filenames client)
  117. "Finds FILES and returns the list CLIENT with the buffers nconc'd."
  118. (let (client-record)
  119. (while filenames
  120. (save-excursion
  121. (let ((obuf (get-file-buffer (car filenames))))
  122. ;; If there is an existing buffer that's not modified,
  123. ;; revert it--don't ask for confirmation as usually would.
  124. (if (and obuf (not (buffer-modified-p obuf))
  125. (file-exists-p (buffer-file-name obuf)))
  126. (progn
  127. (set-buffer obuf)
  128. (revert-buffer t t))
  129. (set-buffer (find-file-noselect (car filenames)))))
  130. (setq server-buffer-clients (cons (car client) server-buffer-clients))
  131. (setq client-record (cons (current-buffer) client-record)))
  132. (setq filenames (cdr filenames)))
  133. (nconc client client-record)))
  134. (defun server-buffer-done (buffer)
  135. "Mark BUFFER as \"done\" for its client(s).
  136. Buries the buffer, and returns another server buffer
  137. as a suggestion for what to select next."
  138. (let ((running (eq (process-status server-process) 'run))
  139. (next-buffer nil)
  140. (old-clients server-clients))
  141. (while old-clients
  142. (let ((client (car old-clients)))
  143. (or next-buffer
  144. (setq next-buffer (nth 1 (memq buffer client))))
  145. (delq buffer client)
  146. ;; If client now has no pending buffers,
  147. ;; tell it that it is done, and forget it entirely.
  148. (if (cdr client) nil
  149. (if running
  150. (progn
  151. (send-string server-process
  152. (format "Close: %s Done\n" (car client)))
  153. (server-log (format "Close: %s Done\n" (car client)))))
  154. (setq server-clients (delq client server-clients))))
  155. (setq old-clients (cdr old-clients)))
  156. (if (buffer-name buffer)
  157. (save-excursion
  158. (set-buffer buffer)
  159. (setq server-buffer-clients nil)))
  160. (bury-buffer buffer)
  161. next-buffer))
  162. (defun server-done ()
  163. "Offer to save current buffer, mark it as \"done\" for clients,
  164. bury it, and return a suggested buffer to select next."
  165. (let ((buffer (current-buffer)))
  166. (if server-buffer-clients
  167. (progn
  168. (if (string= (buffer-name) "draft")
  169. (progn (save-buffer buffer)
  170. (write-region (point-min) (point-max)
  171. (concat buffer-file-name "~"))
  172. (kill-buffer buffer))
  173. (if (and (buffer-modified-p)
  174. (y-or-n-p (concat "Save file" buffer-file-name "? ")))
  175. (save-buffer buffer)))
  176. (server-buffer-done buffer)))))
  177. (defun server-edit (&optional arg)
  178. "Switch to next server editing buffer; say \"Done\" for current buffer.
  179. If a server buffer is current, it is marked \"done\" and optionally saved.
  180. MH <draft> files are always saved and backed up, no questions asked.
  181. When all of a client's buffers are marked as \"done\", the client is notified.
  182. If there is no server process running, one is started and that's all."
  183. (interactive)
  184. (if (or arg
  185. (not server-process)
  186. (memq (process-status server-process) '(signal exit)))
  187. (server-start nil)
  188. (server-switch-buffer (server-done))))
  189. (defun server-switch-buffer (next-buffer)
  190. "Switch to another buffer, preferably one that has a client.
  191. Arg NEXT-BUFFER is a suggestion; if it is a live buffer, use it."
  192. (if next-buffer
  193. (if (and (bufferp next-buffer)
  194. (buffer-name next-buffer))
  195. (switch-to-buffer next-buffer)
  196. ;; If NEXT-BUFFER is a dead buffer,
  197. ;; remove the server records for it
  198. ;; and try the next surviving server buffer.
  199. (server-switch-buffer
  200. (server-buffer-done next-buffer)))
  201. (if server-clients
  202. (server-switch-buffer (nth 1 (car server-clients)))
  203. (switch-to-buffer (other-buffer)))))
  204. (global-set-key "\C-x#" 'server-edit)