Annotation of 43BSDReno/contrib/emacs-18.55/lisp/server.el, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.