LoginSignup
8
9

More than 5 years have passed since last update.

ALEでgometalinterを使う

Last updated at Posted at 2017-07-14

tl;dr

https://gyazo.com/81a3557563de001f9cc1a23d9ee4a1b5

  • Vim8 or NeoVimからgometalinterを使う
  • linterプラギンとしてALEを使う
  • 画像のような表示にするためにNerd Fontsを使う

gometalinter

Go用のlinterはいくつかあるがこれらを統合的に扱えるようにしたものである。
サポートしているlinterはgithub上に記載されている。
https://github.com/alecthomas/gometalinter#supported-linters

Install

go get -u gopkg.in/alecthomas/gometalinter.v1
gometalinter --install --update

それぞれのlinterについては以下のような記事を参考にされたし。
- Go の CI で Lint と カバレッジ回して非人間的なレビューは自動化しよう in 2016年
- Go Meta Linter がサポートするツールまとめ

ALE

ALEは、Vim8もしくはNeoVimで非同期にlinterを実行してくれるプラギンである。
Go以外にも様々な言語1に対応している。
似たようなプラギンは多数存在するわけだが、設定なしでもすぐ使えるという点がよい。
なにも考えなければインストールするだけで使える、便利。
Goでもいくつかのlinterを使えるようになっているが、デフォルトはgofmtになっているのでgometalinterにする必要がある。

plugin managerにはdein.vimを使っているのでその場合だと以下ような感じになる。

init.vim
if &compatible
  set nocompatible
endif
let s:dein_dir='~/.cache/dein/repos/github.com/Shougo/dein.vim'
set runtimepath+=s:dein_dir

if dein#load_state('~/.cache/dein')
  call dein#begin({)

  call dein#add(s:dein_dir)
  call dein#add('w0rp/ale')
  call dein#end()
  call dein#save_state()
endif

filetype plugin indent on
syntax enable

" for ALE
let g:ale_lint_on_text_changed = 'never'
let g:ale_set_loclist = 0
let g:ale_set_quickfix = 1
let g:ale_sign_column_always = 1
let g:ale_lint_on_enter = 0
let g:ale_open_list = 1
let g:ale_keep_list_window_open = 0
" for go
let g:ale_linters.go ='gometalinter'
let g:ale_go_gometalinter_options = '--fast --enable=staticcheck --enable=gosimple --enable=unused'

g:ale_go_gometalinter_optionsでgometalinter実行時のoptionを渡せる。
--fastは実行に時間のかかるlinterを除いて実行してくれる。
上記の設定だとファイル保存時にlintしてくれる。非同期に実行するとはいえ、--fastなしだともっさりしてしまうのでつけている。
それ以外の--enableはお好みで追加。

これだけでALEがgometalinterを実行してくれるようになる。

Powerline

linter結果にPowerlineフォントを使う。
みんな大好きRictyのpowerlineパッチのインストールは以下。

brew tap sanemat/font
brew install ricty --powerline --vim-powerline

terminalのfontをRictyPowelineにしつつ、ALEの設定に以下を追加する。

init.vim
let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
let g:ale_sign_error = '⤫'
let g:ale_sign_warning = '⚠'

Nerd Fonts

icon fontをstatuslineに表示するためにNerd Fontsのパッチを以下の手順でRictyにあてあげる必要がある。

brew install fontforge
git clone https://github.com/ryanoasis/nerd-fonts
cd nerd-fonts
chmod +x font-patcher
fontforge -script ./font-patcher ~/Library/Fonts/Ricty\ Regular\ for\ Powerline.ttf --fontawesome --fontlinux --oct
icons --pomicons --powerline --powerlineextra
cp -f ./Ricty\ Regular\ for\ Powerline\ Nerd\ Font\ Plus\ Font\ Awesome\ Plus\ Octicons\ Plus\ Pomicons\ Plus\ Font\ Linux.ttf ~/Library/Fonts/
fc-cache -vf

nerd-fontsのcloneにはそれなりに時間がかかるのでcoffeeでも飲むとよい :coffee:

ここで作ったフォントをiTerm2とかの設定で使うようにする。
ALEの設定に以下を追加。

lightline

statuslineにはlightline.vimを使う。
またlightlineのcolorthemeにtender.vimを使い、NerdFontを表示するためにvim-deviconsをいれる。

プラギンの追加のところに以下を追記。
ちなみにvim-deviconsを先に読み込む必要がある。

init.vim
call dein#add('ryanoasis/vim-devicons')
call dein#add('itchyny/lightline.vim')
call dein#add('jacoborus/tender.vim')

lightline用の設定として以下を追加します。(長文)

init.vim
let g:lightline = {
      \ 'colorscheme': 'tender',
      \ 'active': {
      \   'left': [ [ 'mode', 'paste' ], [ 'fugitive', 'filename' ] ],
      \   'right': [ [ 'lineinfo' ], ['percent'], [ 'ale_error', 'ale_warning', 'ale_ok', 'char_code', 'fileformat', 'fileencoding', 'filetype' ] ]
      \ },
      \ 'component_function': {
      \   'fugitive': 'LightLineFugitive',
      \   'filename': 'LightLineFilename',
      \   'fileformat': 'LightLineFileformat',
      \   'filetype': 'LightLineFiletype',
      \   'fileencoding': 'LightLineFileencoding',
      \   'mode': 'LightLineMode',
      \   'char_code': 'LightLineCharCode',
      \ },
      \ 'component_function_visible_condition': {
      \   'mode': 1,
      \ },
      \ 'component_expand': {
      \   'ale_error': 'LightLineAleError',
      \   'ale_warning': 'LightLineAleWarning',
      \   'ale_ok': 'LightLineAleOk',
      \ },
      \ 'component_type': {
      \   'ale_error': 'error',
      \   'ale_waring': 'waring',
      \   'ale_ok': 'ok',
      \ },
      \ 'separator': {'left': '⮀', 'right': '⮂'},
      \ 'subseparator': {'left': '⮁', 'right': '⮃'}
      \ }

