Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/windows.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ require("windows").setup({
help = 2,
},
},
autoheight = { -- only auto adjust height
enable = false,
winheight = 5,
filetype = {
help = 2,
},
},
autoboth = { -- scale both axis.
enable = false,
-- Uses: winwidth, winheight, filetype - from autowidth/autoheight
},
ignore = { -- |windows.ignore|
buftype = { "quickfix" },
filetype = { "NvimTree", "neo-tree", "undotree", "gundo" }
Expand Down
136 changes: 136 additions & 0 deletions lua/windows/autoboth.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
local api = vim.api
local fn = vim.fn
local calc_layout = require('windows.calculate-layout')
local config = require('windows.config')
local cache = require('windows.cache')
local Window = require('windows.lib.api').Window
local resize_windows = require('windows.lib.resize-windows').resize_windows
local merge_resize_data = require('windows.lib.resize-windows').merge_resize_data
local tbl_is_empty = vim.tbl_isempty
local autocmd = vim.api.nvim_create_autocmd
local augroup = vim.api.nvim_create_augroup('windows.autoboth', {})
local command = vim.api.nvim_create_user_command
local M = {}

local curwin ---@type win.Window
local curbufnr ---@type integer

---Flag for when a new window has been created.
---@type boolean
local new_window = false

---To avoid multiple layout resizing in row, when several autocommands were
---triggered.
---@type boolean
M.resizing_request = false

---@type win.ResizeWindowsAnimated | nil
local animation
if config.animation.enable then
local ResizeWindowsAnimated = require('windows.lib.resize-windows-animated')
animation = ResizeWindowsAnimated:new()
end

local function setup_layout()
if not curwin or not M.resizing_request then
return
end
M.resizing_request = false

local winsdata = calc_layout.autoboth(curwin)
if tbl_is_empty(winsdata) then return end

if cache.maximized then
cache.maximized = nil
end
new_window = false

if animation then
animation:load(winsdata)
animation:run()
else
resize_windows(winsdata)
end
end

---Enable autoboth
function M.enable()
autocmd('BufWinEnter', { group = augroup, callback = function(ctx)
local win = Window(0) ---@type win.Window
if win:is_floating()
or (new_window and win:is_ignored())
or win:get_type() == 'command' -- "[Command Line]" window
then
return
end

M.resizing_request = true

curbufnr = ctx.buf
setup_layout()
end })

autocmd('VimResized', { group = augroup, callback = function()
M.resizing_request = true
setup_layout()
end })

autocmd('WinEnter', { group = augroup, callback = function(ctx)
local win = Window(0) ---@type win.Window
if win:is_floating()
or win:is_ignored()
or (win == curwin and ctx.buf == curbufnr)
then
return
end
curwin = win

M.resizing_request = true

-- Defer resizing to handle the case when a new buffer is opened.
-- Then 'BufWinEnter' event will be fired after 'WinEnter'.
vim.defer_fn(setup_layout, 10)
end })

autocmd('WinNew', { group = augroup, callback = function()
new_window = true
end })

if animation then
autocmd('WinClosed', { group = augroup, callback = function(ctx)
---Id of the closing window.
local id = tonumber(ctx.match) --[[@as integer]]
local win = Window(id)

if not win:is_floating() then
animation:finish()
end
end })

autocmd('TabLeave', { group = augroup, callback = function()
animation:finish()
end })
end
end

---Disable autoboth
function M.disable()
api.nvim_clear_autocmds({ group = augroup })
end

---Toggle autoboth
function M.toggle()
if config.autoboth.enable then
M.disable()
config.autoboth.enable = false
else
M.enable()
config.autoboth.enable = true
end
end

command('WindowsEnableAutoboth', M.enable, { bang = true })
command('WindowsDisableAutoboth', M.disable, { bang = true })
command('WindowsToggleAutoboth', M.toggle, { bang = true })

return M
141 changes: 141 additions & 0 deletions lua/windows/autoheight.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
local api = vim.api
local fn = vim.fn
local calc_layout = require('windows.calculate-layout')
local config = require('windows.config')
local cache = require('windows.cache')
local Window = require('windows.lib.api').Window
local resize_windows = require('windows.lib.resize-windows').resize_windows
local merge_resize_data = require('windows.lib.resize-windows').merge_resize_data
local tbl_is_empty = vim.tbl_isempty
local autocmd = vim.api.nvim_create_autocmd
local augroup = vim.api.nvim_create_augroup('windows.autoheight', {})
local command = vim.api.nvim_create_user_command
local M = {}

local curwin ---@type win.Window
local curbufnr ---@type integer

---Flag for when a new window has been created.
---@type boolean
local new_window = false

---To avoid multiple layout resizing in row, when several autocommands were
---triggered.
---@type boolean
M.resizing_request = false

---@type win.ResizeWindowsAnimated | nil
local animation
if config.animation.enable then
local ResizeWindowsAnimated = require('windows.lib.resize-windows-animated')
animation = ResizeWindowsAnimated:new()
end

local function setup_layout()
if not curwin or not M.resizing_request then
return
end
M.resizing_request = false

local winsdata = calc_layout.autoheight(curwin)
if tbl_is_empty(winsdata) then return end

if cache.maximized then
if cache.maximized.width then
local width_data = new_window and calc_layout.equalize_wins(true, false)
or cache.maximized.width
winsdata = merge_resize_data(winsdata, width_data)
end
cache.maximized = nil
end
new_window = false

if animation then
animation:load(winsdata)
animation:run()
else
resize_windows(winsdata)
end
end

---Enable autoheight
function M.enable()
autocmd('BufWinEnter', { group = augroup, callback = function(ctx)
local win = Window(0) ---@type win.Window
if win:is_floating()
or (new_window and win:is_ignored())
or win:get_type() == 'command' -- "[Command Line]" window
then
return
end

M.resizing_request = true

curbufnr = ctx.buf
setup_layout()
end })

autocmd('VimResized', { group = augroup, callback = function()
M.resizing_request = true
setup_layout()
end })

autocmd('WinEnter', { group = augroup, callback = function(ctx)
local win = Window(0) ---@type win.Window
if win:is_floating()
or win:is_ignored()
or (win == curwin and ctx.buf == curbufnr)
then
return
end
curwin = win

M.resizing_request = true

-- Defer resizing to handle the case when a new buffer is opened.
-- Then 'BufWinEnter' event will be fired after 'WinEnter'.
vim.defer_fn(setup_layout, 10)
end })

autocmd('WinNew', { group = augroup, callback = function()
new_window = true
end })

if animation then
autocmd('WinClosed', { group = augroup, callback = function(ctx)
---Id of the closing window.
local id = tonumber(ctx.match) --[[@as integer]]
local win = Window(id)

if not win:is_floating() then
animation:finish()
end
end })

autocmd('TabLeave', { group = augroup, callback = function()
animation:finish()
end })
end
end

---Disable autoheight
function M.disable()
api.nvim_clear_autocmds({ group = augroup })
end

---Toggle autoheight
function M.toggle()
if config.autoheight.enable then
M.disable()
config.autoheight.enable = false
else
M.enable()
config.autoheight.enable = true
end
end

command('WindowsEnableAutoheight', M.enable, { bang = true })
command('WindowsDisableAutoheight', M.disable, { bang = true })
command('WindowsToggleAutoheight', M.toggle, { bang = true })

return M
77 changes: 69 additions & 8 deletions lua/windows/calculate-layout.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local Frame = require('windows.lib.frame')
local merge_resize_data = require('windows.lib.resize-windows').merge_resize_data
local M = {}

---Calculate layout for auotwidth
---Calculate layout for autowidth
---@param curwin win.Window
---@return win.WinResizeData[]
function M.autowidth(curwin)
Expand Down Expand Up @@ -31,15 +31,38 @@ function M.autowidth(curwin)
end

local data = topFrame:get_data_for_width_resizing()
return data
end

-- --------------------------------------------------------
-- local t = {};
-- for _, d in ipairs(data) do
-- t[#t+1] = string.format('%d : %d', d.win.id, d.width)
-- end
-- print(table.concat(t, ' | '))
-- --------------------------------------------------------
---Calculate layout for autoheight
---@param curwin win.Window
---@return win.WinResizeData[]
function M.autoheight(curwin)
local topFrame = Frame() ---@type win.Frame
if topFrame.type == 'leaf' then
return {}
end

if curwin:is_valid()
and not curwin:is_floating()
and not curwin:get_option('winfixheight')
and not curwin:is_ignored()
then
local curwinLeaf = topFrame:find_window(curwin)
local topFrame_height = topFrame:get_height()
local curwin_wanted_height = curwin:get_wanted_height()
local topFrame_wanted_height = topFrame:get_min_height(curwin, curwin_wanted_height)

if topFrame_wanted_height > topFrame_height then
topFrame:maximize_window(curwinLeaf, false, true)
else
topFrame:autoheight(curwinLeaf)
end
else
topFrame:equalize_windows(false, true)
end

local data = topFrame:get_data_for_height_resizing()
return data
end

Expand All @@ -63,6 +86,44 @@ function M.maximize_win(win, do_width, do_height)
return width_data, height_data
end

---Calculate layout for autoboth (width and height)
---@param curwin win.Window
---@return win.WinResizeData[]
function M.autoboth(curwin)
local topFrame = Frame() ---@type win.Frame
if topFrame.type == 'leaf' then
return {}
end

if curwin:is_valid()
and not curwin:is_floating()
and not curwin:get_option('winfixwidth')
and not curwin:get_option('winfixheight')
and not curwin:is_ignored()
then
local curwinLeaf = topFrame:find_window(curwin)
local topFrame_width = topFrame:get_width()
local topFrame_height = topFrame:get_height()
local curwin_wanted_width = curwin:get_wanted_width()
local curwin_wanted_height = curwin:get_wanted_height()
local topFrame_wanted_width = topFrame:get_min_width(curwin, curwin_wanted_width)
local topFrame_wanted_height = topFrame:get_min_height(curwin, curwin_wanted_height)

if topFrame_wanted_width > topFrame_width or topFrame_wanted_height > topFrame_height then
topFrame:maximize_window(curwinLeaf, true, true)
else
topFrame:autowidth(curwinLeaf)
topFrame:autoheight(curwinLeaf)
end
else
topFrame:equalize_windows(true, true)
end

local width_data = topFrame:get_data_for_width_resizing()
local height_data = topFrame:get_data_for_height_resizing()
return merge_resize_data(width_data, height_data)
end

---@param do_width boolean
---@param do_height boolean
---@return win.WinResizeData[]
Expand Down
Loading