summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2024-03-12 23:04:21 +0000
committerJosh Rahm <rahm@google.com>2024-03-12 23:04:21 +0000
commitd7415ac09d7afecc430d64ea17b57ceab7432c2e (patch)
tree7ab43d8c002c7b31d119a9b5e5dfe67a2e164489
parentff00585c7c9e0cac8d1c75a8cb60fd82519b6856 (diff)
downloadnvim-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.lua138
-rw-r--r--lua/warp/col_selectors/grid.lua10
-rw-r--r--lua/warp/col_selectors/null.lua8
-rw-r--r--lua/warp/col_selectors/words.lua9
-rw-r--r--lua/warp/row_selectors/grid.lua111
-rw-r--r--lua/warp/row_selectors/null.lua5
-rw-r--r--lua/warp/util.lua77
-rw-r--r--lua/warp/win_selectors/null.lua (renamed from lua/warp/win_selectors/current.lua)0
-rw-r--r--plugin/warp.vim38
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>