diff options
Diffstat (limited to 'home-configuration/config/nvim/after/plugin/netrw_fix.lua')
| -rw-r--r-- | home-configuration/config/nvim/after/plugin/netrw_fix.lua | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/home-configuration/config/nvim/after/plugin/netrw_fix.lua b/home-configuration/config/nvim/after/plugin/netrw_fix.lua new file mode 100644 index 0000000..be253ac --- /dev/null +++ b/home-configuration/config/nvim/after/plugin/netrw_fix.lua @@ -0,0 +1,122 @@ +local orig = {} + +local function parse(line) + local prefix, name = line:match('^([| ]*)(.-)%s*$') + local _, depth = prefix:gsub('|', '') + return depth, name +end + +local function open_entry() + local buf = vim.api.nvim_get_current_buf() + local lnum = vim.fn.line('.') + local depth, name = parse(vim.fn.getline(lnum)) + + local function fallback() + local rhs = orig[buf] and orig[buf].rhs + if rhs and rhs ~= '' then + vim.api.nvim_feedkeys(vim.keycode(rhs), 'n', false) + end + end + + if name == '' or name:sub(-1) == '/' or depth == 0 then + return fallback() + end + + local parts, cur, top = {}, depth, nil + for l = lnum - 1, 1, -1 do + local d, n = parse(vim.fn.getline(l)) + if n ~= '' and d < cur and n:sub(-1) == '/' then + if d == 0 then + top = n + break + end + table.insert(parts, 1, n) + cur = d + end + end + + if not top or not top:match('^%a+://') then + return fallback() + end + + vim.cmd('edit ' .. vim.fn.fnameescape(top .. table.concat(parts) .. name)) +end + +local function install(buf) + local m = vim.fn.maparg('<CR>', 'n', false, true) + if m.callback then return end + orig[buf] = m + vim.keymap.set('n', '<CR>', open_entry, { buffer = buf, silent = true }) +end + +vim.api.nvim_create_autocmd({ 'BufEnter', 'CursorMoved' }, { + callback = function(a) + if vim.bo[a.buf].filetype == 'netrw' and vim.g.netrw_liststyle == 3 then + install(a.buf) + end + end, +}) + +local pending = {} + +local function parse_url(url) + local host, path = url:match('^s[cf]tp://([^/]+)/(.*)$') + if not host then return end + local port + local h, p = host:match('^(.+):(%d+)$') + if h then host, port = h, p end + return host, port, path +end + +local function upload(a) + local buf, url = a.buf, a.match + local host, port, path = parse_url(url) + if not host then + vim.notify('cannot parse ' .. url, vim.log.levels.ERROR) + return + end + + local tmp = vim.fn.tempname() + vim.fn.writefile(vim.api.nvim_buf_get_lines(buf, 0, -1, false), tmp) + + local cmd = { 'scp', '-q', '-o', 'BatchMode=yes' } + if port then vim.list_extend(cmd, { '-P', port }) end + vim.list_extend(cmd, { tmp, host .. ':' .. path }) + + local name = vim.fn.fnamemodify(url, ':t') + vim.bo[buf].modified = false + + local id = #pending + 1 + pending[id] = vim.system(cmd, { text = true }, function(res) + pending[id] = false + os.remove(tmp) + vim.schedule(function() + if res.code == 0 then + vim.notify(name .. ': uploaded') + else + if vim.api.nvim_buf_is_valid(buf) then + vim.bo[buf].modified = true + end + local err = (vim.trim(res.stderr or ''):gsub('%s*\n%s*', ' ')) + vim.notify(name .. ': upload failed: ' .. err, vim.log.levels.ERROR) + end + end) + end) +end + +for _, pat in ipairs({ 'scp://*', 'sftp://*' }) do + pcall(vim.api.nvim_clear_autocmds, { event = 'BufWriteCmd', pattern = pat }) +end + +vim.api.nvim_create_autocmd('BufWriteCmd', { + pattern = { 'scp://*', 'sftp://*' }, + callback = upload, +}) + +vim.api.nvim_create_autocmd('VimLeavePre', { + callback = function() + for _, obj in pairs(pending) do + if obj then obj:wait() end + end + end, +}) |
