-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathtools.lua
More file actions
154 lines (129 loc) · 4.01 KB
/
tools.lua
File metadata and controls
154 lines (129 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
---@alias _layout { type: string, winid: integer, bufnr: integer, win_opts: { string: any}, children: _layout[] }
---@alias layout_egg { layout: _layout, restore: string }
-- vim.fn.winlayout() example structure:
-- { "row", { { "leaf", winid }, { "col", { { "leaf", winid }, { "leaf", winid } } } } }
local M = {}
-- list all non-floating windows from the current tabpage
---@return integer[] # list of non floating window ids
local function list_non_floating_wins()
return vim.fn.filter(vim.api.nvim_tabpage_list_wins(vim.api.nvim_get_current_tabpage()), function(_, v)
return vim.api.nvim_win_get_config(v).relative == ""
end)
end
-- makes the window the only one on screen
-- same as ":only" except ignores floating windows
---@param winid integer
function M.make_only(winid)
if not winid or winid == 0 then
winid = vim.api.nvim_get_current_win()
end
for _, wid in ipairs(list_non_floating_wins()) do
if wid ~= winid then
local winnr = vim.fn.win_id2win(wid)
vim.cmd(winnr .. "wincmd c")
end
end
end
-- exact clone of the builtin "winrestcmd()" with exclusion of floating windows
-- https://github.com/neovim/neovim/blob/fcf3519c65a2d6736de437f686e788684a6c8564/src/nvim/eval/window.c#L770
---@return string
local function winrestcmd()
local cmd = ""
-- Do this twice to handle some window layouts properly.
for _ = 1, 2 do
local winnr = 1
for _, winid in ipairs(list_non_floating_wins()) do
cmd = string.format("%s%dresize %d|", cmd, winnr, vim.api.nvim_win_get_height(winid))
cmd = string.format("%svert %dresize %d|", cmd, winnr, vim.api.nvim_win_get_width(winid))
winnr = winnr + 1
end
end
return cmd
end
-- add bufnr to leaf
local function add_details(layout)
if layout[1] == "leaf" then
local win = layout[2]
-- window options
local all_options = vim.api.nvim_get_all_options_info()
local v = vim.wo[win]
local options = {}
for key, val in pairs(all_options) do
if val.global_local == false and val.scope == "win" then
options[key] = v[key]
end
end
-- create dict structure with added buffer and window opts
---@type _layout
local l = {
type = layout[1],
winid = win,
bufnr = vim.fn.winbufnr(win),
win_opts = options,
}
return l
else
local children = {}
for _, child_layout in ipairs(layout[2]) do
table.insert(children, add_details(child_layout))
end
return { type = layout[1], children = children }
end
end
---@return layout_egg layout egg (use with restore())
function M.save()
local layout = vim.fn.winlayout()
local restore_cmd = winrestcmd()
layout = add_details(layout)
return { layout = layout, restore = restore_cmd }
end
---@param layout _layout
local function apply_layout(layout)
if layout.type == "leaf" then
-- open the previous buffer
if vim.fn.bufexists(layout.bufnr) == 1 then
vim.cmd("b " .. layout.bufnr)
end
-- apply window options
for opt, val in pairs(layout.win_opts) do
if val ~= nil then
vim.wo[opt] = val
end
end
else
-- split cols or rows, split n-1 times
local split_method = "rightbelow vsplit"
if layout.type == "col" then
split_method = "rightbelow split"
end
local wins = { vim.fn.win_getid() }
for i in ipairs(layout.children) do
if i ~= 1 then
vim.cmd(split_method)
table.insert(wins, vim.fn.win_getid())
end
end
-- recursive into child windows
for index, win in ipairs(wins) do
vim.fn.win_gotoid(win)
apply_layout(layout.children[index])
end
end
end
---@param egg layout_egg layout to restore
function M.restore(egg)
egg = egg or {}
if not egg.layout or not egg.restore then
return
end
-- make a new window and set it as the only one
vim.cmd("new")
M.make_only(0)
local tmp_buf = vim.api.nvim_get_current_buf()
-- apply layout and perform resize_cmd
apply_layout(egg.layout)
vim.cmd(egg.restore)
-- delete temporary buffer
vim.cmd("bd " .. tmp_buf)
end
return M