local Border = require "plenary.window.border" local tbl = require "plenary.tbl" _AssociatedBufs = {} local clear_buf_on_leave = function(bufnr) vim.cmd( string.format( "autocmd WinLeave,BufLeave,BufDelete ++once ++nested lua require('plenary.window.float').clear(%s)", bufnr, bufnr ) ) end local win_float = {} win_float.default_options = { winblend = 15, percentage = 0.9, } function win_float.default_opts(options) options = tbl.apply_defaults(options, win_float.default_options) local width = math.floor(vim.o.columns * options.percentage) local height = math.floor(vim.o.lines * options.percentage) local top = math.floor(((vim.o.lines - height) / 2) - 1) local left = math.floor((vim.o.columns - width) / 2) local opts = { relative = "editor", row = top, col = left, width = width, height = height, style = "minimal", } return opts end function win_float.centered(options) options = tbl.apply_defaults(options, win_float.default_options) local win_opts = win_float.default_opts(options) local bufnr = options.bufnr or vim.api.nvim_create_buf(false, true) local win_id = vim.api.nvim_open_win(bufnr, true, win_opts) vim.cmd "setlocal nocursorcolumn" vim.api.nvim_win_set_option(win_id, "winblend", options.winblend) vim.cmd(string.format("autocmd WinLeave silent! execute 'bdelete! %s'", bufnr)) return { bufnr = bufnr, win_id = win_id, } end function win_float.centered_with_top_win(top_text, options) options = tbl.apply_defaults(options, win_float.default_options) table.insert(top_text, 1, string.rep("=", 80)) table.insert(top_text, string.rep("=", 80)) local primary_win_opts = win_float.default_opts(nil, nil, options) local minor_win_opts = vim.deepcopy(primary_win_opts) primary_win_opts.height = primary_win_opts.height - #top_text - 1 primary_win_opts.row = primary_win_opts.row + #top_text + 1 minor_win_opts.height = #top_text local minor_bufnr = vim.api.nvim_create_buf(false, true) local minor_win_id = vim.api.nvim_open_win(minor_bufnr, true, minor_win_opts) vim.cmd "setlocal nocursorcolumn" vim.api.nvim_win_set_option(minor_win_id, "winblend", options.winblend) vim.api.nvim_buf_set_lines(minor_bufnr, 0, -1, false, top_text) local primary_bufnr = vim.api.nvim_create_buf(false, true) local primary_win_id = vim.api.nvim_open_win(primary_bufnr, true, primary_win_opts) vim.cmd "setlocal nocursorcolumn" vim.api.nvim_win_set_option(primary_win_id, "winblend", options.winblend) -- vim.cmd( -- string.format( -- "autocmd WinLeave,BufDelete,BufLeave ++once ++nested silent! execute 'bdelete! %s'", -- primary_buf, -- minor_buf -- ) -- ) -- vim.cmd( -- string.format( -- "autocmd WinLeave,BufDelete,BufLeave ++once ++nested silent! execute 'bdelete! %s'", -- primary_buf -- ) -- ) local primary_border = Border:new(primary_bufnr, primary_win_id, primary_win_opts, {}) local minor_border = Border:new(minor_bufnr, minor_win_id, minor_win_opts, {}) _AssociatedBufs[primary_bufnr] = { primary_win_id, minor_win_id, primary_border.win_id, minor_border.win_id, } clear_buf_on_leave(primary_bufnr) return { bufnr = primary_bufnr, win_id = primary_win_id, minor_bufnr = minor_bufnr, minor_win_id = minor_win_id, } end --- Create window that takes up certain percentags of the current screen. --- --- Works regardless of current buffers, tabs, splits, etc. --@param col_range number | Table: -- If number, then center the window taking up this percentage of the screen. -- If table, first index should be start, second_index should be end --@param row_range number | Table: -- If number, then center the window taking up this percentage of the screen. -- If table, first index should be start, second_index should be end --@param win_opts Table --@param border_opts Table function win_float.percentage_range_window(col_range, row_range, win_opts, border_opts) win_opts = tbl.apply_defaults(win_opts, win_float.default_options) local default_win_opts = win_float.default_opts(win_opts) default_win_opts.relative = "editor" local height_percentage, row_start_percentage if type(row_range) == "number" then assert(row_range <= 1) assert(row_range > 0) height_percentage = row_range row_start_percentage = (1 - height_percentage) / 2 elseif type(row_range) == "table" then height_percentage = row_range[2] - row_range[1] row_start_percentage = row_range[1] else error(string.format("Invalid type for 'row_range': %p", row_range)) end default_win_opts.height = math.ceil(vim.o.lines * height_percentage) default_win_opts.row = math.ceil(vim.o.lines * row_start_percentage) local width_percentage, col_start_percentage if type(col_range) == "number" then assert(col_range <= 1) assert(col_range > 0) width_percentage = col_range col_start_percentage = (1 - width_percentage) / 2 elseif type(col_range) == "table" then width_percentage = col_range[2] - col_range[1] col_start_percentage = col_range[1] else error(string.format("Invalid type for 'col_range': %p", col_range)) end default_win_opts.col = math.floor(vim.o.columns * col_start_percentage) default_win_opts.width = math.floor(vim.o.columns * width_percentage) local bufnr = win_opts.bufnr or vim.api.nvim_create_buf(false, true) local win_id = vim.api.nvim_open_win(bufnr, true, default_win_opts) vim.api.nvim_win_set_buf(win_id, bufnr) vim.cmd "setlocal nocursorcolumn" vim.api.nvim_win_set_option(win_id, "winblend", win_opts.winblend) local border = Border:new(bufnr, win_id, default_win_opts, border_opts or {}) _AssociatedBufs[bufnr] = { win_id, border.win_id } clear_buf_on_leave(bufnr) return { bufnr = bufnr, win_id = win_id, border_bufnr = border.bufnr, border_win_id = border.win_id, } end function win_float.clear(bufnr) if _AssociatedBufs[bufnr] == nil then return end for _, win_id in ipairs(_AssociatedBufs[bufnr]) do if vim.api.nvim_win_is_valid(win_id) then vim.api.nvim_win_close(win_id, true) end end _AssociatedBufs[bufnr] = nil end return win_float