有LSP,我试图创建一个用Vim(NeoVim)编写Java的环境,但毕竟我无法击败IDE …


我认为大约是一年前,但是我使用eclim与NeoVim创建了Java开发环境。

该eclim具有很高的性能,因为它在后台启动Eclipse并提供Java开发环境,但是它需要像Eclipse这样的工作区,并且Eclipse在后台启动,因此即使是Vim,它也很沉重。麻烦且难以自动化,并且有许多痛苦的部分,因此我在不使用它的情况下将其删除。

因此,毕竟,我在编写Java时使用了IDE,但是最近我发现了一个名为eclipse.jdt.ls的Java LSP。

广受赞誉,在竞选期间我用LSP

代替了开发环境

"它看起来像是eclipse的官方私有标签,并且似乎环境构建可以自动化,并且这赢得了(白痴)"

我试图以

的感觉来构建环境。

毕竟我无法击败IDE,但是我对此感到满意,因此我将对其进行介绍。

我正在使用NeoVim,但是我应该能够以相同的方式使用普通的Vim构建环境。

首先...什么是LSP?

LSP是Microsoft在2016年6月发布的规范Language Server Protocel的缩写。

这究竟是什么?它定义了提供IDE即服务所需功能的通用规范,例如代码完成和错误分析。

通过以这种方式对规范进行标准化,只要存在LSP语言实现并且所使用的编辑器具有LSP客户端,IDE功能就可以在任何环境中使用。

LSP在本文中有详细描述,其规范已在官方网站和GitHub上发布,因此,如果您有兴趣,请看看。

  • 关于语言服务器协议(第1部分)-Qiita
  • 语言服务器协议
  • Microsoft / language-server-protocol --GitHub

另外,下面总结了每种语言的实现和每种编辑器的客户端。

  • Langserver.org

在此环境构建中,我尝试使用eclipse.jdt.ls(它是此LSP的Java实现)和LanguageClient-neovim(它是NeoVim的LSP客户端)创建Java开发环境。

这是我这次使用的一些最酷的工具!

病毒

不认识这个人的人据说是Moguri(自我检查),这是Shougo先生开发的一种插件管理工具,也称为Dark Beauty。
在不同的地方进行介绍,并省略其说明。

有关详细信息,请参阅此处。

  • 尝试使用dein.vim-Qiita
  • 我安装了neovim并尝试使用dein.toml --Qiita进行插件管理

deoplete.nvim

一个由Shougo开发的代码完成插件。
我现在也不需要谈论它。 (适当)

我将在另一篇文章中详细介绍。

  • 从Neocomplete到Deoplete --rcmdnk的Vim中的补充工具插件

eclipse.jdt.ls

上面提到的LSP的Java实现。这次的主角,第1部分。
NeoVim启动时,它将自动启动,并通过与稍后描述的LanguageClient-neovim交换消息,这是一个可恶的家伙,将IDE的风吹进了NeoVim。

启动速度和内存使用率比eclim好得多,并且安装很容易暂时实现自动化。

语言客户端新

上面提到的LSP NeoVim客户端。这次的主角,第2部分。

代码完成,代码格式,语法检查,文档显示,定义源跳转等(似乎是编码的最低要求)可以通过为每种语言(最好是A鱿鱼混蛋)准备此代码和LSP来完成。

就我而言,我不使用语法检查和代码格式,因为我让另一个插件来做。

中也有MS员工开发的vim-lsp(我想我在某处听说过),但是我使用它是因为它支持deoplete。
GitHub上的许多明星都是Language Client-neovim。

顺便说一句,尽管它的名字叫neovim,但似乎可以与普通vim一起使用。
我还没试过

ale.vim

一个在编码过程中异步执行语法检查的插件。

图片图片
ale.vim

LanguageClient-neovim具有类似的功能,但是我使用的是不支持LSP的语言,因此出于统一目的使用此插件。

