diff options
| author | venomade <venomade@venomade.com> | 2026-01-18 16:07:54 +0000 |
|---|---|---|
| committer | venomade <venomade@venomade.com> | 2026-01-18 16:07:54 +0000 |
| commit | 8d688d1107c46b6dfdcaf02fa5c9c4c8a4640e65 (patch) | |
| tree | 76edfeb78094eb8491b1f32a2acd45b6ba95ffa2 /.emacs.d/pkg/consult-jdt.el | |
| parent | edcf5dd381c26274a939f4e703539b15c0058e99 (diff) | |
KDE & Emacs
Diffstat (limited to '.emacs.d/pkg/consult-jdt.el')
| -rw-r--r-- | .emacs.d/pkg/consult-jdt.el | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/.emacs.d/pkg/consult-jdt.el b/.emacs.d/pkg/consult-jdt.el new file mode 100644 index 0000000..6959f72 --- /dev/null +++ b/.emacs.d/pkg/consult-jdt.el @@ -0,0 +1,105 @@ +(require 'consult) +(require 'eglot) +(require 'jsonrpc) +(require 'subr-x) + +(defvar eglot-jdt--symbolkind-map + '((1 . "File") (2 . "Module") (3 . "Namespace") (4 . "Package") + (5 . "Class") (6 . "Method") (7 . "Property") (8 . "Field") + (9 . "Constructor") (10 . "Enum") (11 . "Interface") (12 . "Function") + (13 . "Variable") (14 . "Constant") (15 . "String") (16 . "Number") + (17 . "Boolean") (18 . "Array") (19 . "Object") (20 . "Key") + (21 . "Null") (22 . "EnumMember") (23 . "Struct") (24 . "Event") + (25 . "Operator") (26 . "TypeParameter")) + "Mapping of LSP SymbolKind integers to human-readable names.") + +(defun eglot-jdt--get (obj key) + "Robustly retrieve KEY from LSP OBJ (plist/alist)." + (let* ((kname (substring (symbol-name key) 1)) + (sym-key (intern kname))) + (or (plist-get obj key) + (alist-get key obj) + (alist-get sym-key obj) + (alist-get kname obj)))) + +(defun eglot-jdt--fetch-symbols (&optional query) + "Synchronously fetch workspace symbols for QUERY from Eglot/JDTLS." + (unless (eglot-managed-p) + (user-error "Eglot is not managing this buffer")) + (let* ((server (eglot-current-server)) + (symbols (jsonrpc-request server :workspace/symbol `(:query ,(or query ""))))) + (when (vectorp symbols) + (setq symbols (append symbols nil))) + symbols)) + +;; Helper to pad strings +(defun eglot-jdt--pad-right (str width) + "Pad STR on the right with spaces to WIDTH." + (let ((len (length str))) + (if (< len width) + (concat str (make-string (- width len) ?\s)) + str))) + +;; Main formatting function with faces +(defun eglot-jdt--format-symbols-table (symbols) + "Format SYMBOLS into a table with faces for Consult, showing Kind first." + (let* ((rows (mapcar (lambda (sym) + (let ((kind-num (eglot-jdt--get sym :kind))) + (list (or (alist-get kind-num eglot-jdt--symbolkind-map) + (format "Kind %s" kind-num)) + (eglot-jdt--get sym :name) + (or (eglot-jdt--get sym :containerName) "<no-package>") + (let ((location (eglot-jdt--get sym :location))) + (eglot-jdt--get location :uri))))) + symbols)) + ;; compute max width for each column + (max-kind (apply #'max (mapcar (lambda (r) (length (nth 0 r))) rows))) + (max-name (apply #'max (mapcar (lambda (r) (length (nth 1 r))) rows))) + (max-package (apply #'max (mapcar (lambda (r) (length (nth 2 r))) rows))) + ;; faces + (divider-face 'shadow) ;; low opacity / dim for dividers + (kind-face 'font-lock-function-name-face) + (name-face 'font-lock-variable-name-face) + (package-face 'font-lock-keyword-face)) + ;; create table rows with faces + (mapcar (lambda (r) + (let* ((kind (propertize (eglot-jdt--pad-right (nth 0 r) max-kind) 'face kind-face)) + (name (propertize (eglot-jdt--pad-right (nth 1 r) max-name) 'face name-face)) + (package (propertize (eglot-jdt--pad-right (nth 2 r) max-package) 'face package-face)) + (divider (propertize "|" 'face divider-face))) + (cons (format "%s %s %s %s %s" + kind divider name divider package) + (nth 3 r)))) + rows))) + +(defun eglot-jdt--open-uri (uri) + "Open a URI returned by the language server, handling jdt:// URIs." + (if (and uri (string-prefix-p "jdt://" uri)) + (find-file (expand-file-name uri)) ; your jdt-file-name-handler takes care of this + (find-file (eglot-uri-to-path uri)))) + +(defun eglot-jdt--sort-by-query (symbols query) + "Sort SYMBOLS by how closely their names match QUERY." + (let ((query (or query ""))) + (sort symbols + (lambda (a b) + (< (string-distance (eglot-jdt--get a :name) query) + (string-distance (eglot-jdt--get b :name) query)))))) + +(defun consult-eglot-jdt-symbols (&optional query) + "Consult interface for Java workspace symbols via Eglot/JDTLS. +Sorts results based on closeness to QUERY." + (interactive "sSymbol query (blank for all): ") + (let* ((symbols (eglot-jdt--fetch-symbols query)) + (sorted-symbols (eglot-jdt--sort-by-query symbols query)) + (candidates (eglot-jdt--format-symbols-table sorted-symbols)) + (selection (consult--read + (mapcar #'car candidates) + :prompt "Symbol: " + :sort nil + :require-match t + :category 'symbol))) + (when selection + (let ((uri (cdr (assoc selection candidates)))) + (when uri + (eglot-jdt--open-uri uri)))))) |
