J'ai un LSP et j'ai essayé de créer un environnement pour écrire Java avec Vim (NeoVim), mais je n'ai pas pu battre l'IDE ...

Je pense que c'était il y a environ un an, mais j'ai utilisé eclim pour créer un environnement de développement Java avec NeoVim.

Cet eclim est assez performant car il démarre Eclipse en arrière-plan et fournit un environnement de développement Java, mais il nécessite un espace de travail comme Eclipse, et Eclipse démarre en arrière-plan, donc il est lourd même s'il s'agit de Vim, l'installation est Il y avait de nombreuses parties douloureuses, comme être ennuyeuses et difficiles à automatiser, alors je les ai effacées presque sans utilisation.

Donc, après tout, j'utilisais l'EDI lors de l'écriture de Java, mais il y a récemment un LSP Java appelé eclipse.jdt.ls. j'ai trouvé

Pour moi lors de la campagne de remplacement de l'environnement de développement par LSP

"Cela ressemble au programme officiel d'éclipse, et il semble que la construction de l'environnement puisse être automatisée, et cela a gagné (chi blanc)"

J'ai essayé de créer un environnement avec un sentiment similaire.

Après tout, je ne pouvais pas battre l'IDE, mais j'en étais satisfait, alors je vais vous le présenter.

J'utilise NeoVim, mais je devrais être capable de créer un environnement avec un Vim normal de la même manière.

En premier lieu ... Qu'est-ce que LSP?

LSP est une abréviation de `Language Server Protocol ', qui est une spécification publiée par Microsoft en juin 2016.

Qu'est-ce que c'est exactement? Il définit des spécifications communes pour fournir des fonctions telles que la complétion de code et l'analyse des erreurs requises pour l'EDI en tant que services.

En normalisant les spécifications de cette manière, la fonction IDE peut être utilisée dans n'importe quel environnement tant qu'il existe une implémentation du langage LSP et que l'éditeur utilisé a un client LSP.

LSP est décrit en détail dans cet article, et les spécifications sont publiées sur le site officiel et GitHub, donc si vous êtes intéressé, jetez un œil.

De plus, l'implémentation pour chaque langue et le client pour chaque éditeur sont résumés ci-dessous.

Dans cette construction d'environnement, j'ai essayé de créer un environnement de développement Java en utilisant ʻeclipse.jdt.ls, qui est l'implémentation Java de ce LSP, et LanguageClient-neovim`, qui est le client LSP de NeoVim.

Voici quelques-uns des outils les plus cool que j'ai utilisés cette fois!

dein.vim Celui qui ne connaît pas cette personne serait Moguri (auto-examen), un outil de gestion de plug-in développé par Shougo, également connu sous le nom de Dark Minou. Il est introduit à divers endroits et l'explication est omise.

Veuillez consulter ici pour plus de détails.

deoplete.nvim Un plug-in de complétion de code également développé par Shougo. Je n'ai pas besoin d'en parler maintenant non plus. (adapté)

Je jetterai les détails dans un autre article.

eclipse.jdt.ls Implémentation Java de LSP mentionnée ci-dessus. Le rôle principal de cette époque, partie 1. Quand NeoVim démarre, il démarre automatiquement, et en échangeant des messages avec LanguageClient-neovim, qui sera décrit plus tard, c'est un type haineux qui souffle le vent de l'IDE dans NeoVim.

La vitesse de démarrage et l'utilisation de la mémoire sont bien meilleures qu'eclim, et l'installation est assez facile à automatiser pour le moment.

LanguageClient-neovim Client NeoVim de LSP mentionné ci-dessus. Le rôle principal de cette fois, partie 2.

La complétion du code, le format du code, la vérification de la syntaxe, l'affichage du document, le saut de source de définition, etc., ce qui semble être le minimum nécessaire pour le codage peut être fait en préparant ce gars et LSP pour chaque langue, le meilleur squid guy ..

Dans mon cas, je n'utilise pas de vérification de syntaxe et de format de code car je laisse un autre plug-in le faire.

