2023-01-10 02:38:06 +01:00
|
|
|
local M = {
|
|
|
|
-- keybinds where you only hit the head once
|
|
|
|
"anuvyklack/hydra.nvim",
|
|
|
|
dependencies = {
|
|
|
|
"mrjones2014/smart-splits.nvim", -- the name says it all
|
|
|
|
},
|
2023-09-08 19:49:18 +02:00
|
|
|
keys = { "<C-S-w>" },
|
2023-01-10 02:38:06 +01:00
|
|
|
}
|
|
|
|
|
2023-09-08 19:49:18 +02:00
|
|
|
-- {{{ Helpers
|
|
|
|
local function identity(x)
|
|
|
|
return x
|
|
|
|
end
|
|
|
|
|
|
|
|
local function len(x)
|
|
|
|
return #x
|
|
|
|
end
|
|
|
|
|
|
|
|
local function box(value, w, h)
|
|
|
|
return { value = value, width = w, height = h }
|
|
|
|
end
|
|
|
|
|
|
|
|
local function min(l, r)
|
|
|
|
if l < r then
|
|
|
|
return l
|
|
|
|
else
|
|
|
|
return r
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function max(l, r)
|
|
|
|
return -min(-l, -r)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function zip_with(l, r, f, default)
|
|
|
|
local output = {}
|
|
|
|
for i = 1, max(#l, #r), 1 do
|
|
|
|
output[i] = f(l[i] or default, r[i] or default)
|
|
|
|
end
|
|
|
|
|
|
|
|
return output
|
|
|
|
end
|
|
|
|
|
|
|
|
local function flatten_list(list)
|
|
|
|
local output = {}
|
|
|
|
|
|
|
|
for i = 1, #list, 1 do
|
|
|
|
for j = 1, #list[i], 1 do
|
|
|
|
table.insert(output, list[i][j])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return output
|
|
|
|
end
|
|
|
|
|
|
|
|
local function map_list(list, f)
|
|
|
|
local output = {}
|
|
|
|
for i = 1, #list, 1 do
|
|
|
|
output[i] = f(list[i])
|
|
|
|
end
|
|
|
|
return output
|
|
|
|
end
|
|
|
|
|
|
|
|
local function l_repeat(v, times)
|
|
|
|
if times == 0 then
|
|
|
|
return {}
|
|
|
|
end
|
|
|
|
|
|
|
|
local o = {}
|
|
|
|
|
|
|
|
for i = 1, times, 1 do
|
|
|
|
o[i] = v
|
|
|
|
end
|
|
|
|
|
|
|
|
return o
|
|
|
|
end
|
|
|
|
|
|
|
|
local function s_repeat(text, times)
|
|
|
|
local o = ""
|
|
|
|
|
|
|
|
for _ = 1, times, 1 do
|
|
|
|
o = o .. text
|
|
|
|
end
|
|
|
|
|
|
|
|
return o
|
|
|
|
end
|
|
|
|
local function string_split(text, sep)
|
|
|
|
---@diagnostic disable-next-line: redefined-local
|
|
|
|
local sep, fields = sep or ":", {}
|
|
|
|
local pattern = string.format("([^%s]+)", sep)
|
|
|
|
text:gsub(pattern, function(c)
|
|
|
|
fields[#fields + 1] = c
|
|
|
|
end)
|
|
|
|
return fields
|
|
|
|
end
|
|
|
|
|
|
|
|
local function table_max(list, f, default)
|
|
|
|
if #list == 0 then
|
|
|
|
return default
|
|
|
|
end
|
|
|
|
---@diagnostic disable-next-line: redefined-local
|
|
|
|
local f = f or identity
|
|
|
|
local c_max = list[1]
|
|
|
|
for i = 1, #list, 1 do
|
|
|
|
if f(list[i]) >= f(c_max) then
|
|
|
|
c_max = list[i]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return c_max
|
|
|
|
end
|
|
|
|
|
|
|
|
local function string_value(t)
|
|
|
|
if type(t) == "string" then
|
|
|
|
return t
|
|
|
|
end
|
|
|
|
|
|
|
|
return t.value
|
|
|
|
end
|
|
|
|
|
|
|
|
local function lines(text)
|
|
|
|
return string_split(string_value(text), "\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
local function unlines(text)
|
|
|
|
return table.concat(text, "\n")
|
|
|
|
end
|
|
|
|
|
|
|
|
local function map_lines(text, f)
|
|
|
|
return unlines(map_list(lines(text), f))
|
|
|
|
end
|
|
|
|
|
|
|
|
local function string_width(t)
|
|
|
|
if type(t) == "string" then
|
|
|
|
return #table_max(lines(t), len, "")
|
|
|
|
end
|
|
|
|
|
|
|
|
return t.width
|
|
|
|
end
|
|
|
|
|
|
|
|
local function string_height(t)
|
|
|
|
if type(t) == "string" then
|
|
|
|
return #lines(t)
|
|
|
|
end
|
|
|
|
|
|
|
|
return t.height
|
|
|
|
end
|
|
|
|
|
|
|
|
local function half_down(num)
|
|
|
|
return math.floor(num / 2)
|
|
|
|
end
|
|
|
|
|
|
|
|
local function half_up(num)
|
|
|
|
return math.ceil(num / 2)
|
|
|
|
end
|
|
|
|
-- }}}
|
|
|
|
-- {{{ Hint helpers
|
|
|
|
local H = {}
|
2023-01-10 02:38:06 +01:00
|
|
|
|
2023-09-08 19:49:18 +02:00
|
|
|
function H.highlight(t)
|
|
|
|
return box("_" .. t .. "_", string_width(t), 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.spacing(amount)
|
|
|
|
return s_repeat(" ", amount)
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.spacing_for(text)
|
|
|
|
return H.spacing(string_width(text))
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.spacing_largest(values)
|
|
|
|
return H.spacing_for(table_max(values))
|
|
|
|
end
|
|
|
|
|
|
|
|
H.nojustify = { justify = "nojustify" }
|
|
|
|
|
|
|
|
function H.pad_left(text, length)
|
|
|
|
local spaces = length - string_width(text)
|
|
|
|
|
|
|
|
return box(
|
|
|
|
map_lines(text, function(line)
|
|
|
|
return H.spacing(spaces) .. line
|
|
|
|
end),
|
|
|
|
length,
|
|
|
|
string_height(text)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.pad_right(text, length)
|
|
|
|
local spaces = length - string_width(text)
|
|
|
|
return box(
|
|
|
|
map_lines(text, function(line)
|
|
|
|
return line .. H.spacing(spaces)
|
|
|
|
end),
|
|
|
|
length,
|
|
|
|
string_height(text)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.pad_around(text, length)
|
|
|
|
local spaces = length - string_width(text)
|
|
|
|
return box(
|
|
|
|
map_lines(text, function(line)
|
|
|
|
return H.spacing(half_up(spaces)) .. line .. H.spacing(half_down(spaces))
|
|
|
|
end),
|
|
|
|
length,
|
|
|
|
string_height(text)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.pad(text, length, justify)
|
|
|
|
if justify == "nojustify" then
|
|
|
|
return text
|
|
|
|
elseif justify == "center" then
|
|
|
|
return H.pad_around(text, length)
|
|
|
|
elseif justify == "right" then
|
|
|
|
return H.pad_left(text, length)
|
2023-09-18 02:15:13 +02:00
|
|
|
elseif justify == "left" then
|
2023-09-08 19:49:18 +02:00
|
|
|
return H.pad_right(text, length)
|
|
|
|
end
|
2023-09-18 02:15:13 +02:00
|
|
|
|
|
|
|
error("No justify provided")
|
2023-09-08 19:49:18 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function H.directional(h, j, k, l, spacing_amount)
|
|
|
|
---@diagnostic disable-next-line: redefined-local
|
|
|
|
local spacing_amount = spacing_amount or 1
|
|
|
|
|
|
|
|
return H.concat_many_w({
|
|
|
|
H.highlight(k),
|
|
|
|
H.concat_many_h({
|
|
|
|
H.highlight(h),
|
|
|
|
H.spacing(spacing_amount),
|
|
|
|
H.highlight(l),
|
|
|
|
}),
|
|
|
|
H.highlight(j),
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.add_title(title, body)
|
|
|
|
local width = max(string_width(title), string_width(body))
|
|
|
|
|
|
|
|
return H.concat_many_w({
|
|
|
|
title,
|
|
|
|
s_repeat("-", width),
|
|
|
|
body,
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.concat_h(left, right, spacing_amount)
|
|
|
|
---@diagnostic disable-next-line: redefined-local
|
|
|
|
local spacing_amount = spacing_amount or 0
|
|
|
|
|
|
|
|
return box(
|
|
|
|
unlines(zip_with(lines(left), lines(right), function(l, r)
|
|
|
|
return l .. H.spacing(spacing_amount) .. r
|
|
|
|
end, "")),
|
|
|
|
string_width(left) + string_width(right) + spacing_amount,
|
|
|
|
max(string_height(left), string_height(right))
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.concat_w(above, below, opts)
|
|
|
|
---@diagnostic disable-next-line: redefined-local
|
|
|
|
local opts = opts or {}
|
|
|
|
local spacing_amount = opts.spacing_amount or 0
|
|
|
|
local justify = opts.justify or "center"
|
|
|
|
local width = max(string_width(above), string_width(below))
|
|
|
|
|
|
|
|
return box(
|
|
|
|
unlines(flatten_list({
|
|
|
|
{ H.pad(above, width, justify).value },
|
|
|
|
l_repeat(H.spacing(width), spacing_amount),
|
|
|
|
{ H.pad(below, width, justify).value },
|
|
|
|
})),
|
|
|
|
width,
|
|
|
|
spacing_amount + string_height(above) + string_height(below)
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.concat_many_h(list, spacing_amount)
|
|
|
|
local result = list[1]
|
|
|
|
|
|
|
|
for i = 2, #list, 1 do
|
|
|
|
result = H.concat_h(result, list[i], spacing_amount)
|
|
|
|
end
|
|
|
|
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.concat_many_w(list, opts)
|
|
|
|
local result = list[1]
|
|
|
|
|
|
|
|
for i = 2, #list, 1 do
|
|
|
|
result = H.concat_w(result, list[i], opts)
|
|
|
|
end
|
|
|
|
|
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
|
|
|
function H.pad_lengths_right(list)
|
|
|
|
local max_length = table_max(list, string_width)
|
|
|
|
return map_list(list, function(t)
|
|
|
|
return H.concat_h(t, H.spacing(max_length - string_width(t)))
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
M.hint = H
|
|
|
|
-- }}}
|
|
|
|
|
|
|
|
local window_hint_old = [[
|
|
|
|
^^^^^^ Move ^^^^^^ ^^ Size ^^ ^^ Split
|
|
|
|
^^^^^^-------------^^^^^^ ^^-----------^^ ^^---------------
|
2023-09-04 04:58:39 +02:00
|
|
|
^ ^ _k_ ^ ^ ^ ^ _K_ ^ ^ ^ _<C-k>_ ^ _s_: horizontally
|
2023-01-10 02:38:06 +01:00
|
|
|
_h_ ^ ^ _l_ _H_ ^ ^ _L_ _<C-h>_ _<C-l>_ _v_: vertically
|
|
|
|
^ ^ _j_ ^ ^ ^ ^ _J_ ^ ^ ^ _<C-j>_ ^ _q_: close
|
2023-09-08 19:49:18 +02:00
|
|
|
^^^focus^^^ ^^^window^^^ ^_=_: equalize^ _o_: close remaining
|
2023-01-10 02:38:06 +01:00
|
|
|
]]
|
|
|
|
|
2023-09-08 19:49:18 +02:00
|
|
|
local window_hint = H.concat_many_h({
|
|
|
|
H.add_title(
|
|
|
|
"Move",
|
|
|
|
H.concat_h(
|
|
|
|
H.concat_w(H.directional("h", "j", "k", "l", 3), "focus"),
|
|
|
|
H.concat_w(
|
|
|
|
H.directional("H", "J", "K", "L", 3),
|
|
|
|
"window",
|
|
|
|
{ justify = "left" }
|
|
|
|
),
|
|
|
|
2
|
|
|
|
)
|
|
|
|
),
|
|
|
|
H.add_title(
|
|
|
|
"Size",
|
|
|
|
H.concat_w(
|
|
|
|
H.directional("<C-h>", "<C-j>", "<C-k>", "<C-l>"),
|
|
|
|
H.concat_many_h({
|
|
|
|
H.highlight("="),
|
|
|
|
": equalize",
|
|
|
|
})
|
|
|
|
)
|
|
|
|
),
|
|
|
|
H.add_title(
|
|
|
|
"Split",
|
|
|
|
H.concat_many_w({
|
|
|
|
H.concat_h(H.highlight("s"), ": horizontally"),
|
|
|
|
H.concat_h(H.highlight("v"), ": vertical"),
|
|
|
|
H.concat_h(H.highlight("q"), ": close"),
|
|
|
|
H.concat_h(H.highlight("o"), ": close remaining"),
|
|
|
|
}, { justify = "left" })
|
|
|
|
),
|
|
|
|
}, 3).value
|
|
|
|
|
2023-01-10 02:38:06 +01:00
|
|
|
function M.config()
|
|
|
|
local Hydra = require("hydra")
|
|
|
|
local pcmd = require("hydra.keymap-util").pcmd
|
|
|
|
local splits = require("smart-splits")
|
|
|
|
|
2023-09-04 04:58:39 +02:00
|
|
|
-- {{{ Windows
|
|
|
|
local resize = function(direction)
|
|
|
|
return function()
|
|
|
|
splits["resize_" .. direction](2)
|
|
|
|
end
|
|
|
|
end
|
2023-01-10 02:38:06 +01:00
|
|
|
|
|
|
|
Hydra({
|
|
|
|
name = "Windows",
|
|
|
|
hint = window_hint,
|
|
|
|
config = {
|
|
|
|
invoke_on_body = true,
|
|
|
|
hint = {
|
2023-09-08 20:00:42 +02:00
|
|
|
border = "single",
|
2023-09-04 04:58:39 +02:00
|
|
|
offset = -1, -- vertical offset (larger => higher up)
|
2023-01-10 02:38:06 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
mode = "n",
|
2023-03-16 17:39:46 +01:00
|
|
|
body = "<C-S-w>",
|
2023-01-10 02:38:06 +01:00
|
|
|
heads = {
|
|
|
|
{ "h", "<C-w>h" },
|
|
|
|
{ "j", "<C-w>j" },
|
|
|
|
{ "k", "<C-w>k" },
|
|
|
|
{ "l", "<C-w>l" },
|
|
|
|
|
|
|
|
{ "H", "<C-w>H" },
|
|
|
|
{ "J", "<C-w>J" },
|
|
|
|
{ "K", "<C-w>K" },
|
|
|
|
{ "L", "<C-w>L" },
|
|
|
|
|
2023-09-04 04:58:39 +02:00
|
|
|
{ "<C-h>", resize("left") },
|
|
|
|
{ "<C-j>", resize("down") },
|
|
|
|
{ "<C-k>", resize("up") },
|
|
|
|
{ "<C-l>", resize("right") },
|
2023-01-10 02:38:06 +01:00
|
|
|
{ "=", "<C-w>=", { desc = "equalize" } },
|
|
|
|
{ "s", pcmd("split", "E36") },
|
|
|
|
{ "v", pcmd("vsplit", "E36") },
|
|
|
|
{ "o", "<C-w>o", { exit = true, desc = "remain only" } },
|
|
|
|
{ "q", pcmd("close", "E444"), { desc = "close window" } },
|
|
|
|
},
|
|
|
|
})
|
2023-09-04 04:58:39 +02:00
|
|
|
-- }}}
|
2023-01-10 02:38:06 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
return M
|