My personal Neovim setup, written entirely in Lua. It's built around C++ and game dev (Godot), but handles a bunch of other languages too. I also use it for note-taking with Obsidian.
67 plugins managed by lazy.nvim, all lazy-loaded. ~50 colorscheme variants with a persistent theme switcher that remembers your pick across sessions.
- Full LSP, completion, and debugging for C/C++, Rust, Python, GDScript, and more
- Custom C++ tools I wrote: include auto-sorting, definition extraction from headers, skeleton/boilerplate generator
- Godot engine integration with GDScript/GDShader LSP and DAP
- Obsidian vault integration with multi-workspace support, daily notes, and a custom template engine
- Typst auto-compile on save with PDF preview
- A theme system that detects light/dark mode from your system and persists your choice
- Animated cursor, Discord presence, and all the usual quality-of-life stuff
~/.config/nvim/
├── init.lua # Entry point, LSP log cleanup + module loading
├── lazy-lock.json # Plugin version lockfile
├── lua/ibnojabal/
│ ├── lazy.lua # lazy.nvim bootstrap
│ ├── core/
│ │ ├── init.lua # Core module loader
│ │ ├── options.lua # Editor options (tabs, line numbers, clipboard, etc.)
│ │ ├── keymaps.lua # Global keybindings
│ │ ├── colorschemes.lua # Colorscheme registry with light/dark variants
│ │ ├── theme.lua # Persistent theme engine with system appearance detection
│ │ ├── obsidian.lua # Obsidian workspace detection, templates, config
│ │ ├── godot.lua # Godot integration (auto-RPC, project detection)
│ │ └── koda.lua # Koda colorscheme overrides
│ ├── plugins/
│ │ ├── lsp/ # LSP config (mason, lspconfig, formatting)
│ │ ├── dap.lua # Debug adapter configs
│ │ ├── dap-ui.lua # DAP UI layout and keymaps
│ │ ├── telescope.lua # Fuzzy finder + fzf-native
│ │ ├── treesitter.lua # Treesitter parsers
│ │ ├── nvim-cmp.lua # Autocompletion
│ │ ├── bufferline.lua # Buffer tabs with theme sync
│ │ ├── lualine.lua # Statusline
│ │ ├── alpha.lua # Dashboard
│ │ ├── nvim-tree.lua # File explorer
│ │ ├── obsidian.lua # Obsidian plugin spec + keymaps
│ │ ├── smear_cursor.lua # Animated cursor trail
│ │ ├── presence.lua # Discord Rich Presence (cord.nvim)
│ │ ├── rndr.lua # 3D model preview in Telescope
│ │ ├── render-markdown.lua # In-buffer markdown rendering
│ │ ├── trouble.lua # Diagnostics list
│ │ └── ... # autopairs, surround, mini-move, ufo, etc.
│ └── tools/
│ ├── init.lua # Tools loader and autocommands
│ ├── include_formatter.lua # C/C++ include auto-sorter
│ ├── include_rename.lua # Include path renaming
│ ├── cpp_extract.lua # Extract definitions from headers to source
│ └── skeleton.lua # Boilerplate generator
There's a custom theme system that saves your choice to ~/.local/state/nvim/theme.txt and restores it on startup. It also detects your system's light/dark preference via gsettings. The default is koda.
Use :Theme to pick interactively, :Theme <name> to set directly (tab-completion works), or :ThemeNext / :ThemePrev to cycle through everything.
| Theme | Variants |
|---|---|
| Koda (custom) | koda, koda-dark, koda-light, koda-glade, koda-moss |
| Tokyo Night | tokyonight, night, storm, day, moon |
| Catppuccin | catppuccin, latte, frappe, macchiato, mocha |
| Kanagawa | kanagawa, wave, dragon, lotus |
| Rose Pine | rose-pine, main, moon, dawn |
| Nightfox | nightfox, dayfox, dawnfox, duskfox, nordfox, terafox, carbonfox |
| Material | material, darker, deep-ocean, lighter, oceanic, palenight |
| GitHub | dark, light, dimmed, dark-high-contrast, light-high-contrast, and colorblind variants |
| Dracula | dracula, dracula-soft |
| Gruvbox | gruvbox |
| Everforest | everforest |
| Sonokai | sonokai |
| Edge | edge |
| Nord | nord |
| OneDark | onedark |
| Oxocarbon | oxocarbon |
| Base16 | base16-default-dark, base16-default-light |
| Plain | plain, plain-cterm |
Leader is Space.
| Binding | Mode | What it does |
|---|---|---|
<C-h/j/k/l> |
Normal / Terminal | Move between splits |
<leader>sv |
Normal | Split vertical |
<leader>sh |
Normal | Split horizontal |
<leader>se |
Normal | Equalize splits |
<leader>sx |
Normal | Close split |
<C-Arrow> |
Normal | Resize splits |
| Binding | Mode | What it does |
|---|---|---|
<Tab> / <S-Tab> |
Normal | Next / previous buffer |
<leader>x |
Normal | Close buffer |
<leader>h / <leader>l |
Normal | Move buffer left / right |
<leader>n |
Normal | New tab |
| Binding | Mode | What it does |
|---|---|---|
<leader>ff |
Normal | Find files |
<leader>fw |
Normal | Live grep |
<leader>fc |
Normal | Grep word under cursor |
<leader>fb |
Normal | Browse buffers |
| Binding | Mode | What it does |
|---|---|---|
gd |
Normal | Go to definition |
gR |
Normal | References |
gi |
Normal | Implementations |
gt |
Normal | Type definition |
K |
Normal | Hover docs |
<leader>ca |
Normal | Code actions |
<leader>rn |
Normal | Rename |
<leader>d |
Normal | Buffer diagnostics |
<leader>D |
Normal | Line diagnostics |
<leader>ci / <leader>co |
Normal | Incoming / outgoing calls |
| Binding | Mode | What it does |
|---|---|---|
<leader>dc |
Normal | Continue |
<leader>db |
Normal | Toggle breakpoint |
<leader>ds |
Normal | Step over |
<leader>di |
Normal | Step into |
<leader>do |
Normal | Step out |
<leader>dr |
Normal | Restart |
<leader>dt |
Normal | Terminate |
| Binding | Mode | What it does |
|---|---|---|
<leader>ob |
Normal | Backlinks |
<leader>od |
Normal | Daily note |
<leader>ol |
Normal | Links |
<leader>oo |
Normal | Open in Obsidian |
<leader>oq |
Normal | Quick switch |
<leader>os |
Normal | Search notes |
<leader>ot |
Normal | Insert template |
<leader>oc |
Normal | Toggle checkbox |
| Binding | Mode | What it does |
|---|---|---|
<leader>ts |
Normal | Select theme |
<leader>tn / <leader>tp |
Normal | Next / previous theme |
<leader>t |
Normal | Open vertical terminal |
<C-u> / <C-d> |
Normal | Half-page scroll, centered |
J / K |
Visual | Move selected lines |
| Language | Server | Notes |
|---|---|---|
| C/C++ | clangd |
Background indexing, clang-tidy, C++20, auto-format on save, Qt diagnostic filtering |
| Python | pyright |
|
| Lua | lua_ls |
Configured for Neovim API |
| Rust | rust_analyzer |
Type hints enabled, parameter/chaining hints off |
| TypeScript/JS/TSX | ts_ls |
|
| HTML | html |
|
| CSS | cssls |
|
| Tailwind CSS | tailwindcss |
|
| Svelte | svelte |
|
| GraphQL | graphql |
|
| Emmet | emmet_ls |
|
| Typst | tinymist |
Formatting via conform.nvim |
| Haskell | hls |
Only loaded if the binary exists |
| GDScript | gdscript |
Native Godot LSP |
| GDShader | gdshader_lsp |
Conditional |
json, javascript, typescript, tsx, yaml, html, css, prisma, markdown, markdown_inline, svelte, graphql, bash, lua, vim, vimdoc, dockerfile, gitignore, query, c, cpp, haskell, gdscript, gdshader, godot_resource
DAP is set up for C, C++, and Rust using lldb-dap / codelldb, plus Godot's built-in DAP for GDScript. The debugger will look for binaries in ./, build/, bin/, and out/ automatically. Three launch modes: run, run with args, and attach to process.
These are things I built because I got tired of doing them by hand.
Include formatter (include_formatter.lua): Runs on save for any C/C++ file. Sorts your #includes into three groups: third-party headers, standard library headers (knows about everything up to C++23), and local headers (with self-header first). Removes duplicates. Put // noincludeformat in your file to skip it.
Definition extractor (cpp_extract.lua): Two commands:
:CppExtractDefinitionspulls ALL inline member function bodies out of a class in a header and moves them to the matching.cppfile with proper namespace wrapping:CppExtractFunctionDefinitiondoes the same for just the function under your cursor
It handles nested classes, member initializer lists, strips keywords like static and virtual, and won't duplicate definitions that already exist in the source file. Uses Treesitter for the parsing.
Skeleton generator (skeleton.lua): :Skel drops in boilerplate. For headers you get #pragma once, a namespace derived from the project directory, and a class stub. For source files it figures out the right #include path (reads compile_commands.json if available). For main.cpp it gives you the usual hello world.
Multi-workspace Obsidian integration using obsidian.nvim. Set your vault paths with $OBSIDIAN_VAULT_PERSONAL and $OBSIDIAN_VAULT_WORK (defaults to ~/vaults/personal and ~/vaults/work). It also auto-detects vaults by looking for .obsidian directories.
Daily notes go in notes/dailies/ with a YYYY-MM-DD format, tagged as daily and journal. Note IDs are YYYYMMDD-HHMM-slugified-title. There's a custom patch that adds proper Moment.js-style date format translation for templates ({{date:YYYY-MM-DD}} and friends).
When you open a markdown file in a vault, it sets up wrap, linebreak, conceallevel, and textwidth automatically.
If you're working in a Godot project, the config detects .gd, .gdshader, .tres, .tscn files and registers them with the right filetypes. It starts a Neovim RPC server at <project-root>/godothost so Godot can talk to it as an external editor. This kicks in on VimEnter, DirChanged, and when you open relevant files.
You'll need:
- Neovim 0.9+ (0.10+ is better)
- Git
- A Nerd Font
- ripgrep (for Telescope grep)
- Node.js (for some Mason-installed LSP servers)
- gcc or clang (for Treesitter parser compilation)
- cargo (for cord.nvim)
# back up what you have
mv ~/.config/nvim ~/.config/nvim.bak
# clone
git clone https://github.com/ibnojabal/nvim.git ~/.config/nvim
# open nvim, everything installs automatically
nvimlazy.nvim bootstraps itself and pulls all plugins on first launch. Mason will install the configured LSP servers.
Optional stuff: Zathura for Typst preview, Godot 4 for GDScript dev, Obsidian for vault integration, Discord for presence.
Some things that might trip you up if you're not expecting them:
- Hard tabs,
tabstop=8,shiftwidth=8(enforced on every filetype) - Relative line numbers with the current line showing the absolute number
- System clipboard is always connected
- Case-insensitive search unless you type an uppercase letter
- Folding uses
#pragma region/#pragma endregion - Splits open right and below
| Command | What it does |
|---|---|
:Theme [name] |
Set or pick a colorscheme (persisted) |
:ThemeNext / :ThemePrev |
Cycle themes |
:Skel |
Insert boilerplate for the current file type |
:CppExtractDefinitions |
Move all inline definitions to the .cpp |
:CppExtractFunctionDefinition |
Move the function under cursor to the .cpp |
:TypstPreview |
Open the compiled PDF in Zathura |
:ObsidianToday |
Open or create today's daily note |
:ObsidianNew |
Create a new note |
Do whatever you want with it.