require('vis') local m = vis.modes local mode_strings = { [m.NORMAL] = 'NORMAL', [m.OPERATOR_PENDING] = 'OPERATOR-PENDING', [m.VISUAL] = 'VISUAL', [m.VISUAL_LINE] = 'VISUAL-LINE', [m.INSERT] = 'INSERT', [m.REPLACE] = 'REPLACE', } local e = vis.events -- init e.subscribe(e.INIT, function() -- load theme require("themes/basic") local lexers = vis.lexers lexers.lexers = {} if lexers.load and not lexers.property then lexers.load("text") end -- mappings vis:map(m.NORMAL, 'y', '+') vis:map(m.VISUAL, 'y', '+') vis:map(m.NORMAL, 'y', '+') vis:map(m.VISUAL, 'd', '+') vis:map(m.VISUAL_LINE, 'd', '+') vis:map(m.VISUAL_LINE, 'd', '+') vis:map(m.NORMAL, 'p', '+') vis:map(m.VISUAL, 'p', '+') vis:map(m.VISUAL_LINE, 'p', '+') vis:map(m.NORMAL, 'P', '+') vis:map(m.VISUAL, 'P', '+') vis:map(m.VISUAL_LINE, 'P', '+') vis:map(m.NORMAL, 'gA', '') vis:map(m.NORMAL, '', ''); vis:map(m.NORMAL, '', ''); vis:map(m.NORMAL, 'o', function() local unclosed for win in vis:windows() do if win == vis.win then goto continue end if win:close() then goto continue end unclosed = win ::continue:: end if unclosed then vis.win = unclosed vis:info('No write since last change') end end, 'Close all unfocused windows') vis:map(m.NORMAL, ' e', function() local s, f = vis:pipe('find -type f | vis-menu -l 5 -p "pick file"') if s ~= 0 or not f then return end cmd = ('e "%s"'):format(f:sub(1, -2)) vis:info(cmd) vis:command(cmd) end, 'pick file to :e') vis:map(m.NORMAL, ' o', function() local s, f = vis:pipe('find -type f | vis-menu -l 5 -p "pick file"') if s ~= 0 or not f then return end cmd = ('o "%s"'):format(f:sub(1, -2)) vis:info(cmd) vis:command(cmd) end, 'pick file to :o') vis:map(m.NORMAL, ' b', function() local wins = {} local i, wi = 0, 0 for win in vis:windows() do table.insert(wins, ('%q:%q'):format(i,win.file.name or '[No_Name]')) if win == vis.win then wi = i end i = i + 1 end wins = table.concat(wins, '\n') local s, w = vis:pipe(('printf "%s" | vis-menu -l 5 -p "pick window"'):format(wins)) if s ~= 0 or not w then return end local si = tonumber(w:match('^(%d+):.*$') or wi) if si == wi then return end local action = si > wi and '' or '' for i=1,math.abs(si-wi) do vis:feedkeys(action) end end, 'pick window to move to') vis:map(m.NORMAL, ' g', function() local s, word = vis:pipe( vis.win.file or nil, vis.win.viewport.bytes, 'grep -Eo "\\w\\w\\w+" | sort -u | vis-menu -l 5 -p "grep"') if s ~= 0 or not word then return end word = word:sub(1, -2) local s, f = vis:pipe(('grep -n "%s" ** | tr "\\t" " " | vis-menu -l 5 -p ":o"'):format(word)) if s ~= 0 or not f then return end local file, lineno, line = f:match("^(.+):(%d+):(.*)$") if file == nil then return end -- TODO report error cmd = ('o "%s"'):format(file) vis:info(cmd) vis:command(cmd) vis.win.selection:to(tonumber(lineno), line:find(word)) end, 'grep and pick file to :o') -- editor options vis.options.autoindent = true end) -- window open e.subscribe(e.WIN_OPEN, function(win) win.options.colorcolumn = 81 win.options.relativenumbers = true if win.syntax == 'markdown' then win.options.breakat = " ])}_" win.options.expandtab = true win.options.tabwidth = 2 win.options.wrapcolumn = 81 end if win.syntax == 'css' then win.options.expandtab = true win.options.tabwidth = 2 end end) -- statusline e.subscribe(e.WIN_STATUS, function(win) local left_parts = {} local right_parts = {} local file = win.file local selection = win.selection local file_info = (file.name or '[No Name]')..(file.modified and '[+]' or '') if vis.win == win then -- mode table.insert(left_parts, mode_strings[vis.mode]) -- selection table.insert(left_parts, selection.number..'/'..#win.selections) -- file info file_info = file_info ..':' ..(vis.count or '') ..(vis.input_queue or '') ..(vis.recording and '@' or '') -- syntax table.insert(right_parts, win.syntax) -- character under cursor table.insert(right_parts, '<' ..(string.byte(file:content(selection.pos, 1)) or '0') ..'>') end table.insert(left_parts, file_info) -- line and column count table.insert(right_parts, #file.lines..'/'..selection.line) table.insert(right_parts, selection.col) -- fillchars local left = table.concat(left_parts, ' ') local right = table.concat(right_parts, ' ') win:status(table.concat({ left, ('^'):rep(win.width - #left - #right - 2)}, ' '), right) end) -- title local modified = false local function set_title(title) os.execute('printf "\\e];vis: '..title..(modified and '[+]' or '')..'\\e"') end e.subscribe(e.WIN_OPEN, function(win) set_title(win.file.name or '[No Name]') end) e.subscribe(e.FILE_SAVE_POST, function(file) modified = false set_title(file.name) end) e.subscribe(e.WIN_STATUS, function(win) if not modified and win.file.modified then modified = true set_title(win.file.name or '[No Name]') end end) -- find root e.subscribe(e.WIN_OPEN, function(win) if not win.file.path then return end local dir = win.file.path local home = os.getenv('HOME') if not dir:find(home) then return end while true do dir = dir:match('^(.+)/[^/]+$') or home local _, find = vis:pipe(('find %s ! -path %s -prune -type d -name .git'):format(dir, dir)) if find or dir == home then local cmd = ('cd "%s"'):format(dir) vis:info(cmd) vis:command(cmd) break end end end)