187 lines
7.4 KiB
EmacsLisp
187 lines
7.4 KiB
EmacsLisp
;; -*- lexical-binding: t; -*-
|
|
|
|
;; IDE features
|
|
|
|
;; Company-mode provides inline autocompletion
|
|
(use-package company
|
|
:hook (after-init . global-company-mode)
|
|
:config
|
|
(setq tab-always-indent 'complete)
|
|
(evil-collection-company-setup)
|
|
(general-def company-active-map "RET" #'company-complete-selection)
|
|
:custom
|
|
(company-idle-delay 0.3)
|
|
:general
|
|
([remap indent-for-tab-command] #'company-indent-or-complete-common)
|
|
([remap c-indent-line-or-region] #'company-indent-or-complete-common))
|
|
|
|
;; Quick file overview for supported modes
|
|
(use-package imenu
|
|
:straight (:type built-in)
|
|
:general
|
|
(leader-map "m" #'imenu))
|
|
|
|
;; Find definition/references
|
|
(use-package xref
|
|
:straight (:type built-in)
|
|
:config
|
|
(evil-collection-xref-setup)
|
|
:general
|
|
(normal "M-," #'xref-pop-marker-stack)
|
|
(normal "M-r" #'xref-find-references)
|
|
:custom
|
|
(xref-prompt-for-identifier nil))
|
|
|
|
(use-package eglot
|
|
:commands (eglot)
|
|
:config
|
|
(add-to-list 'eglot-server-programs
|
|
'(js-web-mode . ("typescript-language-server" "--stdio")))
|
|
(add-to-list 'eglot-server-programs
|
|
`(html-web-mode . ,(eglot-alternatives
|
|
'(("vscode-html-language-server" "--stdio")
|
|
("html-languageserver" "--stdio")))))
|
|
;; Custom eglot java server for deeper customization
|
|
(defclass eglot-java-server (eglot-lsp-server) ()
|
|
:documentation "Eglot integration with JDTLS.")
|
|
(add-to-list 'eglot-server-programs
|
|
'(java-mode .
|
|
(eglot-java-server .
|
|
("jdtls" :initializationOptions
|
|
(:extendedClientCapabilities
|
|
(:classFileContentsSupport t)
|
|
:runtimes [(:name "JavaSE-11"
|
|
:path "/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk")
|
|
(:name "JavaSE-17"
|
|
:path "/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk"
|
|
:default t)])))))
|
|
;; Fix JDTLS's weird handling of workspaceEdit
|
|
(cl-defmethod eglot-execute-command
|
|
((_server eglot-java-server) (_cmd (eql java.apply.workspaceEdit)) arguments)
|
|
"Eclipse JDT breaks spec and replies with edits as arguments."
|
|
(mapc #'eglot--apply-workspace-edit arguments))
|
|
;; Support jdtls' ability to jump into class files
|
|
(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))
|
|
;; Java build command
|
|
(defun eglot-java-maven-build ()
|
|
(interactive)
|
|
(if-let ((pom-path (locate-dominating-file default-directory "pom.xml")))
|
|
(let ((pom-uri (eglot--path-to-uri pom-path)))
|
|
(jsonrpc-notify
|
|
(eglot--current-server-or-lose)
|
|
:java/projectConfigurationUpdate
|
|
(list :uri pom-uri))
|
|
(jsonrpc-notify
|
|
(eglot--current-server-or-lose)
|
|
:java/buildWorkspace
|
|
'((:json-false))))
|
|
(user-error "This doesn't appear to be a Maven project, could not find pom.xml.")))
|
|
:init
|
|
(defvar eglot-prefix-map (make-sparse-keymap)
|
|
"Prefix keymap for eglot commands.")
|
|
(general-def eglot-prefix-map
|
|
"a" #'eglot-code-actions
|
|
"r" #'eglot-reconnect
|
|
"s" #'eglot-shutdown
|
|
"R" #'eglot-rename
|
|
"f" #'eglot-format-buffer
|
|
"i" #'eglot-code-action-organize-imports
|
|
"h" #'eldoc
|
|
"e" #'flymake-show-buffer-diagnostics
|
|
"E" #'flymake-show-project-diagnostics)
|
|
:general
|
|
(eglot-mode-map "C-c l" `(,eglot-prefix-map :which-key "eglot"))
|
|
:hook
|
|
(java-mode . eglot-ensure)
|
|
(rust-mode . eglot-ensure)
|
|
(js-mode . eglot-ensure)
|
|
(typescript-mode . eglot-ensure)
|
|
(python-mode . eglot-ensure)
|
|
(js-web-mode . eglot-ensure)
|
|
(html-web-mode . eglot-ensure)
|
|
(scala-mode . eglot-ensure)
|
|
(c-mode . eglot-ensure))
|
|
|
|
;; Some compilation-mode conveniences
|
|
(use-package compile
|
|
:straight (:type built-in)
|
|
:commands compile
|
|
:config
|
|
(evil-collection-compile-setup)
|
|
(defun postprocess-compilation-buffer ()
|
|
(goto-char compilation-filter-start)
|
|
(when (looking-at "\033c")
|
|
(delete-region (point-min) (match-end 0)))
|
|
(ansi-color-apply-on-region (point) (point-max)))
|
|
(add-hook 'compilation-filter-hook 'postprocess-compilation-buffer))
|
|
|
|
;; Code formatting library
|
|
(use-package apheleia
|
|
:straight (apheleia :host github :repo "raxod502/apheleia")
|
|
:general
|
|
("C-c f" #'apheleia-format-buffer))
|
|
|
|
;; Debugger interface
|
|
(use-package realgud
|
|
:defer t
|
|
:config
|
|
(evil-collection-realgud-setup))
|
|
|
|
(provide 'init-ide)
|