diff --git a/dot_config/nvim/plugin/sops.lua b/dot_config/nvim/plugin/sops.lua new file mode 100644 index 0000000..d34537d --- /dev/null +++ b/dot_config/nvim/plugin/sops.lua @@ -0,0 +1,101 @@ +local api = vim.api +local ag = api.nvim_create_augroup('sops', {}) + +local function path_from_uri(uri) + return string.sub(uri, string.len('sops://') + 1) +end + +local function write_buf(buf) + local file = path_from_uri(api.nvim_buf_get_name(buf)) + local cmd = vim.system({ + 'sh', + '-c', + vim.fn.printf( + 'sops encrypt --filename-override %s --output %s <(cat)', -- ugly work around /dev/stdout not existing in vim.system() + vim.fn.shellescape(file), + vim.fn.shellescape(file)), + }, { + stdin = api.nvim_buf_get_lines(buf, 0, -1, true), + }) + + local res = cmd:wait() + + if res.code > 0 then + vim.notify('Could not encrypt ' .. vim.fn.fnamemodify(file, ':p:.') .. ': ' .. res.stderr, vim.log.levels.WARN) + return + end + + api.nvim_set_option_value('modified', false, { buf = buf }) + vim.notify('Saved encrypted file ' .. vim.fn.fnamemodify(file, ':p:.'), vim.log.levels.INFO) +end + + +-- @param buf number +local function setup_buffer(buf) + if api.nvim_get_option_value('buftype', { buf = buf }) == 'acwrite' then + -- was here already + return + end + api.nvim_set_option_value('buftype', 'acwrite', { buf = buf }) + api.nvim_set_option_value('swapfile', false, { buf = buf }) -- encrypted data shouldn't be laying around.... + + api.nvim_create_autocmd('BufWriteCmd', { + group = ag, + buffer = buf, + callback = function(ev) + write_buf(ev.buf) + end, + }) +end + +-- @param file string +-- @return string +local function load_buf(buf) + local file = path_from_uri(api.nvim_buf_get_name(buf)) + local res = vim.system({ 'sops', 'decrypt', file }, { text = true }):wait() + + if res.code > 0 then + vim.notify('Could not decrypt ' .. file .. ': ' .. res.stderr, vim.log.levels.WARN) + return + end + + vim.cmd.doautocmd({"BufReadPre", file}) + api.nvim_buf_set_lines(buf, 0, -1, true, vim.split(res.stdout, '\n')) + setup_buffer(buf) + vim.notify('Decrypted file ' .. vim.fn.fnamemodify(file, ':p:.'), vim.log.levels.INFO) + + vim.cmd.doautocmd({"BufReadPost", file}) +end + +api.nvim_create_autocmd('BufReadCmd', { + group = ag, + pattern = 'sops://*', + callback = function(ev) + local buf = ev.buf + load_buf(buf) + end, +}) + +api.nvim_create_user_command('SopsEdit', function(opts) + local fargs = opts.fargs + local file = nil + local args = { args = {}, bang = opts.bang } + if #fargs == 0 then + file = api.nvim_buf_get_name(0) + if string.sub(file, 0, string.len('sops://')) ~= 'sops://' then + args.args = { 'sops://' .. file } + end + else + file = fargs[1] + if string.sub(file, 0, string.len('sops://')) ~= 'sops://' then + file = 'sops://' .. vim.fn.fnamemodify(file, ':p') + end + args.args = { file } + end + + vim.cmd.edit(args) +end, { + bang = true, + complete = 'file', + nargs = '?', +})