Piega is a Neovim plugin that provides intelligent, scope-aware code folding using Treesitter. It makes it easy to fold and unfold code blocks with intuitive keybindings.
- Fold/Unfold Scope: Intelligently fold or unfold the scope of the current line using Treesitter
- Unfold All: Unfold everything in the current buffer with a single command
- Fold Same Level: Fold all nodes at the same level (e.g., fold all methods in a class)
- Treesitter-Based: Uses Treesitter AST for accurate scope detection
- Universal Compatibility: Works with all major Neovim plugin managers
- Neovim >= 0.7.0
- nvim-treesitter
- Treesitter parsers for your target languages
Using lazy.nvim
{
'amartincodes/piega',
dependencies = { 'nvim-treesitter/nvim-treesitter' },
config = function()
require('piega').setup({
-- your configuration here (optional)
})
end,
}Using packer.nvim
use {
'amartincodes/piega',
requires = { 'nvim-treesitter/nvim-treesitter' },
config = function()
require('piega').setup()
end,
}Using vim-plug
Plug 'nvim-treesitter/nvim-treesitter'
Plug 'amartincodes/piega'
" In your init.vim or after plug#end()
lua << EOF
require('piega').setup()
EOFUsing pathogen
cd ~/.vim/bundle
git clone https://github.com/amartincodes/piega.gitThen in your Neovim config:
require('piega').setup()After installation, add this to your configuration:
require('piega').setup()Default keybindings:
<leader>zf- Fold/unfold the scope of the current line<leader>zu- Unfold everything in the buffer<leader>zl- Fold all nodes at the same level as the current line<leader>zn- Jump to next fold<leader>zp- Jump to previous fold
Here's the default configuration with all available options:
require('piega').setup({
keymaps = {
fold_scope = "<leader>zf", -- Fold/unfold current scope
unfold_all = "<leader>zu", -- Unfold everything
fold_level = "<leader>zl", -- Fold all at same level
next_fold = "<leader>zn", -- Jump to next fold
prev_fold = "<leader>zp", -- Jump to previous fold
},
enabled = true, -- Enable/disable plugin globally
set_foldmethod = true, -- Automatically set foldmethod to manual
custom_foldtext = true, -- Use custom fold text (shows line count)
exclude_filetypes = { -- Filetypes to exclude
"help",
"alpha",
"dashboard",
"NvimTree",
"neo-tree",
"Trouble",
},
foldable_nodes = { -- Node types to consider foldable
lua = {
"function_declaration",
"function_definition",
"if_statement",
"for_statement",
"while_statement",
"table_constructor",
},
python = {
"function_definition",
"class_definition",
"if_statement",
"for_statement",
"while_statement",
"with_statement",
},
javascript = {
"function_declaration",
"function_expression",
"arrow_function",
"class_declaration",
"method_definition",
"if_statement",
"for_statement",
"while_statement",
},
-- See lua/piega/config.lua for the full list
},
})You can customize the keybindings:
require('piega').setup({
keymaps = {
fold_scope = "zf",
unfold_all = "zu",
fold_level = "zl",
next_fold = "<C-j>", -- Or any key you prefer
prev_fold = "<C-k>", -- Or any key you prefer
},
})Or disable default keybindings entirely and set your own:
require('piega').setup({
keymaps = {
fold_scope = false,
unfold_all = false,
fold_level = false,
next_fold = false,
prev_fold = false,
},
})
-- Then set your own keybindings
vim.keymap.set('n', 'zf', require('piega').fold_scope)
vim.keymap.set('n', 'zu', require('piega').unfold_all)
vim.keymap.set('n', 'zl', require('piega').fold_level)
vim.keymap.set('n', 'zn', require('piega').next_fold)
vim.keymap.set('n', 'zp', require('piega').prev_fold)By default, Piega uses a beautiful custom fold text that shows:
- A fold icon ()
- The content of the first line
- Dotted padding for visual alignment
- A line count with icon ( 15 lines)
- Adaptive colors that match your colorscheme
- Italic styling for subtle elegance
Example of a folded block:
icons = vim.g.have_nerd_font and {} or { ··················· 15 lines
To disable custom fold text and use Neovim's default:
require('piega').setup({
custom_foldtext = false,
})To customize the fold display:
require('piega').setup({
foldtext_config = {
fold_icon = "▸", -- Icon before folded content
line_icon = "→", -- Icon before line count
padding_char = "·", -- Character for padding
use_nerd_font = true, -- Use Nerd Font icons
},
})Position your cursor anywhere within a function, class, or other code block and press <leader>zf. Piega will use Treesitter to find the scope boundaries and fold it. Press again to unfold.
Example: With cursor inside a function:
function example()
local x = 1
if x > 0 then
print("positive")
end
endAfter pressing <leader>zf, the entire function will be folded.
Press <leader>zu to unfold all folds in the current buffer. This is useful when you want to see all the code at once.
Press <leader>zl to fold all nodes at the same level as the current line. This is particularly useful for:
- Folding all methods in a class when cursor is on a method
- Folding all functions in a module
- Folding all if statements at the same nesting level
Example: With cursor on any method in this class:
class Example:
def method1(self):
pass
def method2(self):
pass
def method3(self):
passAfter pressing <leader>zl, all three methods will be folded.
Quickly jump between folded sections in your buffer:
- Press
<leader>znto jump to the next fold (closed fold) - Press
<leader>zpto jump to the previous fold (closed fold)
These keybindings:
- Navigate only to closed/collapsed folds
- Work correctly even when your cursor is on a folded line
- Wrap around when reaching the end/beginning of the file
- Show notifications when wrapping or if no folds are found
Perfect for quickly navigating through your folded code!
Piega also provides Vim commands:
:PiegaFoldScope- Fold/unfold current scope:PiegaUnfoldAll- Unfold all in buffer:PiegaFoldLevel- Fold all at same level
You can also use the Lua API directly:
require('piega').fold_scope() -- Fold/unfold current scope
require('piega').unfold_all() -- Unfold all in buffer
require('piega').fold_level() -- Fold all at same level
require('piega').next_fold() -- Jump to next fold
require('piega').prev_fold() -- Jump to previous foldPiega works with any language that has a Treesitter parser. Out of the box, it includes foldable node configurations for:
Systems & Compiled Languages:
- C/C++
- Rust
- Go
- Java
Scripting Languages:
- Lua
- Python
- Bash/Shell
Web Development:
- JavaScript/TypeScript
- JSX/TSX (React)
- HTML
- CSS
Data & Configuration:
- JSON/JSONC
- YAML
- Markdown
You can easily add support for more languages by extending the foldable_nodes configuration. See lua/piega/config.lua for examples, or add custom languages in your setup:
require('piega').setup({
foldable_nodes = {
ruby = {
"method_definition",
"class_definition",
"module_definition",
"if_statement",
"for_statement",
"while_statement",
},
},
})Install nvim-treesitter:
-- Using lazy.nvim
{ 'nvim-treesitter/nvim-treesitter', build = ':TSUpdate' }Install the parser for your language:
:TSInstall <language>For example: :TSInstall python, :TSInstall lua, etc.
Your cursor might be in a location without a recognizable scope. Try moving the cursor inside a function, class, or other code block. You can also extend the foldable_nodes configuration for your language.
Piega includes a comprehensive test suite using plenary.nvim.
Make sure you have plenary.nvim installed, then run:
make testOr run a specific test file:
make test-file FILE=tests/config_spec.luaThe test suite covers:
- Configuration management and merging
- Treesitter node detection and range handling
- Folding operations and buffer management
- All supported languages including JSON
See tests/README.md for more details.
Contributions are welcome! Please feel free to submit a Pull Request.
When contributing:
- Write tests for new features
- Ensure all tests pass with
make test - Follow the existing code style
MIT License - see LICENSE file for details