]> git.eshelyaron.com Git - emacs.git/commitdiff
New eglot-ensure to put in a major-mode's hook
authorJoão Távora <joaotavora@gmail.com>
Sun, 10 Jun 2018 12:41:10 +0000 (13:41 +0100)
committerJoão Távora <joaotavora@gmail.com>
Sun, 10 Jun 2018 13:35:48 +0000 (14:35 +0100)
* eglot.el (Commentary): Mention eglo-ensure.
(eglot--connect): Rearrange args.
(eglot--guess-contact): Rename from eglot--interactive.
(eglot): Use eglot--guess-contact.
(eglot, eglot-reconnect): Rearrange call to eglot--connect.
(eglot-ensure): New command to put in mode hook.

* eglot-tests.el (eglot--tests-connect): New helper.
(auto-detect-running-server, auto-reconnect, rls-watches-files)
(rls-basic-diagnostics, rls-hover-after-edit, rls-rename)
(basic-completions, hover-after-completions): Use it.

GitHub-reference: close https://github.com/joaotavora/eglot/issues/17

lisp/progmodes/eglot.el

index 4d3a46970e3b3bf36c716693854357f2436028c1..47352f75234052428c6d466c84bf7a080ee09d04 100644 (file)
 ;; To "unmanage" these buffers, shutdown the server with M-x
 ;; eglot-shutdown.
 ;;
+;; You can also do:
+;;
+;;   (add-hook 'foo-mode-hook 'eglot-ensure)
+;;
+;; To attempt to start an eglot session automatically everytime a
+;; foo-mode buffer is visited.
+;;
 ;;; Code:
 
 (require 'json)
@@ -279,7 +286,7 @@ CONTACT is in `eglot'.  Returns a process object."
 
 (defvar eglot-connect-hook nil "Hook run after connecting in `eglot--connect'.")
 
-(defun eglot--connect (project managed-major-mode contact server-class)
+(defun eglot--connect (managed-major-mode project server-class contact)
   "Connect for PROJECT, MANAGED-MAJOR-MODE and CONTACT.
 INTERACTIVE is t if inside interactive call.  Return an object of
 class SERVER-CLASS."
@@ -331,8 +338,10 @@ class SERVER-CLASS."
 (defvar eglot--command-history nil
   "History of COMMAND arguments to `eglot'.")
 
-(defun eglot--interactive ()
-  "Helper for `eglot'."
+(defun eglot--guess-contact (&optional interactive)
+  "Helper for `eglot'.
+Return (MANAGED-MODE PROJECT CONTACT CLASS).
+If INTERACTIVE, maybe prompt user."
   (let* ((guessed-mode (if buffer-file-name major-mode))
          (managed-mode
           (cond
@@ -349,17 +358,20 @@ class SERVER-CLASS."
          (class (and (consp guess) (symbolp (car guess))
                      (prog1 (car guess) (setq guess (cdr guess)))))
          (program (and (listp guess) (stringp (car guess)) (car guess)))
-         (base-prompt "[eglot] Enter program to execute (or <host>:<port>): ")
+         (base-prompt
+          (and interactive
+               "[eglot] Enter program to execute (or <host>:<port>): "))
          (prompt
-          (cond (current-prefix-arg base-prompt)
-                ((null guess)
-                 (format "[eglot] Sorry, couldn't guess for `%s'\n%s!"
-                         managed-mode base-prompt))
-                ((and program (not (executable-find program)))
-                 (concat (format "[eglot] I guess you want to run `%s'"
-                                 (combine-and-quote-strings guess))
-                         (format ", but I can't find `%s' in PATH!" program)
-                         "\n" base-prompt))))
+          (and base-prompt
+               (cond (current-prefix-arg base-prompt)
+                     ((null guess)
+                      (format "[eglot] Sorry, couldn't guess for `%s'!\n%s"
+                              managed-mode base-prompt))
+                     ((and program (not (executable-find program)))
+                      (concat (format "[eglot] I guess you want to run `%s'"
+                                      (combine-and-quote-strings guess))
+                              (format ", but I can't find `%s' in PATH!" program)
+                              "\n" base-prompt)))))
          (contact
           (if prompt
               (let ((s (read-shell-command
@@ -371,10 +383,10 @@ class SERVER-CLASS."
                     (list (match-string 1 s) (string-to-number (match-string 2 s)))
                   (split-string-and-unquote s)))
             guess)))
-    (list managed-mode project contact class t)))
+    (list managed-mode project class contact)))
 
 ;;;###autoload
-(defun eglot (managed-major-mode project command server-class
+(defun eglot (managed-major-mode project server-class command
                                  &optional interactive)
   "Manage a project with a Language Server Protocol (LSP) server.
 
@@ -405,7 +417,7 @@ SERVER-CLASS is a symbol naming a class that must inherit from
 `eglot-server', or nil to use the default server class.
 
 INTERACTIVE is t if called interactively."
-  (interactive (eglot--interactive))
+  (interactive (append (eglot--guess-contact t) '(t)))
   (let ((current-server (eglot--current-server)))
     (if (and current-server
              (process-live-p (eglot--process current-server))
@@ -415,10 +427,10 @@ INTERACTIVE is t if called interactively."
       (when (and current-server
                  (process-live-p (eglot--process current-server)))
         (ignore-errors (eglot-shutdown current-server)))
-      (let ((server (eglot--connect project
-                                    managed-major-mode
-                                    command
-                                    server-class)))
+      (let ((server (eglot--connect managed-major-mode
+                                    project
+                                    server-class
+                                    command)))
         (eglot--message "Connected! Server `%s' now \
 managing `%s' buffers in project `%s'."
                         (eglot--name server) managed-major-mode
@@ -431,12 +443,34 @@ INTERACTIVE is t if called interactively."
   (interactive (list (eglot--current-server-or-lose) t))
   (when (process-live-p (eglot--process server))
     (ignore-errors (eglot-shutdown server interactive)))
-  (eglot--connect (eglot--project server)
-                  (eglot--major-mode server)
-                  (eglot--contact server)
-                  (eieio-object-class server))
+  (eglot--connect (eglot--major-mode server)
+                  (eglot--project server)
+                  (eieio-object-class server)
+                  (eglot--contact server))
   (eglot--message "Reconnected!"))
 
+(defvar eglot--managed-mode) ;forward decl
+
+(defun eglot-ensure ()
+  "Start Eglot session for current buffer if there isn't one."
+  (let ((buffer (current-buffer)))
+    (cl-labels
+        ((maybe-connect
+          ()
+          (remove-hook 'post-command-hook #'maybe-connect nil)
+          (eglot--with-live-buffer buffer
+            (if eglot--managed-mode
+                (eglot--message "%s is already managed by existing `%s'"
+                                buffer
+                                (eglot--name (eglot--current-server)))
+              (let ((server (apply #'eglot--connect (eglot--guess-contact))))
+                (eglot--message
+                 "Automatically started `%s' to manage `%s' buffers in project `%s'"
+                 (eglot--name server)
+                 major-mode
+                 (eglot--project-nickname server)))))))
+      (add-hook 'post-command-hook #'maybe-connect 'append nil))))
+
 (defun eglot--process-sentinel (proc change)
   "Called when PROC undergoes CHANGE."
   (let ((server (process-get proc 'eglot-server)))