您也可以根据自己的喜好自定义检查工具。

对于

Java,默认情况下似乎使用javacgoogle-java-format(後述) 1执行语法检查。

vim自动格式化

一个插件,允许您通过指定格式化程序工具来格式化代码。
根据文件类型设置一些默认的格式化程序,除非指定了格式化程序,否则它们将被执行。

ale.vim中有一个类似的功能,但是我已经使用了很长时间了,并且仍在使用中。

保存

代码时,请进行设置,以使其使用稍后描述的google-java-format进行格式化。

Google Java格式

CLI工具,可以根据Google Java Style格式化代码。

默认情况下,它采用2空格缩进格式,许多Java叔叔可能不熟悉该缩进格式。
请放心,您可以通过指定--aosp选项(Android Open Source Project)使其缩进4个空格。

该设置???和自动化????

因此,插件设置的说明。

dein.vimdeoplete.nvim的设置被省略了,因为这次我认为它们并没有多大关系。

顺便说一下,目录结构如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$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

Neovim

周围的LanguageClient-Settings

首先,让我们从LanguageClient-neovim设置开始,它是核心。
dein.toml中定义如下。

dein / dein.toml

1
2
3
4
5
6
7
[[plugins]]
repo             = 'autozimu/LanguageClient-neovim'
rev              = 'next'
# プラグインのアップデート時に呼び出されるコールバック
hook_post_update = 'call hook#post_update#language_client_neovim#load()'
# プラグインが読み込まれる際に呼び出されるコールバック
hook_add         = 'call hook#add#language_client_neovim#load()'

在更新时和加载设置时调用两个函数。

更新

插件时,确定是否已安装eclipse.jdt.ls,如果未安装,则开始安装过程。

