Skip to content

Instantly share code, notes, and snippets.

@jdtsmith
Last active February 16, 2024 18:17
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdtsmith/d936801a4d7fd981bedf2e59dacd675e to your computer and use it in GitHub Desktop.
Save jdtsmith/d936801a4d7fd981bedf2e59dacd675e to your computer and use it in GitHub Desktop.
eglot-booster: boost eglot with emacs-lsp-booster. ****NOTE: USE THIS PACKAGE INSTEAD: https://github.com/jdtsmith/eglot-booster
;;; eglot-booster.el --- boost eglot using emacs-lsp-booster -*- lexical-binding: t; -*-
;; Copyright (C) 2024 J.D. Smith
;;; Commentary:
;; **UPDATE** This has been superseded by the following package:
;; https://github.com/jdtsmith/eglot-booster
;;
;; Boost eglot with emacs-lsp-booster.
;; 1. Download a recent emacs-lsp-booster from
;; https://github.com/blahgeek/emacs-lsp-booster
;; 2. In the cloned directory, build with cargo (rust):
;; cargo build --release
;; 3. place the target/release/emacs-lsp-booster program somewhere on
;; `exec-path'.
;; 4. M-x eglot-booster
;; 5. Use eglot like normal
;;
;; Note: works only with local lsp servers via standard input/output,
;; not remote LSP servers.
;;; Code:
(eval-when-compile (require 'cl-lib))
(require 'seq)
(require 'eglot)
(require 'jsonrpc)
(defun eglot-booster-plain-command (com)
"Test if command COM is a plain eglot server command."
(and (consp com)
(not (integerp (cadr com)))
(not (seq-intersection '(:initializationOptions :autoport) com))))
(defun eglot-booster ()
"Boost plain eglot server programs with emacs-lsp-booster.
The emacs-lsp-booster program must be compiled and available on
variable `exec-path'. Only local stdin/out based lsp servers can
be boosted."
(interactive)
(unless (executable-find "emacs-lsp-booster")
(user-error "The emacs-lsp-booster program is not installed"))
(if (get 'eglot-server-programs 'lsp-booster-p)
(message "eglot-server-programs already boosted.")
(let ((cnt 0)
(orig-read (symbol-function 'jsonrpc--json-read))
(boost '("emacs-lsp-booster" "--json-false-value" ":json-false" "--")))
(dolist (entry eglot-server-programs)
(cond
((functionp (cdr entry))
(cl-incf cnt)
(let ((fun (cdr entry)))
(setcdr entry (lambda (&rest r) ; wrap function
(let ((res (apply fun r)))
(if (eglot-booster-plain-command res)
(append boost res)
res))))))
((eglot-booster-plain-command (cdr entry))
(cl-incf cnt)
(setcdr entry (append boost (cdr entry))))))
(defalias 'jsonrpc--json-read
(lambda ()
(or (and (= (following-char) ?#)
(let ((bytecode (read (current-buffer))))
(when (byte-code-function-p bytecode)
(funcall bytecode))))
(funcall orig-read))))
(message "Boosted %d eglot-server-programs" cnt))
(put 'eglot-server-programs 'lsp-booster-p t)))
(defun eglot-booster-reset ()
(put 'eglot-server-programs 'lsp-booster-p nil))
(provide 'eglot-booster)
;;; eglot-booster.el ends here
@jdtsmith
Copy link
Author

jdtsmith commented Jan 5, 2024

To evaluate this code, put it in an elisp buffer (like *scratch*) and M-x eval-buffer, or put it somewhere on load-path and (require 'eglot-booster). Do not simply copy this code into your .emacs file (unless you have enabled lexical binding there).

@eclig
Copy link

eclig commented Jan 9, 2024

Hello @jdtsmith, thank you for the nice work! May I suggest using the "advice" mechanism instead of simply overwriting jsonrpc--json-read?

(defun eglot-booster--jsonrpc-handle-bytecode (orig-func)
  "Handle bytecode in the JSON stream.
Necessary for using `emacs-lsp-booster'."
  (if (= (following-char) ?#)
      (let ((bytecode (read (current-buffer))))
        (when (byte-code-function-p bytecode)
          (funcall bytecode)))
    (funcall orig-func)))

(advice-add 'jsonrpc--json-read :around #'eglot-booster--jsonrpc-handle-bytecode)

@jdtsmith
Copy link
Author

jdtsmith commented Jan 9, 2024

Update: I turned this into a tiny package which you should use instead of the gist.

@eclig
Copy link

eclig commented Jan 10, 2024

Awesome, thanks!

@Watynecc
Copy link

Update: I turned this into a tiny package which you should use instead of the gist.

Amazing ! thanks !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment