branch: externals/elpa commit 348917660aab0ecef794561160fd95a0fdf820dd Author: João Távora <joaotav...@gmail.com> Commit: João Távora <joaotav...@gmail.com>
Add a mode-line construct and some minor fanciness --- eglot.el | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 112 insertions(+), 14 deletions(-) diff --git a/eglot.el b/eglot.el index 166f23c..92c1216 100644 --- a/eglot.el +++ b/eglot.el @@ -64,6 +64,9 @@ (eglot--define-process-var eglot--message-mark nil "Point where next unread message starts") +(eglot--define-process-var eglot--short-name nil + "A short name") + (eglot--define-process-var eglot--expected-bytes nil "How many bytes declared by server") @@ -92,25 +95,29 @@ (and timeout-fn `((cl-function ,timeout-fn))))) -(defun eglot--command () - (cdr (assoc major-mode eglot-executables))) +(defun eglot--command (&optional errorp) + (let ((probe (cdr (assoc major-mode eglot-executables)))) + (unless (or (not errorp) + probe) + (eglot--error "Don't know how to start EGLOT for %s buffers" + major-mode)) + probe)) -(defun eglot-new-process (&optional interactive) +(defun eglot-new-process (&optional _interactive) "Starts a new EGLOT process and initializes it" (interactive (list t)) (let ((project (project-current)) - (command (eglot--command))) - (unless command (eglot--error "Cannot work without an LSP executable")) + (command (eglot--command 'errorp))) (unless project (eglot--error "Cannot work without a current project!")) (let ((current-process (eglot--current-process))) (when (and current-process (process-live-p current-process)) (eglot-quit-server current-process 'sync))) - (let ((good-name - (format "EGLOT server (%s)" - (file-name-base - (directory-file-name - (car (project-roots (project-current)))))))) + (let* ((short-name (file-name-base + (directory-file-name + (car (project-roots (project-current)))))) + (good-name + (format "EGLOT server (%s)" short-name))) (with-current-buffer (get-buffer-create (format "*%s inferior*" good-name)) (let* ((proc @@ -123,6 +130,7 @@ :stderr (get-buffer-create (format "*%s stderr*" good-name)))) (inhibit-read-only t)) + (setf (eglot--short-name proc) short-name) (puthash (project-current) proc eglot--processes-by-project) (erase-buffer) (let ((marker (point-marker))) @@ -133,9 +141,7 @@ (let ((inhibit-read-only t)) (insert (format "\n-----------------------------------\n")))) - (eglot--protocol-initialize proc) - (when interactive - (display-buffer (eglot-events-buffer proc)))))))) + (eglot--protocol-initialize proc)))))) (defun eglot-quit-server (process &optional sync) (interactive (list (eglot--current-process))) @@ -246,7 +252,7 @@ buffer)) buffer)))) (when interactive - (pop-to-buffer buffer)) + (display-buffer buffer)) buffer)) (defun eglot--log-event (proc type message) @@ -295,6 +301,10 @@ (defun eglot--next-request-id () (setq eglot--next-request-id (1+ eglot--next-request-id))) +(defun eglot-forget-pending-continuations (process) + (interactive (eglot--current-process)) + (clrhash (eglot--pending-continuations process))) + (defun eglot--call-with-request (process async-p method @@ -389,5 +399,93 @@ (apply #'format format args) :warning)) + + +;;; Mode line +;;; + + +(defface eglot-mode-line + '((t (:inherit font-lock-constant-face :weight bold))) + "Face for package-name in EGLOT's mode line." + :group 'eglot) + +(define-minor-mode eglot-mode + "Minor mode for buffers where EGLOT is possible") + +(defvar eglot-menu) + +(defvar eglot-mode-map (make-sparse-keymap)) + +(easy-menu-define eglot-menu eglot-mode-map "SLY" + `("EGLOT" )) + +(defvar eglot--mode-line-format + `(:eval (eglot--mode-line-format))) + +(put 'eglot--mode-line-format 'risky-local-variable t) + +(defun eglot--mode-line-format () + (let* ((proc (eglot--current-process)) + (name (and proc + (process-live-p proc) + (eglot--short-name proc))) + (pending (and proc + (hash-table-count + (eglot--pending-continuations proc)))) + (format-number (lambda (n) (cond ((and n (not (zerop n))) + (format "%d" n)) + (n "-") + (t "*"))))) + (append + `((:propertize "eglot" + face eglot-mode-line + keymap ,(let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] + eglot-menu) + map) + mouse-face mode-line-highlight + help-echo "mouse-1: pop-up EGLOT menu" + )) + (if name + `(" " + (:propertize + ,name + face eglot-mode-line + keymap ,(let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] 'eglot-events-buffer) + (define-key map [mode-line mouse-2] 'eglot-quit-server) + (define-key map [mode-line mouse-3] 'eglot-new-process) + map) + mouse-face mode-line-highlight + help-echo ,(concat "mouse-1: events buffer\n" + "mouse-2: quit server\n" + "mouse-3: new process")) + "/" + (:propertize + ,(funcall format-number pending) + help-echo ,(if name + (format + "%s pending events outgoing\n%s" + pending + (concat "mouse-1: go to events buffer" + "mouse-3: forget pending continuations")) + "No current connection") + mouse-face mode-line-highlight + face ,(cond ((and pending (cl-plusp pending)) + 'warning) + (t + 'eglot-mode-line)) + keymap ,(let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + 'eglot-events-buffer) + (define-key map [mode-line mouse-3] + 'eglot-forget-pending-continuations) + map))))))) + +(add-to-list 'mode-line-misc-info + `(t + (" [" eglot--mode-line-format "] "))) + (provide 'eglot) ;;; eglot.el ends here