diff options
Diffstat (limited to 'config/essentials/vis/complete-line.lua')
-rw-r--r-- | config/essentials/vis/complete-line.lua | 171 |
1 files changed, 43 insertions, 128 deletions
diff --git a/config/essentials/vis/complete-line.lua b/config/essentials/vis/complete-line.lua index 93728a3..98515a9 100644 --- a/config/essentials/vis/complete-line.lua +++ b/config/essentials/vis/complete-line.lua @@ -1,141 +1,56 @@ +--[[ +Based on https://repo.or.cz/vis-complete-line.git +Changes made: +- stylua +- removed <C-x><C-e>, <C-x><C-y> and related functions and variables +--]] + -- SPDX-License-Identifier: GPL-3.0-or-later -- © 2020 Georgi Kirilov local progname = ... -local lpeg = require("lpeg") -local R, C, Cmt = lpeg.R, lpeg.C, lpeg.Cmt - --- copied from vis.h -local VIS_MOVE_NOP = 64 - -local cont = R("\128\191") - -local charpattern = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * - cont + R("\240\244") * cont * cont * cont - local function concat_keys(tbl) - local keys = {} - for k in pairs(tbl) do table.insert(keys, k) end - return table.concat(keys, "\n"), #keys + local keys = {} + for k in pairs(tbl) do + table.insert(keys, k) + end + return table.concat(keys, "\n"), #keys end local function line_complete() - local file = vis.win.file - local sel = vis.win.selection - local cur_line = file.lines[sel.line] - local indent_patt = "^[ \t\v\f]+" - local prefix = cur_line:sub(1, sel.col - 1):gsub(indent_patt, "") - local candidates = {} - for l in file:lines_iterator() do - local unindented = l:gsub(indent_patt, "") - local start, finish = unindented:find(prefix, 1, true) - if start == 1 and finish < #unindented then - candidates[unindented] = true - end - end - local candidates_str, n = concat_keys(candidates) - if n < 2 then - if n == 1 then vis:insert(candidates_str:sub(#prefix + 1)) end - return - end - -- XXX: with too many candidates this command will become longer that the shell can handle: - local command = string.format("vis-menu -l %d <<'EOF'\n%s\nEOF\n", - math.min(n, math.ceil(vis.win.height / 2)), - candidates_str) - local status, output = vis:pipe(nil, nil, command) - if n > 0 and status == 0 then - vis:insert(output:sub(#prefix + 1):gsub("\n$", "")) - end -end - -local function selection_by_pos(pos) - for s in vis.win:selections_iterator() do - if s.pos == pos then return s end - end -end - -local function charwidth(cells_so_far, char) - if char == "\t" then - local tw = vis.tabwidth or 8 - local trail = cells_so_far % tw - return tw - trail - else - return 1 - end -end - -local function virtcol(line, col) - local ncells = 0 - local nchars = 0 - local function upto(_, _, char) - if nchars < col - 1 then - ncells = ncells + charwidth(ncells, char) - nchars = nchars + 1 - return true - end - end - (Cmt(C(charpattern), upto) ^ 0):match(line) - return ncells + 1 -end - -local function neighbor(lines, ln, col, direction) - local line = ln + direction > 0 and lines[ln + direction] - if not line then return end - local column = virtcol(lines[ln], col) - local ncells = 0 - local function upto(_, _, char) - ncells = ncells + charwidth(ncells, char) - return ncells < column - end - return - (Cmt(C(charpattern), upto) ^ (-column + 1) / 0 * C(charpattern)):match( - line) -end - -local function dup_neighbor(direction) - return function(file, _, pos) - local sel = selection_by_pos(pos) - local char = neighbor(file.lines, sel.line, sel.col, direction) - if not char then return pos end - file:insert(pos, char) - return pos + #char - end -end - -local function dup_neighbor_feedkeys(direction) - local sel = vis.win.selection - local file = vis.win.file - local char = neighbor(file.lines, sel.line, sel.col, direction) - if not char then return end - vis:feedkeys(char) -end - -local function operator(handler) - local id = vis:operator_register(handler) - return id >= 0 and function() - vis:operator(id) - vis:motion(VIS_MOVE_NOP) - end + local file = vis.win.file + local sel = vis.win.selection + local cur_line = file.lines[sel.line] + local indent_patt = "^[ \t\v\f]+" + local prefix = cur_line:sub(1, sel.col - 1):gsub(indent_patt, "") + local candidates = {} + for l in file:lines_iterator() do + local unindented = l:gsub(indent_patt, "") + local start, finish = unindented:find(prefix, 1, true) + if start == 1 and finish < #unindented then + candidates[unindented] = true + end + end + local candidates_str, n = concat_keys(candidates) + if n < 2 then + if n == 1 then + vis:insert(candidates_str:sub(#prefix + 1)) + end + return + end + -- XXX: with too many candidates this command will become longer that the shell can handle: + local command = + string.format("vis-menu -l %d <<'EOF'\n%s\nEOF\n", math.min(n, math.ceil(vis.win.height / 2)), candidates_str) + local status, output = vis:pipe(nil, nil, command) + if n > 0 and status == 0 then + vis:insert(output:sub(#prefix + 1):gsub("\n$", "")) + end end vis.events.subscribe(vis.events.INIT, function() - local function h(msg) return string.format("|@%s| %s", progname, msg) end - - local function column_complete(direction) - local binding = operator(dup_neighbor(direction)) - return function() - if #vis.win.selections == 1 then - dup_neighbor_feedkeys(direction) - else - return binding() - end - end - end + local function h(msg) + return string.format("|@%s| %s", progname, msg) + end - vis:map(vis.modes.INSERT, "<C-y>", column_complete(-1), - h "Insert the character which is above the cursor") - vis:map(vis.modes.INSERT, "<C-e>", column_complete(1), - h "Insert the character which is below the cursor") - vis:map(vis.modes.INSERT, "<C-x><C-l>", line_complete, - h "Complete the current line") + vis:map(vis.modes.INSERT, "<C-x><C-l>", line_complete, h("Complete the current line")) end) |