From 9e6442d9370fb00226e62c28a453b571433a6e0e Mon Sep 17 00:00:00 2001 From: Jeremy Dormitzer Date: Thu, 6 Apr 2023 12:51:47 -0400 Subject: [PATCH] Enable eglot to jump-to-def in java class files --- emacs/.emacs.d/config/init-ide.el | 61 +++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/emacs/.emacs.d/config/init-ide.el b/emacs/.emacs.d/config/init-ide.el index 90de730..41b3651 100644 --- a/emacs/.emacs.d/config/init-ide.el +++ b/emacs/.emacs.d/config/init-ide.el @@ -41,6 +41,67 @@ `(html-web-mode . ,(eglot-alternatives '(("vscode-html-language-server" "--stdio") ("html-languageserver" "--stdio"))))) + ;; Support jdtls' ability to jump into class files + (add-to-list 'eglot-server-programs '(java-mode . ("jdtls" :initializationOptions + (:extendedClientCapabilities + (:classFileContentsSupport t))))) + (defun jdt-class-file-name-handler (operation &rest args) + "File name handler for jdtls' `jdt://' URIs." + (cond + ((eq operation 'temporary-file-directory) temporary-file-directory) + ((member operation '(file-remote-p + file-name-case-insensitive-p + make-auto-save-file-name + find-file-backup-name)) nil) + ((member operation '(expand-file-name + directory-file-name + file-truename + file-relative-name + file-name-nondirectory)) (car args)) + (t (let* ((uri (car args)) + (uri-hash (secure-hash 'md5 uri)) + (filename (save-match-data + (string-match "jdt://contents/\\(.*?\\)/\\(.*\\)\.class\\?" uri) + (format "%s.java" + (replace-regexp-in-string "/" "." (match-string 2 uri) t t)))) + (temp-dir (expand-file-name "eglot-jdtls" temporary-file-directory)) + (uri-temp-dir (expand-file-name uri-hash temp-dir)) + (filepath (concat (file-name-as-directory uri-temp-dir) filename)) + (metadata-path (format "%s.%s.metadata" + (file-name-directory filepath) + (file-name-base filepath)))) + (unless (or (file-readable-p filepath) (not (eglot-current-server))) + (let ((contents + (jsonrpc-request (eglot-current-server) + :java/classFileContents + (list :uri uri)))) + (unless (file-directory-p uri-temp-dir) (make-directory uri-temp-dir t)) + (with-temp-file filepath (insert contents)) + (with-temp-file metadata-path (insert uri)))) + (cond + ((eq operation 'file-name-directory) uri-temp-dir) + ((eq operation 'get-file-buffer) (get-buffer filename)) + ((eq operation 'insert-file-contents) + (seq-let (uri visit beg end replace) args + (let ((content (with-temp-buffer + (insert-file-contents filepath nil beg end replace) + (buffer-substring (point-min) (point-max))))) + (insert content) + (when visit + (set-visited-file-name uri t) + (rename-buffer filename) + (set-buffer-modified-p nil) + (read-only-mode)) + (list uri (length content))))) + (t (let ((inhibit-file-name-handlers + (cons 'jdt-class-file-name-handler + (and (eq inhibit-file-name-operation operation) + inhibit-file-name-handlers))) + (inhibit-file-name-operation operation)) + (apply operation args)))))))) + (setq eglot-extend-to-xref t) + (add-to-list 'file-name-handler-alist '("\\`jdt://" . jdt-class-file-name-handler)) + (add-to-list 'auto-mode-alist '("\\`jdt://" . java-mode)) :init (defvar eglot-prefix-map (make-sparse-keymap) "Prefix keymap for eglot commands.")