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 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 end if not win_selector then win_selector = require('warp.win_selectors.current') end local current_pos = vim.api.nvim_win_get_cursor(0) 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 jump_to_win = win_selector.select_win() if not jump_to_win then return end vim.cmd([[redraw!]]) if jump_to_win ~= 0 then 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 if not r then return end vim.cmd("normal! m'") pcall(function() vim.api.nvim_win_set_cursor(0, {r, current_pos[2]}) end) 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)() vim.o.scrolloff = old_scroll end return M