augroup LightLineOnALE
  autocmd!
  autocmd User ALELint call lightline#update()
augroup END

function! LightLineModified()
  return &ft =~ 'help' ? '' : &modified ? '' : &modifiable ? '' : '-'
endfunction

function! LightLineReadonly()
  return &ft !~? 'help' && &readonly ? '' : ''
endfunction

function! LightLineFilepath() abort
  let l:path_string = substitute(expand('%:h'), $HOME, '~', '')
  if winwidth(0) < 120 && len(l:path_string) > 30
    let l:path_string = substitute(l:path_string, '\v([^/])[^/]*%(/)@=', '\1', 'g')
  endif
  return l:path_string
endfunction

function! LightLineFilename()
  let fname = expand('%:t')
  return fname == 'ControlP' ? g:lightline.ctrlp_item :
        \ fname == '__Tagbar__' ? g:lightline.fname :
        \ fname =~ '__Gundo\|NERD_tree' ? '' :
        \ &ft == 'vimfiler' ? vimfiler#get_status_string() :
        \ &ft == 'denite' ? LightLineDenite() :
        \ &ft == 'vimshell' ? vimshell#get_status_string() :
        \ ('' != LightLineReadonly() ? LightLineReadonly() . ' ' : '') .
        \ ('' != fname ? LightLineFilepath().' '.fname : '[No Name]') .
        \ ('' != LightLineModified() ? ' ' . LightLineModified() : '')
endfunction

" ref. https://gist.github.com/pocari/84c78efa38b5c2fc1f659d1aac3face8
function! LightLineDenite()
  let mode_str = substitute(denite#get_status_mode(), "-\\| ", "", "g")
  call lightline#link(tolower(mode_str[0]))
  return mode_str
endfunction

function! LightLineFugitive()
  try
    if expand('%:t') !~? 'Tagbar\|Gundo\|NERD' && &ft !~? 'vimfiler' && exists('*fugitive#head')
      let mark = ' '  " edit here for cool mark
      let _ = fugitive#head()
      return strlen(_) ? mark._ : ''
    endif
  catch
  endtry
  return ''
endfunction

function! LightLineFileformat()
  return winwidth(0) > 120 ? &fileformat . (exists('*WebDevIconsGetFileFormatSymbol') ? ' ' . WebDevIconsGetFileFormatSymbol() : '') : ''
endfunction

function! LightLineFiletype()
  return winwidth(0) > 70 ? (strlen(&filetype) ? &filetype . (exists('*WebDevIconsGetFileTypeSymbol') ? ' ' . WebDevIconsGetFileTypeSymbol() : ''): 'no ft') : ''
endfunction

function! LightLineFileencoding()
  return winwidth(0) > 120 ? (strlen(&fenc) ? &fenc : &enc) : ''
endfunction

function! LightLineMode()
  let fname = expand('%:t')
  return fname == '__Tagbar__' ? 'Tagbar' :
        \ fname == 'ControlP' ? 'CtrlP' :
        \ fname == '__Gundo__' ? 'Gundo' :
        \ fname == '__Gundo_Preview__' ? 'Gundo Preview' :
        \ fname =~ 'NERD_tree' ? 'NERDTree' :
        \ &ft == 'unite' ? 'Unite' :
        \ &ft == 'denite' ? 'Denite' :
        \ &ft == 'vimfiler' ? 'VimFiler' :
        \ &ft == 'vimshell' ? 'VimShell' :
        \ winwidth(0) > 60 ? lightline#mode() : ''
endfunction

function! LightLineCharCode() abort
  if winwidth(0) <= 120
    return ''
  endif
  " if char on cursor is `Λ̊`, :ascii returns below.
  " <Λ> 923, 16進数 039b, 8進数 1633 < ̊> 778, 16進数 030a, 8進数 1412
  redir => l:tmp | silent! ascii | redir END
  let l:chars = []
  call substitute(l:tmp, '<.>\s\+\d\+,\s\+\S\+ \x\+,\s\+\S\+ \d\+', '\=add(l:chars, submatch(0))', 'g')
  if len(l:chars) == 0
    return ''
  endif
  let l:ascii = []
  for l:c in l:chars
    let l:m = matchlist(l:c, '<\(.\)>\s\+\d\+,\s\+\S\+ \(\x\+\)')
    if len(l:m) > 0
      call add(l:ascii, printf('%s %s', l:m[1], l:m[2]))
    endif
  endfor
  return join(l:ascii, ', ')
endfunction

function! LightLineAleError() abort
  return s:ale_string(0)
endfunction

function! LightLineAleWarning() abort
  return s:ale_string(1)
endfunction

function! LightLineAleOk() abort
  return s:ale_string(2)
endfunction

function! s:ale_string(mode)
  if !exists('g:ale_buffer_info')
    return ''
  endif

  let l:buffer = bufnr('%')
  let l:counts = ale#statusline#Count(l:buffer)
  let [l:error_format, l:warning_format, l:no_errors] = g:ale_statusline_format

  if a:mode == 0 " Error
    let l:errors = l:counts.error + l:counts.style_error
    return l:errors ? printf(l:error_format, l:errors) : ''
  elseif a:mode == 1 " Warning
    let l:warnings = l:counts.warning + l:counts.style_warning
    return l:warnings ? printf(l:warning_format, l:warnings) : ''
  endif

  return l:counts.total == 0? l:no_errors: ''
endfunction

以上で完了。

8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9