diff --git a/.gitignore b/.gitignore index 711a60a4e..e24327b02 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,8 @@ python-*-docs-html /recentf .mc-lists.el nov-places +workspace +eclipse.jdt.ls # Private directory private/ diff --git a/layers/+lang/java/README.org b/layers/+lang/java/README.org index 71f1445a1..b22756bed 100644 --- a/layers/+lang/java/README.org +++ b/layers/+lang/java/README.org @@ -24,6 +24,9 @@ - [[#configuration-1][Configuration]] - [[#usage-1][Usage]] - [[#issues][Issues]] + - [[#lsp-java][LSP Java]] + - [[#instalation][Instalation]] + - [[#configuration-2][Configuration]] - [[#key-bindings][Key bindings]] - [[#meghanada-1][Meghanada]] - [[#server][Server]] @@ -58,6 +61,7 @@ - [[#refactoring-2][Refactoring]] - [[#tests-1][Tests]] - [[#repl][REPL]] + - [[#lsp-java-1][LSP Java]] - [[#maven][Maven]] - [[#gradle][Gradle]] @@ -69,6 +73,7 @@ This layer adds support for the Java language. - [[https://github.com/mopemope/meghanada-emacs][Meghanada]] client/server (default), - [[http://eclim.org][Eclim]] client/server, - [[https://ensime.github.io/][ENSIME]] client/server. + - [[https://github.com/emacs-lsp/lsp-java][LSP Java]] client/server. - Each provides: - Auto-completion using company - Linting using flycheck integration @@ -231,6 +236,40 @@ will suffice do the trick. ENSIME is originally built for Scala, so support for java is not complete, in particular refactoring doesn't work. +** LSP Java +LSP Java is the Java adapter for [[https://github.com/emacs-lsp/lsp-mode][LSP Mode]] which is the Emacs client for [[https://github.com/Microsoft/language-server-protocol][Language +Server Protocol]]. + +*** Instalation +Download either [[http://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz][latest]] or [[http://download.eclipse.org/jdtls/snapshots/?d][a specific version]] of Eclipse JDT Language Server +distribution to =~/.emacs.d/eclipse.jdt.ls/server/= + +If you choose to have the server installed in a different directory, set +=lsp-java-server-install-dir= + +If you choose to have the server installed in a different directory, set +=lsp-java-server-install-dir= +On Linux/MacOS you could install/update Eclipse JDT Language Server via running the following commands: + +#+BEGIN_SRC bash + rm -rf ~/.emacs.d/eclipse.jdt.ls/server/ + mkdir -p ~/.emacs.d/eclipse.jdt.ls/server/ + wget http://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz -O /tmp/jdt-latest.tar + tar xf /tmp/jdt-latest.tar -C ~/.emacs.d/eclipse.jdt.ls/server/ +#+END_SRC + +*** Configuration +Specify the list of projects which will be imported in the LSP server. Note that +if project is not imported JDT server will provide only basic java support due +to lack of classpath information. + +#+BEGIN_SRC emacs-lisp +(java :variables java-backend 'lsp + lsp-java--workspace-folders '(list "/path/to/project1" + "/path/to/project2" + ...)) +#+END_SRC + * Key bindings ** Meghanada *** Server @@ -243,7 +282,7 @@ particular refactoring doesn't work. | ~SPC m D k~ | Kill server | | ~SPC m D l~ | Clear server cache | | ~SPC m D p~ | Ping server | - | ~SPC m D r~ | Restarrt server | + | ~SPC m D r~ | Restart server | | ~SPC m D s~ | Start server | | ~SPC m D u~ | Update server | | ~SPC m D v~ | Print version of the server | @@ -522,6 +561,34 @@ particular refactoring doesn't work. | ~SPC m s r~ | send region to the REPL | | ~SPC m s R~ | send region to the REPL and focus the REPL buffer in =insert state= | +** LSP Java + +| Key Binding | Description | +|---------------+---------------------------------------| +| ~SPC m g g~ | Go to definition | +| ~SPC m g r~ | Find references | +| ~SPC m g R~ | Peek references using ~lsp-ui~ | +| ~SPC m g d~ | Goto type definition | +| ~SPC m g a~ | Search type in project | +| ~SPC m g A~ | Search type in project using ~lsp-ui~ | +| ~SPC m h h~ | Describe thing at point | +| ~SPC m e l~ | List project errors/warnings | +| ~SPC m p u~ | Refresh user settings | +| ~SPC m e a~ | Execute code action | +| ~SPC m q r~ | Restart workspace | +| ~SPC m r o i~ | Organize imports | +| ~SPC m r r~ | Rename symbol | +| ~SPC m r a i~ | Add import | +| ~SPC m r a m~ | Add unimplemented methods | +| ~SPC m r c p~ | Create parameter | +| ~SPC m r c f~ | Create field | +| ~SPC m r e c~ | Extract constant | +| ~SPC m r e l~ | Extract local | +| ~SPC m r e m~ | Extract method | +| ~SPC m c c~ | Build project | +| ~SPC m a n~ | Actionable notifications | +| ~SPC m =~ | Format code | + ** Maven | Key Binding | Description | diff --git a/layers/+lang/java/config.el b/layers/+lang/java/config.el index 9b3787dfe..fb64d0fb4 100644 --- a/layers/+lang/java/config.el +++ b/layers/+lang/java/config.el @@ -14,8 +14,8 @@ (spacemacs|define-jump-handlers java-mode) (defvar java-backend 'meghanada - "The backend to use for IDE features. Possible values are `eclim', `ensime' -and `meghanada'.") + "The backend to use for IDE features. Possible values are `eclim', `ensime', + `meghanada' and `lsp'.") (defvar java--ensime-modes '(java-mode) "Modes using ensime. Mainly used to define ENSIME key bindings.") diff --git a/layers/+lang/java/funcs.el b/layers/+lang/java/funcs.el index 297499f7f..a49677aab 100644 --- a/layers/+lang/java/funcs.el +++ b/layers/+lang/java/funcs.el @@ -29,21 +29,24 @@ (pcase java-backend (`meghanada (spacemacs//java-setup-meghanada)) (`eclim (spacemacs//java-setup-eclim)) - (`ensime (spacemacs//java-setup-ensime)))) + (`ensime (spacemacs//java-setup-ensime)) + (`lsp (spacemacs//java-setup-lsp)))) (defun spacemacs//java-setup-company () "Conditionally setup company based on backend." (pcase java-backend (`meghanada (spacemacs//java-setup-meghanada-company)) (`eclim (spacemacs//java-setup-eclim-company)) - (`ensime (spacemacs//java-setup-ensime-company)))) + (`ensime (spacemacs//java-setup-ensime-company)) + (`lsp (spacemacs//java-setup-lsp-company)))) (defun spacemacs//java-setup-flycheck () "Conditionally setup flycheck based on backend." (pcase java-backend (`meghanada (spacemacs//java-setup-meghanada-flycheck)) (`eclim (spacemacs//java-setup-eclim-flycheck)) - (`ensime (spacemacs//java-setup-ensime-flycheck)))) + (`ensime (spacemacs//java-setup-ensime-flycheck)) + (`lsp (spacemacs//java-setup-lsp-flycheck)))) (defun spacemacs//java-setup-flyspell () "Conditionally setup flyspell based on backend." @@ -288,3 +291,36 @@ (when (s-matches? (rx (+ (not space))) (buffer-substring (line-beginning-position) (point))) (delete-horizontal-space t))) + + +;; LSP Java + +(defun spacemacs//java-setup-lsp () + "Setup LSP Java." + (if (configuration-layer/layer-used-p 'lsp) + (progn + (require 'lsp-java) + (require 'company-lsp) + (lsp-java-enable)) + (message "`lsp' layer is not installed, please add `lsp' layer to your dotfile."))) + +(defun spacemacs//java-setup-lsp-company () + "Setup lsp auto-completion." + (if (configuration-layer/layer-used-p 'lsp) + (progn + (spacemacs|add-company-backends + :backends company-lsp + :modes java-mode + :append-hooks nil + :call-hooks t) + (company-mode)) + (message "`lsp' layer is not installed, please add `lsp' layer to your dotfile."))) + +(defun spacemacs//java-setup-lsp-flycheck () + "Setup LSP Java syntax checking." + (if (configuration-layer/layer-used-p 'lsp) + (when (spacemacs/enable-flycheck 'java-mode) + (require 'lsp-ui-flycheck) + (lsp-ui-flycheck-enable nil) + (flycheck-mode)) + (message "`lsp' layer is not installed, please add `lsp' layer to your dotfile."))) diff --git a/layers/+lang/java/packages.el b/layers/+lang/java/packages.el index 4f9b72252..941ab4b15 100644 --- a/layers/+lang/java/packages.el +++ b/layers/+lang/java/packages.el @@ -29,6 +29,7 @@ maven-test-mode (meghanada :toggle (not (version< emacs-version "25.1"))) mvn + (lsp-java :requires lsp-mode lsp-ui company-lsp) org )) @@ -428,6 +429,46 @@ "x:" 'meghanada-run-task)))) +(defun java/init-lsp-java () + (use-package lsp-java + :defer t + :config + (progn + ;; key bindings + (dolist (prefix '(("mc" . "compile") + ("mg" . "goto") + ("mr" . "refactor") + ("mq" . "lsp"))) + (spacemacs/set-leader-keys-for-major-mode 'java-mode + "gg" 'xref-find-definitions + "gr" 'xref-find-references + "gR" 'lsp-ui-peek-find-references + "ga" 'xref-find-apropos + "gA" 'lsp-ui-peek-find-workspace-symbol + "gd" 'lsp-goto-type-definition + "hh" 'lsp-describe-thing-at-point + "el" 'lsp-ui-flycheck-list + "pu" 'lsp-java-update-user-settings + "ea" 'lsp-execute-code-action + "qr" 'lsp-restart-workspace + "roi" 'lsp-java-organize-imports + "rr" 'lsp-rename + "rai" 'lsp-java-add-import + "ram" 'lsp-java-add-unimplemented-methods + "rcp" 'lsp-java-create-parameter + "rcf" 'lsp-java-create-field + "rec" 'lsp-java-extract-to-constant + "rel" 'lsp-java-extract-to-local-variable + "rem" 'lsp-java-extract-method + "cc" 'lsp-java-build-project + "an" 'lsp-java-actionable-notifications + "=" 'lsp-format-buffer) + + (setq lsp-highlight-symbol-at-point nil + lsp-ui-sideline-update-mode 'point + lsp-eldoc-render-all nil + lsp-java-completion-guess-arguments t))))) + (defun java/init-mvn () (use-package mvn :defer t