Enable eglot to jump-to-def in java class files

This commit is contained in:
Jeremy Dormitzer 2023-04-06 12:51:47 -04:00
parent 24177998de
commit 9e6442d937

View File

@ -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.")