diff options
Diffstat (limited to 'mut/vis/vis-format/init.lua')
| -rw-r--r-- | mut/vis/vis-format/init.lua | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/mut/vis/vis-format/init.lua b/mut/vis/vis-format/init.lua new file mode 100644 index 0000000..4b1183b --- /dev/null +++ b/mut/vis/vis-format/init.lua @@ -0,0 +1,224 @@ +local global_options = { + check_same = true, +} + +local func_formatter = function(func, options) + local apply = function(win, range, pos) + local size = win.file.size + local all = { start = 0, finish = size } + if range == nil then + range = all + end + local check_same = (options and options.check_same ~= nil) + and options.check_same + or global_options.check_same + local check = check_same == true + or (type(check_same) == 'number' and check_same >= size) + out, err = func(win, range, pos) + if err ~= nil then + if err:match('\n') then + vis:message(err) + else + vis:info(err) + end + return + elseif out == nil or out == '' then + vis:info('No output from formatter') + elseif not check or win.file:content(all) ~= out then + local start, finish = range.start, range.finish + win.file:delete(range) + win.file:insert(start, out:sub(start + 1, finish + (out:len() - size))) + end + return pos + end + return { + apply = apply, + options = options, + } +end + +local stdio_formatter = function(cmd, options) + return func_formatter(function(win, range, pos) + local command = type(cmd) == 'function' and cmd(win, range, pos) or cmd + local status, out, err = vis:pipe(win.file, range, command) + if status ~= 0 then + return nil, err + end + return out, nil + end, options or { ranged = type(cmd) == 'function' }) +end + +local with_filename = function(win, option) + if win.file.path then + return option .. "'" .. win.file.path:gsub("'", "\\'") .. "'" + else + return '' + end +end + +local formatters = {} +formatters = { + bash = stdio_formatter(function(win) + return 'shfmt ' .. with_filename(win, '--filename ') .. ' -' + end), + csharp = stdio_formatter('dotnet csharpier'), + diff = { + pick = function(win) + for _, pattern in ipairs(vis.ftdetect.filetypes['git-commit'].ext) do + if ((win.file.name or ''):match('[^/]+$') or ''):match(pattern) then + return formatters['git-commit'] + end + end + end, + }, + ['git-commit'] = func_formatter(function(win, range, pos) + local width = (win.options and win.options.colorcolumn ~= 0) + and (win.options.colorcolumn - 1) + or 72 + local parts = {} + local fmt = nil + local summary = true + for line in win.file:lines_iterator() do + local txt = not line:match('^#') + if fmt == nil or fmt ~= txt then + fmt = txt and not summary + local prev = parts[#parts] and parts[#parts].finish or 0 + parts[#parts + 1] = { + fmt = fmt, + start = prev, + finish = prev + #line + 1, + } + summary = summary and not txt + else + parts[#parts].finish = parts[#parts].finish + #line + 1 + end + end + local out = '' + for _, part in ipairs(parts) do + if part.fmt then + local status, partout, err = + vis:pipe(win.file, part, 'fmt -w ' .. width) + if status ~= 0 then + return nil, err + end + out = out .. (partout or '') + else + out = out .. win.file:content(part) + end + end + return out + end, { ranged = false }), + go = stdio_formatter('gofmt'), + lua = { + pick = function(win) + local fz = io.popen([[ + test -e .lua-format && echo luaformatter || echo stylua + ]]) + if fz then + local out = fz:read('*a') + local _, _, status = fz:close() + if status == 0 then + return formatters[out:gsub('\n$', '')] + end + end + end, + }, + luaformatter = stdio_formatter('lua-format'), + markdown = stdio_formatter(function(win) + if win.options and win.options.colorcolumn ~= 0 then + return 'prettier --parser markdown --prose-wrap always ' + .. ('--print-width ' .. (win.options.colorcolumn - 1) .. ' ') + .. with_filename(win, '--stdin-filepath ') + else + return 'prettier --parser markdown ' + .. with_filename(win, '--stdin-filepath ') + end + end, { ranged = false }), + powershell = stdio_formatter([[ + "$( (command -v powershell.exe || command -v pwsh) 2>/dev/null )" -c ' + Invoke-Formatter -ScriptDefinition ` + ([IO.StreamReader]::new([Console]::OpenStandardInput()).ReadToEnd()) + ' | sed -e :a -e '/^[\r\n]*$/{$d;N;};/\n$/ba' + ]]), + rust = stdio_formatter('rustfmt'), + stylua = stdio_formatter(function(win, range) + if range and (range.start ~= 0 or range.finish ~= win.file.size) then + return 'stylua -s --range-start ' + .. range.start + .. ' --range-end ' + .. range.finish + .. with_filename(win, ' --stdin-filepath ') + .. ' -' + else + return 'stylua -s ' .. with_filename(win, '--stdin-filepath ') .. ' -' + end + end), + text = stdio_formatter(function(win) + if win.options and win.options.colorcolumn ~= 0 then + return 'fmt -w ' .. (win.options.colorcolumn - 1) + else + return "fmt | awk -v n=-1 '" + .. ' {' + .. ' if ($0 == "") {' + .. ' n = n <= 0 ? 2 : 1' + .. ' } else {' + .. ' if (n == 0) sub(/^ */, "");' + .. ' n = 0;' + .. ' }' + .. ' printf("%s", $0 (n == 0 ? " " : ""));' + .. ' for(i = 0; i < n; i++)' + .. ' printf("\\n");' + .. ' }' + .. "'" + end + end, { ranged = false }), +} + +local getwinforfile = function(file) + for win in vis:windows() do + if win and win.file and win.file.path == file.path then + return win + end + end +end + +local apply = function(file_or_keys, range, pos) + local win = type(file_or_keys) ~= 'string' and getwinforfile(file_or_keys) + or vis.win + local ret = type(file_or_keys) ~= 'string' + and function() + return pos + end + or function() + return 0 + end + pos = pos or win.selection.pos + local formatter = formatters[win.syntax] + if formatter and formatter.pick then + formatter = formatter.pick(win) + end + if formatter == nil then + vis:info('No formatter for ' .. win.syntax) + return ret() + end + if + range ~= nil + and not formatter.options.ranged + and range.start ~= 0 + and range.finish ~= win.file.size + then + vis:info('Formatter for ' .. win.syntax .. ' does not support ranges') + return ret() + end + pos = formatter.apply(win, range, pos) or pos + vis:insert('') -- redraw and friends don't work + return ret() +end + +return { + formatters = formatters, + options = globalOptions, + apply = apply, + stdio_formatter = stdio_formatter, + with_filename = with_filename, +} |
