Meh I'll figure out submodules later
This commit is contained in:
parent
4ca9d44a90
commit
8cb281f436
352 changed files with 66107 additions and 0 deletions
307
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/README.md
Normal file
307
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/README.md
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
# Layout
|
||||
|
||||
Layout is a helper component for creating complex layout by automatically
|
||||
handling the calculation for position and size of other components.
|
||||
|
||||
**Example**
|
||||
|
||||
```lua
|
||||
local Layout = require("nui.layout")
|
||||
local Popup = require("nui.popup")
|
||||
|
||||
local top_popup = Popup({ border = "double" })
|
||||
local bottom_left_popup = Popup({ border = "single" })
|
||||
local bottom_right_popup = Popup({ border = "single" })
|
||||
|
||||
local layout = Layout(
|
||||
{
|
||||
position = "50%",
|
||||
size = {
|
||||
width = 80,
|
||||
height = 40,
|
||||
},
|
||||
},
|
||||
Layout.Box({
|
||||
Layout.Box(top_popup, { size = "40%" }),
|
||||
Layout.Box({
|
||||
Layout.Box(bottom_left_popup, { size = "50%" }),
|
||||
Layout.Box(bottom_right_popup, { size = "50%" }),
|
||||
}, { dir = "row", size = "60%" }),
|
||||
}, { dir = "col" })
|
||||
)
|
||||
|
||||
layout:mount()
|
||||
```
|
||||
|
||||
_Signature:_ `Layout(options, box)` or `Layout(component, box)`
|
||||
|
||||
`component` can be `Popup` or `Split`.
|
||||
|
||||
## Options (for float layout)
|
||||
|
||||
### `anchor`
|
||||
|
||||
**Type:** `"NW"` / `"NE"` / `"SW"` / `"SE"`
|
||||
|
||||
Decides which corner of the layout to place at `position`.
|
||||
|
||||
---
|
||||
|
||||
### `relative`
|
||||
|
||||
**Type:** `string` or `table`
|
||||
|
||||
This option affects how `position` and `size` are calculated.
|
||||
|
||||
**Examples**
|
||||
|
||||
Relative to cursor on current window:
|
||||
|
||||
```lua
|
||||
relative = "cursor",
|
||||
```
|
||||
|
||||
Relative to the current editor screen:
|
||||
|
||||
```lua
|
||||
relative = "editor",
|
||||
```
|
||||
|
||||
Relative to the current window (_default_):
|
||||
|
||||
```lua
|
||||
relative = "win",
|
||||
```
|
||||
|
||||
Relative to the window with specific id:
|
||||
|
||||
```lua
|
||||
relative = {
|
||||
type = "win",
|
||||
winid = 5,
|
||||
},
|
||||
```
|
||||
|
||||
Relative to the buffer position:
|
||||
|
||||
```lua
|
||||
relative = {
|
||||
type = "buf",
|
||||
-- zero-indexed
|
||||
position = {
|
||||
row = 5,
|
||||
col = 5,
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `position`
|
||||
|
||||
**Type:** `number` or `percentage string` or `table`
|
||||
|
||||
Position is calculated from the top-left corner.
|
||||
|
||||
If `position` is `number` or `percentage string`, it applies to both `row` and `col`.
|
||||
Or you can pass a table to set them separately.
|
||||
|
||||
For `percentage string`, position is calculated according to the option `relative`.
|
||||
If `relative` is set to `"buf"` or `"cursor"`, `percentage string` is not allowed.
|
||||
|
||||
**Examples**
|
||||
|
||||
```lua
|
||||
position = 50,
|
||||
```
|
||||
|
||||
```lua
|
||||
position = "50%",
|
||||
```
|
||||
|
||||
```lua
|
||||
position = {
|
||||
row = 30,
|
||||
col = 20,
|
||||
},
|
||||
```
|
||||
|
||||
```lua
|
||||
position = {
|
||||
row = "20%",
|
||||
col = "50%",
|
||||
},
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `size`
|
||||
|
||||
**Type:** `number` or `percentage string` or `table`
|
||||
|
||||
Determines the size of the layout.
|
||||
|
||||
If `size` is `number` or `percentage string`, it applies to both `width` and `height`.
|
||||
You can also pass a table to set them separately.
|
||||
|
||||
For `percentage string`, `size` is calculated according to the option `relative`.
|
||||
If `relative` is set to `"buf"` or `"cursor"`, window size is considered.
|
||||
|
||||
Decimal `number` in `(0,1)` range is treated similar to `percentage string`. For
|
||||
example: `0.5` is same as `"50%"`.
|
||||
|
||||
**Examples**
|
||||
|
||||
```lua
|
||||
size = 50,
|
||||
```
|
||||
|
||||
```lua
|
||||
size = "50%",
|
||||
```
|
||||
|
||||
```lua
|
||||
size = 0.5,
|
||||
```
|
||||
|
||||
```lua
|
||||
size = {
|
||||
width = 80,
|
||||
height = 40,
|
||||
},
|
||||
```
|
||||
|
||||
```lua
|
||||
size = {
|
||||
width = "80%",
|
||||
height = 0.6,
|
||||
},
|
||||
```
|
||||
|
||||
## Options (for split layout)
|
||||
|
||||
### `relative`
|
||||
|
||||
**Type:** `string` or `table`
|
||||
|
||||
This option affects how `size` is calculated.
|
||||
|
||||
**Examples**
|
||||
|
||||
Split current editor screen:
|
||||
|
||||
```lua
|
||||
relative = "editor"
|
||||
```
|
||||
|
||||
Split current window (_default_):
|
||||
|
||||
```lua
|
||||
relative = "win"
|
||||
```
|
||||
|
||||
Split window with specific id:
|
||||
|
||||
```lua
|
||||
relative = {
|
||||
type = "win",
|
||||
winid = 42,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `position`
|
||||
|
||||
**Type:** `"top" | "right"| "bottom" | "left"`.
|
||||
|
||||
---
|
||||
|
||||
### `size`
|
||||
|
||||
**Type:** `number` or `percentage string`
|
||||
|
||||
Determines the size of the layout.
|
||||
|
||||
For `percentage string`, size is calculated according to the option `relative`.
|
||||
|
||||
## Layout.Box
|
||||
|
||||
_Signature:_ `Layout.Box(box, options)`
|
||||
|
||||
**Parameters**
|
||||
|
||||
| Name | Type | Description |
|
||||
| --------- | ------------------------------ | ----------------------------------------- |
|
||||
| `box` | `Layout.Box[]` / nui component | list of `Layout.Box` or any nui component |
|
||||
| `options` | `table` | box options |
|
||||
|
||||
`options` is a `table` having the following keys:
|
||||
|
||||
| Key | Type | Description |
|
||||
| ------ | ----------------------------- | ------------------------------------------------------ |
|
||||
| `dir` | `"col"` / `"row"` (_default_) | arrangement direction, only if `box` is `Layout.Box[]` |
|
||||
| `grow` | `number` | growth factor to fill up the box free space |
|
||||
| `size` | `number` / `string` / `table` | optional if `grow` is present |
|
||||
|
||||
## Methods
|
||||
|
||||
### `layout:mount`
|
||||
|
||||
_Signature:_ `layout:mount()`
|
||||
|
||||
Mounts the layout with all the components.
|
||||
|
||||
**Examples**
|
||||
|
||||
```lua
|
||||
layout:mount()
|
||||
```
|
||||
|
||||
### `layout:unmount`
|
||||
|
||||
_Signature:_ `layout:unmount()`
|
||||
|
||||
Unmounts the layout with all the components.
|
||||
|
||||
**Examples**
|
||||
|
||||
```lua
|
||||
layout:unmount()
|
||||
```
|
||||
|
||||
### `layout:hide`
|
||||
|
||||
_Signature:_ `layout:hide()`
|
||||
|
||||
Hides the layout with all the components. Preserves the buffer (related content, autocmds and keymaps).
|
||||
|
||||
### `layout:show`
|
||||
|
||||
_Signature:_ `layout:show()`
|
||||
|
||||
Shows the hidden layout with all the components.
|
||||
|
||||
### `layout:update`
|
||||
|
||||
_Signature:_ `layout:update(config, box?)` or `layout:update(box?)`
|
||||
|
||||
**Parameters**
|
||||
|
||||
`config` is a `table` having the following keys:
|
||||
|
||||
| Key | Type |
|
||||
| ---------- | --------------------------------- |
|
||||
| `anchor` | `"NW"` / `"NE"` / `"SW"` / `"SE"` |
|
||||
| `relative` | `string` / `table` |
|
||||
| `position` | `string` / `table` |
|
||||
| `size` | `string` / `table` |
|
||||
|
||||
`box` is a `table` returned by `Layout.Box`.
|
||||
|
||||
They are the same options used for layout initialization.
|
||||
|
||||
## Wiki Page
|
||||
|
||||
You can find additional documentation/examples/guides/tips-n-tricks in
|
||||
[nui.layout wiki page](https://github.com/MunifTanjim/nui.nvim/wiki/nui.layout).
|
||||
239
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/float.lua
Normal file
239
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/float.lua
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
local utils = require("nui.utils")
|
||||
local layout_utils = require("nui.layout.utils")
|
||||
|
||||
local u = {
|
||||
is_type = utils.is_type,
|
||||
calculate_window_size = layout_utils.calculate_window_size,
|
||||
}
|
||||
|
||||
local mod = {}
|
||||
|
||||
local function get_child_position(box, child, current_position, canvas_position)
|
||||
local position = box.dir == "row" and {
|
||||
row = canvas_position.row,
|
||||
col = current_position.col,
|
||||
} or {
|
||||
col = canvas_position.col,
|
||||
row = current_position.row,
|
||||
}
|
||||
|
||||
if child.component then
|
||||
local border = child.component.border
|
||||
if border and border._.type == "complex" then
|
||||
position.col = position.col + math.floor(border._.size_delta.width / 2 + 0.5)
|
||||
position.row = position.row + math.floor(border._.size_delta.height / 2 + 0.5)
|
||||
end
|
||||
end
|
||||
|
||||
return position
|
||||
end
|
||||
|
||||
---@param parent table Layout.Box
|
||||
---@param child table Layout.Box
|
||||
---@param container_size table
|
||||
---@param growable_dimension_per_factor? number
|
||||
local function get_child_size(parent, child, container_size, growable_dimension_per_factor)
|
||||
local child_size = {
|
||||
width = child.size.width,
|
||||
height = child.size.height,
|
||||
}
|
||||
|
||||
if child.grow and growable_dimension_per_factor then
|
||||
if parent.dir == "col" then
|
||||
child_size.height = math.floor(growable_dimension_per_factor * child.grow)
|
||||
else
|
||||
child_size.width = math.floor(growable_dimension_per_factor * child.grow)
|
||||
end
|
||||
end
|
||||
|
||||
local outer_size = u.calculate_window_size(child_size, container_size)
|
||||
|
||||
local inner_size = {
|
||||
width = outer_size.width,
|
||||
height = outer_size.height,
|
||||
}
|
||||
|
||||
if child.component then
|
||||
if child.component.border then
|
||||
inner_size.width = inner_size.width - child.component.border._.size_delta.width
|
||||
inner_size.height = inner_size.height - child.component.border._.size_delta.height
|
||||
|
||||
if inner_size.height <= 0 then
|
||||
local height_adjustment = math.abs(inner_size.height) + 1
|
||||
inner_size.height = inner_size.height + height_adjustment
|
||||
outer_size.height = outer_size.height + height_adjustment
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return outer_size, inner_size
|
||||
end
|
||||
|
||||
function mod.process(box, meta)
|
||||
-- luacov: disable
|
||||
if box.mount or box.component or not box.box then
|
||||
return error("invalid parameter: box")
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
local container_size = meta.container_size
|
||||
|
||||
-- luacov: disable
|
||||
if not u.is_type("number", container_size.width) or not u.is_type("number", container_size.height) then
|
||||
return error("invalid value: box.size")
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
local current_position = box.dir == "row" and {
|
||||
col = meta.position.col,
|
||||
row = 0,
|
||||
} or {
|
||||
col = 0,
|
||||
row = meta.position.row,
|
||||
}
|
||||
|
||||
local growable_child_factor = 0
|
||||
|
||||
for _, child in ipairs(box.box) do
|
||||
if meta.process_growable_child or not child.grow then
|
||||
local position = get_child_position(box, child, current_position, meta.position)
|
||||
local outer_size, inner_size = get_child_size(box, child, container_size, meta.growable_dimension_per_factor)
|
||||
|
||||
if child.component then
|
||||
child.component:set_layout({
|
||||
size = inner_size,
|
||||
relative = {
|
||||
type = "win",
|
||||
winid = meta.winid,
|
||||
},
|
||||
position = position,
|
||||
})
|
||||
else
|
||||
mod.process(child, {
|
||||
winid = meta.winid,
|
||||
container_size = outer_size,
|
||||
position = position,
|
||||
})
|
||||
end
|
||||
|
||||
current_position.col = current_position.col + outer_size.width
|
||||
current_position.row = current_position.row + outer_size.height
|
||||
end
|
||||
|
||||
if child.grow then
|
||||
growable_child_factor = growable_child_factor + child.grow
|
||||
end
|
||||
end
|
||||
|
||||
if meta.process_growable_child or growable_child_factor == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local growable_width = container_size.width - current_position.col
|
||||
local growable_height = container_size.height - current_position.row
|
||||
local growable_dimension = box.dir == "col" and growable_height or growable_width
|
||||
local growable_dimension_per_factor = growable_dimension / growable_child_factor
|
||||
|
||||
mod.process(box, {
|
||||
winid = meta.winid,
|
||||
container_size = meta.container_size,
|
||||
position = meta.position,
|
||||
process_growable_child = true,
|
||||
growable_dimension_per_factor = growable_dimension_per_factor,
|
||||
})
|
||||
end
|
||||
|
||||
function mod.mount_box(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
child.component:mount()
|
||||
else
|
||||
mod.mount_box(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
function mod.show_box(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
child.component:show()
|
||||
else
|
||||
mod.show_box(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mod.unmount_box(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
child.component:unmount()
|
||||
else
|
||||
mod.unmount_box(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
function mod.hide_box(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
child.component:hide()
|
||||
else
|
||||
mod.hide_box(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
---@return table<string, table>
|
||||
local function collect_box_components(box, components)
|
||||
if not components then
|
||||
components = {}
|
||||
end
|
||||
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
components[child.component._.id] = child.component
|
||||
else
|
||||
collect_box_components(child, components)
|
||||
end
|
||||
end
|
||||
|
||||
return components
|
||||
end
|
||||
|
||||
---@param curr_box table Layout.Box
|
||||
---@param prev_box table Layout.Box
|
||||
function mod.process_box_change(curr_box, prev_box)
|
||||
if curr_box == prev_box then
|
||||
return
|
||||
end
|
||||
|
||||
local curr_components = collect_box_components(curr_box)
|
||||
local prev_components = collect_box_components(prev_box)
|
||||
|
||||
for id, component in pairs(curr_components) do
|
||||
if not prev_components[id] then
|
||||
if not component.winid then
|
||||
if component._.mounted then
|
||||
component:show()
|
||||
else
|
||||
component:mount()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for id, component in pairs(prev_components) do
|
||||
if not curr_components[id] then
|
||||
if component._.mounted then
|
||||
if component.winid then
|
||||
component:hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return mod
|
||||
573
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/init.lua
Normal file
573
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/init.lua
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
local Object = require("nui.object")
|
||||
local Popup = require("nui.popup")
|
||||
local Split = require("nui.split")
|
||||
local utils = require("nui.utils")
|
||||
local layout_utils = require("nui.layout.utils")
|
||||
local float_layout = require("nui.layout.float")
|
||||
local split_layout = require("nui.layout.split")
|
||||
local split_utils = require("nui.split.utils")
|
||||
local autocmd = require("nui.utils.autocmd")
|
||||
|
||||
local _ = utils._
|
||||
|
||||
local defaults = utils.defaults
|
||||
local is_type = utils.is_type
|
||||
local u = {
|
||||
get_next_id = _.get_next_id,
|
||||
position = layout_utils.position,
|
||||
size = layout_utils.size,
|
||||
split = split_utils,
|
||||
update_layout_config = layout_utils.update_layout_config,
|
||||
}
|
||||
|
||||
-- GitHub Issue: https://github.com/neovim/neovim/issues/18925
|
||||
local function apply_workaround_for_float_relative_position_issue_18925(layout)
|
||||
local winids_len = 1
|
||||
local winids = { layout.winid }
|
||||
local function collect_anchor_winids(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
local border = child.component.border
|
||||
if border and border.winid then
|
||||
winids_len = winids_len + 1
|
||||
winids[winids_len] = border.winid
|
||||
end
|
||||
else
|
||||
collect_anchor_winids(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
collect_anchor_winids(layout._.box)
|
||||
|
||||
vim.schedule(function()
|
||||
-- check in case layout was immediately hidden or unmounted
|
||||
if layout.winid == winids[1] and vim.api.nvim_win_is_valid(winids[1]) then
|
||||
vim.cmd(
|
||||
("noa call nvim_set_current_win(%s)\nnormal! jk\nredraw\n"):rep(winids_len):format(unpack(winids))
|
||||
.. ("noa call nvim_set_current_win(%s)"):format(vim.api.nvim_get_current_win())
|
||||
)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---@param options nui_layout_options
|
||||
local function merge_default_options(options)
|
||||
options.relative = defaults(options.relative, "win")
|
||||
|
||||
return options
|
||||
end
|
||||
|
||||
---@param options nui_layout_options
|
||||
local function normalize_options(options)
|
||||
options = _.normalize_layout_options(options)
|
||||
|
||||
return options
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
local function is_box(object)
|
||||
return object and (object.box or object.component)
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
local function is_component(object)
|
||||
return object and object.mount
|
||||
end
|
||||
|
||||
local function is_component_mounted(component)
|
||||
return is_type("number", component.winid)
|
||||
end
|
||||
|
||||
---@param component NuiPopup|NuiSplit
|
||||
local function get_layout_config_relative_to_component(component)
|
||||
return {
|
||||
relative = { type = "win", winid = component.winid },
|
||||
position = { row = 0, col = 0 },
|
||||
size = { width = "100%", height = "100%" },
|
||||
}
|
||||
end
|
||||
|
||||
---@param layout NuiLayout
|
||||
---@param box table Layout.Box
|
||||
local function wire_up_layout_components(layout, box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
autocmd.create({ "BufWipeout", "QuitPre" }, {
|
||||
group = layout._.augroup.unmount,
|
||||
buffer = child.component.bufnr,
|
||||
callback = vim.schedule_wrap(function()
|
||||
layout:unmount()
|
||||
end),
|
||||
}, child.component.bufnr)
|
||||
|
||||
autocmd.create("BufWinEnter", {
|
||||
group = layout._.augroup.unmount,
|
||||
buffer = child.component.bufnr,
|
||||
callback = function()
|
||||
local winid = child.component.winid
|
||||
if layout._.type == "float" and not winid then
|
||||
--[[
|
||||
`BufWinEnter` does not contain window id and
|
||||
it is fired before `nvim_open_win` returns
|
||||
the window id.
|
||||
--]]
|
||||
winid = vim.fn.bufwinid(child.component.bufnr)
|
||||
end
|
||||
|
||||
autocmd.create("WinClosed", {
|
||||
group = layout._.augroup.hide,
|
||||
nested = true,
|
||||
pattern = tostring(winid),
|
||||
callback = function()
|
||||
layout:hide()
|
||||
end,
|
||||
}, child.component.bufnr)
|
||||
end,
|
||||
}, child.component.bufnr)
|
||||
else
|
||||
wire_up_layout_components(layout, child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@class nui_layout_options
|
||||
---@field anchor? nui_layout_option_anchor
|
||||
---@field relative? nui_layout_option_relative_type|nui_layout_option_relative
|
||||
---@field position? number|string|nui_layout_option_position
|
||||
---@field size? number|string|nui_layout_option_size
|
||||
|
||||
---@class NuiLayout
|
||||
local Layout = Object("NuiLayout")
|
||||
|
||||
---@return '"float"'|'"split"' layout_type
|
||||
local function get_layout_type(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component and child.type then
|
||||
return child.type
|
||||
end
|
||||
|
||||
local type = get_layout_type(child)
|
||||
if type then
|
||||
return type
|
||||
end
|
||||
end
|
||||
|
||||
error("unexpected empty box")
|
||||
end
|
||||
|
||||
---@param options nui_layout_options|NuiPopup|NuiSplit
|
||||
---@param box NuiLayout.Box|NuiLayout.Box[]
|
||||
function Layout:init(options, box)
|
||||
local id = u.get_next_id()
|
||||
|
||||
box = Layout.Box(box)
|
||||
|
||||
local type = get_layout_type(box)
|
||||
|
||||
self._ = {
|
||||
id = id,
|
||||
type = type,
|
||||
box = box,
|
||||
loading = false,
|
||||
mounted = false,
|
||||
augroup = {
|
||||
hide = string.format("%s_hide", id),
|
||||
unmount = string.format("%s_unmount", id),
|
||||
},
|
||||
}
|
||||
|
||||
if type == "float" then
|
||||
local container
|
||||
if is_component(options) then
|
||||
container = options --[[@as NuiPopup|NuiSplit]]
|
||||
options = get_layout_config_relative_to_component(container)
|
||||
else
|
||||
---@cast options -NuiPopup, -NuiSplit
|
||||
options = merge_default_options(options)
|
||||
options = normalize_options(options)
|
||||
end
|
||||
|
||||
self._[type] = {
|
||||
container = container,
|
||||
layout = {},
|
||||
win_enter = false,
|
||||
win_config = {
|
||||
border = "none",
|
||||
focusable = false,
|
||||
style = "minimal",
|
||||
anchor = options.anchor,
|
||||
zindex = 49,
|
||||
},
|
||||
win_options = {
|
||||
winblend = 100,
|
||||
},
|
||||
}
|
||||
|
||||
if not is_component(container) or is_component_mounted(container) then
|
||||
self:update(options)
|
||||
end
|
||||
end
|
||||
|
||||
if type == "split" then
|
||||
options = u.split.merge_default_options(options)
|
||||
options = u.split.normalize_options(options)
|
||||
|
||||
self._[type] = {
|
||||
layout = {},
|
||||
position = options.position,
|
||||
size = {},
|
||||
win_config = {
|
||||
pending_changes = {},
|
||||
},
|
||||
}
|
||||
|
||||
self:update(options)
|
||||
end
|
||||
end
|
||||
|
||||
function Layout:_process_layout()
|
||||
local type = self._.type
|
||||
|
||||
if type == "float" then
|
||||
local info = self._.float
|
||||
|
||||
float_layout.process(self._.box, {
|
||||
winid = self.winid,
|
||||
container_size = info.size,
|
||||
position = {
|
||||
row = 0,
|
||||
col = 0,
|
||||
},
|
||||
})
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if type == "split" then
|
||||
local info = self._.split
|
||||
|
||||
split_layout.process(self._.box, {
|
||||
position = info.position,
|
||||
relative = info.relative,
|
||||
container_size = info.size,
|
||||
container_fallback_size = info.container_info.size,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function Layout:_open_window()
|
||||
if self._.type == "float" then
|
||||
local info = self._.float
|
||||
|
||||
self.winid = vim.api.nvim_open_win(self.bufnr, info.win_enter, info.win_config)
|
||||
assert(self.winid, "failed to create popup window")
|
||||
|
||||
_.set_win_options(self.winid, info.win_options)
|
||||
end
|
||||
end
|
||||
|
||||
function Layout:_close_window()
|
||||
if not self.winid then
|
||||
return
|
||||
end
|
||||
|
||||
if vim.api.nvim_win_is_valid(self.winid) then
|
||||
vim.api.nvim_win_close(self.winid, true)
|
||||
end
|
||||
|
||||
self.winid = nil
|
||||
end
|
||||
|
||||
function Layout:mount()
|
||||
if self._.loading or self._.mounted then
|
||||
return
|
||||
end
|
||||
|
||||
self._.loading = true
|
||||
|
||||
local type = self._.type
|
||||
|
||||
if type == "float" then
|
||||
local info = self._.float
|
||||
|
||||
local container = info.container
|
||||
if is_component(container) and not is_component_mounted(container) then
|
||||
container:mount()
|
||||
self:update(get_layout_config_relative_to_component(container))
|
||||
end
|
||||
|
||||
if not self.bufnr then
|
||||
self.bufnr = vim.api.nvim_create_buf(false, true)
|
||||
assert(self.bufnr, "failed to create buffer")
|
||||
end
|
||||
|
||||
self:_open_window()
|
||||
end
|
||||
|
||||
self:_process_layout()
|
||||
|
||||
if type == "float" then
|
||||
float_layout.mount_box(self._.box)
|
||||
|
||||
apply_workaround_for_float_relative_position_issue_18925(self)
|
||||
end
|
||||
|
||||
if type == "split" then
|
||||
split_layout.mount_box(self._.box)
|
||||
end
|
||||
|
||||
self._.loading = false
|
||||
self._.mounted = true
|
||||
end
|
||||
|
||||
function Layout:unmount()
|
||||
if self._.loading or not self._.mounted then
|
||||
return
|
||||
end
|
||||
|
||||
pcall(autocmd.delete_group, self._.augroup.hide)
|
||||
pcall(autocmd.delete_group, self._.augroup.unmount)
|
||||
|
||||
self._.loading = true
|
||||
|
||||
local type = self._.type
|
||||
|
||||
if type == "float" then
|
||||
float_layout.unmount_box(self._.box)
|
||||
|
||||
if self.bufnr then
|
||||
if vim.api.nvim_buf_is_valid(self.bufnr) then
|
||||
vim.api.nvim_buf_delete(self.bufnr, { force = true })
|
||||
end
|
||||
self.bufnr = nil
|
||||
end
|
||||
|
||||
self:_close_window()
|
||||
end
|
||||
|
||||
if type == "split" then
|
||||
split_layout.unmount_box(self._.box)
|
||||
end
|
||||
|
||||
self._.loading = false
|
||||
self._.mounted = false
|
||||
end
|
||||
|
||||
function Layout:hide()
|
||||
if self._.loading or not self._.mounted then
|
||||
return
|
||||
end
|
||||
|
||||
self._.loading = true
|
||||
|
||||
pcall(autocmd.delete_group, self._.augroup.hide)
|
||||
|
||||
local type = self._.type
|
||||
|
||||
if type == "float" then
|
||||
float_layout.hide_box(self._.box)
|
||||
|
||||
self:_close_window()
|
||||
end
|
||||
|
||||
if type == "split" then
|
||||
split_layout.hide_box(self._.box)
|
||||
end
|
||||
|
||||
self._.loading = false
|
||||
end
|
||||
|
||||
function Layout:show()
|
||||
if self._.loading then
|
||||
return
|
||||
end
|
||||
|
||||
if not self._.mounted then
|
||||
return self:mount()
|
||||
end
|
||||
|
||||
self._.loading = true
|
||||
|
||||
autocmd.create_group(self._.augroup.hide, { clear = true })
|
||||
|
||||
local type = self._.type
|
||||
|
||||
if type == "float" then
|
||||
self:_open_window()
|
||||
end
|
||||
|
||||
self:_process_layout()
|
||||
|
||||
if type == "float" then
|
||||
float_layout.show_box(self._.box)
|
||||
|
||||
apply_workaround_for_float_relative_position_issue_18925(self)
|
||||
end
|
||||
|
||||
if type == "split" then
|
||||
split_layout.show_box(self._.box)
|
||||
end
|
||||
|
||||
self._.loading = false
|
||||
end
|
||||
|
||||
---@param config? NuiLayout.Box|NuiLayout.Box[]|nui_layout_options
|
||||
---@param box? NuiLayout.Box
|
||||
function Layout:update(config, box)
|
||||
config = config or {} --[[@as nui_layout_options]]
|
||||
|
||||
if not box and is_box(config) or is_box(config[1]) then
|
||||
box = config --[=[@as NuiLayout.Box|NuiLayout.Box[]]=]
|
||||
---@type nui_layout_options
|
||||
config = {}
|
||||
end
|
||||
|
||||
autocmd.create_group(self._.augroup.hide, { clear = true })
|
||||
autocmd.create_group(self._.augroup.unmount, { clear = true })
|
||||
|
||||
local prev_box = self._.box
|
||||
|
||||
if box then
|
||||
self._.box = Layout.Box(box)
|
||||
self._.type = get_layout_type(self._.box)
|
||||
end
|
||||
|
||||
if self._.type == "float" then
|
||||
local info = self._.float
|
||||
|
||||
u.update_layout_config(info, config)
|
||||
|
||||
if self.winid then
|
||||
vim.api.nvim_win_set_config(self.winid, info.win_config)
|
||||
|
||||
self:_process_layout()
|
||||
|
||||
float_layout.process_box_change(self._.box, prev_box)
|
||||
|
||||
apply_workaround_for_float_relative_position_issue_18925(self)
|
||||
end
|
||||
|
||||
wire_up_layout_components(self, self._.box)
|
||||
end
|
||||
|
||||
if self._.type == "split" then
|
||||
local info = self._.split
|
||||
|
||||
local relative_winid = info.relative and info.relative.win
|
||||
|
||||
local prev_winid = vim.api.nvim_get_current_win()
|
||||
if relative_winid then
|
||||
vim.api.nvim_set_current_win(relative_winid)
|
||||
end
|
||||
|
||||
local curr_box = self._.box
|
||||
if prev_box ~= curr_box then
|
||||
self._.box = prev_box
|
||||
self:hide()
|
||||
self._.box = curr_box
|
||||
end
|
||||
|
||||
u.split.update_layout_config(info, config)
|
||||
|
||||
if prev_box == curr_box then
|
||||
self:_process_layout()
|
||||
else
|
||||
self:show()
|
||||
end
|
||||
|
||||
if vim.api.nvim_win_is_valid(prev_winid) then
|
||||
vim.api.nvim_set_current_win(prev_winid)
|
||||
end
|
||||
|
||||
wire_up_layout_components(self, self._.box)
|
||||
end
|
||||
end
|
||||
|
||||
---@class nui_layout_box_options
|
||||
---@field dir? 'row'|'col'
|
||||
---@field grow? integer
|
||||
---@field size? number|string|table<'height'|'width', number|string>
|
||||
|
||||
---@class NuiLayout.Box
|
||||
---@field type? 'float'|'split'
|
||||
---@field component? NuiPopup|NuiSplit
|
||||
---@field box? NuiLayout.Box[]
|
||||
---@field grow? integer
|
||||
---@field size? nui_layout_option_size
|
||||
|
||||
---@param box NuiPopup|NuiSplit|NuiLayout.Box|NuiLayout.Box[]
|
||||
---@param options? nui_layout_box_options
|
||||
---@return NuiLayout.Box
|
||||
function Layout.Box(box, options)
|
||||
options = options or {}
|
||||
|
||||
if is_box(box) then
|
||||
return box --[[@as NuiLayout.Box]]
|
||||
end
|
||||
|
||||
if box.mount then
|
||||
local type
|
||||
---@diagnostic disable: undefined-field
|
||||
if box:is_instance_of(Popup) then
|
||||
type = "float"
|
||||
elseif box:is_instance_of(Split) then
|
||||
type = "split"
|
||||
end
|
||||
---@diagnostic enable: undefined-field
|
||||
|
||||
if not type then
|
||||
error("unsupported component")
|
||||
end
|
||||
|
||||
return {
|
||||
type = type,
|
||||
component = box,
|
||||
grow = options.grow,
|
||||
size = options.size,
|
||||
}
|
||||
end
|
||||
|
||||
local dir = defaults(options.dir, "row")
|
||||
|
||||
-- normalize children size
|
||||
for _, child in ipairs(box) do
|
||||
if not child.grow and not child.size then
|
||||
error("missing child.size")
|
||||
end
|
||||
|
||||
if dir == "row" then
|
||||
if type(child.size) ~= "table" then
|
||||
---@diagnostic disable-next-line: assign-type-mismatch
|
||||
child.size = { width = child.size }
|
||||
end
|
||||
if not child.size.height then
|
||||
child.size.height = "100%"
|
||||
end
|
||||
elseif dir == "col" then
|
||||
if not is_type("table", child.size) then
|
||||
---@diagnostic disable-next-line: assign-type-mismatch
|
||||
child.size = { height = child.size }
|
||||
end
|
||||
if not child.size.width then
|
||||
child.size.width = "100%"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
box = box,
|
||||
dir = dir,
|
||||
grow = options.grow,
|
||||
size = options.size,
|
||||
}
|
||||
end
|
||||
|
||||
-- luacheck: push no max comment line length
|
||||
|
||||
---@alias NuiLayout.constructor fun(options: nui_layout_options|NuiPopup|NuiSplit, box: NuiLayout.Box|NuiLayout.Box[]): NuiLayout
|
||||
---@type NuiLayout|NuiLayout.constructor
|
||||
local NuiLayout = Layout
|
||||
|
||||
-- luacheck: pop
|
||||
|
||||
return NuiLayout
|
||||
262
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/split.lua
Normal file
262
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/split.lua
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
local utils = require("nui.utils")
|
||||
local split_utils = require("nui.split.utils")
|
||||
|
||||
local u = {
|
||||
is_type = utils.is_type,
|
||||
split = split_utils,
|
||||
set_win_options = utils._.set_win_options,
|
||||
}
|
||||
|
||||
local mod = {}
|
||||
|
||||
---@param box_dir '"row"'|'"col"'
|
||||
---@return nui_split_internal_position position
|
||||
local function get_child_position(box_dir)
|
||||
if box_dir == "row" then
|
||||
return "right"
|
||||
else
|
||||
return "bottom"
|
||||
end
|
||||
end
|
||||
|
||||
---@param position nui_split_internal_position
|
||||
---@param child { size: nui_layout_option_size, grow?: boolean }
|
||||
---@param container_size { width?: number, height?: number }
|
||||
---@param growable_dimension_per_factor? number
|
||||
local function get_child_size(position, child, container_size, growable_dimension_per_factor)
|
||||
local child_size
|
||||
if position == "left" or position == "right" then
|
||||
child_size = child.size.width
|
||||
else
|
||||
child_size = child.size.height
|
||||
end
|
||||
|
||||
if child.grow and growable_dimension_per_factor then
|
||||
child_size = math.floor(growable_dimension_per_factor * child.grow)
|
||||
end
|
||||
|
||||
return u.split.calculate_window_size(position, child_size, container_size)
|
||||
end
|
||||
|
||||
local function get_container_size(meta)
|
||||
local size = meta.container_size
|
||||
size.width = size.width or meta.container_fallback_size.width
|
||||
size.height = size.height or meta.container_fallback_size.height
|
||||
return size
|
||||
end
|
||||
|
||||
function mod.process(box, meta)
|
||||
-- luacov: disable
|
||||
if box.mount or box.component or not box.box then
|
||||
return error("invalid parameter: box")
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
local container_size = get_container_size(meta)
|
||||
|
||||
-- luacov: disable
|
||||
if not u.is_type("number", container_size.width) and not u.is_type("number", container_size.height) then
|
||||
return error("invalid value: box.size")
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
local consumed_size = {
|
||||
width = 0,
|
||||
height = 0,
|
||||
}
|
||||
|
||||
local growable_child_factor = 0
|
||||
|
||||
for i, child in ipairs(box.box) do
|
||||
if meta.process_growable_child or not child.grow then
|
||||
local position = get_child_position(box.dir)
|
||||
local relative = { type = "win" }
|
||||
local size = get_child_size(position, child, container_size, meta.growable_dimension_per_factor)
|
||||
|
||||
consumed_size.width = consumed_size.width + (size.width or 0)
|
||||
consumed_size.height = consumed_size.height + (size.height or 0)
|
||||
|
||||
if i == 1 then
|
||||
position = meta.position
|
||||
if meta.relative then
|
||||
relative = meta.relative
|
||||
end
|
||||
if position == "left" or position == "right" then
|
||||
size.width = container_size.width
|
||||
else
|
||||
size.height = container_size.height
|
||||
end
|
||||
end
|
||||
|
||||
if child.component then
|
||||
child.component:update_layout({
|
||||
position = position,
|
||||
relative = relative,
|
||||
size = size,
|
||||
})
|
||||
if i == 1 and child.component.winid then
|
||||
if position == "left" or position == "right" then
|
||||
vim.api.nvim_win_set_height(child.component.winid, size.height)
|
||||
else
|
||||
vim.api.nvim_win_set_width(child.component.winid, size.width)
|
||||
end
|
||||
end
|
||||
else
|
||||
mod.process(child, {
|
||||
container_size = size,
|
||||
container_fallback_size = container_size,
|
||||
position = position,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
if child.grow then
|
||||
growable_child_factor = growable_child_factor + child.grow
|
||||
end
|
||||
end
|
||||
|
||||
if meta.process_growable_child or growable_child_factor == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local growable_width = container_size.width - consumed_size.width
|
||||
local growable_height = container_size.height - consumed_size.height
|
||||
local growable_dimension = box.dir == "col" and growable_height or growable_width
|
||||
local growable_dimension_per_factor = growable_dimension / growable_child_factor
|
||||
|
||||
mod.process(box, {
|
||||
container_size = meta.container_size,
|
||||
container_fallback_size = meta.container_fallback_size,
|
||||
position = meta.position,
|
||||
process_growable_child = true,
|
||||
growable_dimension_per_factor = growable_dimension_per_factor,
|
||||
})
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
local function get_first_component(box)
|
||||
if not box.box[1] then
|
||||
return
|
||||
end
|
||||
|
||||
if box.box[1].component then
|
||||
return box.box[1].component
|
||||
end
|
||||
|
||||
return get_first_component(box.box[1])
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
local function unset_win_options_fixsize(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
local winfix = child.component._._layout_orig_winfixsize
|
||||
if winfix then
|
||||
child.component._.win_options.winfixwidth = winfix.winfixwidth
|
||||
child.component._.win_options.winfixheight = winfix.winfixheight
|
||||
child.component._._layout_orig_winfixsize = nil
|
||||
end
|
||||
u.set_win_options(child.component.winid, {
|
||||
winfixwidth = child.component._.win_options.winfixwidth,
|
||||
winfixheight = child.component._.win_options.winfixheight,
|
||||
})
|
||||
else
|
||||
unset_win_options_fixsize(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
---@param action '"mount"'|'"show"'
|
||||
---@param meta? { initial_pass?: boolean }
|
||||
local function do_action(box, action, meta)
|
||||
meta = meta or { root = true }
|
||||
|
||||
for i, child in ipairs(box.box) do
|
||||
if not meta.initial_pass or i == 1 then
|
||||
if child.component then
|
||||
child.component._._layout_orig_winfixsize = {
|
||||
winfixwidth = child.component._.win_options.winfixwidth,
|
||||
winfixheight = child.component._.win_options.winfixheight,
|
||||
}
|
||||
|
||||
child.component._.win_options.winfixwidth = i ~= 1
|
||||
child.component._.win_options.winfixheight = i == 1
|
||||
if box.dir == "col" then
|
||||
child.component._.win_options.winfixwidth = not child.component._.win_options.winfixwidth
|
||||
child.component._.win_options.winfixheight = not child.component._.win_options.winfixheight
|
||||
end
|
||||
|
||||
if child.component and not child.component.winid then
|
||||
child.component._.relative.win = vim.api.nvim_get_current_win()
|
||||
child.component._.win_config.win = child.component._.relative.win
|
||||
end
|
||||
|
||||
child.component[action](child.component)
|
||||
|
||||
if action == "show" and not child.component._.mounted then
|
||||
child.component:mount()
|
||||
end
|
||||
else
|
||||
do_action(child, action, {
|
||||
initial_pass = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not meta.initial_pass then
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.box then
|
||||
local first_component = get_first_component(child)
|
||||
if first_component and first_component.winid then
|
||||
vim.api.nvim_set_current_win(first_component.winid)
|
||||
end
|
||||
|
||||
do_action(child, action, {
|
||||
initial_pass = false,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if meta.root then
|
||||
unset_win_options_fixsize(box)
|
||||
end
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
---@param meta? { initial_pass?: boolean }
|
||||
function mod.mount_box(box, meta)
|
||||
do_action(box, "mount", meta)
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
---@param meta? { initial_pass?: boolean }
|
||||
function mod.show_box(box, meta)
|
||||
do_action(box, "show", meta)
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
function mod.unmount_box(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
child.component:unmount()
|
||||
else
|
||||
mod.unmount_box(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param box table Layout.Box
|
||||
function mod.hide_box(box)
|
||||
for _, child in ipairs(box.box) do
|
||||
if child.component then
|
||||
child.component:hide()
|
||||
else
|
||||
mod.hide_box(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return mod
|
||||
226
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/utils.lua
Normal file
226
.config/nvim/pack/tree/start/nui.nvim/lua/nui/layout/utils.lua
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
local utils = require("nui.utils")
|
||||
|
||||
local _ = utils._
|
||||
local defaults = utils.defaults
|
||||
|
||||
--luacheck: push no max line length
|
||||
|
||||
---@alias nui_layout_option_anchor "NW"|"NE"|"SW"|"SE"
|
||||
---@alias nui_layout_option_relative_type "'cursor'"|"'editor'"|"'win'"|"'buf'"
|
||||
---@alias nui_layout_option_relative { type: nui_layout_option_relative_type, winid?: number, position?: { row: number, col: number } }
|
||||
---@alias nui_layout_option_position { row: number|string, col: number|string }
|
||||
---@alias nui_layout_option_size { width: number|string, height: number|string }
|
||||
---@alias nui_layout_internal_position { relative: "'cursor'"|"'editor'"|"'win'", win: number, bufpos?: number[], row: number, col: number }
|
||||
---@alias nui_layout_container_info { relative: nui_layout_option_relative_type, size: { height: integer, width: integer }, type: "'editor'"|"'window'" }
|
||||
|
||||
--luacheck: pop
|
||||
|
||||
local mod_size = {}
|
||||
local mod_position = {}
|
||||
|
||||
local mod = {
|
||||
size = mod_size,
|
||||
position = mod_position,
|
||||
}
|
||||
|
||||
---@param position nui_layout_option_position
|
||||
---@param size { width: number, height: number }
|
||||
---@param container nui_layout_container_info
|
||||
---@return { row: number, col: number }
|
||||
function mod.calculate_window_position(position, size, container)
|
||||
local row
|
||||
local col
|
||||
|
||||
local is_percentage_allowed = not vim.tbl_contains({ "buf", "cursor" }, container.relative)
|
||||
local percentage_error = string.format("position %% can not be used relative to %s", container.relative)
|
||||
|
||||
local r = utils.parse_number_input(position.row)
|
||||
assert(r.value ~= nil, "invalid position.row")
|
||||
if r.is_percentage then
|
||||
assert(is_percentage_allowed, percentage_error)
|
||||
row = math.floor((container.size.height - size.height) * r.value)
|
||||
else
|
||||
row = r.value
|
||||
end
|
||||
|
||||
local c = utils.parse_number_input(position.col)
|
||||
assert(c.value ~= nil, "invalid position.col")
|
||||
if c.is_percentage then
|
||||
assert(is_percentage_allowed, percentage_error)
|
||||
col = math.floor((container.size.width - size.width) * c.value)
|
||||
else
|
||||
col = c.value
|
||||
end
|
||||
|
||||
return {
|
||||
row = row,
|
||||
col = col,
|
||||
}
|
||||
end
|
||||
|
||||
---@param size { width: number|string, height: number|string }
|
||||
---@param container_size { width: number, height: number }
|
||||
---@return { width: number, height: number }
|
||||
function mod.calculate_window_size(size, container_size)
|
||||
local width = _.normalize_dimension(size.width, container_size.width)
|
||||
assert(width, "invalid size.width")
|
||||
|
||||
local height = _.normalize_dimension(size.height, container_size.height)
|
||||
assert(height, "invalid size.height")
|
||||
|
||||
return {
|
||||
width = width,
|
||||
height = height,
|
||||
}
|
||||
end
|
||||
|
||||
---@param position nui_layout_internal_position
|
||||
---@return nui_layout_container_info
|
||||
function mod.get_container_info(position)
|
||||
local relative = position.relative
|
||||
local winid = position.win == 0 and vim.api.nvim_get_current_win() or position.win
|
||||
|
||||
if relative == "editor" then
|
||||
return {
|
||||
relative = relative,
|
||||
size = utils.get_editor_size(),
|
||||
type = "editor",
|
||||
winid = winid,
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
relative = position.bufpos and "buf" or relative,
|
||||
size = utils.get_window_size(position.win),
|
||||
type = "window",
|
||||
winid = winid,
|
||||
}
|
||||
end
|
||||
|
||||
---@param relative nui_layout_option_relative
|
||||
---@param fallback_winid number
|
||||
---@return nui_layout_internal_position
|
||||
function mod.parse_relative(relative, fallback_winid)
|
||||
local winid = defaults(relative.winid, fallback_winid)
|
||||
|
||||
if relative.type == "buf" then
|
||||
return {
|
||||
relative = "win",
|
||||
win = winid,
|
||||
bufpos = {
|
||||
relative.position.row,
|
||||
relative.position.col,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
return {
|
||||
relative = relative.type,
|
||||
win = winid,
|
||||
}
|
||||
end
|
||||
|
||||
---@param component_internal table
|
||||
---@param config nui_layout_options
|
||||
function mod.update_layout_config(component_internal, config)
|
||||
local internal = component_internal
|
||||
|
||||
local options = _.normalize_layout_options({
|
||||
relative = config.relative,
|
||||
size = config.size,
|
||||
position = config.position,
|
||||
})
|
||||
|
||||
local win_config = internal.win_config
|
||||
|
||||
if config.anchor then
|
||||
win_config.anchor = config.anchor
|
||||
end
|
||||
|
||||
if options.relative then
|
||||
internal.layout.relative = options.relative
|
||||
|
||||
local fallback_winid = internal.position and internal.position.win
|
||||
or internal.layout.relative.type == "cursor" and 0
|
||||
or vim.api.nvim_get_current_win()
|
||||
internal.position =
|
||||
vim.tbl_extend("force", internal.position or {}, mod.parse_relative(internal.layout.relative, fallback_winid))
|
||||
|
||||
win_config.relative = internal.position.relative
|
||||
win_config.win = internal.position.relative == "win" and internal.position.win or nil
|
||||
win_config.bufpos = internal.position.bufpos
|
||||
end
|
||||
|
||||
-- luacov: disable
|
||||
if not win_config.relative then
|
||||
return error("missing layout config: relative")
|
||||
end
|
||||
-- luacov: enable
|
||||
|
||||
local prev_container_size = internal.container_info and internal.container_info.size
|
||||
internal.container_info = mod.get_container_info(internal.position)
|
||||
local container_size_changed = not mod.size.are_same(internal.container_info.size, prev_container_size)
|
||||
|
||||
if
|
||||
options.size
|
||||
-- need_size_refresh
|
||||
or (container_size_changed and internal.layout.size and mod.size.contains_percentage_string(internal.layout.size))
|
||||
then
|
||||
internal.layout.size = options.size or internal.layout.size
|
||||
|
||||
internal.size = mod.calculate_window_size(internal.layout.size, internal.container_info.size)
|
||||
|
||||
win_config.width = internal.size.width
|
||||
win_config.height = internal.size.height
|
||||
end
|
||||
|
||||
if not win_config.width or not win_config.height then
|
||||
return error("missing layout config: size")
|
||||
end
|
||||
|
||||
if
|
||||
options.position
|
||||
-- need_position_refresh
|
||||
or (
|
||||
container_size_changed
|
||||
and internal.layout.position
|
||||
and mod.position.contains_percentage_string(internal.layout.position)
|
||||
)
|
||||
then
|
||||
internal.layout.position = options.position or internal.layout.position
|
||||
|
||||
internal.position = vim.tbl_extend(
|
||||
"force",
|
||||
internal.position,
|
||||
mod.calculate_window_position(internal.layout.position, internal.size, internal.container_info)
|
||||
)
|
||||
|
||||
win_config.row = internal.position.row
|
||||
win_config.col = internal.position.col
|
||||
end
|
||||
|
||||
if not win_config.row or not win_config.col then
|
||||
return error("missing layout config: position")
|
||||
end
|
||||
end
|
||||
|
||||
---@param size_a nui_layout_option_size
|
||||
---@param size_b? nui_layout_option_size
|
||||
---@return boolean
|
||||
function mod_size.are_same(size_a, size_b)
|
||||
return size_b and size_a.width == size_b.width and size_a.height == size_b.height or false
|
||||
end
|
||||
|
||||
---@param size nui_layout_option_size
|
||||
---@return boolean
|
||||
function mod_size.contains_percentage_string(size)
|
||||
return type(size.width) == "string" or type(size.height) == "string"
|
||||
end
|
||||
|
||||
---@param position nui_layout_option_position
|
||||
---@return boolean
|
||||
function mod_position.contains_percentage_string(position)
|
||||
return type(position.row) == "string" or type(position.col) == "string"
|
||||
end
|
||||
|
||||
return mod
|
||||
Loading…
Add table
Add a link
Reference in a new issue