airline.vim 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. " MIT License. Copyright (c) 2013-2021 Bailey Ling et al.
  2. " vim: et ts=2 sts=2 sw=2
  3. scriptencoding utf-8
  4. let g:airline_statusline_funcrefs = get(g:, 'airline_statusline_funcrefs', [])
  5. let g:airline_inactive_funcrefs = get(g:, 'airline_inactive_statusline_funcrefs', [])
  6. let s:sections = ['a','b','c','gutter','x','y','z', 'error', 'warning']
  7. let s:contexts = {}
  8. let s:core_funcrefs = [
  9. \ function('airline#extensions#apply'),
  10. \ function('airline#extensions#default#apply') ]
  11. function! airline#add_statusline_func(name, ...)
  12. let warn = get(a:, 1, 1)
  13. call airline#add_statusline_funcref(function(a:name), warn)
  14. endfunction
  15. function! airline#add_inactive_statusline_func(name, ...)
  16. let warn = get(a:, 1, 1)
  17. call airline#add_inactive_statusline_funcref(function(a:name), warn)
  18. endfunction
  19. function! airline#add_statusline_funcref(function, ...)
  20. if index(g:airline_statusline_funcrefs, a:function) >= 0
  21. let warn = get(a:, 1, 1)
  22. if warn > 0
  23. call airline#util#warning(printf('The airline statusline funcref "%s" has already been added.', string(a:function)))
  24. endif
  25. return
  26. endif
  27. call add(g:airline_statusline_funcrefs, a:function)
  28. endfunction
  29. function! airline#remove_statusline_func(name)
  30. let i = index(g:airline_statusline_funcrefs, function(a:name))
  31. if i > -1
  32. call remove(g:airline_statusline_funcrefs, i)
  33. endif
  34. endfunction
  35. function! airline#add_inactive_statusline_funcref(function, ...)
  36. if index(g:airline_inactive_funcrefs, a:function) >= 0
  37. let warn = get(a:, 1, 1)
  38. if warn > 0
  39. call airline#util#warning(printf('The airline inactive statusline funcref "%s" has already been added.', string(a:function)))
  40. endif
  41. return
  42. endif
  43. call add(g:airline_inactive_funcrefs, a:function)
  44. endfunction
  45. function! airline#load_theme()
  46. let g:airline_theme = get(g:, 'airline_theme', 'dark')
  47. if exists('*airline#themes#{g:airline_theme}#refresh')
  48. call airline#themes#{g:airline_theme}#refresh()
  49. endif
  50. let palette = g:airline#themes#{g:airline_theme}#palette
  51. call airline#themes#patch(palette)
  52. if exists('g:airline_theme_patch_func')
  53. let Fn = function(g:airline_theme_patch_func)
  54. call Fn(palette)
  55. endif
  56. call airline#highlighter#load_theme()
  57. call airline#extensions#load_theme()
  58. call airline#update_statusline()
  59. call airline#util#doautocmd('AirlineAfterTheme')
  60. endfunction
  61. " Load an airline theme
  62. function! airline#switch_theme(name, ...)
  63. let silent = get(a:000, '0', 0)
  64. " get all available themes
  65. let themes = airline#util#themes('')
  66. let err = 0
  67. try
  68. if index(themes, a:name) == -1
  69. " Theme not available
  70. if !silent
  71. call airline#util#warning(printf('The specified theme "%s" cannot be found.', a:name))
  72. endif
  73. throw "not-found"
  74. let err = 1
  75. else
  76. exe "ru autoload/airline/themes/". a:name. ".vim"
  77. let g:airline_theme = a:name
  78. endif
  79. catch /^Vim/
  80. " catch only Vim errors, not "not-found"
  81. call airline#util#warning(printf('There is an error in theme "%s".', a:name))
  82. if &vbs
  83. call airline#util#warning(v:exception)
  84. endif
  85. let err = 1
  86. endtry
  87. if err
  88. if exists('g:airline_theme')
  89. return
  90. else
  91. let g:airline_theme = 'dark'
  92. endif
  93. endif
  94. unlet! w:airline_lastmode
  95. call airline#load_theme()
  96. " this is required to prevent clobbering the startup info message, i don't know why...
  97. call airline#check_mode(winnr())
  98. endfunction
  99. " Try to load the right theme for the current colorscheme
  100. function! airline#switch_matching_theme()
  101. if exists('g:colors_name')
  102. let existing = g:airline_theme
  103. let theme = tr(tolower(g:colors_name), '-', '_')
  104. try
  105. call airline#switch_theme(theme, 1)
  106. return 1
  107. catch
  108. for map in items(g:airline_theme_map)
  109. if match(g:colors_name, map[0]) > -1
  110. try
  111. call airline#switch_theme(map[1], 1)
  112. catch
  113. call airline#switch_theme(existing)
  114. endtry
  115. return 1
  116. endif
  117. endfor
  118. endtry
  119. endif
  120. return 0
  121. endfunction
  122. " Update the statusline
  123. function! airline#update_statusline()
  124. if airline#util#stl_disabled(winnr()) || airline#util#is_popup_window(winnr())
  125. return
  126. endif
  127. " TODO: need to ignore popup windows here as well?
  128. let range = filter(range(1, winnr('$')), 'v:val != winnr()')
  129. " create inactive statusline
  130. call airline#update_statusline_inactive(range)
  131. unlet! w:airline_render_left w:airline_render_right
  132. exe 'unlet! ' 'w:airline_section_'. join(s:sections, ' w:airline_section_')
  133. " Now create the active statusline
  134. let w:airline_active = 1
  135. let context = { 'winnr': winnr(), 'active': 1, 'bufnr': winbufnr(winnr()) }
  136. try
  137. call s:invoke_funcrefs(context, g:airline_statusline_funcrefs)
  138. catch /^Vim\%((\a\+)\)\=:E48:/
  139. " Catch: Sandbox mode
  140. " no-op
  141. endtry
  142. endfunction
  143. " Function to be called to make all statuslines inactive
  144. " Triggered on FocusLost autocommand
  145. function! airline#update_statusline_focuslost()
  146. if get(g:, 'airline_focuslost_inactive', 0)
  147. let bufnr=bufnr('%')
  148. call airline#highlighter#highlight_modified_inactive(bufnr)
  149. call airline#highlighter#highlight(['inactive'], bufnr)
  150. call airline#update_statusline_inactive(range(1, winnr('$')))
  151. endif
  152. endfunction
  153. " Function to draw inactive statuslines for inactive windows
  154. function! airline#update_statusline_inactive(range)
  155. if airline#util#stl_disabled(winnr())
  156. return
  157. endif
  158. for nr in a:range
  159. if airline#util#stl_disabled(nr)
  160. continue
  161. endif
  162. call setwinvar(nr, 'airline_active', 0)
  163. let context = { 'winnr': nr, 'active': 0, 'bufnr': winbufnr(nr) }
  164. if get(g:, 'airline_inactive_alt_sep', 0)
  165. call extend(context, {
  166. \ 'left_sep': g:airline_left_alt_sep,
  167. \ 'right_sep': g:airline_right_alt_sep }, 'keep')
  168. endif
  169. try
  170. call s:invoke_funcrefs(context, g:airline_inactive_funcrefs)
  171. catch /^Vim\%((\a\+)\)\=:E48:/
  172. " Catch: Sandbox mode
  173. " no-op
  174. endtry
  175. endfor
  176. endfunction
  177. " Gather output from all funcrefs which will later be returned by the
  178. " airline#statusline() function
  179. function! s:invoke_funcrefs(context, funcrefs)
  180. let builder = airline#builder#new(a:context)
  181. let err = airline#util#exec_funcrefs(a:funcrefs + s:core_funcrefs, builder, a:context)
  182. if err == 1
  183. let a:context.line = builder.build()
  184. let s:contexts[a:context.winnr] = a:context
  185. let option = get(g:, 'airline_statusline_ontop', 0) ? '&tabline' : '&statusline'
  186. call setwinvar(a:context.winnr, option, '%!airline#statusline('.a:context.winnr.')')
  187. endif
  188. endfunction
  189. " Main statusline function per window
  190. " will be set to the statusline option
  191. function! airline#statusline(winnr)
  192. if has_key(s:contexts, a:winnr)
  193. return '%{airline#check_mode('.a:winnr.')}'.s:contexts[a:winnr].line
  194. endif
  195. " in rare circumstances this happens...see #276
  196. return ''
  197. endfunction
  198. " Check if mode has changed
  199. function! airline#check_mode(winnr)
  200. if !has_key(s:contexts, a:winnr)
  201. return ''
  202. endif
  203. let context = s:contexts[a:winnr]
  204. if get(w:, 'airline_active', 1)
  205. let m = mode(1)
  206. " Refer :help mode() to see the list of modes
  207. " NB: 'let mode' here refers to the display colour _groups_,
  208. " not the literal mode's code (i.e., m). E.g., Select modes
  209. " v, S and ^V use 'visual' since they are of similar ilk.
  210. " Some modes do not get recognised for status line purposes:
  211. " no, nov, noV, no^V, !, cv, and ce.
  212. " Mode name displayed is handled in init.vim (g:airline_mode_map).
  213. "
  214. if m[0] ==# "i"
  215. let mode = ['insert'] " Insert modes + submodes (i, ic, ix)
  216. elseif m[0] == "R"
  217. let mode = ['replace'] " Replace modes + submodes (R, Rc, Rv, Rx) (NB: case sensitive as 'r' is a mode)
  218. elseif m[0] =~ '\v(v|V||s|S|)'
  219. let mode = ['visual'] " Visual and Select modes (v, V, ^V, s, S, ^S))
  220. elseif m ==# "t"
  221. let mode = ['terminal'] " Terminal mode (only has one mode (t))
  222. elseif m[0] =~ '\v(c|r|!)'
  223. let mode = ['commandline'] " c, cv, ce, r, rm, r? (NB: cv and ce stay showing as mode entered from)
  224. else
  225. let mode = ['normal'] " Normal mode + submodes (n, niI, niR, niV; plus operator pendings no, nov, noV, no^V)
  226. endif
  227. if exists("*VMInfos") && !empty(VMInfos())
  228. " Vim plugin Multiple Cursors https://github.com/mg979/vim-visual-multi
  229. let m = 'multi'
  230. endif
  231. " Adjust to handle additional modes, which don't display correctly otherwise
  232. if index(['niI', 'niR', 'niV', 'ic', 'ix', 'Rc', 'Rv', 'Rx', 'multi'], m) == -1
  233. let m = m[0]
  234. endif
  235. let w:airline_current_mode = get(g:airline_mode_map, m, m)
  236. else
  237. let mode = ['inactive']
  238. let w:airline_current_mode = get(g:airline_mode_map, '__')
  239. endif
  240. if g:airline_detect_modified && &modified
  241. call add(mode, 'modified')
  242. endif
  243. if g:airline_detect_paste && &paste
  244. call add(mode, 'paste')
  245. endif
  246. if g:airline_detect_crypt && exists("+key") && !empty(&key)
  247. call add(mode, 'crypt')
  248. endif
  249. if g:airline_detect_spell && &spell
  250. call add(mode, 'spell')
  251. endif
  252. if &readonly || ! &modifiable
  253. call add(mode, 'readonly')
  254. endif
  255. let mode_string = join(mode)
  256. if get(w:, 'airline_lastmode', '') != mode_string
  257. call airline#highlighter#highlight_modified_inactive(context.bufnr)
  258. call airline#highlighter#highlight(mode, string(context.bufnr))
  259. call airline#util#doautocmd('AirlineModeChanged')
  260. let w:airline_lastmode = mode_string
  261. endif
  262. return ''
  263. endfunction
  264. function! airline#update_tabline()
  265. if get(g:, 'airline_statusline_ontop', 0)
  266. call airline#extensions#tabline#redraw()
  267. endif
  268. endfunction
  269. function! airline#mode_changed()
  270. " airline#visual_active
  271. " Boolean: for when to get visual wordcount
  272. " needed for the wordcount extension
  273. let g:airline#visual_active = (mode() =~? '[vs]')
  274. call airline#update_tabline()
  275. endfunction