rcmdnk's blog

20130906_lightline_200_200

lightline はVimのステータスライン表示をリッチにしてくれる プラグインです。

色々な情報を自分の好きな様に表示できますが、 画面が狭くなったりした時に必要な情報から表示するように、 と言ったことをするためにちょっと工夫したことについて。

Sponsored Links

lightline

Vimでステータスライン表示を変更するプラグインは powerlinevim-airline などいくつかありますが、 lightline はそれらを踏まえた上で出てきた比較的新しいプラグインで 他のに比べて動作も軽快なので使っています。

画面幅によって表示させる項目を変える

上の導入時にも画面幅によって項目を変更することはやっていましたが、 この時は関数の呼ばれる順番とかを余り考えていませんでした。

たまたま上手く行くようになってましたが、 今回ちょっとvimrcを見直してる中できちんと想定通り動く様に変更しました。

取り敢えず設定を載せておくとこんな感じ。

.vimrc
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
let g:lightline = {
      \'colorscheme': 'jellybeans',
      \'active': {
            \'left': [['prepare', 'mode', 'filename'], ['fugitive']],
            \'right': [['lineinfo'], ['fileinfo'], ['ale']]},
      \'component_visible_condition': {
            \'fugitive': '(exists("*fugitive#head") && ""!=fugitive#head())'},
      \'component_function': {
            \'prepare': 'LLPrepare',
            \'mode': 'LLMode',
            \'filename': 'LLFileName',
            \'fugitive': 'LLFugitive',
            \'fileinfo': 'LLFileInfo',
            \'lineinfo': 'LLLineInfo',
            \'ale': 'LLAle',
            \},
      \ 'separator': { 'left': '', 'right': '' },
      \ 'subseparator': { 'left': '', 'right': '' }
      \}
let g:lightline.inactive = g:lightline.active

function! LLPrepare()
  let g:ll_mode = ''
  let g:ll_filename = ''
  let g:ll_fugitive = ''
  let g:ll_fileinfo = ''
  let g:ll_lineinfo = ''
  let g:ll_ale = ''

  let l:ww = winwidth('.')
  let l:total_len = 0

  let g:ll_mode = lightline#mode() . (&paste ? ' P' : '')
  if g:ll_mode !=# ''
    let l:total_len += strlen(g:ll_mode) + 2
    if l:ww < l:total_len
      return ''
    endif
  endif

  let g:ll_lineinfo = printf('%d/%d:%d', line('.'), line('$'), col('.'))
  if g:ll_lineinfo !=# ''
    let l:total_len += strlen(g:ll_lineinfo) + 2
    if l:ww < l:total_len
      let g:ll_lineinfo = ''
      return ''
    endif
  endif

  let g:ll_filename = expand('%:t') . (&filetype !~? 'help' && &readonly ? ' RO' : '') . (&modifiable && &modified ? ' +' : '')
  if g:ll_filename !=# ''
    let l:total_len += strlen(g:ll_filename) + 2
    if l:ww < l:total_len
      let g:ll_filename = ''
      return ''
    endif
  endif

  let g:ll_fileinfo = &fileformat . ' ' . (strlen(&fileencoding) ? &fileencoding : &encoding) . ' ' . (strlen(&filetype) ? &filetype : 'no')
  if g:ll_fileinfo !=# ''
    let l:total_len += strlen(g:ll_fileinfo) + 2
    if l:ww < l:total_len
      let g:ll_fileinfo = ''
      return ''
    endif
  endif

  let g:ll_ale = LLGetAle()
  if g:ll_ale !=# ''
    let l:total_len += strlen(g:ll_ale) + 2
    if l:ww < l:total_len
      let g:ll_ale = ''
      return ''
    endif
  endif

  let g:ll_fugitive = exists('*fugitive#head') ? fugitive#head() : ''
  if g:ll_fugitive !=# ''
    let l:total_len += strlen(g:ll_fugitive) + 2
    if l:ww < l:total_len
      let g:ll_fugitive = ''
      return ''
    endif
  endif

  return ''
endfunction

function! LLMode()
  return g:ll_mode
endfunction

function! LLFileName()
  return g:ll_filename
endfunction

function! LLFugitive()
  return g:ll_fugitive
endfunction

function! LLFileInfo()
  return g:ll_fileinfo
endfunction

function! LLLineInfo()
  return g:ll_lineinfo
endfunction

function! LLAle()
  return g:ll_ale
endfunction

if dein#tap('ale')
  function! LLGetAle()
    let l:count = ale#statusline#Count(bufnr(''))
    let l:errors = l:count.error + l:count.style_error
    let l:warnings = l:count.warning + l:count.style_warning
    return l:count.total == 0 ? 'OK' : 'E:' . l:errors . ' W:' . l:warnings
  endfunction
else
  function! LLGetAle()
    return ''
  endfunction
endif

注目すべきところは prepareという疑似項目を作って最初に全ての項目を準備しているところです。

lightlineではacviveに登録された項目に対して component_function等によって表示するものを指定できます。 leftrightの項目にそれぞれ3つずつ違う背景色に置くことが出来、 各領域には複数の項目を置くことも可能です。

上のだと['prepare', 'mode', 'filename']は左側の一番左側の領域、 ['fugitive']は左側の真ん中の領域、 ['lineinfo;']は右側の一番右側の領域に表示されます。

ただし、表示するものが空白('')な場合はなにも表示されません。 表示される時は両側にスペースが入りますが、なにも表示されない場合はこのスペースも入りません。

今やりたいことは、各項目の表示文字数を調べて、 スペース数等も考慮したその合計が画面幅よりも大きいような場合には 表示項目を減らしてきれいに載せる、ということ。

ここで重要になってくるのは、各acvive項目はここでは関数を呼んでその 返り値を表示するようになってますが、 その関数がどのような順番で呼ばれるか、ということ。 lightlineではkのg:lightlineで設定されたactiveの項目の中から、 まずはleftの中の左側から、 次にrightの中の左側の領域から評価されていきます。

配列の順番としてはleftの項目の右側にある項目から、 次にrightの項目の右側にある項目から、と言った感じに評価されていきます。

以前はこの辺あまり考えず、 各項目にあてる関数の中で他の項目の文字数なんかもカウントしながら 取捨選択してましたが、たまたま重要なものを左側に置いていく関係で それでも上手くいっていました。

ただ順番を変えたり表示したい項目を変えると上手く行かなくなるので ちょっと見直して上の様にまず一番最初に呼ばれるprepareの項目に LLPrepareという必要な文字列を準備するだけで空文字を変えず関数をあてました。

この中で一つ一つ使う項目を取得していって、 もしこれまでの物と合わせて画面幅(winwidth('.')で取得)より 大きくなってしまった場合にはその項目は空文字にして以降の文字も空文字のままにしています。 各項目の文字数には両側にスペースが入るため+2しています。

LLPrepareをもうちょっときれいに上手く書けるかもしれませんが、 取り敢えずこの中の評価順序を変えれば 重要なものから選んで表示していくことが出来ます。 さらにはVim起動中に画面の大きさが変わっても都度評価し直して 表示を整えてくれます。

Sponsored Links
Sponsored Links

« Ruby 2.4.2でgemがエラーを出して使えない時の対処法 VimのSyntaxチェッカーをALEにした »