diff --git a/lua/hardline.lua b/lua/hardline.lua index deedb69..b9c8eb7 100644 --- a/lua/hardline.lua +++ b/lua/hardline.lua @@ -16,8 +16,9 @@ M.options = { {class = 'high', item = require('hardline.parts.git').get_item}, {class = 'med', item = require('hardline.parts.filename').get_item}, {class = 'med', item ='%='}, - {class = 'warning', item = require('hardline.parts.lsp').get_warning}, {class = 'error', item = require('hardline.parts.lsp').get_error}, + {class = 'warning', item = require('hardline.parts.lsp').get_warning}, + {class = 'warning', item = require('hardline.parts.whitespace').get_item}, {class = 'high', item = require('hardline.parts.filetype').get_item}, {class = 'mode', item = require('hardline.parts.line').get_item}, }, diff --git a/lua/hardline/common.lua b/lua/hardline/common.lua index 60f9f39..545042c 100644 --- a/lua/hardline/common.lua +++ b/lua/hardline/common.lua @@ -1,3 +1,5 @@ +local cmd, fn, vim = vim.cmd, vim.fn, vim +local g = vim.g local M = { modes = { ['?'] = {text = '???', color = 'inactive'}, @@ -16,13 +18,13 @@ local M = { } function M.echo(hlgroup, msg) - vim.cmd(string.format('echohl %s', hlgroup)) - vim.cmd(string.format('echo "[hardline] %s"', msg)) - vim.cmd('echohl None') + cmd(string.format('echohl %s', hlgroup)) + cmd(string.format('echo "[hardline] %s"', msg)) + cmd('echohl None') end function M.is_active() - return vim.g.statusline_winid == vim.fn.win_getid() + return g.statusline_winid == fn.win_getid() end return M diff --git a/lua/hardline/parts/filename.lua b/lua/hardline/parts/filename.lua index 7d44e31..4c80dd9 100644 --- a/lua/hardline/parts/filename.lua +++ b/lua/hardline/parts/filename.lua @@ -1,5 +1,7 @@ +local fn = vim.fn + local function get_item() - local name = vim.fn.expand('%:~:.') + local name = fn.expand('%:~:.') return table.concat({' ', '%<', name, ' '}) end diff --git a/lua/hardline/parts/filetype.lua b/lua/hardline/parts/filetype.lua index 427c1ba..9ada887 100644 --- a/lua/hardline/parts/filetype.lua +++ b/lua/hardline/parts/filetype.lua @@ -1,5 +1,7 @@ +local bo = vim.bo + local function get_filetype() - return string.format('%s', vim.bo.filetype) + return string.format('%s', bo.filetype) end local function get_item() diff --git a/lua/hardline/parts/git.lua b/lua/hardline/parts/git.lua index fcd2252..8cb1dfb 100644 --- a/lua/hardline/parts/git.lua +++ b/lua/hardline/parts/git.lua @@ -1,6 +1,9 @@ +local fn = vim.fn +local g = vim.g + local function get_hunks() - if not vim.g.loaded_gitgutter then return '' end - local summary = vim.fn.GitGutterGetHunkSummary() + if not g.loaded_gitgutter then return '' end + local summary = fn.GitGutterGetHunkSummary() return table.concat({ string.format('+%d', summary[1]), ' ', string.format('~%d', summary[2]), ' ', @@ -9,8 +12,8 @@ local function get_hunks() end local function get_branch() - if not vim.g.loaded_gitgutter then return '' end - return string.format('(%s)', vim.fn.FugitiveHead()) + if not g.loaded_gitgutter then return '' end + return string.format('(%s)', fn.FugitiveHead()) end local function get_item() diff --git a/lua/hardline/parts/line.lua b/lua/hardline/parts/line.lua index 2b51bf6..526c331 100644 --- a/lua/hardline/parts/line.lua +++ b/lua/hardline/parts/line.lua @@ -1,4 +1,4 @@ -local common = require('hardline.common') +local fn = vim.fn local function get_dots(current, max) current = string.len(tostring(current)) @@ -7,23 +7,23 @@ local function get_dots(current, max) end local function get_line() - local nb_lines = vim.fn.line('$') - local line = vim.fn.line('.') + local nb_lines = fn.line('$') + local line = fn.line('.') local dots = get_dots(line, nb_lines) return string.format('%s%d/%d', dots, line, nb_lines) end local function get_column() - local nb_columns = vim.fn.col('$') - 1 - local column = vim.fn.col('.') + local nb_columns = fn.col('$') - 1 + local column = fn.col('.') local max_dots = get_dots(nb_columns, 999) local dots = get_dots(column, 999) return string.format('|%s%d/%s%d', dots, column, max_dots, nb_columns) end local function get_percent() - local nb_lines = vim.fn.line('$') - local line = vim.fn.line('.') + local nb_lines = fn.line('$') + local line = fn.line('.') local percent = math.floor(line * 100 / nb_lines) local dots = get_dots(percent, 100) return string.format('|%s%d%%%%', dots, percent) diff --git a/lua/hardline/parts/lsp.lua b/lua/hardline/parts/lsp.lua index e6d0e83..6cb87b4 100644 --- a/lua/hardline/parts/lsp.lua +++ b/lua/hardline/parts/lsp.lua @@ -1,6 +1,8 @@ +local lsp, vim = vim.lsp, vim + local function get_diagnostic(prefix, severity) - if vim.tbl_isempty(vim.lsp.buf_get_clients(0)) then return '' end - local count = vim.lsp.diagnostic.get_count(0, severity) + if vim.tbl_isempty(lsp.buf_get_clients(0)) then return '' end + local count = lsp.diagnostic.get_count(0, severity) if count < 1 then return '' end return table.concat({' ', string.format('%s:%d', prefix, count), ' '}) end diff --git a/lua/hardline/parts/mode.lua b/lua/hardline/parts/mode.lua index 0eee386..7bf8dd0 100644 --- a/lua/hardline/parts/mode.lua +++ b/lua/hardline/parts/mode.lua @@ -1,17 +1,19 @@ +local fn = vim.fn +local o, bo, wo = vim.o, vim.bo, vim.wo local common = require('hardline.common') local function get_mode() - return common.modes[vim.fn.mode()].text + return common.modes[fn.mode()].text end local function get_paste() - if not vim.o.paste then return '' end + if not o.paste then return '' end return '|PASTE' end local function get_spell() - if not vim.wo.spell then return '' end - return string.format('|SPELL[%s]', string.upper(vim.bo.spelllang)) + if not wo.spell then return '' end + return string.format('|SPELL[%s]', string.upper(bo.spelllang)) end local function get_item() diff --git a/lua/hardline/parts/whitespace.lua b/lua/hardline/parts/whitespace.lua index ce84ef3..1a45cfd 100644 --- a/lua/hardline/parts/whitespace.lua +++ b/lua/hardline/parts/whitespace.lua @@ -1,8 +1,72 @@ -local M = {} +local cmd, fn, vim = vim.cmd, vim.fn, vim +local bo = vim.bo +local enabled = false +local options = { + c_langs = {'arduino', 'c', 'cpp', 'cuda', 'go', 'javascript', 'ld', 'php'}, + max_lines = 5000, + timeout = 100, +} -function M.get_item() - return table.concat({ - }) +local function search(prefix, pattern) + local line = fn.search(pattern, 'nw', 0, options.timeout) + if line == 0 then return '' end + return string.format('[%s:%d]', prefix, line) end -return M +local function check_trailing() + return search('trailing', [[\s$]]) +end + +local function check_mixed_indent() + local tst = [[(^\t* +\t\s*\S)]] + local tls = string.format([[(^\t+ {%d,}\S)]], bo.tabstop) + local pattern = string.format([[\v%s|%s]], tst, tls) + return search('mix-indent', pattern) +end + +local function check_mixed_indent_file() + local head_spc = [[\v(^ +)]] + if vim.tbl_contains(options.c_langs, bo.filetype) then + head_spc = [[\v(^ +\*@!)]] + end + local indent_tabs = fn.search([[\v(^\t+)]], 'nw', 0, options.timeout) + local indent_spc = fn.search(head_spc, 'nw', 0, options.timeout) + if indent_tabs == 0 or indent_spc == 0 then return '' end + return string.format('[mix-indent-file:%d,%d]', indent_spc, indent_tabs) +end + +local function check_conflict() + local annotation = [[\%([0-9A-Za-z_.:]\+\)\?]] + local raw_pattern = [[^\%%(\%%(<\{7} %s\)\|\%%(=\{7\}\)\|\%%(>\{7\} %s\)\)$]] + if bo.filetype == 'rst' then + raw_pattern = [[^\%%(\%%(<\{7} %s\)\|\%%(>\{7\} %s\)\)$]] + end + local pattern = string.format(raw_pattern, annotation, annotation) + return search('conflict', pattern) +end + +local function get_item() + if not enabled then + cmd 'augroup hardline_whitespace' + cmd 'autocmd!' + cmd 'autocmd CursorHold, BufWritePost * unlet! b:hardline_whitespace' + cmd 'augroup end' + enabled = true + end + if bo.readonly or not bo.modifiable then return '' end + if fn.line('$') > options.max_lines then return '' end + if fn.exists('b:hardline_whitespace') ~= 0 then return '' end + local item = table.concat({ + ' ', + check_trailing(), + check_mixed_indent(), + check_mixed_indent_file(), + check_conflict(), + ' ', + }) + return item == ' ' and '' or item +end + +return { + get_item = get_item, +}