title | description | author | categories | tangle | created | updated | version | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Neovim Config |
My personal neovim config |
Simon H Moore |
|
|
2024-03-06 23:01:44 +0100 |
2025-08-23 13:47:38 +0100 |
1.1.1 |
All of my main config is contained in this file config.norg
, to be able to use this config you have to first tangle
the file to generate the config.lua
file.
- Create
lua
directory. Alua
directory is needed so that theconfig.lua
file can be crated inside of it. Run the below command inside of your shell at the root of this config:
mkdir lua
- Open Neovim to bootstrap the config.
A. Because the Lazy.nvim package manager and Neorg plugin is required to
tangle
the config, you have to bootstrap the config for the first time. Don't worry this happens automatically, you just have to open Neovim by running:
nvim
You will see some errors pop up, don't worry about them this just happens because Neovim expects there to be a config which is not there yet.
B. After this is done, close Neovim again by running the below command:
:qa
- Tangle the
config.norg
file. A. Last, we need totangle
the config.norg file, to do so open the file with Neovim by running the following command:
nvim config.norg
B. After the config.norg
file is opened in Neovim, run the following command inside Neovim:
:Neorg tangle
Neovim will ask you which file to tangle, select config.norg
- Reopen Neovim and enjoy
Close and reopen Neovim and the
Lazy
plugin manager will install everything needed. You might have to reopen Neovim a few times to make sure everything is installed.
Used by many plugins for keybindings, need to be set early as plugins can be dependant on it.
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
Declare common API variables, will be used throughout the config.
| Variable | Value | Descriptions | |----------+---------+------------------------| | o | vim.opt | Inbuilt vim options | | g | vim.g | Inbuilt global options | | cmd | vim.cmd | Run vim ex commands |
local o = vim.opt
local g = vim.g
local cmd = vim.cmd
The P()
function can be used globally to print a lua table for inspection.
P = function(v)
print(vim.inspect(v))
return v
end
The plug()
function is used to add plugins to the plugins
table.
The plugins
table will be used by lazy to install and load plugins.
local plugins = {}
function plug(plugin)
plugins[#plugins +1] = plugin
end
Configure inbuilt Neovim options.
o.autowrite = true -- Enable auto write
o.clipboard = "unnamedplus" -- Sync with system clipboard
o.completeopt = "menu,menuone,noselect" -- Completion options for better experience
o.conceallevel = 3 -- Hide * markup for bold and italic
o.confirm = true -- Confirm to save changes before exiting modified buffer
o.cursorline = true -- Enable highlighting of the current line
o.breakindent = true -- Every wrapped line will honor indent
o.expandtab = true -- Use spaces instead of tabs
o.formatoptions = "jcroqlnt" -- Format options for automatic formatting
o.grepformat = "%f:%l:%c:%m" -- Format for grep output
o.grepprg = "rg --vimgrep" -- Use ripgrep for grep command
o.ignorecase = true -- Ignore case in search patterns
o.inccommand = "nosplit" -- Preview incremental substitute
o.laststatus = 0 -- Never show status line
o.list = true -- Show some invisible characters (tabs, trailing spaces)
o.mouse = "a" -- Enable mouse mode
o.number = true -- Print line number
o.pumblend = 10 -- Popup blend transparency
o.pumheight = 10 -- Maximum number of entries in a popup
o.relativenumber = true -- Relative line numbers
o.scrolloff = 4 -- Lines of context around cursor
o.sessionoptions = { "buffers", "curdir", "tabpages", "winsize" } -- Session save options
o.shiftround = true -- Round indent to multiple of shiftwidth
o.shiftwidth = 2 -- Size of an indent
o.shortmess:append({ W = true, I = true, c = true }) -- Reduce message verbosity
o.showmode = false -- Don't show mode since we have a statusline
o.sidescrolloff = 8 -- Columns of context around cursor
o.signcolumn = "yes" -- Always show the signcolumn, otherwise it would shift the text each time
o.smartcase = true -- Don't ignore case with capitals
o.smartindent = true -- Insert indents automatically
o.spelllang = { "en" } -- Spell checking language
o.splitbelow = true -- Put new windows below current
o.splitright = true -- Put new windows right of current
o.tabstop = 2 -- Number of spaces tabs count for
o.termguicolors = true -- True color support
o.timeoutlen = 300 -- Time to wait for a mapped sequence to complete
o.undofile = true -- Save undo history to file
o.undolevels = 10000 -- Maximum number of changes that can be undone
o.updatetime = 200 -- Save swap file and trigger CursorHold
o.wildmode = "longest:full,full" -- Command-line completion mode
o.winminwidth = 5 -- Minimum window width
o.wrap = false -- Disable line wrap
o.foldlevelstart = 0 -- Enable foldlevel when opening file
o.foldnestmax = 2 -- Set max nested foldlevel
vim.opt.foldenable = true -- Enable folding
vim.opt.foldmethod = "expr" -- Use expression for folding
vim.opt.foldexpr = "v:lua.vim.treesitter.foldexpr()" -- Use treesitter for fold expression
vim.o.foldtext = '' -- Use default fold text
vim.o.fillchars = 'fold: ' -- Characters to fill folds
if vim.fn.has("nvim-0.9.0") == 1 then
o.splitkeep = "screen"
o.shortmess:append({ C = true })
end
-- use powershell on windows
if vim.fn.has("win32") == 1 then
o.shell = vim.fn.executable "pwsh" == 1 and "pwsh" or "powershell"
o.shellcmdflag =
"-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;"
o.shellredir = "-RedirectStandardOutput %s -NoNewWindow -Wait"
o.shellpipe = "2>&1 | Out-File -Encoding UTF8 %s; exit LastExitCode"
o.shellquote = ""
o.shellxquote = ""
end
-- if in a wsl environment WSL_DISTRO_NAME should be set
local in_wsl = os.getenv('WSL_DISTRO_NAME') ~= nil
if in_wsl then
-- Need to install win32yank in windows
-- see https://mitchellt.com/2022/05/15/WSL-Neovim-Lua-and-the-Windows-Clipboard.html
vim.g.clipboard = {
name = "win32yank-wsl",
copy = {
["+"] = "win32yank.exe -i --crlf",
["*"] = "win32yank.exe -i --crlf",
},
paste = {
["+"] = "win32yank.exe -o --lf",
["*"] = "win32yank.exe -o --lf",
},
cache_enabled = true,
}
end
Here I set up the color and syntax used in Neovim buffers.
Enable true color support:
o.termguicolors = true
A retro groove color scheme with warm, earthy tones designed for comfortable long coding sessions. Gruvbox provides excellent contrast and readability while being easy on the eyes.
This colorscheme implementation offers:
-
Warm color palette: Carefully selected browns, oranges, and muted colors that reduce eye strain
-
Treesitter integration: Full support for modern syntax highlighting with semantic tokens
-
Transparency support: Optional transparent background for terminal integration
-
Comprehensive language support: Optimized colors for all major programming languages
-
Dark and light variants: Multiple contrast levels to suit different lighting conditions
-
Accessibility focused: High contrast ratios and colorblind-friendly palette choices
Usage: The colorscheme is automatically applied on startup. The configuration includes transparency mode and custom overrides for better markdown and code block visibility.
Help: The theme provides consistent highlighting across all file types while maintaining the distinctive Gruvbox aesthetic that has made it popular among developers worldwide.
For example, comments appear in a muted gray-brown, strings in warm green, and keywords in bright orange, creating a cohesive and pleasant coding environment.
plug({
"ellisonleao/gruvbox.nvim",
enabled = true,
lazy = false,
priority = 10000,
config = function()
require("gruvbox").setup({
transparent_mode = true,
terminal_colors = false, -- disable gruvbox in terminal
overrides = {
Folded = { bg = "#202020" },
-- fix markdown todo colors
["@lsp.type.class.markdown"] = { fg = "#000000" },
["@neorg.tags.ranged_verbatim.code_block"] = { bg = "#222222" },
}
})
o.background = "dark"
g.gruvbox_italic = true
g.gruvbox_bold = false
g.gruvbox_transparent_bg = true
g.gruvbox_constrast_dark = "hard"
g.gruvbox_improved_strings = false
cmd([[colorscheme gruvbox]])
end,
})
A high-performance color highlighter that displays colors directly in your code for better visual feedback. Colorizer automatically detects and highlights color codes, making it easier to work with CSS, web development, and any files containing color values.
This plugin provides:
-
Real-time color preview: See actual colors rendered inline for hex codes, RGB values, and named colors
-
Multiple format support: Handles #RGB, #RRGGBB, #RRGGBBAA, rgb(), hsl(), and CSS color names
-
Performance optimized: Fast highlighting that doesn't slow down your editor
-
Customizable display: Choose between background highlighting, foreground text, or virtual text display
-
Wide language support: Works with CSS, HTML, JavaScript, Lua, and many other file types
-
Non-intrusive: Only highlights valid color codes without interfering with syntax highlighting
Usage: Colors are automatically highlighted when you open supported files. The plugin runs in the background and updates highlights as you type.
Help: The colorizer makes it instantly clear what colors your code represents, eliminating guesswork when working with color values in web development, theming, or configuration files.
For example,
#ff0000
will show with a red background,rgb(0, 255, 0)
with green, andblue
with the corresponding blue color.
plug({
"norcalli/nvim-colorizer.lua",
enabled = true,
event = { "BufReadPost", "BufNewFile" },
opts = {
default_options = {
RGB = true,
RRGGBB = true,
names = true,
RRGGBBAA = true,
rgb_fn = true,
hsl_fn = true,
css = true,
css_fn = true,
mode = "background",
},
"*", -- highlight all files
},
})
A Neovim plugin that provides rainbow parentheses highlighting using Tree-sitter for enhanced code readability. Rainbow colorizes matching brackets, parentheses, and delimiters with different colors to make nested code structures easier to navigate and understand.
This plugin offers:
-
Tree-sitter integration: Uses modern Tree-sitter parsing for accurate bracket detection and highlighting
-
Multiple delimiter support: Highlights parentheses, brackets, braces, and other delimiters with distinct colors
-
Extended mode: Optional highlighting of non-bracket delimiters like HTML tags and language-specific constructs
-
Performance optimized: Efficient highlighting that works smoothly even with large files
-
Customizable colors: Configure your own color schemes or use the default rainbow palette
-
Language awareness: Intelligent highlighting that respects language syntax and context
Usage: Rainbow highlighting is automatically applied when you open supported files. The plugin cycles through colors for each nesting level, making it easy to match opening and closing delimiters.
Help: The rainbow colors help reduce visual confusion when working with deeply nested code structures, making it easier to spot mismatched brackets and understand code hierarchy at a glance.
For example, in nested function calls like
func(array[index(key)])
, each level of brackets will appear in a different color, making the structure immediately clear.
plug({
"p00f/nvim-ts-rainbow",
event = { "BufReadPost", "BufNewFile" },
main = 'nvim-treesitter.configs',
opts = {
-- for nvim-ts-rainbow plugin
rainbow = {
enable = true,
extended_mode = true, -- Also highlight non-bracket delimiters like html tags, boolean or table: lang -> boolean
max_file_lines = 10000, -- Do not enable for files with more than 10000 lines, int
-- colors = {}, -- table of hex strings
-- termcolors = {} -- table of colour name strings
},
}
})
A modern and enhanced replacement for Neovim's built-in matchparen functionality that provides intelligent bracket and delimiter highlighting. Sentiment offers superior performance and visual feedback for matching pairs in your code.
This plugin enhances code navigation by:
-
Smart pair detection: Accurately highlights matching brackets, parentheses, braces, and other delimiters
-
Performance optimized: Faster and more efficient than the default matchparen plugin
-
Visual clarity: Clear highlighting that makes it easy to identify matching pairs at a glance
-
Customizable appearance: Configure colors and styles to match your preferred theme
-
Language awareness: Intelligent handling of different programming language syntaxes
-
Non-intrusive design: Subtle highlighting that doesn't interfere with your workflow
Usage: Matching pairs are automatically highlighted when your cursor is positioned on or near brackets, parentheses, or other delimiters. The plugin works seamlessly in the background.
Help: The highlighting helps you quickly identify the scope of code blocks, function calls, and nested structures, reducing errors and improving code comprehension.
For example, when your cursor is on an opening
[
, the corresponding closing](
, the corresponding closing)
will be highlighted, making it easy to see the extent of code blocks and nested structures.
plug({
"utilyre/sentiment.nvim",
version = "*",
event = "VeryLazy", -- keep for lazy loading
opts = {
-- config
},
init = function()
-- `matchparen.vim` needs to be disabled manually in case of lazy loading
vim.g.loaded_matchparen = 1
end,
})
This plugin adds highlights for text filetypes, like markdown, orgmode, and neorg.
plug({
"lukas-reineke/headlines.nvim",
dependencies = "nvim-treesitter/nvim-treesitter",
config = function()
vim.cmd [[highlight Headline1 guibg=#1e2718]]
vim.cmd [[highlight Headline2 guibg=#21262d]]
vim.cmd [[highlight CodeBlock guibg=#1c1c1c]]
vim.cmd [[highlight Dash guibg=#D19A66 gui=bold]]
require("headlines").setup {
norg = {
query = vim.treesitter.query.parse(
"norg",
[[
[
(heading1_prefix)
(heading2_prefix)
(heading3_prefix)
(heading4_prefix)
(heading5_prefix)
(heading6_prefix)
] @headline
(weak_paragraph_delimiter) @dash
(strong_paragraph_delimiter) @doubledash
([(ranged_tag
name: (tag_name) @_name
(#eq? @_name "code")
)
(ranged_verbatim_tag
name: (tag_name) @_name
(#eq? @_name "code")
)] @codeblock (#offset! @codeblock 0 0 1 0))
(quote1_prefix) @quote
]]
),
headline_highlights = { "Headline1", "Headline2" },
bullet_highlights = {
"@neorg.headings.1.prefix",
"@neorg.headings.2.prefix",
"@neorg.headings.3.prefix",
"@neorg.headings.4.prefix",
"@neorg.headings.5.prefix",
"@neorg.headings.6.prefix",
},
bullets = { "◉", "○", "✸", "✿" },
codeblock_highlight = false,
dash_highlight = "Dash",
dash_string = "-",
doubledash_highlight = "DoubleDash",
doubledash_string = "=",
quote_highlight = "Quote",
quote_string = "┃",
fat_headlines = true,
fat_headline_upper_string = "▄",
fat_headline_lower_string = "▀",
},
}
end,
})
Here we configure the user interface for Neovim.
A blazing fast and highly customizable statusline plugin for Neovim written in pure Lua. Lualine provides a beautiful and informative status bar that displays essential information about your editing session while maintaining excellent performance.
This statusline implementation offers:
- Lightning-fast performance: Written in Lua with minimal overhead, ensuring your editor stays responsive
- Extensive customization: Configure colors, components, separators, and layout to match your workflow
- Rich component library: Display mode, branch, diagnostics, file info, LSP status, and much more
- Theme integration: Seamlessly integrates with your colorscheme or use custom themes
- Extension support: Built-in support for popular plugins like fugitive, fzf, and nvim-tree
- Winbar support: Optional window-local statuslines for better file navigation
- Tabline functionality: Replace Neovim's default tabline with a customizable alternative
Usage: The statusline is automatically displayed and updates in real-time. The configuration includes custom themes, component positioning, and integration with LSP diagnostics and Git information.
Help: Run :help lualine
for comprehensive documentation. The plugin displays current mode, Git branch, file path, diagnostics, and cursor position by default.
For example, the statusline shows your current Vim mode (Normal, Insert, Visual), Git branch with diff statistics, file encoding, and line/column position, all with color-coded indicators for quick visual reference.
local colors = {
black = "#000000",
white = "#ffffff",
gray = "#444444",
light_gray = "#666666",
background = "#0c0c0c",
green = "#005000",
yellow = "#706000",
blue = "#004090",
paste = "#5518ab",
red = "#800000",
}
local lualine_theme = {
normal = {
a = { fg = colors.white, bg = colors.green },
b = { fg = colors.white, bg = colors.grey },
c = { fg = colors.white, bg = colors.black },
},
insert = { a = { fg = colors.white, bg = colors.blue } },
command = { a = { fg = colors.white, bg = colors.red } },
visual = { a = { fg = colors.white, bg = colors.yellow } },
replace = { a = { fg = colors.white, bg = colors.red } },
inactive = {
a = { fg = colors.white, bg = colors.black },
b = { fg = colors.white, bg = colors.black },
c = { fg = colors.light_gray, bg = colors.black },
},
}
plug({
{
"nvim-lualine/lualine.nvim",
event = "VeryLazy",
opts = function()
return {
options = {
theme = lualine_theme,
component_separators = { left = "", right = "" },
section_separators = { left = "|", right = "|" },
},
sections = {
lualine_a = { "mode" },
lualine_b = { "branch", "diff", "diagnostics" },
lualine_c = {
{
"filename",
path = 4
},
},
lualine_x = { "encoding", "fileformat", "filetype" },
lualine_y = { "progress" },
lualine_z = { "location" },
},
inactive_sections = {
lualine_a = {},
lualine_b = {},
lualine_c = {
{
"filename",
path = 4
},
},
lualine_x = { "location" },
lualine_y = {},
lualine_z = {},
},
tabline = {},
winbar = {
lualine_c = {
{
"filename",
path = 4,
},
"navic"
},
},
inactive_winbar = {
lualine_c = {
{
"filename",
path = 3
}
},
},
extensions = {},
}
end,
},
})
@end
An all-encompassing tool based around structured note taking, project and task management, time tracking, slideshows, writing typeset documents and much more.
plug({
"nvim-neorg/neorg",
build = ":Neorg sync-parsers",
dependencies = {
"nvim-lua/plenary.nvim",
"Pocco81/true-zen.nvim",
"nvim-treesitter/nvim-treesitter",
"nvim-treesitter/nvim-treesitter-textobjects",
"hrsh7th/nvim-cmp",
},
ft = "norg",
cmd = "Neorg",
config = function()
require("neorg").setup({
load = {
["core.defaults"] = {}, -- Loads default behaviour
["core.concealer"] = { -- Adds pretty icons to your documents
config = {
foldlevelstart = "0",
icon_preset = "diamond",
icons = {
code_block = {
width = "content",
min_width = 85,
conceal = true,
},
},
},
},
["core.dirman"] = { -- Manages Neorg workspaces
config = {
workspaces = {
documents = "~/Documents",
notes = "~/Documents/Notes",
career = "~/Documents/Career",
profiles = "~/Documents/Profiles",
},
default_workspace = "documents",
},
},
["core.completion"] = {
config = {
engine = 'nvim-cmp',
name = "[Norg]",
}
},
["core.integrations.nvim-cmp"] = {},
["core.qol.toc"] = {
config = {
close_split_on_jump = true,
toc_split_placement = "right",
}
},
["core.export"] = {},
["core.export.markdown"] = {
config = {
extensions = "all",
}
},
["core.presenter"] = {
config = {
zen_mode = "truezen",
}
},
["core.journal"] = {
config = {
workspace = "journal",
strategy = "flat",
}
},
["core.summary"] = {},
["core.esupports.metagen"] = { config = { type = "auto", update_date = true } },
["core.ui.calendar"] = {},
}
})
local neorg_callbacks = require("neorg.core.callbacks")
neorg_callbacks.on_event("core.keybinds.events.enable_keybinds", function(_, keybinds)
-- Map all the below keybinds only when the "norg" mode is active
keybinds.map_event_to_mode("norg", {
n = { -- Bind keys in normal mode
{ "<localleader>ff", function() Snacks.picker.files({ cwd = vim.fn.getcwd() }) end, opts = { desc = 'Find Norg Files' } },
{ "<localleader>sh", function() Snacks.picker.grep({ cwd = vim.fn.getcwd() }) end, opts = { desc = 'Search Headings' } },
{ "<localleader>cg", "core.looking-glass.magnify-code-block", opts = { desc = 'Looking Glass' } },
},
i = { -- Bind in insert mode
{ "<C-l>", function() print("Link insertion not available with snacks") end, opts = { desc = 'Insert Link (unavailable)' } },
{ "<C-L>", function() print("File link insertion not available with snacks") end, opts = { desc = 'Insert File Link (unavailable)' } },
},
}, {
silent = true,
noremap = true,
})
end)
end,
})
A collection of small QoL plugins for Neovim.
plug({
"folke/snacks.nvim",
priority = 1000,
lazy = false,
---@type snacks.Config
opts = {
-- Keep only the useful non-picker modules
bigfile = { enabled = true },
indent = {
indent = {
enabled = true,
priority = 1,
char = "▎",
},
animate = { enabled = false },
scope = {
enabled = true, -- enable highlighting the current scope
priority = 200,
char = "▎",
},
},
-- Enable snacks notify
notifier = {
enabled = true,
timeout = 1000,
width = { min = 20, max = 50 },
height = { max = 50 },
style = "compact",
top_down = true,
},
-- Enable snacks input to replace dressing.nvim
input = { enabled = true },
-- Enable snacks words for navigation (]] [[)
words = {
enabled = true,
debounce = 200,
},
-- Enable quickfile for better performance
quickfile = { enabled = true },
-- Enable picker instead of telescope
picker = { enabled = true },
-- Keep disabled
dashboard = { enabled = false },
explorer = { enabled = false },
scope = { enabled = false },
scroll = { enabled = false },
statuscolumn = { enabled = false },
},
config = function(_, opts)
require("snacks").setup(opts)
vim.notify = Snacks.notifier.notify
-- Add snacks picker keymaps
local pick = Snacks.picker
-- Shortcuts
vim.keymap.set('n', '<leader>?', pick.recent, { desc = 'Find Recently Files' })
vim.keymap.set('n', '<leader>,', pick.buffers, { desc = 'Find buffers' })
vim.keymap.set('n', '<leader>/', pick.grep_word, { desc = 'Search current word' })
-- Find Files
vim.keymap.set('n', '<leader>ff', pick.files, { desc = 'Find Files' })
vim.keymap.set('n', '<leader>fb', pick.buffers, { desc = 'Find Buffers' })
vim.keymap.set('n', '<leader>fr', pick.recent, { desc = 'Find Recent Files' })
vim.keymap.set('n', '<leader>fg', pick.git_files, { desc = 'Find Git Files' })
vim.keymap.set('n', '<leader>fs', pick.git_status, { desc = 'Find Git Status' })
vim.keymap.set('n', '<leader>fd', function() pick.files({ cwd = '~/Documents' }) end, { desc = 'Find Documents' })
vim.keymap.set('n', '<leader>fD', function() pick.files({ cwd = '~/Downloads' }) end, { desc = 'Find Downloads' })
vim.keymap.set('n', '<leader>fp', function() pick.files({ cwd = '~/Projects' }) end, { desc = 'Find Projects' })
vim.keymap.set('n', '<leader>fc', function() pick.files({ cwd = vim.fn.stdpath('config') }) end, { desc = 'Find Config' })
vim.keymap.set('n', '<leader>fB', function() pick.files({ cwd = '~/.local/bin' }) end, { desc = 'Find Local Bin' })
-- Search for content, help and functions
vim.keymap.set('n', '<leader>sc', pick.git_log, { desc = 'Search Git Commits' })
vim.keymap.set('n', '<leader>st', function() pick.commands() end, { desc = 'Search Commands' })
vim.keymap.set('n', '<leader>sh', pick.help, { desc = 'Search Help' })
vim.keymap.set('n', '<leader>sw', pick.grep_word, { desc = 'Search Current Word' })
vim.keymap.set('n', '<leader>sg', pick.grep, { desc = 'Search by Grep' })
vim.keymap.set('n', '<leader>sd', pick.diagnostics, { desc = 'Search Diagnostics' })
vim.keymap.set('n', '<leader>sk', pick.keymaps, { desc = 'Search Keymaps' })
vim.keymap.set('n', "<leader>s'", pick.marks, { desc = 'Search Marks' })
vim.keymap.set('n', '<leader>s"', pick.registers, { desc = 'Search Registers' })
vim.keymap.set('n', '<leader>sf', pick.grep_word, { desc = 'Search word under cursor' })
end,
keys = {
{
"<leader>;n",
function() Snacks.notifier.show_history() end,
desc = "Notification History"
},
{
"]]",
function() Snacks.words.jump(vim.v.count1) end,
desc = "Next Reference"
},
{
"[[",
function() Snacks.words.jump(-vim.v.count1) end,
desc = "Prev Reference"
},
}
})
Automatically highlighting other uses of the word under the cursor using either LSP, Tree-sitter, or regex matching.
plug({
"RRethy/vim-illuminate",
event = { "BufReadPost", "BufNewFile" },
opts = {
delay = 200,
large_file_cutoff = 2000,
large_file_overrides = {
providers = { "lsp" },
},
},
config = function(_, opts)
require("illuminate").configure(opts)
local function map(key, dir, buffer)
vim.keymap.set("n", key, function()
require("illuminate")["goto_" .. dir .. "_reference"](false)
end, { desc = dir:sub(1, 1):upper() .. dir:sub(2) .. " Reference", buffer = buffer })
end
map("]]", "next")
map("[[", "prev")
-- also set it after loading ftplugins, since a lot overwrite [[ and ]]
vim.api.nvim_create_autocmd("FileType", {
callback = function()
local buffer = vim.api.nvim_get_current_buf()
map("]]", "next", buffer)
map("[[", "prev", buffer)
end,
})
end,
keys = {
{ "]]", desc = "Next Reference" },
{ "[[", desc = "Prev Reference" },
},
})
A revolutionary file explorer that treats your filesystem like a regular Neovim buffer, allowing you to edit directories with the same commands you use for text editing. Oil transforms file management into a native Neovim experience with unparalleled efficiency.
This file explorer provides:
- Buffer-based editing: Navigate and modify your filesystem using familiar Vim motions and commands
- Direct manipulation: Rename files by editing text, delete with
dd
, copy withyy
, and paste withp
- Floating window support: Quick access via floating windows that don't disrupt your workflow
- Cross-platform compatibility: Works seamlessly on Windows, macOS, and Linux systems
- Undo/redo support: Full undo history for filesystem operations with standard Vim commands
- Integration friendly: Works with your existing Neovim plugins and colorschemes
- Performance optimized: Fast directory loading and responsive navigation even in large directories
Usage: Open with <leader>o
for a floating window or <leader>O
for current working directory. Edit filenames directly in the buffer, use dd
to delete files, and save with :w
to apply changes.
Help: Run :help oil
for complete documentation. The plugin treats directories as editable buffers where standard Vim operations translate to filesystem actions.
For example, to rename multiple files, simply edit their names in the buffer using standard text editing commands, then save to apply all changes atomically.
plug({
"stevearc/oil.nvim",
dependencies = { "nvim-tree/nvim-web-devicons" },
enabled = true,
lazy = true,
config = function ()
require("oil").setup({
default_file_explorer = true,
})
end,
cmd = "Oil",
keys = {
{ "<leader>o", function() require("oil").toggle_float() end, desc = "Oil File Manager" },
{ "<leader>O", function() require("oil").toggle_float(vim.fn.getcwd()) end, desc = "Oil File Manager" },
}
})
A comprehensive and modern file explorer for Neovim that provides an intuitive tree-based interface for navigating your filesystem, buffers, and Git status. Neo-Tree offers a feature-rich sidebar experience with extensive customization options.
This file manager delivers:
- Multiple source types: Browse filesystem, open buffers, Git status, and LSP document symbols in unified interface
- Rich visual indicators: File type icons, Git status markers, and diagnostic indicators for comprehensive project overview
- Advanced navigation: Fuzzy finding, bookmarks, and quick access to recently used files
- Git integration: Visual Git status with staging/unstaging capabilities directly from the tree
- Customizable interface: Configurable mappings, filters, and display options to match your workflow
- Performance optimized: Lazy loading and efficient rendering for large directory structures
- Plugin ecosystem: Extensive integration with popular Neovim plugins and LSP servers
Usage: Toggle with <leader>e
for filesystem view or <leader>be
for buffer explorer. Navigate with standard Vim motions, open files with <Enter>
, and use various actions via intuitive key mappings.
Help: Run :help neo-tree
for detailed documentation. The plugin provides context-sensitive help and customizable key mappings for all operations.
For example, press a
to create new files/directories, d
to delete, r
to rename, and c
to copy, all while seeing real-time Git status and file type information.
plug({
"nvim-neo-tree/neo-tree.nvim",
branch = "v3.x",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-tree/nvim-web-devicons", -- not strictly required, but recommended
"MunifTanjim/nui.nvim",
},
cmd = "Neotree",
keys = {
{
"<leader>e",
function()
require("neo-tree.command").execute({ toggle = true, dir = vim.loop.cwd() })
end,
desc = "Explorer NeoTree",
},
{
"<leader>be",
function()
require("neo-tree.command").execute({ toggle = true, source = "buffers" })
end,
desc = "Explorer NeoTree Buffers",
},
},
deactivate = function()
vim.cmd([[Neotree close]])
end,
opts = {
sources = { "filesystem", "buffers", "git_status", "document_symbols" },
open_files_do_not_replace_types = { "terminal", "Trouble", "qf", "Outline" },
filesystem = {
bind_to_cwd = false,
follow_current_file = { enabled = true },
use_libuv_file_watcher = true,
},
window = {
mappings = {
["<space>"] = "none",
},
},
default_component_configs = {
indent = {
with_expanders = true, -- if nil and file nesting is enabled, will enable expanders
expander_collapsed = "",
expander_expanded = "",
expander_highlight = "NeoTreeExpander",
},
},
},
})
An intelligent project management plugin that automatically detects and manages your project workspaces, providing seamless project switching and workspace organization. Project.nvim eliminates the hassle of manual directory management and enhances your development workflow.
This project manager offers:
- Automatic project detection: Intelligently identifies projects using Git repositories, LSP roots, and custom patterns
- Smart directory switching: Automatically changes working directory when switching between projects
- Recent project history: Maintains a history of recently accessed projects for quick switching
- Multiple detection methods: Supports Git, LSP, and custom file patterns for flexible project identification
- Integration ready: Works seamlessly with telescope, dashboard, and other popular plugins
- Session persistence: Optional integration with session management for complete workspace restoration
- Customizable patterns: Define your own project root indicators for specialized workflows
Usage: Projects are automatically detected when you open files. Use <leader>sp
to search and switch between recent projects. The plugin maintains context and working directory automatically.
Help: Run :help project_nvim
for configuration options. The plugin works silently in the background, tracking your project usage patterns.
For example, when you open a file in a Git repository, Project.nvim automatically sets that repository as your current project and remembers it for future quick access via the project picker.
plug({
"ahmedkhalf/project.nvim",
enabled = true,
lazy = false,
config = function()
require("project_nvim").setup({
detection_methods = { "lsp", "pattern" },
patterns = { ".project", ".git", "_darcs", ".hg", ".bzr", ".svn", "Makefile", "package.json" },
silent_chdir = false,
})
end,
keys = {
{
"<leader>sp",
function()
local projects = require("project_nvim").get_recent_projects()
Snacks.picker.pick({
items = projects,
format = function(item) return vim.fn.fnamemodify(item, ":t") .. " (" .. item .. ")" end,
preview = false,
}, function(item)
vim.cmd("cd " .. item)
end)
end,
desc = 'Search for Project',
},
},
})
An innovative motion enhancement plugin that provides unique visual indicators for f/F/t/T movements, making character-based navigation significantly faster and more accurate. Eyeliner eliminates guesswork in horizontal navigation by highlighting optimal jump targets.
This navigation enhancer provides:
- Unique character highlighting: Each reachable character gets a distinct visual indicator during f/F/t/T motions
- Smart target selection: Prioritizes the most efficient jump targets based on distance and frequency
- Customizable appearance: Configure highlight colors and styles to match your visual preferences
- Performance optimized: Minimal overhead with highlights that appear only when needed
- Dimming support: Optional dimming of non-target characters for better focus
- Multi-line awareness: Intelligent handling of line boundaries and wrapped text
- Integration friendly: Works seamlessly with existing motion plugins and colorschemes
Usage: Simply use f, F, t, or T motions as normal. Eyeliner automatically highlights available targets with unique indicators, making it easy to identify the exact character to jump to.
Help: The plugin works transparently with Vim's built-in motions. Customize highlight colors and behavior through the setup configuration.
For example, when you press f
to find a character, Eyeliner highlights each occurrence of that character on the current line with different colors, allowing you to instantly see which one to target.
plug({
"jinh0/eyeliner.nvim",
priority = 200,
keys = { "f", "F", "t", "T" },
opts = {
highlight_on_key = true,
dim = true
},
init = function()
vim.api.nvim_create_autocmd('ColorScheme', {
pattern = '*',
callback = function()
vim.api.nvim_set_hl(0, 'EyelinerPrimary', { fg = '#aa00aa', bold = true, underline = false })
vim.api.nvim_set_hl(0, 'EyelinerSecondary', { fg = '#a0f050', bold = true, underline = false })
end,
})
end,
})
Enhanced word motions that move by subwords and skip insignificant punctuation, making navigation through code more precise and efficient.
This plugin improves Vim's standard w
, e
, b
, and ge
motions by:
-
Subword navigation: Stops at each meaningful part of camelCase, PascalCase, snake_case, and kebab-case identifiers
-
Smart punctuation handling: Skips over insignificant punctuation marks that don't add semantic meaning
-
Programming-optimized: Perfect for navigating through variable names, function names, and code identifiers
-
Customizable patterns: Allows configuration of what constitutes word boundaries
Usage: The plugin automatically replaces the default
w
,e
,b
, andge
motions. Use them as normal - they will now be smarter about stopping at meaningful word boundaries.Help: Run
:help spider
in Neovim for detailed documentation and configuration options.For example, with
myVariableName.someMethod()
, thew
motion will stop at each meaningful part:my
,Variable
,Name
,some
,Method
rather than jumping over entire compound words.
plug({
"chrisgrieser/nvim-spider",
enabled = true,
lazy = false,
config = function()
vim.keymap.set({ "n", "o", "x" }, "w", "<cmd>lua require('spider').motion('w')<cr>", { desc = "Spider-w" })
vim.keymap.set({ "n", "o", "x" }, "e", "<cmd>lua require('spider').motion('e')<cr>", { desc = "Spider-e" })
vim.keymap.set({ "n", "o", "x" }, "b", "<cmd>lua require('spider').motion('b')<cr>", { desc = "Spider-b" })
vim.keymap.set({ "n", "o", "x" }, "ge", "<cmd>lua require('spider').motion('ge')<cr>", { desc = "Spider-ge" })
end,
})
A Git wrapper so awesome, it should be illegal. Fugitive is the premier Vim plugin for Git, providing a comprehensive interface for Git operations directly within Neovim.
This plugin transforms Neovim into a powerful Git client by:
-
Complete Git workflow integration: Stage, commit, push, pull, and merge without leaving your editor
-
Interactive Git status: Browse and manipulate your repository state with intuitive commands
-
Advanced diff viewing: Compare branches, commits, and working directory changes with sophisticated diff tools
-
Blame integration: See line-by-line authorship and commit history inline with your code
-
Branch management: Create, switch, and merge branches seamlessly
-
Conflict resolution: Resolve merge conflicts with visual three-way diffs
Usage: Access Git operations through
:Git
commands or use the configured keybindings. The plugin provides both command-line Git access and specialized buffers for interactive Git operations.Help: Run
:help fugitive
in Neovim for comprehensive documentation and command reference.For example,
:Git
opens an interactive status window where you can stage files withs
, unstage withu
, and commit withcc
, all while seeing a live diff of your changes.
plug({
'tpope/vim-fugitive',
enabled = true,
lazy = true,
keys = {
{ "<leader>gg",
"<cmd>Git<cr>",
desc = "Git"
},
{ "<leader>gp",
"<cmd>Git push<cr>",
desc = "Git Push"
},
{ "<leader>gP",
"<cmd>Git pull<cr>",
desc = "Git Pull"
},
{ "<leader>gl",
"<cmd>Git log<cr>",
desc = "Git Log"
},
{ "<leader>gd",
"<cmd>Git diff<cr>",
desc = "Git Diff"
},
}
})
Super fast git decorations implemented purely in Lua. Gitsigns provides comprehensive Git integration for Neovim buffers, displaying visual indicators and enabling seamless Git workflow management.
This plugin enhances your Git workflow by:
-
Visual Git indicators: Display added, modified, and deleted lines with customizable signs in the gutter
-
Hunk navigation: Jump between Git hunks with intuitive keybindings for efficient code review
-
Interactive staging: Stage and unstage individual hunks or entire buffers without leaving your editor
-
Inline blame information: View Git blame data directly in your buffer to understand code history
-
Real-time diff preview: Preview changes with floating windows before committing
-
Branch and status integration: See current branch and repository status at a glance
-
Conflict resolution support: Visual aids for resolving merge conflicts
Usage: Git signs appear automatically in the gutter when editing tracked files. Use the configured keybindings to navigate hunks (
]h
/[h
), stage changes (<leader>hs
), and preview modifications (<leader>hp
).Help: Run
:help gitsigns
in Neovim for comprehensive documentation and configuration options.For example, when you modify a tracked file, you'll see
~
signs for changed lines,+
for additions, and-
for deletions, allowing you to quickly identify and manage your changes.
plug({
'lewis6991/gitsigns.nvim',
enabled = true,
opts = {
-- See `:help gitsigns.txt`
on_attach = function(bufnr)
local gs = package.loaded.gitsigns
vim.keymap.set('n', '[h', gs.prev_hunk, { buffer = bufnr, desc = 'Go to Previous Hunk' })
vim.keymap.set('n', ']h', gs.next_hunk, { buffer = bufnr, desc = 'Go to Next Hunk' })
vim.keymap.set('n', '<leader>hs', gs.stage_hunk, { buffer = bufnr, desc = 'Git Stage Hunk' })
vim.keymap.set('n', '<leader>hS', gs.stage_buffer, { buffer = bufnr, desc = 'Git Stage Entire Buffer' })
vim.keymap.set('n', '<leader>hr', gs.reset_hunk, { buffer = bufnr, desc = 'Git Reset Hunk' })
vim.keymap.set('n', '<leader>hR', gs.reset_buffer, { buffer = bufnr, desc = 'Git Reset Entire Buffer' })
vim.keymap.set('v', '<leader>hs', function() gs.stage_hunk { vim.fn.line('.'), vim.fn.line('v') } end,
{ buffer = bufnr, desc = 'Git Stage Selected Hunk' })
vim.keymap.set('v', '<leader>gr', function() gs.reset_hunk { vim.fn.line('.'), vim.fn.line('v') } end,
{ buffer = bufnr, desc = 'Git Reset Selected Hunk' })
vim.keymap.set('n', '<leader>hu', gs.undo_stage_hunk, { buffer = bufnr, desc = 'Git Undo Stage Hunk' })
vim.keymap.set('n', '<leader>ht', gs.toggle_deleted, { buffer = bufnr, desc = 'Git Toggle Deleted' })
vim.keymap.set('n', '<leader>hd', gs.diffthis, { buffer = bufnr, desc = 'Git Diff Hunk' })
vim.keymap.set('n', '<leader>hD', function() gs.diffthis('~') end, { buffer = bufnr, desc = 'Git Diff Hunk' })
vim.keymap.set('n', '<leader>hp', gs.preview_hunk, { buffer = bufnr, desc = 'Git Preview Hunk' })
vim.keymap.set('n', '<leader>hb', gs.blame_line, { buffer = bufnr, desc = 'Git Blame Line' })
vim.keymap.set('n', '<leader>hB', gs.toggle_current_line_blame,
{ buffer = bufnr, desc = 'Git Blame Line Toggle' })
-- Text object
vim.keymap.set({ 'o', 'x' }, 'ih', ':<C-U>Gitsigns select_hunk<CR>', { desc = 'Hunk' })
vim.keymap.set({ 'o', 'x' }, 'ah', ':<C-U>Gitsigns select_hunk<CR>', { desc = 'Hunk' })
end,
},
})
Single tabpage interface for easily cycling through diffs for all modified files for any git rev.
plug({
"sindrets/diffview.nvim",
enabled = true,
lazy = true,
keys = {
{
"<leader>dd",
"<cmd>DiffviewOpen<cr>",
desc = "Open Diff View",
}
},
})
Language Server Protocol
The Language Server Protocol (LSP) defines the protocol used between an editor or IDE and a language server that provides language features like auto complete, go to definition, find all references etc. The goal of the Language Server Index Format (LSIF, pronounced like "else if") is to support rich code navigation in development tools or a Web UI without needing a local copy of the source code.
plug({
-- Collection of functions that will help you setup Neovim's LSP client
'VonHeikemen/lsp-zero.nvim',
branch = 'v3.x',
dependencies = {
-- LSP Support
{ 'neovim/nvim-lspconfig' }, -- Required
{ 'williamboman/mason.nvim' }, -- Optional
{ 'williamboman/mason-lspconfig.nvim' }, -- Optional
-- Format
{ 'onsails/lspkind.nvim' }, -- shows icons on completion menu
{ 'kosayoda/nvim-lightbulb' },
{
'weilbith/nvim-code-action-menu',
cmd = 'CodeActionMenu',
},
-- Autocompletion
{ 'hrsh7th/nvim-cmp' },
{ 'hrsh7th/cmp-nvim-lsp' },
{
'L3MON4D3/LuaSnip',
dependencies = { "rafamadriz/friendly-snippets" },
},
{ 'nvimtools/none-ls.nvim', dependencies = { 'nvim-lua/plenary.nvim' } },
{ "jay-babu/mason-null-ls.nvim" },
{ 'saadparwaiz1/cmp_luasnip' },
{ 'hrsh7th/cmp-nvim-lua' },
{ 'hrsh7th/cmp-buffer' },
{ 'hrsh7th/cmp-cmdline' },
{ 'hrsh7th/cmp-path' },
{ 'hrsh7th/cmp-emoji' },
{ 'hrsh7th/cmp-calc' },
},
config = function()
local lsp_zero = require('lsp-zero')
lsp_zero.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp_zero.default_keymaps({ buffer = bufnr })
local opts = function(desc)
return { buffer = bufnr, remap = false, desc = desc }
end
vim.keymap.set({ 'n', 'x' }, '<leader>lf', function()
vim.lsp.buf.format({ async = false, timeout_ms = 10000 })
end, opts('Lsp format buffer'))
vim.keymap.set("n", "[d", function() vim.diagnostic.goto_next() end, opts("Go To Next Diagnostic"))
vim.keymap.set("n", "]d", function() vim.diagnostic.goto_prev() end, opts("Go To Previous Diagnostic"))
vim.keymap.set("n", "gd", function() Snacks.picker.lsp_definitions() end, opts("Go To Definition"))
vim.keymap.set("n", "<leader>la", function() vim.lsp.buf.code_action() end, opts("Code Action"))
vim.keymap.set("n", "<leader>lh", function() vim.lsp.buf.hover() end, opts("Hover"))
vim.keymap.set("n", "<leader>lH", function() vim.lsp.buf.signature_help() end, opts("Signiture Help"))
vim.keymap.set("n", "<leader>ls", function() Snacks.picker.lsp_workspace_symbols() end, opts("Workspace Symbol"))
vim.keymap.set("n", "<leader>lr", function() Snacks.picker.lsp_references() end, opts("References"))
vim.keymap.set("n", "<leader>li", function() vim.lsp.buf.implementation() end, opts("Implementation"))
vim.keymap.set("n", "<leader>lR", function() vim.lsp.buf.rename() end, opts("Rename"))
vim.keymap.set("n", "<leader>lI", '<cmd>LspInfo<CR>', opts("LspInfo"))
end)
require('mason').setup({})
require('mason-lspconfig').setup({
ensure_installed = {
'lua_ls',
'bashls',
'pyright', -- python
'html',
'clangd',
"marksman", -- markdown
},
handlers = {
lsp_zero.default_setup,
lua_ls = function()
local lua_opts = lsp_zero.nvim_lua_ls()
require('lspconfig').lua_ls.setup(lua_opts)
end,
marksman = function()
require('lspconfig').marksman.setup({})
end,
}
})
-- Open Mason UI
vim.keymap.set("n", "<leader>;m", "<cmd>Mason<cr>", { desc = "Mason Plugin Manager" })
local null_ls = require("null-ls")
local o = vim.o
null_ls.setup({
sources = {
null_ls.builtins.formatting.stylua.with({ extra_args = { '--indent_type=spaces', '--indent_width=' .. o.tabstop } }),
null_ls.builtins.diagnostics.eslint,
null_ls.builtins.diagnostics.trail_space,
null_ls.builtins.formatting.black, -- python formatting
null_ls.builtins.completion.spell,
null_ls.builtins.diagnostics.codespell,
null_ls.builtins.diagnostics.write_good,
null_ls.builtins.formatting.prettierd,
null_ls.builtins.diagnostics.markdownlint, -- markdown
},
})
require("mason-null-ls").setup({
ensure_installed = {
"stylua",
"ruff", -- python linter
"mypy", -- python type checker
"black", -- python formatter
"eslint",
"trail_space",
"spell",
"codespell",
"write_good",
"prettierd",
"markdownlint", -- markdown linter
}
})
local cmp = require('cmp')
local cmp_action = require('lsp-zero').cmp_action()
-- load snippets
require('luasnip.loaders.from_lua').lazy_load({ paths = './snippets/' })
require('luasnip.loaders.from_vscode').lazy_load()
local types = require("luasnip.util.types")
require('luasnip').config.set_config({
-- This one is cool cause if you have dynamic snippets, it updates as you type!
updateevents = "TextChanged,TextChangedI",
enable_autosnippets = true,
ext_opts = {
[types.choiceNode] = {
active = {
virt_text = { { " ⬅️c ", "NonTest" } },
},
},
[types.insertNode] = {
active = {
virt_text = { { " ⬅️t", "NonTest" } },
},
},
},
})
-- snippet keymap
vim.keymap.set("i", "<c-o>", require "luasnip.extras.select_choice")
vim.keymap.set("n", "<leader>csc", require "luasnip.extras.select_choice")
vim.keymap.set("i", "<c-d>", "<Plug>luasnip-next-choice")
vim.keymap.set("s", "<c-d>", "<Plug>luasnip-next-choice")
vim.keymap.set("i", "<c-u>", "<Plug>luasnip-prev-choice")
vim.keymap.set("s", "<c-u>", "<Plug>luasnip-prev-choice")
cmp.setup({
sources = {
{ name = 'nvim_lsp' }, -- completion for neovim
{ name = 'nvim_lua' }, -- completion for neovim lua api
{ name = 'luasnip' }, -- show snippets
{ name = 'buffer' }, -- show elements from your buffer
{ name = 'path' }, -- show file paths
{ name = 'calc' }, -- completion for math calculation
{ name = 'emoji' }, -- show emoji's
},
snippet = {
expand = function(args)
require('luasnip').lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
['<CR>'] = cmp.mapping.confirm({ select = false }),
-- scroll up and down the documentation window
['<C-u>'] = cmp.mapping.scroll_docs(-4),
['<C-d>'] = cmp.mapping.scroll_docs(4),
['<C-l>'] = cmp_action.luasnip_jump_forward(),
['<C-h>'] = cmp_action.luasnip_jump_backward(),
}),
formatting = {
fields = { 'abbr', 'kind', 'menu' },
format = require('lspkind').cmp_format({
mode = 'symbol_text', -- show only symbol annotations
maxwidth = 50, -- prevent the popup from showing more than provided characters
ellipsis_char = '...', -- when popup menu exceed maxwidth, the truncated part would show ellipsis_char instead
})
}
})
-- `/` cmdline setup.
cmp.setup.cmdline('/', {
mapping = cmp.mapping.preset.cmdline(),
sources = {
{ name = 'buffer' }
}
})
-- `:` cmdline setup.
cmp.setup.cmdline(':', {
mapping = cmp.mapping.preset.cmdline(),
sources = cmp.config.sources({
{ name = 'path' }
}, {
{ name = 'cmdline' }
})
})
require("nvim-lightbulb").setup({
autocmd = { enabled = true },
virtual_text = {
enabled = true,
text = ''
},
})
end,
})
A Debug Adapter Protocol client implementation for Neovim
plug({
'mfussenegger/nvim-dap',
dependencies = {
-- Creates a beautiful debugger UI
'rcarriga/nvim-dap-ui',
-- add virtual text
'theHamsta/nvim-dap-virtual-text',
-- Installs the debug adapters for you
'williamboman/mason.nvim',
'jay-babu/mason-nvim-dap.nvim',
-- Add your own debuggers here
{ 'leoluz/nvim-dap-go', ft = { 'go' } },
{ 'mfussenegger/nvim-dap-python', ft = { 'python' } },
},
config = function()
local dap = require("dap")
local dapui = require("dapui")
local mason_registry = require("mason-registry")
require("mason-nvim-dap").setup {
-- Makes a best effort to setup the various debuggers with
-- reasonable debug configurations
automatic_setup = true,
-- You can provide additional configuration to the handlers,
-- see mason-nvim-dap README for more information
handlers = {},
-- You'll need to check that you have the required things installed
-- online, please don't ask me how to install them :)
ensure_installed = {
-- Update this to ensure that you have the debuggers for the langs you want
'delve',
'debugpy',
},
}
-- Basic debugging keymaps, feel free to change to your liking!
vim.keymap.set('n', '<F5>', dap.continue, { desc = 'Debug: Start/Continue' })
vim.keymap.set('n', '<F1>', dap.step_into, { desc = 'Debug: Step Into' })
vim.keymap.set('n', '<F2>', dap.step_over, { desc = 'Debug: Step Over' })
vim.keymap.set('n', '<F3>', dap.step_out, { desc = 'Debug: Step Out' })
vim.keymap.set('n', '<F4>', dap.step_back, { desc = 'Debug: Step Back' })
vim.keymap.set('n', '<leader>db', dap.toggle_breakpoint, { desc = 'Debug: Toggle Breakpoint' })
vim.keymap.set('n', '<leader>dB', dap.set_breakpoint, { desc = 'Debug: Set Breakpoint' })
vim.keymap.set('n', '<leader>dl', dap.run_last, { desc = 'Debug: Run Last' })
vim.keymap.set('n', '<leader>dc', function()
dap.set_breakpoint(vim.fn.input 'Breakpoint condition: ')
end, { desc = 'Debug: Set Breakpoint Condition' })
-- Add virtual text showing contained values
require("nvim-dap-virtual-text").setup({
highlight_new_as_changed = true, -- highlight new variables in the same way as changed variables (if highlight_changed_variables)
only_first_definition = false, -- only show virtual text at first definition (if there are multiple)
})
-- Dap UI setup
-- For more information, see |:help nvim-dap-ui|
dapui.setup {
-- Set icons to characters that are more likely to work in every terminal.
-- Feel free to remove or use ones that you like more! :)
-- Don't feel like these are good choices.
icons = { expanded = '▾', collapsed = '▸', current_frame = '*' },
controls = {
icons = {
pause = '⏸',
play = '▶',
step_into = '⏎',
step_over = '⏭',
step_out = '⏮',
step_back = 'b',
run_last = '▶▶',
terminate = '⏹',
disconnect = '⏏',
},
},
}
-- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception.
vim.keymap.set('n', '<F7>', dapui.toggle, { desc = 'Debug: See last session result.' })
dap.listeners.after.event_initialized['dapui_config'] = dapui.open
dap.listeners.before.event_terminated['dapui_config'] = dapui.close
dap.listeners.before.event_exited['dapui_config'] = dapui.close
-- Setup golang dap
require('dap-go').setup()
-- Setup python dap
local debug_py_path = mason_registry.get_package("debugpy"):get_install_path() .. "/venv/bin/python"
require('dap-python').setup(debug_py_path)
end,
})
Smart and Powerful commenting plugin for neovim
plug({ 'numToStr/Comment.nvim', opts = {} })
Extended increment/decrement plugin
plug({
'monaqa/dial.nvim',
config = function()
local augend = require("dial.augend")
require("dial.config").augends:register_group {
-- default augends used when no group name is specified
default = {
augend.integer.alias.decimal, -- nonnegative decimal number (0, 1, 2, 3, ...)
augend.constant.alias.bool, -- boolean value (true <-> false)
augend.integer.alias.hex, -- nonnegative hex number (0x01, 0x1a1f, etc.)
augend.date.alias["%Y/%m/%d"], -- date (2022/02/19, etc.)
augend.date.alias["%Y-%m-%d"],
augend.date.alias["%m/%d"],
augend.date.alias["%H:%M"],
augend.constant.new {
elements = { "and", "or" },
word = true, -- if false, "sand" is incremented into "sor", "doctor" into "doctand", etc.
cyclic = true, -- "or" is incremented into "and".
preserve_case = true,
},
augend.constant.new {
elements = { "yes", "no" },
word = true, -- if false, "sand" is incremented into "sor", "doctor" into "doctand", etc.
cyclic = true, -- "or" is incremented into "and".
preserve_case = true,
},
augend.constant.new {
elements = { "&&", "||" },
word = false,
cyclic = true,
},
},
}
vim.keymap.set("n", "<C-a>", require("dial.map").inc_normal(), { noremap = true })
vim.keymap.set("n", "<C-x>", require("dial.map").dec_normal(), { noremap = true })
vim.keymap.set("n", "g<C-a>", require("dial.map").inc_gnormal(), { noremap = true })
vim.keymap.set("n", "g<C-x>", require("dial.map").dec_gnormal(), { noremap = true })
vim.keymap.set("v", "<C-a>", require("dial.map").inc_visual(), { noremap = true })
vim.keymap.set("v", "<C-x>", require("dial.map").dec_visual(), { noremap = true })
vim.keymap.set("v", "g<C-a>", require("dial.map").inc_gvisual(), { noremap = true })
vim.keymap.set("v", "g<C-x>", require("dial.map").dec_gvisual(), { noremap = true })
end,
})
Add, delete, change and select surrounding pairs
plug({
"kylechui/nvim-surround",
version = "*", -- Use for stability; omit to use `main` branch for the latest features
event = "VeryLazy",
config = function()
require("nvim-surround").setup({
-- Configuration here, or leave empty to use defaults
})
end,
})
Bundle of more than two dozen new textobjects for Neovim.
plug({
"chrisgrieser/nvim-various-textobjs",
lazy = false,
opts = {
keymaps = {
useDefault = true,
disable = { "gc" },
}
},
})
A plugin for splitting/joining blocks of code like arrays, hashes, statements, objects, dictionaries and more.
plug({
"Wansmer/treesj",
dependencies = "nvim-treesitter/nvim-treesitter",
keys = {
{ "<leader>j", function() require("treesj").toggle() end, desc = " Split-join lines" },
},
})
Case conversion, upper to lower to camel to snake and more.
plug({
"johmsalas/text-case.nvim",
init = function()
local casings = {
{ char = "u", arg = "upper", desc = "UPPER CASE" },
{ char = "l", arg = "lower", desc = "lower case" },
{ char = "t", arg = "title", desc = "Title Case" },
{ char = "c", arg = "camel", desc = "camelCase" },
{ char = "C", arg = "pascal", desc = "CamelCase" },
{ char = "s", arg = "snake", desc = "snake_case" },
{ char = "_", arg = "snake", desc = "snake_case" },
{ char = "d", arg = "dash", desc = "dash-case" },
{ char = "D", arg = "title_dash", desc = "Title-Dash-Case" },
{ char = "-", arg = "dash", desc = "dash-case" },
{ char = "p", arg = "phrase", desc = "Phrase case" },
{ char = "/", arg = "path", desc = "path/case" },
{ char = "S", arg = "constant", desc = "UPPER_SNAKE_CASE" },
{ char = ".", arg = "dot", desc = "dot.case" },
}
for _, case in pairs(casings) do
vim.keymap.set(
"n",
"<leader>c" .. case.char,
("<cmd>lua require('textcase').current_word('to_%s_case')<CR>"):format(case.arg),
{ desc = case.desc }
)
vim.keymap.set(
"v",
"<leader>c" .. case.char,
("<cmd>lua require('textcase').operator('to_%s_case')<CR>"):format(case.arg),
{ desc = case.desc }
)
vim.keymap.set(
"n",
"<leader>C" .. case.char,
("<cmd>lua require('textcase').lsp_rename('to_%s_case')<CR>"):format(case.arg),
{ desc = " " .. case.desc }
)
end
end,
})
Automatic list continuation and formatting.
plug({
"gaoDean/autolist.nvim",
ft = {
"markdown",
"text",
"tex",
"plaintex",
"norg",
},
config = function()
require("autolist").setup()
-- vim.keymap.set("i", "<tab>", "<cmd>AutolistTab<cr>")
-- vim.keymap.set("i", "<s-tab>", "<cmd>AutolistShiftTab<cr>")
-- vim.keymap.set("i", "<c-t>", "<c-t><cmd>AutolistRecalculate<cr>") -- an example of using <c-t> to indent
vim.keymap.set("i", "<CR>", "<CR><cmd>AutolistNewBullet<cr>")
vim.keymap.set("n", "o", "o<cmd>AutolistNewBullet<cr>")
vim.keymap.set("n", "O", "O<cmd>AutolistNewBulletBefore<cr>")
vim.keymap.set("n", "<CR>", "<cmd>AutolistToggleCheckbox<cr><CR>")
vim.keymap.set("n", "<C-r>", "<cmd>AutolistRecalculate<cr>")
-- cycle list types with dot-repeat
vim.keymap.set("n", "<leader>ln", require("autolist").cycle_next_dr, { expr = true })
vim.keymap.set("n", "<leader>lp", require("autolist").cycle_prev_dr, { expr = true })
-- if you don't want dot-repeat
-- vim.keymap.set("n", "<leader>cn", "<cmd>AutolistCycleNext<cr>")
-- vim.keymap.set("n", "<leader>cp", "<cmd>AutolistCycleNext<cr>")
-- functions to recalculate list on edit
vim.keymap.set("n", ">>", ">><cmd>AutolistRecalculate<cr>")
vim.keymap.set("n", "<<", "<<<cmd>AutolistRecalculate<cr>")
vim.keymap.set("n", "dd", "dd<cmd>AutolistRecalculate<cr>")
vim.keymap.set("v", "d", "d<cmd>AutolistRecalculate<cr>")
end,
})
Persist and toggle multiple terminals during an editing session.
plug({
'akinsho/toggleterm.nvim',
version = "*",
opts = {},
config = function()
require("toggleterm").setup()
-- set keymaps to toggle toggleterm
vim.keymap.set('n', '<c-b>', [[<Cmd>exe v:count1 . "ToggleTerm size=12 direction=horizontal"<CR>]],
{ desc = 'Toggle Term Horizontal' })
vim.keymap.set('i', '<c-b>', [[<Cmd>exe v:count1 . "ToggleTerm size=12 direction=horizontal"<CR>]],
{ desc = 'Toggle Term Horizontal' })
vim.keymap.set('t', '<c-b>', [[<Cmd>exe v:count1 . "ToggleTerm size=12 direction=horizontal"<CR>]],
{ desc = 'Toggle Term Horizontal' })
vim.keymap.set('n', '<c-t>', [[<Cmd>exe v:count1 . "ToggleTerm size=80 direction=vertical"<CR>]],
{ desc = 'Toggle Term Vertical' })
vim.keymap.set('i', '<c-t>', [[<Cmd>exe v:count1 . "ToggleTerm size=80 direction=vertical"<CR>]],
{ desc = 'Toggle Term Vertical' })
vim.keymap.set('t', '<c-t>', [[<Cmd>exe v:count1 . "ToggleTerm size=80 direction=vertical"<CR>]],
{ desc = 'Toggle Term Vertical' })
vim.keymap.set('n', '<c-f>', [[<Cmd>exe v:count1 . "ToggleTerm size=80 direction=float"<CR>]],
{ desc = 'Toggle Term Vertical' })
vim.keymap.set('i', '<c-f>', [[<Cmd>exe v:count1 . "ToggleTerm size=80 direction=float"<CR>]],
{ desc = 'Toggle Term Vertical' })
vim.keymap.set('t', '<c-f>', [[<Cmd>exe v:count1 . "ToggleTerm size=80 direction=float"<CR>]],
{ desc = 'Toggle Term Vertical' })
local terminal = require("toggleterm.terminal").Terminal
-- Set up task warrior Vit tui app toggle
local vit = terminal:new({
cmd = "vit",
count = 1000,
direction = "horizontal",
hidden = true,
close_on_exit = true,
auto_scroll = false,
start_in_insert = true,
})
vim.keymap.set({"n", "i", "t", "v"}, "<cm-v>", function () vit:toggle() end, {noremap = true, silent = true, desc = "Toggle Vit"})
-- Set up powershell toggle term
local powershell = terminal:new({
cmd = "powershell.exe",
count = 2,
direction = "horizontal",
hidden = false,
close_on_exit = false,
auto_scroll = true,
start_in_insert = true,
})
vim.keymap.set({"n", "i", "t", "v"}, "<cm-p>", function () powershell:toggle() end, {noremap = true, silent = true, desc = "Toggle Powershell"})
end,
})
Open files from terminal buffers without creating a nested session.
plug({
"willothy/flatten.nvim",
branch = "1.0-dev",
opts = function()
---@type Terminal?
local saved_terminal
return {
window = {
open = "alternate",
},
callbacks = {
should_block = function(argv)
-- Note that argv contains all the parts of the CLI command, including
-- Neovim's path, commands, options and files.
-- See: :help v:argv
-- In this case, we would block if we find the `-b` flag
-- This allows you to use `nvim -b file1` instead of
-- `nvim --cmd 'let g:flatten_wait=1' file1`
return vim.tbl_contains(argv, "-b")
-- Alternatively, we can block if we find the diff-mode option
-- return vim.tbl_contains(argv, "-d")
end,
pre_open = function()
local term = require("toggleterm.terminal")
local termid = term.get_focused_id()
saved_terminal = term.get(termid)
end,
post_open = function(bufnr, winnr, ft, is_blocking)
if is_blocking and saved_terminal then
-- Hide the terminal while it's blocking
saved_terminal:close()
else
-- If it's a normal file, just switch to its window
vim.api.nvim_set_current_win(winnr)
end
-- If the file is a git commit, create one-shot autocmd to delete its buffer on write
-- If you just want the toggleable terminal integration, ignore this bit
if ft == "gitcommit" or ft == "gitrebase" then
vim.api.nvim_create_autocmd("BufWritePost", {
buffer = bufnr,
once = true,
callback = vim.schedule_wrap(function()
vim.api.nvim_buf_delete(bufnr, {})
end),
})
end
end,
block_end = function()
-- After blocking ends (for a git commit, etc), reopen the terminal
vim.schedule(function()
if saved_terminal then
saved_terminal:open()
saved_terminal = nil
end
end)
end,
},
}
end,
})
Table creator & formatter allowing one to create neat tables as you type.
plug({ "https://github.com/dhruvasagar/vim-table-mode" })
To highlight and search for todo comments like TODO, HACK, BUG in your code base.
plug({
"folke/todo-comments.nvim",
enabled = true,
cmd = { "TodoTrouble", "TodoTelescope" },
event = { "BufReadPost", "BufNewFile" },
config = true,
-- stylua: ignore
keys = {
{ "]t", function() require("todo-comments").jump_next() end, desc = "Next todo comment" },
{ "[t", function() require("todo-comments").jump_prev() end, desc = "Previous todo comment" },
{ "<leader>xt", "<cmd>TodoTrouble<cr>", desc = "Todo (Trouble)" },
{ "<leader>xT", "<cmd>TodoTrouble keywords=TODO,FIX,FIXME<cr>", desc = "Todo/Fix/Fixme (Trouble)" },
{ "<leader>st", "<cmd>TodoTelescope<cr>", desc = "Todo" },
{ "<leader>sT", "<cmd>TodoTelescope keywords=TODO,FIX,FIXME<cr>", desc = "Todo/Fix/Fixme" },
},
})
A better user experience for interacting with and manipulating Vim marks.
plug({
'chentoast/marks.nvim',
enabled = true,
config = function()
require 'marks'.setup {
default_mappings = true,
signs = true,
mappings = {}
}
end,
})
Generate table of contents for markdown files.
plug({
'richardbizik/nvim-toc',
ft = { 'markdown' },
config = function()
require('nvim-toc').setup({})
end,
})
Preview markdown code directly in your neovim terminal.
You must install Glow
.
GitHub
plug({
"ellisonleao/glow.nvim",
config = true,
cmd = "Glow",
})
Preview Markdown in your modern browser with synchronised scrolling and flexible configuration.
plug({
"iamcco/markdown-preview.nvim",
cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" },
ft = { "markdown" },
build = function() vim.fn["mkdp#util#install"]() end,
})
Add treesitter highlights to markdown code blocks.
plug({
'yaocccc/nvim-hl-mdcodeblock.lua',
enabled = false,
dependencies = {'nvim-treesitter/nvim-treesitter'},
config = function()
require('hl-mdcodeblock').setup({
-- option
})
end
})
A pretty list for showing diagnostics, references, telescope results, quickfix and location lists to help you solve all the trouble your code is causing.
plug({
"folke/trouble.nvim",
enabled = true,
lazy = true,
dependencies = { "nvim-tree/nvim-web-devicons" },
keys = {
{ "<leader>xx", function() require("trouble").open() end, desc = "Trouble" },
{ "<leader>xw", function() require("trouble").open("workspace_diagnostics") end, desc = "Workspace Diagnostics" },
{ "<leader>xd", function() require("trouble").open("document_diagnostics") end, desc = "Document Diagnostics" },
{ "<leader>xq", function() require("trouble").open("quickfix") end, desc = "Quickfix" },
{ "<leader>xl", function() require("trouble").open("loclist") end, desc = "Local List" },
{ "gR", function() require("trouble").open("lsp_references") end, desc = "Lsp References" },
},
})
A lua plugin that displays a popup with possible key bindings of the command you started typing.
plug({
'folke/which-key.nvim',
enabled = true,
config = function()
local wk = require('which-key')
wk.register({
['<leader>'] = {
["<Tab>"] = { name = '+Tab' },
[";"] = { name = '+Command' },
b = { name = '+Buffer' },
c = { name = '+Case' },
C = { name = '+Case' },
d = { name = '+Debug' },
f = { name = '+Find' },
g = { name = '+Git' },
h = { name = '+Hunk' },
l = { name = '+Lsp' },
s = { name = '+Search' },
t = { name = '+Table' },
T = { name = '+Text' },
w = { name = '+Window' },
x = { name = '+Diagnostics' },
},
})
end,
})
Nvim-hlslens helps you better glance at matched information, seamlessly jump between matched instances. When searching, search count is shown next to the cursor as virtual text.
plug({
"kevinhwang91/nvim-hlslens",
enabled = true,
opts = {},
})
Improve yank and put functionalities for Neovim.
plug({
"gbprod/yanky.nvim",
dependencies = {
{
"kkharji/sqlite.lua",
enabled = not jit.os:find("Windows")
},
},
config = function()
require("yanky").setup({
ring = {
history_length = 100,
sync_with_numbered_registers = true,
cancel_event = "update",
},
system_clipboard = {
sync_with_ring = true,
},
highlight = {
on_put = true,
on_yank = true,
timer = 500,
},
preserve_cursor_position = {
enabled = true,
},
})
end,
keys = {
{
"<leader>p",
function()
local yanky = require("yanky")
local history = yanky.history()
Snacks.picker.pick({
items = history,
format = function(item) return item.regcontents end,
preview = false,
}, function(item)
yanky.put(item)
end)
end,
desc = "Open Yank History"
},
{
"y",
"<Plug>(YankyYank)",
mode = { "n", "x" },
desc =
"Yank text"
},
{
"p",
"<Plug>(YankyPutAfter)",
mode = { "n", "x" },
desc =
"Put yanked text after cursor"
},
{
"P",
"<Plug>(YankyPutBefore)",
mode = { "n", "x" },
desc =
"Put yanked text before cursor"
},
{
"gp",
"<Plug>(YankyGPutAfter)",
mode = { "n", "x" },
desc =
"Put yanked text after selection"
},
{
"gP",
"<Plug>(YankyGPutBefore)",
mode = { "n", "x" },
desc =
"Put yanked text before selection"
},
{
"[y",
"<Plug>(YankyCycleForward)",
desc =
"Cycle forward through yank history"
},
{
"]y",
"<Plug>(YankyCycleBackward)",
desc =
"Cycle backward through yank history"
},
{
"]p",
"<Plug>(YankyPutIndentAfterLinewise)",
desc =
"Put indented after cursor (linewise)"
},
{
"[p",
"<Plug>(YankyPutIndentBeforeLinewise)",
desc =
"Put indented before cursor (linewise)"
},
{
"]P",
"<Plug>(YankyPutIndentAfterLinewise)",
desc =
"Put indented after cursor (linewise)"
},
{
"[P",
"<Plug>(YankyPutIndentBeforeLinewise)",
desc =
"Put indented before cursor (linewise)"
},
{
">p",
"<Plug>(YankyPutIndentAfterShiftRight)",
desc =
"Put and indent right"
},
{
"<p",
"<Plug>(YankyPutIndentAfterShiftLeft)",
desc =
"Put and indent left"
},
{
">P",
"<Plug>(YankyPutIndentBeforeShiftRight)",
desc =
"Put before and indent right"
},
{
"<P",
"<Plug>(YankyPutIndentBeforeShiftLeft)",
desc =
"Put before and indent left"
},
{
"=p",
"<Plug>(YankyPutAfterFilter)",
desc =
"Put after applying a filter"
},
{
"=P",
"<Plug>(YankyPutBeforeFilter)",
desc =
"Put before applying a filter"
},
},
})
@end
Session management (read, write, delete)
plug({
'echasnovski/mini.sessions',
version = false,
config = function()
require('mini.sessions').setup({
})
vim.api.nvim_create_user_command(
'SessionWrite',
function(opts)
if (opts['args']) then
MiniSessions.write(opts.args)
end
end,
{ nargs = 1 }
)
end,
})
The goal of nvim-treesitter is both to provide a simple and easy way to use the interface for tree-sitter in Neovim and to provide some basic functionality such as highlighting based on it.
plug({
-- Highlight, edit, and navigate code
'nvim-treesitter/nvim-treesitter',
priority = 5000,
dependencies = {
'nvim-treesitter/nvim-treesitter-textobjects',
{ "JoosepAlviste/nvim-ts-context-commentstring", lazy = true }
},
build = ':TSUpdate',
main = 'nvim-treesitter.configs',
opts = {
-- Add languages to be installed here that you want installed for treesitter
ensure_installed = {
'lua',
'vim',
'vimdoc',
'norg',
'regex',
'bash',
'c',
'cpp',
'make',
'markdown',
'markdown_inline',
'comment',
'html',
'php',
'http',
'css',
'javascript',
'typescript',
'go',
'python',
'json',
'toml',
'yaml',
'sql',
'r',
'gitattributes',
'gitignore',
},
-- Autoinstall languages that are not installed. Defaults to false (but you can change for yourself!)
auto_install = true,
highlight = { enable = true },
indent = { enable = true },
incremental_selection = {
enable = true,
keymaps = {
init_selection = '<c-space>',
node_incremental = '<c-space>',
scope_incremental = '<c-s>',
node_decremental = '<M-space>',
},
},
textobjects = {
select = {
enable = true,
lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
keymaps = {
-- You can use the capture groups defined in textobjects.scm
['aa'] = '@parameter.outer',
['ia'] = '@parameter.inner',
['af'] = '@function.outer',
['if'] = '@function.inner',
['ac'] = '@class.outer',
['ic'] = '@class.inner',
},
},
move = {
enable = true,
set_jumps = true, -- whether to set jumps in the jumplist
goto_next_start = {
[']m'] = '@function.outer',
[']]'] = '@class.outer',
},
goto_next_end = {
[']M'] = '@function.outer',
[']['] = '@class.outer',
},
goto_previous_start = {
['[m'] = '@function.outer',
['[['] = '@class.outer',
},
goto_previous_end = {
['[M'] = '@function.outer',
['[]'] = '@class.outer',
},
},
swap = {
enable = true,
swap_next = {
['<leader>a'] = '@parameter.inner',
},
swap_previous = {
['<leader>A'] = '@parameter.inner',
},
},
},
-- nvim-treesitter-endwise
endwise = { enable = true },
}
})
Wisely add "end" in Ruby, Lua, Vimscript, etc.
plug({ -- basically autopair, but for keywords
"RRethy/nvim-treesitter-endwise",
-- event = "InsertEnter",
dependencies = "nvim-treesitter/nvim-treesitter",
})
Shows virtual text of the current context after functions, methods, statements, etc.
plug({ -- virtual text context at the end of a scope
"haringsrob/nvim_context_vt",
event = "VeryLazy",
dependencies = "nvim-treesitter/nvim-treesitter",
opts = {
prefix = "",
highlight = "NonText",
min_rows = 1,
disable_ft = { "markdown" },
min_rows_ft = { python = 10, yaml = 15, css = 15 },
-- set up custom parser to return the whole line for context
custom_parser = function(node, _, opts)
-- If you return `nil`, no virtual text will be displayed.
if node:type() == 'function' then
return nil
end
-- get the context line
local bufnr = vim.api.nvim_get_current_buf()
local start_row, _, _, _ = vim.treesitter.get_node_range(node)
local line = vim.api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1]
-- remove whitespace before context
local context = string.gsub(line, '^%s*', '')
return opts.prefix .. ' ' .. context
end,
},
})
Extend and create a/i textobjects.
plug({ -- extend and create a/i textobjects
"echasnovski/mini.ai",
event = "VeryLazy",
dependencies = { "nvim-treesitter-textobjects" },
opts = function()
local ai = require("mini.ai")
return {
n_lines = 500,
custom_textobjects = {
o = ai.gen_spec.treesitter({
a = { "@block.outer", "@conditional.outer", "@loop.outer" },
i = { "@block.inner", "@conditional.inner", "@loop.inner" },
}, {}),
f = ai.gen_spec.treesitter({ a = "@function.outer", i = "@function.inner" }, {}),
c = ai.gen_spec.treesitter({ a = "@class.outer", i = "@class.inner" }, {}),
},
}
end,
config = function(_, opts)
require("mini.ai").setup(opts)
-- register all text objects with which-key
local i = {
[" "] = "Whitespace",
['"'] = 'Balanced "',
["'"] = "Balanced '",
["`"] = "Balanced `",
["("] = "Balanced (",
[")"] = "Balanced ) including white-space",
[">"] = "Balanced > including white-space",
["<lt>"] = "Balanced <",
["]"] = "Balanced ] including white-space",
["["] = "Balanced [",
["}"] = "Balanced } including white-space",
["{"] = "Balanced {",
["?"] = "User Prompt",
_ = "Underscore",
a = "Argument",
b = "Balanced ), ], }",
c = "Class",
f = "Function",
o = "Block, conditional, loop",
q = "Quote `, \", '",
t = "Tag",
}
local a = vim.deepcopy(i)
for k, v in pairs(a) do
a[k] = v:gsub(" including.*", "")
end
local ic = vim.deepcopy(i)
local ac = vim.deepcopy(a)
for key, name in pairs({ n = "Next", l = "Last" }) do
i[key] = vim.tbl_extend("force", { name = "Inside " .. name .. " textobject" }, ic)
a[key] = vim.tbl_extend("force", { name = "Around " .. name .. " textobject" }, ac)
end
require("which-key").register({
mode = { "o", "x" },
i = i,
a = a,
})
end,
})
Set up the lazy.nvim
plugin manager, use the plugins
table to install and load plugins.
See Lazy Helper Function for the plugin()
function.
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable', -- latest stable release
lazypath,
}
end
vim.opt.rtp:prepend(lazypath)
-- Plugins to be installed
-- Help with plugin setup: https://github.com/folke/lazy.nvim#-structuring-your-plugins
require('lazy').setup(plugins, {})
-- open lazy menu
vim.keymap.set("n", "<leader>;l", "<cmd>Lazy<cr>", { desc = "Lazy Plugin Manager" })
Here I configure my native neovim keybindings, these are any key binds not involved with any plugin.
local function map(mode, lhs, rhs, opts)
local keys = require("lazy.core.handler").handlers.keys
---@cast keys LazyKeysHandler
-- do not create the keymap if a lazy keys handler exists
if not keys.active[keys.parse({ lhs, mode = mode }).id] then
opts = opts or {}
opts.silent = opts.silent ~= false
if opts.remap and not vim.g.vscode then
opts.remap = nil
end
vim.keymap.set(mode, lhs, rhs, opts)
end
end
-- better up/down
map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
-- Move to window using the <ctrl> hjkl keys
map("n", "<C-h>", "<C-w>h", { desc = "Go to left window", remap = true })
map("n", "<C-j>", "<C-w>j", { desc = "Go to lower window", remap = true })
map("n", "<C-k>", "<C-w>k", { desc = "Go to upper window", remap = true })
map("n", "<C-l>", "<C-w>l", { desc = "Go to right window", remap = true })
-- Resize window using <ctrl> arrow keys
map("n", "<C-Up>", "<cmd>resize +2<cr>", { desc = "Increase window height" })
map("n", "<C-Down>", "<cmd>resize -2<cr>", { desc = "Decrease window height" })
map("n", "<C-Left>", "<cmd>vertical resize -2<cr>", { desc = "Decrease window width" })
map("n", "<C-Right>", "<cmd>vertical resize +2<cr>", { desc = "Increase window width" })
-- Move Lines
map("n", "<A-j>", "<cmd>m .+1<cr>==", { desc = "Move down" })
map("n", "<A-k>", "<cmd>m .-2<cr>==", { desc = "Move up" })
map("i", "<A-j>", "<esc><cmd>m .+1<cr>==gi", { desc = "Move down" })
map("i", "<A-k>", "<esc><cmd>m .-2<cr>==gi", { desc = "Move up" })
map("v", "<A-j>", ":m '>+1<cr>gv=gv", { desc = "Move down" })
map("v", "<A-k>", ":m '<-2<cr>gv=gv", { desc = "Move up" })
-- Navigate through buffers
map("n", "<S-h>", "<cmd>bprevious<cr>", { desc = "Prev buffer" })
map("n", "<S-l>", "<cmd>bnext<cr>", { desc = "Next buffer" })
map("n", "[b", "<cmd>bprevious<cr>", { desc = "Prev buffer" })
map("n", "]b", "<cmd>bnext<cr>", { desc = "Next buffer" })
map("n", "<leader>bb", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
map("n", "<leader>`", "<cmd>e #<cr>", { desc = "Switch to Other Buffer" })
-- Clear search with <esc>
map({ "i", "n" }, "<esc>", "<cmd>noh<cr><esc>", { desc = "Escape and clear hlsearch" })
-- Clear search, diff update and redraw
-- taken from runtime/lua/_editor.lua
map(
"n",
"<leader>ur",
"<Cmd>nohlsearch<Bar>diffupdate<Bar>normal! <C-L><CR>",
{ desc = "Redraw / clear hlsearch / diff update" }
)
map({ "n", "x" }, "gw", "*N", { desc = "Search word under cursor" })
-- https://github.com/mhinz/vim-galore#saner-behavior-of-n-and-n
map("n", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" })
map("x", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" })
map("o", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" })
map("n", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" })
map("x", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" })
map("o", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" })
-- Add undo break-points
map("i", ",", ",<c-g>u")
map("i", ".", ".<c-g>u")
map("i", ";", ";<c-g>u")
-- save file
map({ "i", "v", "n", "s" }, "<C-s>", "<cmd>w<cr><esc>", { desc = "Save file" })
--keywordprg
map("n", "<leader>K", "<cmd>norm! K<cr>", { desc = "Keywordprg" })
-- better indenting
map("v", "<", "<gv")
map("v", ">", ">gv")
-- new file
map("n", "<leader>fn", "<cmd>enew<cr>", { desc = "New File" })
map("n", "<leader>xl", "<cmd>lopen<cr>", { desc = "Location List" })
map("n", "<leader>xq", "<cmd>copen<cr>", { desc = "Quickfix List" })
-- quit
map("n", "<leader>qq", "<cmd>qa<cr>", { desc = "Quit all" })
-- highlights under cursor
if vim.fn.has("nvim-0.9.0") == 1 then
map("n", "<leader>ui", vim.show_pos, { desc = "Inspect Pos" })
end
-- Terminal Mappings
map("t", "<esc><esc>", "<c-\\><c-n>", { desc = "Enter Normal Mode" })
map("t", "<c-[><c-[>", "<c-\\><c-n>", { desc = "Enter Normal Mode" })
map("t", "<C-h>", "<cmd>wincmd h<cr>", { desc = "Go to left window" })
map("t", "<C-j>", "<cmd>wincmd j<cr>", { desc = "Go to lower window" })
map("t", "<C-k>", "<cmd>wincmd k<cr>", { desc = "Go to upper window" })
map("t", "<C-l>", "<cmd>wincmd l<cr>", { desc = "Go to right window" })
map("t", "<C-/>", "<cmd>close<cr>", { desc = "Hide Terminal" })
map("t", "<c-_>", "<cmd>close<cr>", { desc = "which_key_ignore" })
-- windows
map("n", "<leader>ww", "<C-W>p", { desc = "Other window", remap = true })
map("n", "<leader>wd", "<C-W>c", { desc = "Delete window", remap = true })
map("n", "<leader>w-", "<C-W>s", { desc = "Split window below", remap = true })
map("n", "<leader>w|", "<C-W>v", { desc = "Split window right", remap = true })
map("n", "<leader>-", "<C-W>s", { desc = "Split window below", remap = true })
map("n", "<leader>|", "<C-W>v", { desc = "Split window right", remap = true })
-- tabs
map("n", "<leader><tab>G", "<cmd>tablast<cr>", { desc = "Last Tab" })
map("n", "<leader><tab>g", "<cmd>tabfirst<cr>", { desc = "First Tab" })
map("n", "<leader><tab><tab>", "<cmd>tabnew<cr>", { desc = "New Tab" })
map("n", "<leader><tab>]", "<cmd>tabnext<cr>", { desc = "Next Tab" })
map("n", "<leader><tab>d", "<cmd>tabclose<cr>", { desc = "Close Tab" })
map("n", "<leader><tab>[", "<cmd>tabprevious<cr>", { desc = "Previous Tab" })
map("n", "<leader><tab>s", "<cmd>tab split<cr>", { desc = "Split Tab" })
-- Convenience
map('n', '\\', ':%s//g<left><left>', { desc = "Search buffer" })
map('v', '\\', ':s//g<Left><Left>', { desc = "Search selection" })
map("n", "<leader>S", "<cmd>set spell!<cr>", { desc = "Toggle spell" })
-- Insert file name
map("i", "<C-f>f", '<C-R>=expand("%:t")<cr>', { desc = "Insert current filename" })
map("i", "<C-f>F", '<C-R>=expand("%:t:r")<cr>', { desc = "Insert current filename without extension" })
map("i", "<C-f>e", '<C-R>=expand("%:e")<cr>', { desc = "Insert extendion of current file" })
map("i", "<C-f>p", '<C-R>=expand("%:p:h")<cr>', { desc = "Insert absolute path of current directory" })
map("i", "<C-f>P", '<C-R>=expand("%:h")<cr>', { desc = "Insert relative path of current directory" })
map("i", "<C-f>d", '<C-R>=expand("%:p:h:t")<cr>', { desc = "Insert parent directory of current file" })
Here I configure any highlights.
local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true })
vim.api.nvim_create_autocmd('TextYankPost', {
callback = function()
vim.highlight.on_yank()
end,
group = highlight_group,
pattern = '*',
})
Here I configure any autocommands.
local function augroup(name)
return vim.api.nvim_create_augroup("shm_" .. name, { clear = true })
end
-- Use internal formatting for bindings like gq.
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
vim.bo[args.buf].formatexpr = nil
end,
})
-- Check if we need to reload the file when it changed
vim.api.nvim_create_autocmd({ "FocusGained", "TermClose", "TermLeave" }, {
group = augroup("checktime"),
command = "checktime",
})
-- Highlight on yank
vim.api.nvim_create_autocmd("TextYankPost", {
group = augroup("highlight_yank"),
callback = function()
vim.highlight.on_yank()
end,
})
-- resize splits if window got resized
vim.api.nvim_create_autocmd({ "VimResized" }, {
group = augroup("resize_splits"),
callback = function()
vim.cmd("tabdo wincmd =")
end,
})
-- go to last loc when opening a buffer
vim.api.nvim_create_autocmd("BufReadPost", {
group = augroup("last_loc"),
callback = function()
local exclude = { "gitcommit" }
local buf = vim.api.nvim_get_current_buf()
if vim.tbl_contains(exclude, vim.bo[buf].filetype) then
return
end
local mark = vim.api.nvim_buf_get_mark(buf, '"')
local lcount = vim.api.nvim_buf_line_count(buf)
if mark[1] > 0 and mark[1] <= lcount then
pcall(vim.api.nvim_win_set_cursor, 0, mark)
end
end,
})
-- close some filetypes with <q>
vim.api.nvim_create_autocmd("FileType", {
group = augroup("close_with_q"),
pattern = {
"PlenaryTestPopup",
"help",
"lspinfo",
"man",
"notify",
"qf",
"spectre_panel",
"startuptime",
"tsplayground",
"neotest-output",
"checkhealth",
"neotest-summary",
"neotest-output-panel",
"fugitive",
},
callback = function(event)
vim.bo[event.buf].buflisted = false
vim.keymap.set("n", "q", "<cmd>close<cr>", { buffer = event.buf, silent = true })
end,
})
-- close some filetypes with <esc>
vim.api.nvim_create_autocmd("FileType", {
group = augroup("close_with_esc"),
pattern = {
"fugitive",
"git",
},
callback = function(event)
vim.bo[event.buf].buflisted = false
vim.keymap.set("n", "<esc>", "<cmd>close<cr>", { buffer = event.buf, silent = true })
end,
})
-- wrap and check for spell in text filetypes
vim.api.nvim_create_autocmd("FileType", {
group = augroup("wrap_spell"),
pattern = { "gitcommit", "markdown" },
callback = function()
vim.opt_local.wrap = true
vim.opt_local.spell = true
end,
})
-- Auto create dir when saving a file, in case some intermediate directory does not exist
vim.api.nvim_create_autocmd({ "BufWritePre" }, {
group = augroup("auto_create_dir"),
callback = function(event)
if event.match:match("^%w%w+://") then
return
end
local file = vim.loop.fs_realpath(event.match) or event.match
vim.fn.mkdir(vim.fn.fnamemodify(file, ":p:h"), "p")
end,
})
-- disable line numbering and start in insert mode for terminal
vim.api.nvim_create_autocmd({ "TermOpen", "TermEnter" }, {
group = augroup("terminal"),
callback = function ()
vim.opt_local.number = false
vim.opt_local.relativenumber = false
vim.cmd("startinsert")
end,
})
-- reload folds for treesitter bug
-- see https://github.com/nvim-treesitter/nvim-treesitter/issues/1337
vim.api.nvim_create_autocmd({ "BufReadPost" }, {
group = augroup("folds"),
callback = function()
vim.cmd([[ norm zx
norm zM ]])
end
})
Here I configure any custom commands.
local command = vim.api.nvim_create_user_command
command("Shell", function (args)
local shell = args.args
if (shell == "powershell") then
shell = "powershell.exe"
elseif (shell == "cmd") then
shell = "cmd.exe"
end
vim.cmd("terminal " .. shell)
end, {
nargs = 1,
complete = function ()
return {
"powershell",
"cmd",
"zsh",
"bash",
"dash",
}
end,
})
Here I configure some commonly used personal information.
local shm = {}
shm.name = {
'Simon H Moore',
'Simon Hugh Moore',
'Simon Moore',
'SH Moore',
}
shm.initials = 'SHM'
shm.email = '[email protected]'
shm.workemail = '[email protected]'
shm.signiture = "Simon H Moore <[email protected]>"
shm.worksigniture = "Simon H Moore <[email protected]>"
Here go any helper utilities and functions.
local util = {}
util.number_ordinal = function(n)
local last_digit = n % 10
if last_digit == 1 and n ~= 11
then
return 'st'
elseif last_digit == 2 and n ~= 12
then
return 'nd'
elseif last_digit == 3 and n ~= 13
then
return 'rd'
else
return 'th'
end
end
util.datef = function(datestr, date)
local date = date or os.date("*t", os.time())
local datestr = string.gsub(datestr, "%%o", M.number_ordinal(date.day))
return os.date(datestr, os.time(date))
end
Here I configure my custom snippets.
These are used to create snippets.
local ls = require("luasnip")
local snippet = ls.add_snippets
local s = ls.snippet
local t = ls.text_node
local f = ls.function_node
local i = ls.insert_node
local c = ls.choice_node
local d = ls.dynamic_node
local sn = ls.snippet_node
local fmt = require("luasnip.extras.fmt").fmt
Here I configure snippet related utilities and functions.
local snip_utils = {}
snip_utils.get_name_choice = function()
local nodes = {}
for _, name in ipairs(shm.name) do
table.insert(nodes, t(name))
end
return c(1, nodes)
end
snip_utils.shebang = {
lua = "!/bin/lua",
sh = "!/bin/sh",
bash = "!/bin/bash",
zsh = "!/bin/zsh",
}
snip_utils.get_date_choice = function (arg)
return c(arg and arg or 1, {
f(function() return utils.datef("%d%o %B %Y") end),
f(function() return utils.datef(os.date "%d%o %b %Y") end),
f(function() return utils.datef(os.date "%a %d%o %b %Y") end),
f(function() return utils.datef(os.date "%A %d%o %b %Y") end),
f(function() return utils.datef(os.date "%a %d%o %B %Y") end),
f(function() return utils.datef(os.date "%A %d%o %B %Y") end),
f(function() return os.date "%d-%m-%Y" end),
f(function() return os.date "%d/%m/%Y" end),
f(function() return os.date "%d-%m-%y" end),
f(function() return os.date "%d/%m/%y" end),
})
end
snip_utils.get_header = function(opts)
opts = opts and opts or {}
local sntable = {
c = t(opts.commentstr and opts.commentstr or "# "),
name = c(1, {
f(function() return vim.fn.expand("%:t") end),
f(function() return vim.fn.expand("%:h:t") .. "/" .. vim.fn.expand("%:t") end),
f(function() return vim.fn.expand("%:t:r") end),
}),
author = c(2, {t(shm.signiture), t(shm.worksigniture)}),
date = M.get_date_choice(3),
desc = i(4, "Description"),
}
local formattable = {
"{c}filename: {name}",
"{c}author: {author}",
"{c}date: {date}",
"{c}desc: {desc}",
}
if opts.shebang then
table.insert(formattable, 1, "{c}{shebang}")
sntable.shebang = t(opts.shebang)
end
return fmt(table.concat(formattable, "\n"), sntable, {dedent = true})
end
local greeting_choice = function(arg)
return c(arg and arg or 1, {
t("Hope you are well."),
t("I hope you are having a nice day."),
t("I hope you are having a good morning."),
t("I hope you are having a nice end to the week."),
t("Nice speaking to you on the phone the other day."),
})
end
local message_end = function(arg)
return c(arg and arg or 1, {
t("Thank you"),
t("Kind Regards"),
})
end
Common snippets for all file types.
snippet("all", {
s({
trig = 'name',
priority = 10000,
desc = 'My name'
},
{ snip_utils.get_name_choice()
}),
s({
trig = 'email',
priority = 10000,
desc = 'My email'
},
{
c(1, {
t("[email protected]"),
t("[email protected]"),
}),
}),
s({
trig = 'workemail',
priority = 10000,
desc = 'Work Email'
},
{
t(shm.workemail)
}),
s({
trig = 'sign',
priority = 10000,
desc = 'My signiture'
},
{
c(1, {
t(shm.signiture),
t(shm.worksigniture),
}),
}),
s({
trig = 'worksign',
priority = 10000,
desc = 'Work Sign'
},
{
t("Simon H Moore <[email protected]>")
}),
s({
trig = 'date',
priority = 10000,
desc = 'Current date'
},
{ snip_utils.get_date_choice()
}),
s({
trig = 'americandate',
priority = 10000,
desc = 'Current american date, month comes first',
},
{
c(1, {
f(function() return os.date "%m/%d/%Y" end),
f(function() return os.date "%m-%d-%Y" end),
f(function() return os.date "%m/%d/%y" end),
f(function() return os.date "%m-%d-%y" end),
})
}),
s({
trig = 'time',
priority = 10000,
desc = 'Current time',
},
{
c(1, {
f(function() return os.date "%H:%M" end),
f(function() return os.date "%I:%M %p" end),
f(function() return os.date "%H:%M:%S" end),
f(function() return os.date "%I:%M:%S %p" end),
})
}),
s({
trig = 'vigogreeting',
desc = 'A greeting for vigo email'
}, fmt([[
Hi {name},
{greeting}
]], {
name = i(1, "Name"),
greeting = greeting_choice(2),
}
)
),
s({
trig = "vigopass",
desc = "Complete builds message"
}, fmt([[
Hi {name},
{greeting}
I am currently setting up your {device} and I need your password to continue. Could you send it to me please?
If you feel uncomfortable sharing your password over email{passmsg}
Could you also send me a list of apps you would like to see installed?
{outmsg},
Simon
]], {
name = i(1, "Name"),
--NOTE: Could separate out the greeting to be reused
greeting = greeting_choice(2),
device = c(3,{
t("new laptop"),
t("laptop"),
t("new desktop"),
t("desktop"),
i(1, "device"),
}),
passmsg = c(4,{
t(", you can call our office, or we can reset your password to a temporary one."),
t(" you can also call our office."),
}),
outmsg = message_end(5),
}
)
),
s({
trig = "vigoPassReset",
desc = "Email client for password reset"
}, fmt([[
Hi {name},
{greeting}
I will reset your password to: {password}
Please confirm you have read and taken note of this password by replying to this email. We will only proceed with the password reset once you have replied.
Important: Once we reset your password, you may be signed out of all sessions you are currently logged in. You can log back in using the new password mentioned above.
{outmsg},
Simon
]], {
name = i(1, "Name"),
--NOTE: Could separate out the greeting to be reused
greeting = greeting_choice(2),
password = i(3, "PASSWORD"),
outmsg = message_end(4),
}
)
),
s({
trig = "vigocomplete",
desc = "Complete builds message"
}, fmt([[
Hi {name},
{greeting}
We have completed setting up {name2} {device} and it is ready for collection, we are open Monday to Friday 9am to 5pm.
Alternatively, I can arrange to have one of our mobile engineers drop the laptop of for you.
{outmsg},
Simon
]], {
name = i(1, "Name"),
--NOTE: Could separate out the greeting to be reused
greeting = greeting_choice(2),
name2 = i(3, "Name"),
device = c(4, {t("laptop"), t("desktop")}),
outmsg = message_end(5),
}
)
),
})
Snippets only for lua file types.
snippet("lua", {
-- auto type require definition
s('req',
fmt([[local {} = require("{}")]], { f(function(import_name)
local parts = vim.split(import_name[1][1], ".", { plain = true })
return parts[#parts] or ""
end, { 1 }), i(1) })
),
-- import luasnip functions
s({
trig = 'luasnip import',
priority = 10000,
desc = 'import luasnip functions',
},
{
d(1, function()
local import_table = {
'local ls = require("luasnip")',
'local s = ls.snippet',
'local t = ls.text_node',
'local i = ls.insert_node',
'local f = ls.function_node',
'local c = ls.choice_node',
'local fmt = require("luasnip.extras.fmt").fmt',
'local d = ls.dynamic_node',
'local sn = ls.snippet_node',
'local isn = ls.indent_snippet_node',
'local r = ls.restore_node',
'local events = require("luasnip.util.events")',
'local ai = require("luasnip.nodes.absolute_indexer")',
'local extras = require("luasnip.extras")',
'local l = extras.lambda',
'local rep = extras.rep',
'local p = extras.partial',
'local m = extras.match',
'local n = extras.nonempty',
'local dl = extras.dynamic_lambda',
'local fmta = require("luasnip.extras.fmt").fmta',
'local conds = require("luasnip.extras.expand_conditions")',
'local postfix = require("luasnip.extras.postfix").postfix',
'local types = require("luasnip.util.types")',
'local parse = require("luasnip.util.parser").parse_snippet',
'local ms = ls.multi_snippet',
'local k = require("luasnip.nodes.key_indexer").new_key',
}
return sn(nil, c(1, {
t({ unpack(import_table, 1, 7) }),
t({ unpack(import_table, 1, 9) }),
t(import_table),
}))
end)
}
),
})
Snippets for git commit file type, used for committing with fugitive.
snippet("gitcommit", {
-- conventional commit snippets
-- see https://www.conventionalcommits.org/en/v1.0.0/#summary
s({trig = "^br", regTrig = true}, t("BREAKING CHANGE: ")),
s({trig = "^fe", regTrig = true}, fmt([[feat({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "new feature")})),
s({trig = "^fi", regTrig = true}, fmt([[fix({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "bug fix")})),
s({trig = "^do", regTrig = true}, fmt([[docs({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "documentation only change")})),
s({trig = "^bu", regTrig = true}, fmt([[build({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "build system or external dependency change")})),
s({trig = "^pe", regTrig = true}, fmt([[perf({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "performance improvement change")})),
s({trig = "^re", regTrig = true}, fmt([[refactor({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "code change that neither fixes a bug or adds a feature")})),
s({trig = "^st", regTrig = true}, fmt([[style({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "change that does not affect the meaning of the code")})),
s({trig = "^pe", regTrig = true}, fmt([[perf({}){}: {}]], { i(1, "scope"), c(3, {t(""),t("!")}), i(2, "adding new or correcting existing test")})),
},{ type = "autosnippets" })
vim.api.nvim_create_autocmd("BufEnter", {
group = augroup("ftplugin"),
pattern = "norg",
callback = function()
o.wrap = true
o.foldlevelstart = 0 -- Enable foldlevel when opening file
o.foldnestmax = 6 -- Set max nested foldlevel
o.foldenable = true
end,
})