#env

Configurando Emacs como Java IDE

IntelliJ, Android Studio e outras IDEs são extremamente poderosas, isso é fato. Mas muitas vezes queremos leveza, um ambiente produtivo sem dezenas de features que levam minutos para carregar.

Um ambiente onde nos permite abrir o editor o mais rápido possível e apenas começar a programar!

No Emacs, podemos usar um servidor de linguagem (LSP) para ter o mínimo de IntelliSense disponível no editor. Assim como o IntelliJ, Eclipse e outras IDEs fazem.

Ele funciona graças ao frontend eglot que já vem junto com o Emacs.

Vou mostrar um exemplo de configuração no MacOS, contudo vai funcionar também em outros sistemas operacionais, desde que você tenha o jdtls em seu computador e apontando corretamente o caminho dele no script que irei mostrar no decorrer deste post.

Instalando o Java Language Server

Com o Homebrew, instale com o jdtls com o comando

brew install jdtls.

Encontre o caminho de instalação com o brew --prefix jdtls.

Se estiver em outro sistema operacional, baixe o language server diretamente do repositório oficial do jdtls.

Script jdtls

Dentro do dotfiles você encontra o script start-jdtls.sh que irá inicializar o servidor de linguagem Java a partir do workspace definido como argumento.

Os parâmetros está configurado para o ambiente macOS. Logo, adapte o JDTLS_HOME para o seu sistema operacional e o -configuration se necessário.

Ainda não deu tempo de deixar o script cross-platform, uso macOS 90% do tempo. Sorry!

O workspace será encontrado automaticamente pelo Emacs a partir do diretório do projeto que contenha a estrutura base com um dos arquivos na raiz: .project, .classpath, pom.xml ou build.gradle.

Ou seja, se o projeto estiver na estrutura correta ele irá carregar automaticamente e iniciar o E-glot com LSP.

Coloque o script start-jdtls.sh na HOME, seja com link simbólico ou copiando para o caminho ~/.start-jdtls.sh - note que está oculto com ponto (.) no diretório HOME.

Faça o mesmo para o .emacs e .emacs.d.

.emacs

Caso não utilize o meu .emacs, você pode configurar no seu próprio. Eu extrai somente as partes relevantes para o ambiente Java IDE no Emacs.

O gerenciador de pacotes que utilizo é o use-package.

Instale também o company para o autocomplete.

Garanta que o java esteja instalado corretamente e que o Emacs possa encontrá-lo em seu JAVA_HOME.

Por aqui eu utilizo o java 21.

;;
;; .emacs (coloque no ~/.emacs)
;;
(setq taguiar-jdtls-script "~/.start-jdtls.sh")

(use-package eglot
  :config
  (setq eldoc-echo-area-use-multiline-p nil)
  (setq eglot-events-buffer-size 0)
  (add-hook 'eglot-managed-mode-hook (lambda () (eglot-inlay-hints-mode -1)))  ;; disable param hint
  :config
  (add-to-list 'eglot-server-programs
               `(java-mode . ,#'my-jdtls-command)))


;; auto complete com company
(add-hook 'java-mode-hook 'global-company-mode)


(defun my-java-project-root ()
  (or
   (locate-dominating-file default-directory ".project")
   (locate-dominating-file default-directory ".classpath")
   (locate-dominating-file default-directory "pom.xml")
   (locate-dominating-file default-directory "build.gradle")
   default-directory))


(defun my-jdtls-command (&rest _)
  (let* ((root (my-java-project-root))
         (project-name (file-name-nondirectory
                        (directory-file-name root)))
         (workspace (expand-file-name
                     (concat "~/.jdtls-workspace/" project-name))))

    (message "------------------------------")
    (message "[JDTLS] Root: %s" root)
    (message "[JDTLS] Project: %s" project-name)
    (message "[JDTLS] Workspace: %s" workspace)
    (message "[JDTLS] Default dir (before): %s" default-directory)

    (make-directory workspace t)

    (message "[JDTLS] Starting server...")

    (list (expand-file-name taguiar-jdtls-script) workspace)))


(defun my-eglot-java-init ()
  (let ((project-root (my-java-project-root)))
    (when project-root
      (setq default-directory project-root))
    (eglot-ensure)))

(add-hook 'java-mode-hook #'my-eglot-java-init)

;; format Java code after save
(add-hook 'java-mode-hook
          (lambda ()
            (add-hook 'before-save-hook #'eglot-format-buffer nil t)))

Veja um exemplo de projeto Java com a estrutura básica (usando maven ou gradle o lsp encontrará automaticamente também).

root
├── .classpath
├── .project
└── src
    └── dev
        └── tiagoaguiar
            └── projeto
                └── App.java

Meu Acesso Rápido

  • Baixar o jdtls com homebrew
  • Clonar o dotfiles
  • Criar links simbólicos para ~/.emacs, ~/.emacs.d, ~/.start-jdtls.sh
  • Estruturar projeto java com .project e .classpath na raiz