dotfiles

configuration files for shell, text editor, graphical environment, etc.
git clone git://src.adamsgaard.dk/dotfiles
Log | Files | Refs | README | LICENSE Back to index

commit fb76c9b46219e45ec4197a4454ff223da275aed4
parent a3000d8857f2f617f1cce7b89d55cfaeaf7bbff2
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Wed, 19 Jun 2019 09:13:04 +0200

Add ÆØÅ snippets and ctags plugin

Diffstat:
A.config/vis/plugins/ctags.lua | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M.config/vis/plugins/snippets.lua | 8+++++++-
M.config/vis/visrc.lua | 4++++
3 files changed, 282 insertions(+), 1 deletion(-)

diff --git a/.config/vis/plugins/ctags.lua b/.config/vis/plugins/ctags.lua @@ -0,0 +1,271 @@ +require('vis') + +local positions = {} + +local function get_path(prefix, path) + if string.find(path, '^./') ~= nil then + path = path:sub(3) + end + + return prefix .. path, path +end + +local function find_tags(path) + for i = #path, 1, -1 do + if path:sub(i, i) == '/' then + local prefix = path:sub(1, i) + local filename = prefix .. 'tags' + local file = io.open(filename, 'r') + + if file ~= nil then + return file, prefix + end + end + end +end + +local function bsearch(file, word) + local buffer_size = 8096 + local format = '\n(.-)\t(.-)\t(.-);\"\t' + + local from = 0 + local to = file:seek('end') + local startpos = nil + + while from <= to do + local mid = from + math.floor((to - from) / 2) + file:seek('set', mid) + + local content = file:read(buffer_size, '*line') + if content ~= nil then + local key, filename, excmd = string.match(content, format) + if key == nil then + break + end + + if key == word then + startpos = mid + end + + if key >= word then + to = mid - 1 + else + from = mid + 1 + end + else + to = mid - 1 + end + end + + if startpos ~= nil then + file:seek('set', startpos) + + local result = {} + while true do + local content = file:read(buffer_size, '*line') + if content == nil then + break + end + + for key, filename, excmd in string.gmatch(content, format) do + if key == word then + result[#result + 1] = {name = filename, excmd = excmd} + else + return result + end + end + end + + return result + end +end + +local function get_query() + local line = vis.win.selection.line + local pos = vis.win.selection.col + local str = vis.win.file.lines[line] + + local from, to = 0, 0 + while pos > to do + from, to = str:find('[%a_]+[%a%d_]*', to + 1) + if from == nil or from > pos then + return nil + end + end + + return string.sub(str, from, to) +end + +local function get_matches(word, path) + local file, prefix = find_tags(path) + + if file ~= nil then + local results = bsearch(file, word) + file:close() + + if results ~= nil then + local matches = {} + for i = 1, #results do + local result = results[i] + local path, name = get_path(prefix, result.name) + local desc = string.format('%s%s', name, tonumber(result.excmd) and ":"..result.excmd or "") + + matches[#matches + 1] = {desc = desc, path = path, excmd = result.excmd} + end + + return matches + end + end +end + +local function get_match(word, path) + local matches = get_matches(word, path) + if matches ~= nil then + for i = 1, #matches do + if matches[i].path == path then + return matches[i] + end + end + + return matches[1] + end +end + +local function escape(text) + return text:gsub("[][)(}{|+?*.]", "\\%0") + :gsub("%^", "\\^"):gsub("^/\\%^", "/^") + :gsub("%$", "\\$"):gsub("\\%$/$", "$/") + :gsub("\\\\%$%$/$", "\\$$") +end + +--[[ +- Can't test vis:command() as it will still return true if the edit command fails. +- Can't test File.modified as the edit command can succeed if the current file is + modified but open in another window and this behavior is useful. +- Instead just check the path again after trying the edit command. +]] +local function goto_pos(pos) + if pos.path ~= vis.win.file.path then + vis:command(string.format('e %s', pos.path)) + if pos.path ~= vis.win.file.path then + return false + end + end + if tonumber(pos.excmd) then + vis.win.selection:to(pos.excmd, pos.col) + else + vis.win.selection:to(1, 1) + vis:command(escape(pos.excmd)) + vis.win.selection.pos = vis.win.selection.range.start + vis.mode = vis.modes.NORMAL + end + return true +end + +local function goto_tag(path, excmd) + local old = { + path = vis.win.file.path, + excmd = vis.win.selection.line, + col = vis.win.selection.col, + } + + local last_search = vis.registers['/'] + if goto_pos({ path = path, excmd = excmd, col = 1 }) then + positions[#positions + 1] = old + vis.registers['/'] = last_search + end +end + +local function pop_pos() + if #positions < 1 then + return + end + if goto_pos(positions[#positions]) then + table.remove(positions, #positions) + end +end + +local function get_path() + if vis.win.file.path == nil then + return os.getenv('PWD') .. '/' + end + return vis.win.file.path +end + +local function tag_cmd(tag) + local match = get_match(tag, get_path()) + if match == nil then + vis:info(string.format('Tag not found: %s', tag)) + else + goto_tag(match.path, match.excmd) + end +end + +local function tselect_cmd(tag) + local matches = get_matches(tag, get_path()) + if matches == nil then + vis:info(string.format('Tag not found: %s', tag)) + else + local keys = {} + for i = 1, #matches do + table.insert(keys, matches[i].desc) + end + + local command = string.format( + [[echo -e "%s" | vis-menu -p "Choose tag:"]], table.concat(keys, [[\n]])) + + local status, output = + vis:pipe(vis.win.file, {start = 0, finish = 0}, command) + + if status ~= 0 then + vis:info('Command failed') + return + end + + local choice = string.match(output, '(.*)\n') + for i = 1, #matches do + local match = matches[i] + if match.desc == choice then + goto_tag(match.path, match.excmd) + break + end + end + end +end + +vis:command_register("tag", function(argv, force, win, selection, range) + if #argv == 1 then + tag_cmd(argv[1]) + end +end) + +vis:command_register("tselect", function(argv, force, win, selection, range) + if #argv == 1 then + tselect_cmd(argv[1]) + end +end) + +vis:command_register("pop", function(argv, force, win, selection, range) + pop_pos() +end) + +vis:map(vis.modes.NORMAL, '<C-]>', function(keys) + local query = get_query() + if query ~= nil then + tag_cmd(query) + end + return 0 +end) + +vis:map(vis.modes.NORMAL, 'g<C-]>', function(keys) + local query = get_query() + if query ~= nil then + tselect_cmd(query) + end + return 0 +end) + +vis:map(vis.modes.NORMAL, '<C-t>', function(keys) + pop_pos() + return 0 +end) diff --git a/.config/vis/plugins/snippets.lua b/.config/vis/plugins/snippets.lua @@ -1,4 +1,3 @@ --- snippets vis:map(vis.modes.INSERT, '`sig', '-- \n' .. 'Anders Damsgaard\n' .. @@ -7,3 +6,10 @@ vis:map(vis.modes.INSERT, '`sig', 'Photography: https://andersdamsgaard.com\n' .. 'PGP public key: https://adamsgaard.dk/ad-public-key.txt\n' .. 'PGP fingerprint: 5C95 9DF2 43CE 4DD1 7A5B 2610 B790 F4AD 1BF8 58FE') + +vis:map(vis.modes.INSERT, '`ae', 'æ') +vis:map(vis.modes.INSERT, '`AE', 'Æ') +vis:map(vis.modes.INSERT, '`oe', 'ø') +vis:map(vis.modes.INSERT, '`OE', 'Ø') +vis:map(vis.modes.INSERT, '`aa', 'å') +vis:map(vis.modes.INSERT, '`AA', 'Å') diff --git a/.config/vis/visrc.lua b/.config/vis/visrc.lua @@ -3,6 +3,7 @@ require('plugins/myfiletype') require('plugins/vis-commentary') require('plugins/fzf-mru') require('plugins/snippets') +require('plugins/ctags') leader = '<Space>' @@ -62,11 +63,13 @@ vis.events.subscribe(vis.events.INIT, function() vis:map(vis.modes.NORMAL, leader..'B', ':e "$BIB"<Enter>') vis:map(vis.modes.NORMAL, leader..'C', ':e ~/.config/vis/visrc.lua<Enter>') + vis:map(vis.modes.NORMAL, leader..'d', ':< date') vis:map(vis.modes.NORMAL, leader..'e', ':fzf true<Enter>') vis:map(vis.modes.NORMAL, leader..'g', ':rg true<Enter>') vis:map(vis.modes.NORMAL, leader..'G', ':rg<Enter>') vis:map(vis.modes.NORMAL, leader..'l', ':set show-newline!<Enter>') vis:map(vis.modes.NORMAL, leader..'m', ':!make<Enter>') + -- vis:map(vis.modes.NORMAL, leader..'m', ':!tmux split-window -p 25 "make"', vis:map(vis.modes.NORMAL, leader..'n', ':set numbers!<Enter>') vis:map(vis.modes.NORMAL, leader..'N', ':set relativenumbers!<Enter>') vis:map(vis.modes.NORMAL, leader..'o', ':fzf<Enter>') @@ -76,6 +79,7 @@ vis.events.subscribe(vis.events.INIT, function() vis:map(vis.modes.NORMAL, leader..'T', ':e ~/doc/todo.md<Enter>') vis:map(vis.modes.NORMAL, leader..'w', ':w<Enter>') vis:map(vis.modes.NORMAL, leader..'x', ':wq<Enter>') + vis:map(vis.modes.VISUAL, leader..'X', '') vis:map(vis.modes.VISUAL, leader..'y', ':> xclip<Enter>') vis:map(vis.modes.NORMAL, '<F7>', ':!sent $vis_filepath &<Enter>')