diff --git a/ext/doom/autoload/eglot-booster.el b/ext/doom/autoload/eglot-booster.el new file mode 100644 index 0000000..ec4d0b8 --- /dev/null +++ b/ext/doom/autoload/eglot-booster.el @@ -0,0 +1,124 @@ +;;; eglot-booster.el --- Boost eglot using lsp-booster -*- lexical-binding: t; -*- +;; Copyright (C) 2024 J.D. Smith + +;; Author: J.D. Smith +;; Homepage: https://github.com/jdtsmith/eglot-booster +;; Package-Requires: ((emacs "29.1") (jsonrpc "1.0") (eglot "1.0") (seq "2.24")) +;; Version: 0.0.1 +;; Keywords: convenience, programming +;; Prefix: eglot-booster +;; Separator: - + +;; eglot-booster is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of the +;; License, or (at your option) any later version. + +;; eglot-booster is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; This small minor mode boosts eglot with emacs-lsp-booster. +;; Using it is simple: +;; +;; 1. Download/build a recent emacs-lsp-booster from +;; https://github.com/blahgeek/emacs-lsp-booster using the +;; instructions there. +;; 2. Enable eglot-booster-mode either in your init or, interactively, +;; use M-x eglot-booster-mode. +;; 3. Use eglot like normal. +;; +;; You can disable boosting by turning the minor mode off; any boosted +;; eglot servers will need to be restarted. Note: boosting works only +;; with local lsp servers programs which communicate via standard +;; input/output, not remote or network-port LSP servers. + +;;; Code: +(require 'eglot) +(require 'jsonrpc) + +(defcustom eglot-booster-no-remote-boost nil + "If non-nil, do not boost remote hosts." + :group 'eglot + :type 'boolean) + +(defun eglot-booster-plain-command (com) + "Test if command COM is a plain eglot server command." + (and (consp com) + (not (integerp (cadr com))) + (not (memq :autoport com)))) + +(defvar-local eglot-booster-boosted nil) +(defun eglot-booster--jsonrpc--json-read (orig-func) + "Read JSON or bytecode, wrapping the ORIG-FUNC JSON reader." + (if eglot-booster-boosted ; local to process-buffer + (or (and (= (following-char) ?#) + (let ((bytecode (read (current-buffer)))) + (when (byte-code-function-p bytecode) + (funcall bytecode)))) + (funcall orig-func)) + ;; Not in a boosted process, fallback + (funcall orig-func))) + +(defun eglot-booster--init (server) + "Register eglot SERVER as boosted if it is." + (when-let ((server) + (proc (jsonrpc--process server)) + (com (process-command proc)) + (buf (process-buffer proc))) + (unless (and (file-remote-p default-directory) eglot-booster-no-remote-boost) + (if (file-remote-p default-directory) ; com will likely be /bin/sh -i or so + (when (seq-find (apply-partially #'string-search "emacs-lsp-booster") + (process-get proc 'remote-command)) ; tramp applies this + (with-current-buffer buf (setq eglot-booster-boosted t))) + (when (string-search "emacs-lsp-booster" (car-safe com)) + (with-current-buffer buf (setq eglot-booster-boosted t))))))) + +(defvar eglot-booster--boost + '("emacs-lsp-booster" "--json-false-value" ":json-false" "--")) + +(defun eglot-booster--wrap-contact (args) + "Wrap contact within ARGS if possible." + (let ((contact (nth 3 args))) + (cond + ((and eglot-booster-no-remote-boost (file-remote-p default-directory))) + ((functionp contact) + (setf (nth 3 args) + (lambda (&optional interactive) + (let ((res (funcall contact interactive))) + (if (eglot-booster-plain-command res) + (append eglot-booster--boost res) + res))))) + ((eglot-booster-plain-command contact) + (setf (nth 3 args) (append eglot-booster--boost contact)))) + args)) + +;;;###autoload +(define-minor-mode eglot-booster-mode + "Minor mode which boosts 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." + :global t + :group 'eglot + (cond + (eglot-booster-mode + (unless (executable-find "emacs-lsp-booster") + (setq eglot-booster-mode nil) + (user-error "The emacs-lsp-booster program is not installed")) + (advice-add 'jsonrpc--json-read :around #'eglot-booster--jsonrpc--json-read) + (advice-add 'eglot--connect :filter-args #'eglot-booster--wrap-contact) + (add-hook 'eglot-server-initialized-hook #'eglot-booster--init)) + (t + (advice-remove 'jsonrpc--json-read #'eglot-booster--jsonrpc--json-read) + (advice-remove 'eglot--connect #'eglot-booster--wrap-contact) + (remove-hook 'eglot-server-initialized-hook #'eglot-booster--init)))) + +(provide 'eglot-booster) +;;; eglot-booster.el ends here diff --git a/ext/doom/autoload/lsp-booster.el b/ext/doom/autoload/lsp-booster.el new file mode 100644 index 0000000..8325bf3 --- /dev/null +++ b/ext/doom/autoload/lsp-booster.el @@ -0,0 +1,33 @@ +;;; lsp-booster.el --- Boost emacs-lsp using lsp-booster -*- lexical-binding: t; -*- + +(defun lsp-booster--advice-json-parse (old-fn &rest args) + "Try to parse bytecode instead of json." + (or + (when (equal (following-char) ?#) + (let ((bytecode (read (current-buffer)))) + (when (byte-code-function-p bytecode) + (funcall bytecode)))) + (apply old-fn args))) +(advice-add (if (progn (require 'json) + (fboundp 'json-parse-buffer)) + 'json-parse-buffer + 'json-read) + :around + #'lsp-booster--advice-json-parse) + +(defun lsp-booster--advice-final-command (old-fn cmd &optional test?) + "Prepend emacs-lsp-booster command to lsp CMD." + (let ((orig-result (funcall old-fn cmd test?))) + (if (and (not test?) ;; for check lsp-server-present? + (not (file-remote-p default-directory)) ;; see lsp-resolve-final-command, it would add extra shell wrapper + lsp-use-plists + (not (functionp 'json-rpc-connection)) ;; native json-rpc + (executable-find "emacs-lsp-booster")) + (progn + (message "Using emacs-lsp-booster for %s!" orig-result) + (cons "emacs-lsp-booster" orig-result)) + orig-result))) +(advice-add 'lsp-resolve-final-command :around #'lsp-booster--advice-final-command) + +(provide 'lsp-booster) +;;; lsp-booster.el ends here diff --git a/ext/doom/config.el b/ext/doom/config.el index 1854c7c..2d17837 100644 --- a/ext/doom/config.el +++ b/ext/doom/config.el @@ -131,6 +131,17 @@ :config (global-activity-watch-mode)) +;; lsp-booster + +(use-package lsp-booster + :after lsp) + + +(use-package eglot-booster + :after eglot + :config + (eglot-booster-mode)) + ;; rust (setq! lsp-inlay-hint-enable t) (setq! lsp-rust-analyzer-cargo-run-build-scripts t) diff --git a/flake.lock b/flake.lock index 924f4fe..e78e72f 100644 --- a/flake.lock +++ b/flake.lock @@ -201,6 +201,26 @@ "type": "github" } }, + "emacs-lsp-booster": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1716274896, + "narHash": "sha256-WsyEkdt8ReGQ40+yV4Cb99A2MEmV0O/i6rmFQura5ww=", + "owner": "slotThe", + "repo": "emacs-lsp-booster-flake", + "rev": "7d110295988fc9bf7fd43bb0cabfbe58a4a5ecf8", + "type": "github" + }, + "original": { + "owner": "slotThe", + "repo": "emacs-lsp-booster-flake", + "type": "github" + } + }, "emacs-overlay": { "inputs": { "flake-utils": [ @@ -214,17 +234,17 @@ ] }, "locked": { - "lastModified": 1723799695, - "narHash": "sha256-8W/xxCpwQC9LOnwUO0Q7aGAF463ozaxcwQ6/toqtz0M=", + "lastModified": 1724662747, + "narHash": "sha256-8ehh6fm5C7TRNc3HmTr9KCyi7FqfFR1MqlqdynLKrMA=", "owner": "nix-community", "repo": "emacs-overlay", - "rev": "3b4f8179de2b4950540d70161854e43fe1010eae", + "rev": "3052bb01d404ee9bd03b040c9ae898febca05b81", "type": "github" }, "original": { "owner": "nix-community", "repo": "emacs-overlay", - "rev": "3b4f8179de2b4950540d70161854e43fe1010eae", + "rev": "3052bb01d404ee9bd03b040c9ae898febca05b81", "type": "github" } }, @@ -806,6 +826,7 @@ "inputs": { "chaotic": "chaotic", "disko": "disko", + "emacs-lsp-booster": "emacs-lsp-booster", "emacs-overlay": "emacs-overlay", "envfs": "envfs", "flake-compat": "flake-compat", diff --git a/flake.nix b/flake.nix index 1561e19..f26ff7e 100644 --- a/flake.nix +++ b/flake.nix @@ -61,11 +61,15 @@ inputs.nixpkgs.follows = "nixpkgs"; }; emacs-overlay = { - url = "github:nix-community/emacs-overlay/3b4f8179de2b4950540d70161854e43fe1010eae"; + url = "github:nix-community/emacs-overlay/3052bb01d404ee9bd03b040c9ae898febca05b81"; inputs.flake-utils.follows = "flake-utils"; inputs.nixpkgs-stable.follows = "nixpkgs-stable"; inputs.nixpkgs.follows = "nixpkgs"; }; + emacs-lsp-booster = { + url = "github:slotThe/emacs-lsp-booster-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + }; disko = { url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; @@ -128,6 +132,7 @@ , home-manager , plasma-manager , emacs-overlay + , emacs-lsp-booster , nur , nix-index-database , disko @@ -147,6 +152,7 @@ overlays = [ my-overlay emacs-overlay.overlay + emacs-lsp-booster.overlays.default inputs.nix-alien.overlays.default inputs.nix-ld-rs.overlays.default ]; diff --git a/home-mods/desktop/default.nix b/home-mods/desktop/default.nix index ad14379..a887ed4 100644 --- a/home-mods/desktop/default.nix +++ b/home-mods/desktop/default.nix @@ -9,7 +9,7 @@ }; programs.thunderbird = { enable = true; - package = pkgs.betterbird; + package = pkgs.thunderbird-128; profiles."main" = { isDefault = true; }; diff --git a/home-mods/shell/default.nix b/home-mods/shell/default.nix index 6ad943e..bbe8ebe 100644 --- a/home-mods/shell/default.nix +++ b/home-mods/shell/default.nix @@ -9,14 +9,14 @@ let doomemacsSrc = builtins.fetchGit { url = "https://github.com/doomemacs/doomemacs"; ref = "master"; - rev = "1912571c9cec35d06f869637573e75ec529f6c7c"; + rev = "c862968f4843fa7c30b9dbca688d8e400729196b"; }; neofetchThemesSrc = builtins.fetchGit { url = "https://github.com/Chick2D/neofetch-themes"; ref = "main"; rev = "c7392136bed264258c9b8788b14410e1ff06d602"; }; - myEmacs = (pkgs.emacsPackagesFor pkgs.emacs-pgtk).emacsWithPackages (epkgs: + myEmacs = (pkgs.emacsPackagesFor pkgs.emacs-unstable-pgtk).emacsWithPackages (epkgs: with epkgs; [ vterm treesit-grammars.with-all-grammars @@ -317,6 +317,7 @@ in # TODO Disable gui apps & switch to emacs-git instead of pgtk on headless systems packages = with pkgs; [ myEmacs + emacs-lsp-booster any-nix-shell atool aspell