diff options
-rw-r--r-- | lua/warp.lua | 74 | ||||
-rw-r--r-- | lua/warp/strategy/default.lua | 92 | ||||
-rw-r--r-- | lua/warp/strategy/null.lua | 12 | ||||
-rw-r--r-- | lua/warp/strategy/words.lua | 84 | ||||
-rw-r--r-- | plugin/warp.vim | 3 |
5 files changed, 209 insertions, 56 deletions
diff --git a/lua/warp.lua b/lua/warp.lua index d3b6337..a2332f4 100644 --- a/lua/warp.lua +++ b/lua/warp.lua @@ -19,7 +19,7 @@ local function new_panel(buf, row, col, width, height) col = col, width = width, height = height, - focusable = false, + focusable = true, style = 'minimal' }) vim.api.nvim_win_set_option(w, "winhighlight", "Normal:WarpNormal") @@ -57,35 +57,8 @@ M.open_horiz = function() local width = vim.api.nvim_win_get_width(current_win) - width_of_garbage M.horiz_bufnr = vim.api.nvim_create_buf(0, 1) - local col = 0 - local line = '' - - local v = '' - local c = nil - local i = 0 local line_at = vim.fn.getline(curpos[1]) - M.col_map = {} local max_width = math.min(width, #line_at + 1) - while col < max_width do - v = char_at(hsel1, i) - if c then - if M.col_map[v .. c] then break end - M.col_map[c .. v] = col - 1 - end - c = char_at(hsel2, i) - if M.col_map[c .. v] then break end - line = line .. v - col = col + 1 - if col < max_width then - line = line .. c - M.col_map[v .. c] = col - 1 - col = col + 1 - i = i + 1 - end - end - - vim.api.nvim_buf_set_lines(M.horiz_bufnr, 0, -1, 0, {' ' .. line}) - M.horiz_line = line return new_panel(M.horiz_bufnr, curpos[1] - topline + 1, width_of_garbage - 1, max_width + 2, 1) @@ -127,7 +100,11 @@ local function next_char() return vim.fn.nr2char(vim.fn.getchar()) end -M.run = function() +M.run = function(strat_fn) + if not strat_fn then + strat_fn = require('warp.strategy.default').default_col_strategy + end + local current_pos = vim.api.nvim_win_get_cursor(0) local old_scroll = vim.o.scrolloff vim.o.scrolloff = 0 @@ -164,36 +141,21 @@ M.run = function() vim.api.nvim_win_set_cursor(0, {r, current_pos[2]}) - local read_col = function() - w = M.open_horiz() - local hch1 = next_char() - - if hch1 == '\x1b' then - return nil - elseif hch1 == '.' then - return current_pos[2] - elseif not hch1:match('[a-z]') then - return hch1 - else - M.filter_horiz_string(hch1) - - local hch2 = next_char() - if hch2 == '\x1b' then return end - return M.col_map[hch1 .. hch2] + local strat = strat_fn() + w = M.open_horiz() + local disp = strat.display() + if disp then + vim.api + .nvim_buf_set_lines(M.horiz_bufnr, 0, -1, 0, {' ' .. disp}) + local ch = next_char() + while ch ~= '\x1b' and strat.on_char(ch) do + vim.api.nvim_buf_set_lines(M.horiz_bufnr, 0, -1, 0, + {' ' .. strat.display()}) + ch = next_char() end end - local c = read_col() - if w then cleanup(w) end - if not c then return end - - if c == '$' or c == '^' then - vim.cmd("normal! " .. c) - elseif type(c) == 'string' then - vim.cmd("normal! f" .. c) - else - vim.cmd("normal! " .. (c + 1) .. "|") -- handle multibyte characters - end + cleanup(w) end)() vim.o.scrolloff = old_scroll diff --git a/lua/warp/strategy/default.lua b/lua/warp/strategy/default.lua new file mode 100644 index 0000000..55019d8 --- /dev/null +++ b/lua/warp/strategy/default.lua @@ -0,0 +1,92 @@ +local vim = assert(vim) + +local M = {} + +local hsel1 = "tnshrdlcumwfgypkbvjxqz" -- 21 +local hsel2 = "aeiou" -- 5 + +local function char_at(s, i) + local m = (i % #s) + 1 + return string.sub(s, m, m) +end + +local function make_big_line() + local col = 0 + local line = '' + + local v = '' + local c = nil + local i = 0 + local col_map = {} + while true do + v = char_at(hsel1, i) + if c then + if col_map[v .. c] then break end + col_map[c .. v] = col + end + c = char_at(hsel2, i) + if col_map[c .. v] then break end + line = line .. v + col = col + 1 + line = line .. c + col_map[v .. c] = col + col = col + 1 + i = i + 1 + end + + return line, col_map +end + +local big_line, col_map = make_big_line() + +M.default_strategy = function () + local filter + + return { + display = function () + local curpos = vim.api.nvim_win_get_cursor(0) + local line_at = vim.fn.getline(curpos[1]) + local unfiltered = big_line:sub(1, #line_at + 1) + local line = unfiltered + + if filter then + line = "" + local i = 1 + while i <= #unfiltered do + local curch = char_at(unfiltered, i - 1) + if curch == filter then + line = line .. char_at(unfiltered, i) + else + line = line .. ' ' + end + i = i + 1 + end + end + + return line + end, + + on_char = function (ch) + if not filter then + if ch == '$' or ch == '^' then + vim.cmd("normal! " .. ch) + return false + elseif not ch:match('[a-z]') then + vim.cmd("normal! f" .. ch) + return false + else + filter = ch + return true + end + else + if col_map[filter .. ch] then + vim.cmd("normal! " .. col_map[filter .. ch] .. "|") + end + end + + return false + end + } +end + +return M diff --git a/lua/warp/strategy/null.lua b/lua/warp/strategy/null.lua new file mode 100644 index 0000000..9464547 --- /dev/null +++ b/lua/warp/strategy/null.lua @@ -0,0 +1,12 @@ +local vim = assert(vim) + +local M = {} + +M.null_strategy = function () + return { + display = function () return nil end, + on_char = function () return false end + } +end + +return M diff --git a/lua/warp/strategy/words.lua b/lua/warp/strategy/words.lua new file mode 100644 index 0000000..d255203 --- /dev/null +++ b/lua/warp/strategy/words.lua @@ -0,0 +1,84 @@ +local vim = assert(vim) + +local M = {} +local alphabet = "etansihrdlocumwfgypkbvjxqz" + +local function split_lines(line) + local i + local j = 1 + + local chars_to_col = {} + local col_to_chars = {} + + local run_regex = function(rx, off) + if #alphabet < j then + return + end + + if not off then + off = 0 + end + + i = 0 + while true do + i = string.find(line, rx, i) + if i == nil then break end + i = i + 1 + + if #alphabet < j then + return + end + + local nextalph = alphabet:sub(j, j) + j = j + 1 + chars_to_col[nextalph] = i + off + col_to_chars[i + off] = nextalph + end + end + + run_regex("%W%w") + run_regex("%s%S") + run_regex("%w%W", - 1) + + local winstr = "" + i = 1 + while i <= #line do + if col_to_chars[i] then + winstr = winstr .. col_to_chars[i] + else + winstr = winstr .. " " + end + i = i + 1 + end + + return winstr, chars_to_col +end + +M.words_strategy = function () + local chartab + + return { + display = function () + local curpos = vim.api.nvim_win_get_cursor(0) + local line_at = vim.fn.getline(curpos[1]) + local str, tab = split_lines(line_at) + chartab = tab + return str + end, + + on_char = function (ch) + if ch == '$' or ch == '^' then + vim.cmd("normal! " .. ch) + elseif not ch:match('[a-z]') then + vim.cmd("normal! f" .. ch) + else + if chartab[ch] then + vim.cmd("norma! " .. chartab[ch] .. "|") + end + end + return false + end + } +end + +return M diff --git a/plugin/warp.vim b/plugin/warp.vim new file mode 100644 index 0000000..2190d31 --- /dev/null +++ b/plugin/warp.vim @@ -0,0 +1,3 @@ +command! WarpGrid lua require('warp').run(require('warp.strategy.default').default_strategy) +command! WarpWords lua require('warp').run(require('warp.strategy.words').words_strategy) +command! WarpLine lua require('warp').run(require('warp.strategy.null').null_strategy) |