diff options
author | Josh Rahm <rahm@google.com> | 2024-03-12 23:04:21 +0000 |
---|---|---|
committer | Josh Rahm <rahm@google.com> | 2024-03-12 23:04:21 +0000 |
commit | d7415ac09d7afecc430d64ea17b57ceab7432c2e (patch) | |
tree | 7ab43d8c002c7b31d119a9b5e5dfe67a2e164489 | |
parent | ff00585c7c9e0cac8d1c75a8cb60fd82519b6856 (diff) | |
download | nvim-warp-d7415ac09d7afecc430d64ea17b57ceab7432c2e.tar.gz nvim-warp-d7415ac09d7afecc430d64ea17b57ceab7432c2e.tar.bz2 nvim-warp-d7415ac09d7afecc430d64ea17b57ceab7432c2e.zip |
Big refactor to warp.
Now two lines are displayed for row-choosing. Made row-choosing modular
as well.
-rw-r--r-- | lua/warp.lua | 138 | ||||
-rw-r--r-- | lua/warp/col_selectors/grid.lua | 10 | ||||
-rw-r--r-- | lua/warp/col_selectors/null.lua | 8 | ||||
-rw-r--r-- | lua/warp/col_selectors/words.lua | 9 | ||||
-rw-r--r-- | lua/warp/row_selectors/grid.lua | 111 | ||||
-rw-r--r-- | lua/warp/row_selectors/null.lua | 5 | ||||
-rw-r--r-- | lua/warp/util.lua | 77 | ||||
-rw-r--r-- | lua/warp/win_selectors/null.lua (renamed from lua/warp/win_selectors/current.lua) | 0 | ||||
-rw-r--r-- | plugin/warp.vim | 38 |
9 files changed, 255 insertions, 141 deletions
diff --git a/lua/warp.lua b/lua/warp.lua index 1b0141d..3ea4dba 100644 --- a/lua/warp.lua +++ b/lua/warp.lua @@ -1,90 +1,13 @@ local vim = assert(vim) local M = {} -local cons = "tnshrdlcumwfgypkbvjxqz" -- 21 -local vowel = "aeiou" -- 5 - -local function char_at(s, i) - local m = (i % #s) + 1 - return string.sub(s, m, m) -end - -local function new_panel(buf, row, col, width, height) - local w = vim.api.nvim_open_win(buf, false, { - relative = 'win', - row = row, - col = col, - width = width, - height = height, - focusable = true, - style = 'minimal' - }) - vim.api.nvim_win_set_option(w, "winhighlight", "Normal:WarpNormal") - return w -end - -M.open_vertical = function() - local current_win = vim.api.nvim_get_current_win() - local height = vim.api.nvim_win_get_height(current_win) - local topline = vim.fn.line('w0') - local width_of_garbage = vim.fn.getwininfo(current_win)[1].textoff - - M.row_map = {} - - M.vert_buf = vim.api.nvim_create_buf(0, 1) - local line = 0 - M.vert_lines = {} - local real_width = math.max(3, width_of_garbage) - while line < height do - local t = char_at(cons, line) .. char_at(vowel, line) - table.insert(M.vert_lines, (' '):rep(real_width - 3) .. t .. ' ') - M.row_map[t] = topline + line - line = line + 1 +M.run = function(win_selector, row_selector, col_selector) + if not row_selector then + row_selector = require('warp.row_selectors.grid') end - vim.api.nvim_buf_set_lines(M.vert_buf, 0, -1, 0, M.vert_lines) - -- local curpos = vim.api.nvim_win_get_cursor(0) - return new_panel(M.vert_buf, 0, 0, real_width, height); -end -M.open_horiz = function() - local current_win = vim.api.nvim_get_current_win() - local curpos = vim.api.nvim_win_get_cursor(0) - local topline = vim.fn.line('w0') - - local width_of_garbage = vim.fn.getwininfo(current_win)[1].textoff - local width = vim.api.nvim_win_get_width(current_win) - width_of_garbage - - M.horiz_bufnr = vim.api.nvim_create_buf(0, 1) - local line_at = vim.fn.getline(curpos[1]) - local max_width = math.min(width, #line_at + 1) - - return new_panel(M.horiz_bufnr, curpos[1] - topline + 1, width_of_garbage - 1, - max_width + 2, 1) -end - -M.filter_vert_text = function(ch) - local new_vert_text = {} - for _, t in pairs(M.vert_lines) do - local str = t:gsub("^%s*" .. ch, function(m) return (' '):rep(#m) end) - - if t:match('^%s*' .. ch) then - table.insert(new_vert_text, str) - else - table.insert(new_vert_text, "") - end - end - M.vert_lines = new_vert_text - vim.api.nvim_buf_set_lines(M.vert_buf, 0, -1, 0, M.vert_lines) -end - -local function next_char() - vim.cmd("redraw!") - return vim.fn.nr2char(vim.fn.getchar()) -end - -M.run = function(col_selector, win_selector) if not col_selector then - col_selector = require('warp.col_selectors.grid').strategy + col_selector = require('warp.col_selectors.grid') end if not win_selector then @@ -95,13 +18,7 @@ M.run = function(col_selector, win_selector) local old_scroll = vim.o.scrolloff vim.o.scrolloff = 0 - (function() - local w - - local cleanup = function(win) - vim.api.nvim_buf_delete(vim.api.nvim_win_get_buf(win), {force = true}) - end - + local f = function() local jump_to_win = win_selector.select_win() if not jump_to_win then return @@ -111,47 +28,18 @@ M.run = function(col_selector, win_selector) vim.api.nvim_set_current_win(jump_to_win) end - local read_row = function() - w = M.open_vertical() - local vch1 = next_char() - if vch1 == '\x1b' then - return - elseif vch1 == '.' then - return current_pos[1] - else - M.filter_vert_text(vch1) - local vch2 = next_char() - if vch1 == '\x1b' then return end - return M.row_map[vch1 .. vch2] - end - end - - local r = read_row() - if w then - cleanup(w) - w = nil - end - + local r = row_selector.read_row() if not r then return end + if r == '.' then + r = current_pos[1] + end vim.cmd("normal! m'") - pcall(function() vim.api.nvim_win_set_cursor(0, {r, current_pos[2]}) end) + vim.api.nvim_win_set_cursor(0, {r, current_pos[2]}) - local strat = col_selector() - 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 - - cleanup(w) - end)() + col_selector.run() + end + f () vim.o.scrolloff = old_scroll end diff --git a/lua/warp/col_selectors/grid.lua b/lua/warp/col_selectors/grid.lua index bc37b56..5f575d8 100644 --- a/lua/warp/col_selectors/grid.lua +++ b/lua/warp/col_selectors/grid.lua @@ -1,5 +1,6 @@ local vim = assert(vim) +local util = require('warp.util') local M = {} local hsel1 = "tnshrdlcmwfpgkbvjxy" -- 19 @@ -41,7 +42,7 @@ local big_line, col_map = make_big_line() M.strategy = function() local filter - return { + return util.wrap_col_selector({ display = function() local curpos = vim.api.nvim_win_get_cursor(0) local line_at = vim.fn.getline(curpos[1]) @@ -85,7 +86,12 @@ M.strategy = function() return false end - } + }) end +M.run = function () + M.strategy().run() +end + + return M diff --git a/lua/warp/col_selectors/null.lua b/lua/warp/col_selectors/null.lua index eb00921..61a1f79 100644 --- a/lua/warp/col_selectors/null.lua +++ b/lua/warp/col_selectors/null.lua @@ -1,12 +1,6 @@ -local vim = assert(vim) - local M = {} -M.null_strategy = function() - return { - display = function() return nil end, - on_char = function() return false end - } +M.run = function () end return M diff --git a/lua/warp/col_selectors/words.lua b/lua/warp/col_selectors/words.lua index 8135a45..305477c 100644 --- a/lua/warp/col_selectors/words.lua +++ b/lua/warp/col_selectors/words.lua @@ -2,6 +2,7 @@ local vim = assert(vim) local M = {} local alphabet = "etansihrdlocumwfgypkbvjxqz" +local util = require('warp.util') local function split_lines(line) local i @@ -49,10 +50,14 @@ local function split_lines(line) return winstr, chars_to_col end +M.run = function () + M.words_strategy().run() +end + M.words_strategy = function() local chartab - return { + return util.wrap_col_selector({ display = function() local curpos = vim.api.nvim_win_get_cursor(0) local line_at = vim.fn.getline(curpos[1]) @@ -71,7 +76,7 @@ M.words_strategy = function() end return false end - } + }) end return M diff --git a/lua/warp/row_selectors/grid.lua b/lua/warp/row_selectors/grid.lua new file mode 100644 index 0000000..d32a2a1 --- /dev/null +++ b/lua/warp/row_selectors/grid.lua @@ -0,0 +1,111 @@ +local M = {} +local util = require("warp.util") + +local cons = "tnshrdlcumwfgypkbvjxqz" -- 21 +local vowel = "aeiou" -- 5 + +local function char_at(s, i) + local m = (i % #s) + 1 + return string.sub(s, m, m) +end + +local function open_vertical(opts) + local current_win = vim.api.nvim_get_current_win() + local height = vim.api.nvim_win_get_height(current_win) + local topline = vim.fn.line('w0') + local width_of_garbage = vim.fn.getwininfo(current_win)[1].textoff + local row_map = {} + local left_buf = vim.api.nvim_create_buf(0, 1) + local right_buf = vim.api.nvim_create_buf(0, 1) + local line = 0 + local real_width = math.max(3, width_of_garbage) + local left_lines = {} + local right_lines = {} + local undecorated_lines = {} + + local function pad_left(t) + return (' '):rep(real_width - 3) .. t .. ' ' + end + + local function pad_right(t) + return ' ' .. t .. ' ' + end + + while line < height do + local t = char_at(cons, line) .. char_at(vowel, line) + table.insert(undecorated_lines, t) + table.insert(left_lines, pad_left(t)) + table.insert(right_lines, pad_right(t)) + row_map[t] = topline + line + line = line + 1 + end + vim.api.nvim_buf_set_lines(left_buf, 0, -1, 0, left_lines) + vim.api.nvim_buf_set_lines(right_buf, 0, -1, 0, right_lines) + -- local curpos = vim.api.nvim_win_get_cursor(0) + util.new_panel(left_buf, 0, 0, real_width, height) + if opts.two_columns then + local pos = vim.o.textwidth + width_of_garbage + pos = math.min(pos, vim.api.nvim_win_get_width(0) - 4) + util.new_panel(right_buf, 0, pos, 4, height) + end + return { + row_map = row_map, + cleanup = function () + vim.api.nvim_buf_delete(left_buf, {force = true}) + vim.api.nvim_buf_delete(right_buf, {force = true}) + end, + filter_vert_text = function(ch) + local new_left_text = {} + local new_right_text = {} + + for _, t in pairs(undecorated_lines) do + local str = t:gsub("^" .. ch, function(m) return (' '):rep(#m) end) + + if t:match('^' .. ch) then + table.insert(new_left_text, pad_left(str)) + table.insert(new_right_text, pad_right(str)) + else + table.insert(new_left_text, "") + table.insert(new_right_text, "") + end + end + + vim.api.nvim_buf_set_lines(left_buf, 0, -1, 0, new_left_text) + vim.api.nvim_buf_set_lines(right_buf, 0, -1, 0, new_right_text) + end + } +end + +M.read_row = function(opts) + local data + + if not opts then + opts = {} + end + + local row = (function () + data = open_vertical(opts) + local vch1 = util.next_char() + if vch1 == '\x1b' then + return + elseif vch1 == '.' then + return '.' + else + data.filter_vert_text(vch1) + local vch2 = util.next_char() + if vch1 == '\x1b' then return end + return data.row_map[vch1 .. vch2] + end + end)() + + data.cleanup() + return row +end + +M.with_opts = function(opts) + return { + read_row = function() return M.read_row(opts) end + } +end + +return M diff --git a/lua/warp/row_selectors/null.lua b/lua/warp/row_selectors/null.lua new file mode 100644 index 0000000..8e8e9f5 --- /dev/null +++ b/lua/warp/row_selectors/null.lua @@ -0,0 +1,5 @@ +local M = {} + +M.read_row = function () return '.' end + +return M diff --git a/lua/warp/util.lua b/lua/warp/util.lua new file mode 100644 index 0000000..4f1858e --- /dev/null +++ b/lua/warp/util.lua @@ -0,0 +1,77 @@ +local M = {} + +M.next_char = function() + vim.cmd("redraw!") + return vim.fn.nr2char(vim.fn.getchar()) +end + +M.new_panel = function(buf, row, col, width, height) + local w = vim.api.nvim_open_win(buf, false, { + relative = 'win', + row = row, + col = col, + width = width, + height = height, + focusable = true, + style = 'minimal' + }) + vim.api.nvim_win_set_option(w, "winhighlight", "Normal:WarpNormal") + return w +end + +M.open_horiz = function() + local current_win = vim.api.nvim_get_current_win() + local curpos = vim.api.nvim_win_get_cursor(0) + local topline = vim.fn.line('w0') + + local width_of_garbage = vim.fn.getwininfo(current_win)[1].textoff + local width = vim.api.nvim_win_get_width(current_win) - width_of_garbage + + local horiz_bufnr = vim.api.nvim_create_buf(0, 1) + local line_at = vim.fn.getline(curpos[1]) + local max_width = math.min(width, #line_at + 1) + + return { + buf = horiz_bufnr, + panel = M.new_panel(horiz_bufnr, curpos[1] - topline + 1, width_of_garbage - 1, + max_width + 2, 1) + } +end + +M.wrap_col_selector = function(strat) + local cleanup = function(win) + vim.api.nvim_buf_delete(vim.api.nvim_win_get_buf(win), {force = true}) + end + local w + + return { + run = function() + local data = M.open_horiz() + w = data.panel + + local f = function () + local disp = strat.display() + if disp then + vim.api.nvim_buf_set_lines(data.buf, 0, -1, 0, {' ' .. disp}) + local ch = M.next_char() + while ch ~= '\x1b' and strat.on_char(ch) do + vim.api.nvim_buf_set_lines(data.buf, 0, -1, 0, + {' ' .. strat.display()}) + ch = M.next_char() + end + end + end + f () + + cleanup(w) + end + } +end + +M.cleanup = function(win) + if win then + vim.api.nvim_buf_delete(vim.api.nvim_win_get_buf(win), {force = true}) + end +end + +return M diff --git a/lua/warp/win_selectors/current.lua b/lua/warp/win_selectors/null.lua index 2d2a75f..2d2a75f 100644 --- a/lua/warp/win_selectors/current.lua +++ b/lua/warp/win_selectors/null.lua diff --git a/plugin/warp.vim b/plugin/warp.vim index 95391a1..6b1fe68 100644 --- a/plugin/warp.vim +++ b/plugin/warp.vim @@ -1,16 +1,44 @@ " Uses a strategy that allows the user to select an arbitrary line and column by " using 2x2 key strokes. Is more complex, but most powerful. -command! WarpFull lua require('warp').run(require('warp.col_selectors.grid').grid_strategy, require('warp.win_selectors.prompt')) +command! WarpFull + \ lua require('warp').run( + \ require('warp.win_selectors.prompt'), + \ require('warp.row_selectors.grid').with_opts({ two_columns = true }), + \ require('warp.col_selectors.grid')) " Uses a strategy that allows the user to select an arbitrary line and column by " using 2x2 key strokes. Is more complex, but most powerful. -command! WarpGrid lua require('warp').run(require('warp.col_selectors.grid').grid_strategy) +command! WarpGrid + \ lua require('warp').run( + \ require('warp.win_selectors.null'), + \ require('warp.row_selectors.grid').with_opts({ two_columns = true }), + \ require('warp.col_selectors.grid')) " Has the user select the column based on nows. -command! WarpWords lua require('warp').run(require('warp.col_selectors.words').words_strategy) +command! WarpWords lua require('warp').run( + \ require('warp.win_selectors.null'), + \ require('warp.row_selectors.grid').with_opts({ two_columns = true }), + \ require('warp.col_selectors.words')) " Warps to the line and leaves the cursor on the current line. -command! WarpLine lua require('warp').run(require('warp.col_selectors.null').null_strategy) +command! WarpLine lua require('warp').run( + \ require('warp.win_selectors.null'), + \ require('warp.row_selectors.grid').with_opts({ two_columns = true }), + \ require('warp.col_selectors.null')) + +" Warps to the column and leaves the cursor on the same line +command! WarpCol lua require('warp').run( + \ require('warp.win_selectors.null'), + \ require('warp.row_selectors.null'), + \ require('warp.col_selectors.grid')) + +" Warps to a window +command! WarpWin + \ lua require('warp').run( + \ require('warp.win_selectors.prompt'), + \ require('warp.row_selectors.null'), + \ require('warp.col_selectors.null')) + noremap <Plug>(warp-grid) <cmd>WarpGrid<cr> noremap <Plug>(warp-words) <cmd>WarpWords<cr> @@ -18,4 +46,4 @@ noremap <Plug>(warp-line) <cmd>WarpLine<cr> onoremap v<Plug>(warp-grid) <cmd>WarpGrid<cr> onoremap v<Plug>(warp-words) <cmd>WarpWords<cr> -onoremap v<Plug>(warp-line) <cmd>WarpLine<cr> +onoremap V<Plug>(warp-line) <cmd>WarpLine<cr> |