summaryrefslogtreecommitdiffstats
path: root/.config/nvim/plugin/50-format.lua
blob: e021227d0c5573ea8899fb32ca7e94848771d001 (plain)
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
--
-- 50-format.lua
--
-- * Specifies the formatters to use for different file types.
-- * Creates an autocommand to format on 'BufWritePre'.
--
-- User commands:
--   FormatToggle: toggle formatting on write for the current buffer

local function toggle_format()
	vim.b.format = not vim.b.format
end

local function format_impl(cmd, lines)
	local r = vim.system(cmd, { stdin = lines, text = true }):wait()
	if r.code ~= 0 then
		vim.notify(cmd[1] .. " error:\n" .. r.stderr, vim.log.levels.WARN)
		return nil
	end
	return vim.split(r.stdout, "\n", { trimempty = true })
end

local formatters = {
	["sh"] = function(lines)
		return format_impl({ "shfmt", "-" }, lines)
	end,
	["lua"] = function(lines)
		return format_impl({ "stylua", "--search-parent-directories", "-" }, lines)
	end,
	["markdown"] = function(lines)
		return format_impl({ "mdformat", "-" }, lines)
	end,
	["python"] = function(lines)
		return format_impl({ "black", "-" }, lines)
	end,
}
formatters.bash = formatters.sh

--- Format the buffer `ev.buf` with the formatter for its filetype.
--- This function is meant to be an event handler for `vim.api.nvim_create_autocmd()`
--- @param ev table `ev` argument passed from `vim.api.nvim_create_autocmd()`
local function on_format(ev)
	if vim.b[ev.buf].format ~= true then
		return
	end
	local ft = vim.bo[ev.buf].filetype
	local format = formatters[ft]
	if not format then
		vim.notify("No formatter registered for " .. ft, vim.log.levels.ERROR)
		return
	end
	local lines_in = vim.api.nvim_buf_get_lines(ev.buf, 0, -1, false)
	local lines_out = format(lines_in)
	if not lines_out or vim.deep_equal(lines_in, lines_out) then
		return
	end
	local view = vim.fn.winsaveview()
	vim.api.nvim_buf_set_lines(ev.buf, 0, -1, false, lines_out)
	vim.fn.winrestview(view)
end

vim.api.nvim_create_autocmd("BufWritePre", {
	desc = "Format buffer",
	group = vim.g.dotfiles.augroup,
	callback = on_format,
})

vim.api.nvim_create_user_command("FormatToggle", toggle_format, { desc = "Toggle format on save" })