Il y a aussi vim-lsp développé par un employé MS (je pense que je l'ai entendu quelque part), mais il prend en charge deoplete. J'utilise ça. La plupart des stars sur GitHub sont Language Client-neovim.

Au fait, le nom dit «neovim», mais il semble qu'il puisse être utilisé avec des vim ordinaires. Je n'ai pas essayé.

ale.vim Un plug-in qui effectue des vérifications de syntaxe de manière asynchrone pendant le codage.

** Image Image ** ale.vim

LanguageClient-neovim a une fonction similaire, mais j'utilise ce plug-in dans le but d'unifier car j'utilise des langages qui ne prennent pas en charge LSP.

Vous pouvez également personnaliser l'outil de vérification à votre guise.

Dans le cas de Java, il semble que le standard utilise javac et google-java-format (décrit plus loin) [^ 1] pour effectuer la vérification de la syntaxe. [^ 1]: La vérification avec google-java-format est exécutée uniquement lorsque l'outil est installé.

vim-autoformat Un plug-in qui vous permet de spécifier un outil de formatage pour le formatage du code. Certains formateurs par défaut sont définis en fonction du type de fichier, et ils sont exécutés à moins que le formateur ne soit spécifié.

Il existe une fonction similaire dans ʻale.vim`, mais j'utilise ce plug-in depuis longtemps et il est toujours utilisé.

Lorsque vous enregistrez le code, réglez-le de sorte qu'il soit formaté avec le google-java-format décrit plus loin.

google-java-format Un outil CLI qui peut formater le code selon Google Java Style.

Par défaut, il est formaté avec un retrait de deux espaces que de nombreux oncles Java ne sont peut-être pas familiers. Soyez assuré que vous pouvez créer un retrait de 4 espaces en spécifiant l'option --aosp (projet Open Source Android).

Paramètres pour ça ... et automatisation pour ça ...?

Donc, l'explication des paramètres du plug-in.

Les paramètres pour dein.vim et deoplete.nvim sont omis car je ne pense pas qu'ils aient grand-chose à voir avec cette fois.

Au fait, la structure des répertoires ressemble à ceci.

$XDG_CONFIG_HOME/nvim
  ├── autoload
  │   └── hook
  │       ├── add
  │       │   ├── ale.vim
  │       │   ├── language_client_neovim.vim
  │       │   └── vim_autoformat.vim
  │       ├── post_update
  │       │   ├── ale.vim
  │       │   ├── language_client_neovim.vim
  │       │   └── vim_autoformat.vim
  │       └── source
  │           └── deoplete.vim
  ├── dein
  │   ├── dein.toml
  │   └── dein_lazy.toml
  └── init.vim

LanguageClient-Settings autour de neovim

Tout d'abord, c'est à partir du réglage de la fonction principale LanguageClient-neovim. Il est défini dans «dein.toml» comme suit.

dein/dein.toml


[[plugins]]
repo             = 'autozimu/LanguageClient-neovim'
rev              = 'next'
#Rappel appelé lors de la mise à jour d'un plug-in
hook_post_update = 'call hook#post_update#language_client_neovim#load()'
#Rappel qui est appelé lorsque le plug-in est chargé
hook_add         = 'call hook#add#language_client_neovim#load()'

Deux fonctions sont appelées au moment de la mise à jour et au moment du chargement à paramétrer.

Lors de la mise à jour d'un plug-in, il est déterminé si ʻeclipse.jdt.ls` est installé et s'il n'est pas installé, le processus d'installation démarre.

autoload/hook/post_update/language_client_neovim.vim


function! hook#post_update#language_client_neovim#load() abort
  !./install.sh
  " g:outher_package_le chemin est`eclipse.jdt.ls`Le répertoire dans lequel sont installés les outils externes tels que.
  "Bien que omis,`init.vim`Il est installé.
  let l:jdt_lsp_path = expand(g:outher_package_path) . "/jdt-lsp"
  "Dans le répertoire spécifié`eclipse.jdt.ls`Vérifier s'il existe
  if !executable(l:jdt_lsp_path . "/plugins/org.eclipse.equinox.launcher_1.5.0.v20180207-1446.jar")
    " `eclipse.jdt.ls`Télécharger
    !curl -o /tmp/tmp_jdt_lsp.tar.gz http://download.eclipse.org/jdtls/snapshots/jdt-language-server-0.16.0-201803280253.tar.gz
    " `eclipse.jdt.ls`Créez un répertoire de destination pour
    call mkdir(l:jdt_lsp_path, "p")
    "Décompressez le fichier téléchargé dans le répertoire de destination de l'enregistrement
    execute "!tar xf /tmp/tmp_jdt_lsp.tar.gz -C " . l:jdt_lsp_path
    " tar.Supprimer le fichier gz
    !rm /tmp/tmp_jdt_lsp.tar.gz
  endif
endfunction

Vient ensuite le réglage au moment de la lecture. Les paramètres de démarrage du LSP sont définis et il est appelé à chaque démarrage de NeoVim.

autoload/hook/add/language_client_neovim.vim


function! hook#add#language_client_neovim#load() abort
  let g:LanguageClient_autoStart         = 1 "LSP démarre automatiquement au démarrage de NeoVim
  let g:LanguageClient_diagnosticsEnable = 0 "Désactiver la vérification de la syntaxe

  let g:LanguageClient_serverCommands = {}
  " `eclipse.jdt.ls`Confirmation de l'existence du répertoire de destination de stockage des données utilisé dans
  "Créer un répertoire s'il n'existe pas
  let l:jdt_lsp_data_dir = expand(g:outher_package_path) . "/jdt-data"
  if !isdirectory(l:jdt_lsp_data_dir)
    call mkdir(l:jdt_lsp_data_dir, "p")
  endif
  "Paramètres de démarrage du LSP
  " `configuration`Les options doivent être définies différemment pour chaque système d'exploitation.
  " `eclipse.jdt.ls`Dans le répertoire d'installation`config_linux`, `config_mac`, `config_win`Puisqu'il existe un répertoire appelé, spécifiez le chemin du fichier de configuration en fonction de chaque système d'exploitation.
  let g:LanguageClient_serverCommands["java"] = [
        \ 'java',
        \ '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044',
        \ '-Declipse.application=org.eclipse.jdt.ls.core.id1',
        \ '-Dosgi.bundles.defaultStartLevel=4',
        \ '-Declipse.product=org.eclipse.jdt.ls.core.product',
        \ '-Dlog.protocol=true',
        \ '-Dlog.level=ALL',
        \ '-noverify',
        \ '-Xmx1G',
        \ '-jar',
        \ expand(g:outher_package_path) . '/jdt-lsp/plugins/org.eclipse.equinox.launcher_1.5.0.v20180207-1446.jar',
        \ '-configuration',
        \ expand(g:outher_package_path) . '/jdt-lsp/config_mac',
        \ '-data',
        \ l:jdt_lsp_data_dir]

  "Cartographie des clés
  nnoremap <silent> K :call LanguageClient_textDocument_hover()<CR>
  nnoremap <silent> gd :call LanguageClient_textDocument_definition()<CR>
  nnoremap <silent> <F2> :call LanguageClient_textDocument_rename()<CR>
  nnoremap <silent> <F3> :call LanguageClient_textDocument_references()<CR>
endfunction

ale.vim Pour Java, ale.vim utilise les paramètres par défaut. Étant donné que le symbole au moment de la vérification de la syntaxe est modifié, je vais l'introduire pour le moment

dein/dein.toml


[[plugins]]
repo     = 'w0rp/ale'
#Rappel lors du chargement d'un plug-in
hook_add = 'call hook#add#ale#load()'

autoload/hook/add/ale.vim


function! hook#add#ale#load() abort
  let g:ale_sign_error      = '✖' "Symbole d'erreur
  let g:ale_sign_warning    = '⚠' "Symbole d'avertissement
endfunction

vim-autoformat Semblable à LanguageClient-neovim, le formateur est installé au moment de la mise à jour et le plug-in est défini au moment du chargement.

dein/dein.toml


[[plugins]]
repo             = 'Chiel92/vim-autoformat'
#Rappel lors du chargement d'un plug-in
hook_add         = 'call hook#add#vim_autoformat#load()'
#Rappel lors de la mise à jour d'un plug-in
hook_post_update = 'call hook#post_update#vim_autoformat#load()'

Le processus de rappel au moment de la mise à jour ressemble à ceci

autoload/hook/post_update/vim_autoformat.vim


function! hook#post_update#vim_autoformat#load() abort
  " `google_java_formatter`Vérifiez si est installé
  let l:google_java_formatter = expand(g:outher_package_path) . "/google-java-format-1.5-all-deps.jar"
  if !executable(l:google_java_formatter)
    "Télécharger le fichier jar s'il n'est pas installé
    execute "!wget https://github.com/google/google-java-format/releases/download/google-java-format-1.5/google-java-format-1.5-all-deps.jar -P " . expand(g:outher_package_path)
  endif
endfunction

Les paramètres au moment de la lecture sont comme ça. Les paramètres du formateur et le format automatique lors de l'enregistrement sont définis.

autoload/hook/add/vim_autoformat.vim


function! hook#add#vim_autoformat#load() abort
  let g:autoformat_remove_trailing_spaces = 1 "Suppression des espaces de fin

  " google_java_paramètres de la commande de démarrage du formateur
  let g:formatdef_google_java_formatter = '"java -jar ' . g:outher_package_path . '/' . g:google_java_formatter . ' - --aosp"'

  "Paramètres du formateur Java
  let g:formatters_java = ['google_java_formatter']

  "Défini pour le formatage automatique du code lors de l'enregistrement
  call s:set_autoformat("java")
endfunction

function! s:set_autoformat(...) abort
  augroup AutoIndentPreWrite
    autocmd!
  augroup End

  for var in a:000
    let l:cmd = 'autocmd AutoIndentPreWrite BufWrite *.' . var . ' :Autoformat'
    execute l:cmd
  endfor
endfunction

Wow, ça bouge (petite sensation moyenne)

Si vous le définissez pour ce qui précède, cela fonctionnera comme ça.

** Saisie du code et mise en forme automatique **

Comme cela, l'expression Lambda complète également fermement le code.

** Référence de document et saut de source de définition **

Je ne pouvais pas accéder à un package standard ou à une bibliothèque externe.

Hmm. Alors quelle est la douleur?

  1. Aucune importation automatique
  2. La méthode abstraite n'est pas automatiquement implémentée lorsque l'interface est implémentée.
  3. Cela ne fonctionne pas bien dans le projet ~~ Gradle. ~~

Principalement ici. Je n'avais pas envie de Go pour 1 et 2, alors j'ai pensé que je pourrais aller à Java, mais c'était incroyablement douloureux.

Concernant ~~ 3, dans le projet Maven, l'achèvement du code du package externe et la référence du document fonctionnent correctement, il y a donc une possibilité que quelque chose ne va pas avec les paramètres ...? ~~ [Addition-Cela a bien fonctionné dans le projet Gradle](Cela a bien fonctionné dans le projet #gradle)

Postscript

## Cela a bien fonctionné dans le projet Gradle Pour le projet Gradle, j'avais besoin du «plugin eclipse».

build.gradle


plugins {
    id 'java'
    id 'application'
    id 'eclipse'
}

mainClassName = 'App'

dependencies {
    compile 'com.google.guava:guava:23.0'

    testCompile 'junit:junit:4.12'
}

repositories {
    jcenter()
}

Après avoir appliqué le plugin ʻeclipse, exécutez la tâche ʻeclipseJdt à la racine du projet.

$ gradle eclipseJdt
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

Vous pouvez maintenant utiliser la fonction LSP dans le projet Gradle.

Résumé

C'est pourquoi je n'ai pas pu battre l'IDE ... Cependant, il est plus facile d'éditer le code que l'EDI, et la complétion du code est également assez agréable, il semble donc peu probable que vous le supprimiez sans l'utiliser du tout comme eclim.

Même si vous pensez que c'est difficile en ce moment, il peut être plus facile de s'y habituer, et peut-être qu'il existe un outil utile simplement parce que vous ne le savez pas, alors je vais revoir l'environnement même pendant mon temps libre.

Site de référence

Recommended Posts

J'ai un LSP et j'ai essayé de créer un environnement pour écrire Java avec Vim (NeoVim), mais je n'ai pas pu battre l'IDE ...
J'ai essayé de créer un environnement de développement java8 avec Chocolatey
[Java] J'ai installé JDBC et essayé de me connecter avec servlet + MySQL. (Il existe une version utilisant DAO / Bean)
J'ai construit un environnement CentOS 8 avec Vagrant et essayé de sync_folder, mais j'ai eu une erreur, donc je l'ai résolue.
J'ai essayé de créer une fonction / écran d'administrateur de site commercial avec Java et Spring
J'ai essayé de résoudre le problème de la machine à karaoké Ruby (il y a un exemple de réponse)
J'ai essayé de résoudre le problème de la boisson bonus Ruby (il y a un exemple de réponse)
[Rails 6.0, Docker] J'ai essayé de résumer la construction de l'environnement Docker et les commandes nécessaires pour créer un portfolio
J'ai essayé de résumer les bases de kotlin et java
De quoi avez-vous besoin à la fin pour créer une application Web en utilisant Java? Expliquer le mécanisme et ce qui est nécessaire pour apprendre
J'ai essayé de créer un environnement de développement padrino avec Docker
J'ai essayé de résoudre le problème de création de carte de bingo Ruby (il y a un exemple de réponse)
Après avoir appris Progate, j'ai essayé de créer une application SNS en utilisant Rails dans l'environnement local
J'ai essayé de créer un environnement de serveur UML Plant avec Docker
J'ai essayé de créer un environnement de développement http2 avec Eclipse + Tomcat
J'ai essayé de créer une application Android avec MVC maintenant (Java)
J'ai essayé de résumer les méthodes de Java String et StringBuilder
J'ai essayé de résoudre les 10 dernières questions qui devraient être résolues après m'être inscrit auprès d'AtCoder en Java
J'ai essayé d'interagir avec Java
[Introduction à Java] J'ai essayé de résumer les connaissances que j'estime essentielles
01. J'ai essayé de créer un environnement avec SpringBoot + IntelliJ + MySQL (MyBatis) (Windows 10)
J'ai essayé de mesurer et de comparer la vitesse de Graal VM avec JMH
Après tout, je voulais prévisualiser le contenu de mysql avec Docker ...
Après avoir vérifié le problème de Montyhall avec Ruby, c'était une histoire que je pouvais bien comprendre et que je ne comprenais pas bien
J'ai essayé de créer une méthode qui applique plusieurs filtres à la fois avec l'API Java Stream. Cela vous convient-il?
J'ai créé un programme qui recherche la classe cible à partir du processus surchargé avec Java