-;;; server.el --- Lisp code for GNU Emacs running as server process.
+;;; server.el --- Lisp code for GNU Emacs running as server process
-;; Copyright (C) 1986, 87, 92, 94, 95, 96, 97, 98, 99, 2000
+;; Copyright (C) 1986, 87, 92, 94, 95, 96, 97, 98, 99, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: William Sommerfeld <wesommer@athena.mit.edu>
:type '(repeat function))
(defvar server-process nil
- "the current server process")
+ "The current server process")
(defvar server-previous-string "")
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.")
+ "List of client ids for clients requesting editing of current buffer.")
(make-variable-buffer-local 'server-buffer-clients)
;; Changing major modes should not erase this local.
(put 'server-buffer-clients 'permanent-local t)
(setq minor-mode-alist (cons '(server-buffer-clients " Server") minor-mode-alist)))
(defvar server-existing-buffer nil
- "Non-nil means a server buffer existed before visiting a file.")
+ "Non-nil means a buffer existed before the Emacs server was asked visit it.
+This means that the server should not kill the buffer when you say you
+are done with it in the server. This variable is local in each buffer
+where it is set.")
(make-variable-buffer-local 'server-existing-buffer)
;; If a *server* buffer exists,
default-file-name-coding-system)))
client nowait
(files nil)
- (lineno 1))
+ (lineno 1)
+ (columnno 0))
;; Remove this line from STRING.
(setq string (substring string (match-end 0)))
(if (string-match "^Error: " request)
(setq request (substring request (match-end 0)))
(if (string-match "\\`-nowait" arg)
(setq nowait t)
- (if (string-match "\\`\\+[0-9]+\\'" arg)
- ;; ARG is a line number option.
- (setq lineno (read (substring arg 1)))
+ (cond
+ ;; ARG is a line number option.
+ ((string-match "\\`\\+[0-9]+\\'" arg)
+ (setq lineno (string-to-int (substring arg 1))))
+ ;; ARG is line number:column option.
+ ((string-match "\\`+\\([0-9]+\\):\\([0-9]+\\)\\'" arg)
+ (setq lineno (string-to-int (match-string 1 arg))
+ columnno (string-to-int (match-string 2 arg))))
+ (t
;; ARG is a file name.
;; Collapse multiple slashes to single slashes.
(setq arg (command-line-normalize-file-name arg))
(if coding-system
(setq arg (decode-coding-string arg coding-system)))
(setq files
- (cons (list arg lineno)
+ (cons (list arg lineno columnno)
files))
- (setq lineno 1)))))
+ (setq lineno 1)
+ (setq columnno 0))))))
+ (run-hooks 'pre-command-hook)
(server-visit-files files client nowait)
+ (run-hooks 'post-command-hook)
;; CLIENT is now a list (CLIENTNUM BUFFERS...)
(if (null (cdr client))
;; This client is empty; get rid of it immediately.
(defun server-visit-files (files client &optional nowait)
"Finds FILES and returns the list CLIENT with the buffers nconc'd.
-FILES is an alist whose elements are (FILENAME LINENUMBER).
+FILES is an alist whose elements are (FILENAME LINENUMBER COLUMNNUMBER).
NOWAIT non-nil means this client is not waiting for the results,
so don't mark these buffers specially, just visit them normally."
;; Bind last-nonmenu-event to force use of keyboard, not mouse, for queries.
(obuf (get-file-buffer filen)))
(push filen file-name-history)
(if (and obuf (set-buffer obuf))
- (cond ((file-exists-p filen)
- (if (or (not (verify-visited-file-modtime obuf))
- (buffer-modified-p obuf))
- (revert-buffer t nil)))
- (t
- (if (y-or-n-p
- (concat "File no longer exists: "
- filen
- ", write buffer to file? "))
- (write-file filen))))
+ (progn
+ (cond ((file-exists-p filen)
+ (if (or (not (verify-visited-file-modtime obuf))
+ (buffer-modified-p obuf))
+ (revert-buffer t nil)))
+ (t
+ (if (y-or-n-p
+ (concat "File no longer exists: "
+ filen
+ ", write buffer to file? "))
+ (write-file filen))))
+ (setq server-existing-buffer t)
+ (goto-line (nth 1 (car files))))
(set-buffer (find-file-noselect filen))
- (setq server-existing-buffer t)
+ (goto-line (nth 1 (car files)))
+ (let ((column-number (nth 2 (car files))))
+ (when (> column-number 0)
+ (move-to-column (1- column-number))))
(run-hooks 'server-visit-hook)))
- (goto-line (nth 1 (car files)))
(if (not nowait)
(setq server-buffer-clients
(cons (car client) server-buffer-clients)))
(unless for-killing
(when (and (not killed)
server-kill-new-buffers
- (save-excursion
- (set-buffer buffer)
- server-existing-buffer))
+ (with-current-buffer buffer
+ (not server-existing-buffer)))
(setq killed t)
(bury-buffer buffer)
(kill-buffer buffer))
(defun server-done ()
"Offer to save current buffer, mark it as \"done\" for clients.
-This buries the buffer, then returns a list of the form (NEXT-BUFFER KILLED).
-NEXT-BUFFER is another server buffer, as a suggestion for what to select next,
-or nil. KILLED is t if we killed BUFFER
-\(typically, because it was visiting a temp file)."
+This kills or buries the buffer, then returns a list
+of the form (NEXT-BUFFER KILLED). NEXT-BUFFER is another server buffer,
+as a suggestion for what to select next, or nil.
+KILLED is t if we killed BUFFER, which happens if it was created
+specifically for the clients and did not exist before their request for it."
(let ((buffer (current-buffer)))
(if server-buffer-clients
(progn
(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.
+The buffer is also killed if it did not exist before the clients asked for it.
When all of a client's buffers are marked as \"done\", the client is notified.
Temporary files such as MH <draft> files are always saved and backed up,
(if (window-minibuffer-p (selected-window))
(select-window (next-window nil 'nomini 0)))
;; Move to a non-dedicated window, if we have one.
- (select-window (some-window (lambda (w) (not (window-dedicated-p w)))
- 'nomini 'visible (selected-window)))
+ (when (window-dedicated-p (selected-window))
+ (select-window (get-window-with-predicate
+ (lambda (w) (not (window-dedicated-p w)))
+ 'nomini 'visible (selected-window))))
(set-window-dedicated-p (selected-window) nil)
(if next-buffer
(if (and (bufferp next-buffer)
(switch-to-buffer (other-buffer))))))
(global-set-key "\C-x#" 'server-edit)
+
+(defun server-unload-hook ()
+ (remove-hook 'kill-buffer-query-functions 'server-kill-buffer-query-function)
+ (remove-hook 'kill-emacs-query-functions 'server-kill-emacs-query-function)
+ (remove-hook 'kill-buffer-hook 'server-kill-buffer))
\f
(provide 'server)