A Neovim plugin to easily create and manage predefined window layouts, bringing a new edge to your workflow.
- 🔄 Automatically move windows (including floating windows) in a pre-defined layout
- 📐 Manage layouts while keeping your main editor splits untouched.
- 🔧 Personalize edgebar window options to fit your style.
- 📌 Pinned views are always shown in the edgebar even when they have no windows.
- ⌨️ Make navigation easier with personalized buffer-local keymaps for edgebar windows.
- 🎆 Pretty animations (works well with mini.animate)
- 🧩 Works with any plugin. Check Show and Tell for snippets to integrate even better with plugins like neo-tree.nvim, bufferline.nvim
- fully collapsing windows only works with the global statusline.
- edgebar windows can not be resized like normal windows.
It's tricky to detect if a window was resized by the user or by a plugin.
Check the config section about
keys
. Regular window keymaps have been added for resizing windows. - requires Neovim >= 0.9.2 or Neovim >= 0.10.0 (after June 5, 2023)
for proper folding. If you're on an older nightly, you can set
fix_win_height
totrue
to make it work. - some flickering may occur when windows are being moved in their
correct position. Should be minimal, but may be more visible for some plugins
that don't set the buffer
filetype
during the frame where the window was created.
Install the plugin with your preferred package manager:
{
"folke/edgy.nvim",
event = "VeryLazy",
opts = {}
}
If you're not using lazy.nvim, make sure to call
require("edgy").setup(opts?)
.
Recommended Neovim options:
-- views can only be fully collapsed with the global statusline
vim.opt.laststatus = 3
-- Default splitting will cause your main splits to jump when opening an edgebar.
-- To prevent this, set `splitkeep` to either `screen` or `topline`.
vim.opt.splitkeep = "screen"
edgy.nvim comes with the following defaults:
{
left = {}, ---@type (Edgy.View.Opts|string)[]
bottom = {}, ---@type (Edgy.View.Opts|string)[]
right = {}, ---@type (Edgy.View.Opts|string)[]
top = {}, ---@type (Edgy.View.Opts|string)[]
---@type table<Edgy.Pos, {size:integer | fun():integer, wo?:vim.wo}>
options = {
left = { size = 30 },
bottom = { size = 10 },
right = { size = 30 },
top = { size = 10 },
},
-- edgebar animations
animate = {
enabled = true,
fps = 100, -- frames per second
cps = 120, -- cells per second
on_begin = function()
vim.g.minianimate_disable = true
end,
on_end = function()
vim.g.minianimate_disable = false
end,
-- Spinner for pinned views that are loading.
-- if you have noice.nvim installed, you can use any spinner from it, like:
-- spinner = require("noice.util.spinners").spinners.circleFull,
spinner = {
frames = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" },
interval = 80,
},
},
-- enable this to exit Neovim when only edgy windows are left
exit_when_last = false,
-- close edgy when all windows are hidden instead of opening one of them
-- disable to always keep at least one edgy split visible in each open section
close_when_all_hidden = true,
-- global window options for edgebar windows
---@type vim.wo
wo = {
-- Setting to `true`, will add an edgy winbar.
-- Setting to `false`, won't set any winbar.
-- Setting to a string, will set the winbar to that string.
winbar = true,
winfixwidth = true,
winfixheight = false,
winhighlight = "WinBar:EdgyWinBar,Normal:EdgyNormal",
spell = false,
signcolumn = "no",
},
-- buffer-local keymaps to be added to edgebar buffers.
-- Existing buffer-local keymaps will never be overridden.
-- Set to false to disable a builtin.
---@type table<string, fun(win:Edgy.Window)|false>
keys = {
-- close window
["q"] = function(win)
win:close()
end,
-- hide window
["<c-q>"] = function(win)
win:hide()
end,
-- close sidebar
["Q"] = function(win)
win.view.edgebar:close()
end,
-- next open window
["]w"] = function(win)
win:next({ visible = true, focus = true })
end,
-- previous open window
["[w"] = function(win)
win:prev({ visible = true, focus = true })
end,
-- next loaded window
["]W"] = function(win)
win:next({ pinned = false, focus = true })
end,
-- prev loaded window
["[W"] = function(win)
win:prev({ pinned = false, focus = true })
end,
-- increase width
["<c-w>>"] = function(win)
win:resize("width", 2)
end,
-- decrease width
["<c-w><lt>"] = function(win)
win:resize("width", -2)
end,
-- increase height
["<c-w>+"] = function(win)
win:resize("height", 2)
end,
-- decrease height
["<c-w>-"] = function(win)
win:resize("height", -2)
end,
-- reset all custom sizing
["<c-w>="] = function(win)
win.view.edgebar:equalize()
end,
},
icons = {
closed = " ",
open = " ",
},
-- enable this on Neovim <= 0.10.0 to properly fold edgebar windows.
-- Not needed on a nightly build >= June 5, 2023.
fix_win_height = vim.fn.has("nvim-0.10.0") == 0,
}
Property | Type | Description |
---|---|---|
ft | string |
File type of the view |
filter | fun(buf:buffer, win:window)? |
Optional function to filter buffers and windows |
title | string? or fun():string |
Optional title of the view. Defaults to the capitalized filetype |
size | number or fun():number |
Size of the short edge of the edgebar. For edgebars, this is the minimum width. For panels, minimum height. |
pinned | boolean? |
If true, the view will always be shown in the edgebar even when it has no windows |
collapsed | boolean? |
If true, the view will be initially closed/collapsed in the edgebar |
open | fun() or string |
Function or command to open a pinned view |
wo | vim.wo? |
View-specific window options |
Just open windows/buffers as you normally do, but now they will be displayed in your layout.
Keymap | Description |
---|---|
q |
Close the window |
<c-q> |
Hide the window |
Q |
Close the edgebar |
]w , [w |
Next/Prev open window |
]W , [W |
Next/Prev loaded window |
require("edgy").select(pos?, filter?)
select a window withvim.ui.select
in the given position or in all edgebars using an optional filterrequire("edgy").close(pos?)
close all edgebars or a edgebar in the given positionrequire("edgy").open(pos?)
open all pinned views in the given positionrequire("edgy").toggle(pos?)
toggle all pinned views in the given positionrequire("edgy").goto_main()
move the cursor to the last focused main windowrequire("edgy").get_win(window?)
get the Edgy.Window object for the given window or the current window
{
"folke/edgy.nvim",
event = "VeryLazy",
init = function()
vim.opt.laststatus = 3
vim.opt.splitkeep = "screen"
end,
opts = {
bottom = {
-- toggleterm / lazyterm at the bottom with a height of 40% of the screen
{
ft = "toggleterm",
size = { height = 0.4 },
-- exclude floating windows
filter = function(buf, win)
return vim.api.nvim_win_get_config(win).relative == ""
end,
},
{
ft = "lazyterm",
title = "LazyTerm",
size = { height = 0.4 },
filter = function(buf)
return not vim.b[buf].lazyterm_cmd
end,
},
"Trouble",
{ ft = "qf", title = "QuickFix" },
{
ft = "help",
size = { height = 20 },
-- only show help buffers
filter = function(buf)
return vim.bo[buf].buftype == "help"
end,
},
{ ft = "spectre_panel", size = { height = 0.4 } },
},
left = {
-- Neo-tree filesystem always takes half the screen height
{
title = "Neo-Tree",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "filesystem"
end,
size = { height = 0.5 },
},
{
title = "Neo-Tree Git",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "git_status"
end,
pinned = true,
collapsed = true, -- show window as closed/collapsed on start
open = "Neotree position=right git_status",
},
{
title = "Neo-Tree Buffers",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "buffers"
end,
pinned = true,
collapsed = true, -- show window as closed/collapsed on start
open = "Neotree position=top buffers",
},
{
title = function()
local buf_name = vim.api.nvim_buf_get_name(0) or "[No Name]"
return vim.fn.fnamemodify(buf_name, ":t")
end,
ft = "Outline",
pinned = true,
open = "SymbolsOutlineOpen",
},
-- any other neo-tree windows
"neo-tree",
},
},
}
-
disable edgy for a window/buffer by setting
vim.b[buf].edgy_disable
orvim.w[win].edgy_disable
. You can even set this after the facts. Edgy will then expunge the window from the layout. -
check the Show and Tell section of the github discussions for snippets for better integration with plugins like neo-tree.nvim, bufferline.nvim, ...