自动加载/挂钩/post_update/language_client_neovim.vim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function! hook#post_update#language_client_neovim#load() abort
  !./install.sh
  " g:outher_package_pathは、`eclipse.jdt.ls`などの外部ツールのインストール先ディレクトリ。
  " 省略しているが、`init.vim`で設定している。
  let l:jdt_lsp_path = expand(g:outher_package_path) . "/jdt-lsp"
  " 指定のディレクトリに`eclipse.jdt.ls`が存在するか確認
  if !executable(l:jdt_lsp_path . "/plugins/org.eclipse.equinox.launcher_1.5.0.v20180207-1446.jar")
    " `eclipse.jdt.ls`のダウンロード
    !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`の保存先ディレクトリを作成
    call mkdir(l:jdt_lsp_path, "p")
    " ダウンロードしてきたファイルを保存先ディレクトリに解凍
    execute "!tar xf /tmp/tmp_jdt_lsp.tar.gz -C " . l:jdt_lsp_path
    " tar.gzファイルを削除
    !rm /tmp/tmp_jdt_lsp.tar.gz
  endif
endfunction

接下来是读取时的设置。
它被设置为启动LSP,并在每次NeoVim启动时被调用。

自动加载/挂钩/添加/language_client_neovim.vim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function! hook#add#language_client_neovim#load() abort
  let g:LanguageClient_autoStart         = 1 " NeoVim起動時にLSPを自動スタート
  let g:LanguageClient_diagnosticsEnable = 0 " シンタックスチェックをOFF

  let g:LanguageClient_serverCommands = {}
  " `eclipse.jdt.ls`で利用する、データ保存先ディレクトリの存在確認
  " ディレクトリが存在しない場合は作成する
  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
  " LSPの起動設定
  " `configuration`オプションはOSごとに別の設定にする必要がある。
  " `eclipse.jdt.ls`インストールディレクトリに、 `config_linux`, `config_mac`, `config_win` というディレクトリがあるので、それぞれOSに併せて設定ファイルパスを指定する。
  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]

  " キーマッピング
  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

对于Java,ale.vim使用默认设置。
由于语法检查时的符号已更改,因此我暂时将其介绍

dein / dein.toml

1
2
3
4
[[plugins]]
repo     = 'w0rp/ale'
# プラグイン読み込み時のコールバック
hook_add = 'call hook#add#ale#load()'

自动加载/挂钩/添加/ ale.vim

1
2
3
4
function! hook#add#ale#load() abort
  let g:ale_sign_error      = '?' " エラーシンボル
  let g:ale_sign_warning    = '?' " 警告シンボル
endfunction

vim-自动格式化

与LanguageClient-neovim类似,格式化程序在更新时安装,而插件在加载时设置

dein / dein.toml

1
2
3
4
5
6
[[plugins]]
repo             = 'Chiel92/vim-autoformat'
# プラグイン読み込み時のコールバック
hook_add         = 'call hook#add#vim_autoformat#load()'
# プラグインアップデート時のコールバック
hook_post_update = 'call hook#post_update#vim_autoformat#load()'

更新时的回调处理如下

自动加载/挂钩/post_update/vim_autoformat.vim

1
2
3
4
5
6
7
8
function! hook#post_update#vim_autoformat#load() abort
  " `google_java_formatter`がインストールさてれているか確認
  let l:google_java_formatter = expand(g:outher_package_path) . "/google-java-format-1.5-all-deps.jar"
  if !executable(l:google_java_formatter)
    " 未インストールの場合はjarをダウンロード
    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

读取时的设置是这样的。
设置了格式化程序设置和保存时的自动格式。

自动加载/挂钩/添加/ vim_autoformat.vim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function! hook#add#vim_autoformat#load() abort
  let g:autoformat_remove_trailing_spaces = 1 " 末尾スペースの除去

  " google_java_formatterの起動コマンド設定
  let g:formatdef_google_java_formatter = '"java -jar ' . g:outher_package_path . '/' . g:google_java_formatter . ' - --aosp"'

  " Javaのフォーマッタの設定
  let g:formatters_java = ['google_java_formatter']

  " 保存時に自動でコードフォーマットされる用に設定
  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

哇,它动了(平均感觉很小)

如果为上述设置,它会那样工作。

代码完成和自动格式化

这样,Lambda表达式也可以牢固地完成代码。

文档参考和定义源跳转

我无法将定义源跳转到标准软件包或外部库。

唔。那是什么痛苦呢?

  • 没有自动导入
  • 在实现接口时,抽象方法不会自动实现
  • 在Gradle项目中效果不佳。
  • 主要在这里。
    我不喜欢Go for 1和2,所以我以为可以使用Java,但这出乎意料地痛苦。

    关于

    3,在Maven项目中,外部软件包的代码完成和文档参考均正常工作,因此设置中可能存在一些错误...?
    Postscript-

    在Gradle项目中运行良好

    后记

    在Gradle项目中运行良好

    对于

    Gradle项目,需要eclipse plugin

    build.gradle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    plugins {
        id 'java'
        id 'application'
        id 'eclipse'
    }

    mainClassName = 'App'

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

        testCompile 'junit:junit:4.12'
    }

    repositories {
        jcenter()
    }

    应用

    eclipse plugin后,在项目根目录中执行eclipseJdt任务。

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

    现在您可以在Gradle项目中使用LSP功能。

    概括

    这就是为什么我无法击败IDE的原因...
    但是,与IDE相比,编辑代码更容易,并且代码完成也非常好,因此,看起来像eclim一样根本不使用它就不可能删除它。

    即使您认为现在很难,也可以习惯它,也许有一个有用的工具只是因为您不了解它,所以让我们即使在业余时间也要再次检查环境。我认为。

    参考网站

    • 关于语言服务器协议(第1部分)-Qiita
    • 尝试使用dein.vim-Qiita
    • 我安装了neovim并尝试使用dein.toml --Qiita进行插件管理
    • 从Neocomplete到Deoplete --rcmdnk的Vim中的补充工具插件
  • google-java-format的检查仅在安装工具时执行。 ?