dotnvim is the .NET tooling for Neovim that you've always wanted. .NET development in Neovim can be challenging due to the lack of robust tooling, especially compared to the support available for other languages like Rust with rustaceanvim, and of course the ide that shall not be named. This plugin aims to fill that gap, providing a seamless development experience for .NET developers who prefer Neovim. Enjoy!
If you like what dotnvim is doing here, want to see more, or just not ready to add it to your config: please leave a star, it means the world.
If you would like to try out the plugin in a containerized way, go ahead and check out dotnvim-config to try out the plugin. And while you are there, give it a star as well ;)
- Features
- Sample Config
- Task System
- Required Executables
- Neovim Plugin Dependencies
- Neovim Plugin Optional Dependencies
- Credits
return {
{
'adamkali/dotnvim',
ft = { 'cs', 'vb', 'csproj', 'sln', 'slnx', 'props', 'csx', 'targets' },
keys = {
{ '<leader>ds', function() require('dotnvim').bootstrap() end, desc = 'Bootstrap Class' },
{ '<leader>db', function() require('dotnvim').build(true) end, desc = 'Build Last Project' },
{ '<leader>dw', function() require('dotnvim').watch(true) end, desc = 'Watch Last Project' },
{ '<F10>', function() require('dotnvim').restart_watch() end, desc = 'Restart Watch Job'},
{ '<F34>', function() require('dotnvim').shutdown_watch() end, desc = 'Shutdown Watch Job'},
{ '<leader>dna', function() require('dotnvim').nuget_auth() end, desc = 'Authenticate Nuget Sources' },
{ '<leader>dt', ':DotnvimTaskRun<CR>', desc = 'Run Task' }
},
opts = {
-- Builder configuration
builders = {
build_output_callback = nil,
https_launch_setting_always = true,
},
-- UI configuration
ui = {
no_pretty_uis = false,
},
-- DAP (debugging) configuration
dap = {
adapter = {
type = 'executable',
command = "netcoredbg",
args = { '--interpreter=vscode' },
},
configurations = {}, -- Optional: add custom DAP configurations here
},
-- NuGet authentication
nuget = {
sources = {
"your-nuget-source-name"
},
authenticators = {
{
cmd = "aws",
args = { "codeartifact", "login", "--tool", "dotnet", "--domain", "YOUR_LIB", "--domain-owner", "AWSID", "--repository", "YOUR_REPO" }
},
-- Add more authenticators as needed
},
},
-- Task system configuration
tasks = {
enabled = true,
execution_mode = "dependency_aware", -- "sequential" or "dependency_aware"
dap_integration = {
enabled = true,
pre_debug_tasks = nil, -- Auto-discover or specify: {"pre-debug", "build"}
block_on_failure = true,
timeout_seconds = 300,
}
},
debug = {
enabled = true, -- Enable comprehensive debug logging
log_file_path = nil, -- Optional: custom log file path (defaults to ~/.local/share/nvim/dotnvim.log)
}
}
},
}If you prefer the traditional approach or need more complex setup logic:
return {
{
'adamkali/dotnvim',
ft = { 'cs', 'vb', 'csproj', 'sln', 'slnx', 'props', 'csx', 'targets' },
keys = {
{ '<leader>ds', function() require('dotnvim').bootstrap() end, desc = 'Bootstrap Class' },
{ '<leader>db', function() require('dotnvim').build(true) end, desc = 'Build Last Project' },
{ '<leader>dw', function() require('dotnvim').watch(true) end, desc = 'Watch Last Project' },
{ '<F10>', function() require('dotnvim').restart_watch() end, desc = 'Restart Watch Job'},
{ '<F34>', function() require('dotnvim').shutdown_watch() end, desc = 'Shutdown Watch Job'},
{ '<leader>dna', function() require('dotnvim').nuget_auth() end, desc = 'Authenticate Nuget Sources' },
{ '<leader>dt', ':DotnvimTaskRun<CR>', desc = 'Run Task' }
},
config = function(_, opts)
require('dotnvim').setup(opts)
end,
opts = {
-- Same configuration options as above
nuget = {
sources = { "your-nuget-source-name" },
authenticators = {
{
cmd = "aws",
args = { "codeartifact", "login", "--tool", "dotnet", "--domain", "YOUR_LIB", "--domain-owner", "AWSID", "--repository", "YOUR_REPO" }
},
},
},
tasks = {
enabled = true,
execution_mode = "dependency_aware",
dap_integration = {
enabled = true,
pre_debug_tasks = {"pre-debug", "build"},
block_on_failure = true,
timeout_seconds = 300,
}
}
}
},
}All configuration options can be passed through the opts table in Lazy.nvim. Here's a complete reference:
opts = {
-- Builder configuration
builders = {
build_output_callback = function(output) end, -- Optional callback for build output
https_launch_setting_always = true, -- Always use HTTPS in launch settings
},
-- UI configuration
ui = {
no_pretty_uis = false, -- Disable fancy UI components (falls back to vim.ui.select)
},
-- DAP (Debug Adapter Protocol) configuration
dap = {
adapter = {
type = 'executable', -- DAP adapter type
command = "netcoredbg", -- Path to netcoredbg
args = { '--interpreter=vscode' }, -- Arguments for the debugger
},
configurations = {}, -- Optional: Custom DAP configurations (alternative to .vscode/launch.json)
},
-- NuGet package source authentication
nuget = {
sources = { -- List of NuGet source names to authenticate
"your-source-name",
},
authenticators = { -- Authentication commands for each source
{
cmd = "aws", -- Command to run
args = { -- Arguments for the command
"codeartifact", "login", "--tool", "dotnet",
"--domain", "YOUR_DOMAIN",
"--domain-owner", "YOUR_AWS_ACCOUNT_ID",
"--repository", "YOUR_REPO"
}
},
{
cmd = "dotnet",
args = { "nuget", "setapikey", "your-api-key", "--source", "your-source" }
}
},
},
-- Task system configuration
tasks = {
enabled = true, -- Enable/disable task system
execution_mode = "dependency_aware", -- "sequential" or "dependency_aware"
-- DAP integration for pre-debug tasks
dap_integration = {
enabled = true, -- Enable automatic pre-debug task execution
pre_debug_tasks = nil, -- Specific tasks to run (nil = auto-discover)
block_on_failure = true, -- Block debugging if tasks fail
timeout_seconds = 300, -- Task execution timeout
}
},
-- Debug logging configuration
debug = {
enabled = false, -- Enable comprehensive debug logging
log_file_path = nil, -- Custom log file path (nil uses default: ~/.local/share/nvim/dotnvim.log)
}
}dotnvim includes comprehensive debug logging to help troubleshoot task execution issues:
- Log file location:
~/.local/share/nvim/dotnvim.log(by default) - Automatic rotation: Log files are rotated when they exceed 10MB
- Debug mode: When enabled, logs detailed information about:
- DAP hook execution and state changes
- Task discovery and parsing
- Task execution flow and callbacks
- State management and cleanup
Use the :DotnvimLog command to open the log file, or view it directly:
tail -f ~/.local/share/nvim/dotnvim.logdotnvim fully supports Lazy.nvim's automatic setup mechanism. When you provide opts, Lazy.nvim automatically calls require('dotnvim').setup(opts) for you. This means the basic configuration example above will work without any additional config function.
You only need a custom config function if you need:
- Complex setup logic
- Conditional configuration
- Integration with other plugins that must be loaded first
- Custom initialization that goes beyond the standard
setup(opts)pattern
dotnvim includes a powerful task system that allows you to define and execute custom build workflows with dependency resolution and DAP integration. Tasks can be configured in multiple formats and automatically run before debugging sessions.
Tasks are configured in project files located in either .nvim/ or .vscode/ directory:
.nvim/tasks.json,.nvim/tasks.yaml,.nvim/tasks.toml.vscode/tasks.json,.vscode/tasks.yaml,.vscode/tasks.toml
The plugin searches .nvim/ first, then falls back to .vscode/ for compatibility.
{
"version": "0.1.0",
"tasks": [
{
"name": "restore",
"command": "dotnet restore ${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {"DOTNET_NOLOGO": "true"}
},
{
"name": "build",
"previous": ["restore"],
"command": "dotnet build ${workspaceFolder} --no-restore",
"cwd": "${workspaceFolder}",
"env": {
"DOTNET_NOLOGO": "true",
"PROJECT_ROOT": "${workspaceFolder}"
}
},
{
"name": "test",
"previous": ["build"],
"command": "dotnet test ${workspaceFolder} --no-build",
"cwd": "${workspaceFolder}",
"env": {
"ASPNETCORE_ENVIRONMENT": "Test",
"TEST_OUTPUT": "${workspaceFolder}/TestResults"
}
},
{
"name": "pre-debug",
"previous": ["build"],
"command": "echo 'Ready for debugging ${workspaceFolderBasename}'",
"cwd": "${workspaceFolder}"
}
]
}version: "0.1.0"
tasks:
- name: restore
command: dotnet restore ${workspaceFolder}
cwd: ${workspaceFolder}
env:
DOTNET_NOLOGO: "true"
- name: build
previous: [restore]
command: dotnet build ${workspaceFolder} --no-restore
cwd: ${workspaceFolder}
env:
DOTNET_NOLOGO: "true"
PROJECT_ROOT: ${workspaceFolder}
- name: pre-debug
previous: [build]
command: echo 'Ready for debugging ${workspaceFolderBasename}'
cwd: ${workspaceFolder}version = "0.1.0"
[[tasks]]
name = "restore"
command = "dotnet restore ${workspaceFolder}"
cwd = "${workspaceFolder}"
[tasks.env]
DOTNET_NOLOGO = "true"
[[tasks]]
name = "build"
previous = ["restore"]
command = "dotnet build ${workspaceFolder} --no-restore"
cwd = "${workspaceFolder}"
[tasks.env]
DOTNET_NOLOGO = "true"
PROJECT_ROOT = "${workspaceFolder}"
[[tasks]]
name = "pre-debug"
previous = ["build"]
command = "echo 'Ready for debugging ${workspaceFolderBasename}'"
cwd = "${workspaceFolder}"- name: Unique task identifier
- command: Shell command to execute (supports variable substitution)
- cwd: Working directory (supports variable substitution)
- env: Environment variables (optional, supports variable substitution)
- previous: Array of task dependencies (optional)
dotnvim supports VSCode-style variable substitution in task configurations. Variables are enclosed in ${variableName} format and are resolved at runtime.
${workspaceFolder}- Root directory of the workspace/project${workspaceFolderBasename}- Name of the workspace folder${file}- Currently open file (absolute path)${relativeFile}- Currently open file relative to workspace${relativeFileDirname}- Directory of currently open file relative to workspace${fileBasename}- Basename of currently open file${fileBasenameNoExtension}- Basename without extension${fileDirname}- Directory of currently open file${fileExtname}- Extension of currently open file${cwd}- Current working directory${pathSeparator}- Path separator for the current OS
{
"version": "0.1.0",
"tasks": [
{
"name": "build-project",
"command": "dotnet build ${workspaceFolder}/MyProject.csproj",
"cwd": "${workspaceFolder}",
"env": {
"PROJECT_ROOT": "${workspaceFolder}",
"OUTPUT_PATH": "${workspaceFolder}/bin/Debug"
}
},
{
"name": "test-current",
"command": "dotnet test ${fileDirname}/${fileBasenameNoExtension}.Tests.csproj",
"cwd": "${fileDirname}",
"env": {
"TEST_FILE": "${file}"
}
}
]
}dotnvim provides several commands for task management:
:DotnvimTaskRun [task_name]- Run a specific task or select from available tasks:DotnvimTaskStatus- Show task system status and configuration:DotnvimTaskCancel- Cancel running tasks:DotnvimTaskInit [format]- Initialize example task configuration (json, yaml, toml)
- dependency_aware (default): Resolves and executes task dependencies automatically
- sequential: Executes tasks in the order specified
The task system integrates seamlessly with nvim-dap for pre-debug task execution:
- Automatically discovers and runs
pre-debug,debug-prep,prepare-debug, orbefore-debugtasks - Configurable timeout and failure handling
- Synchronous execution to ensure tasks complete before debugging starts
Configure DAP integration through the opts.tasks.dap_integration section:
-- In your Lazy.nvim configuration
opts = {
tasks = {
dap_integration = {
enabled = true, -- Enable DAP integration
pre_debug_tasks = {"pre-debug"}, -- Specific tasks to run (or nil for auto-discovery)
block_on_failure = true, -- Block debugging if tasks fail
timeout_seconds = 300, -- Task timeout in seconds
}
}
}For programmatic access:
local dotnvim = require('dotnvim')
-- Run a single task
dotnvim.run_task("build")
-- Run multiple tasks
dotnvim.run_tasks({"restore", "build"})
-- Check task status
local status = dotnvim.task_status()
-- Get available tasks
local tasks = dotnvim.get_available_tasks()
-- Cancel running tasks
dotnvim.cancel_tasks()
-- Create example configuration
dotnvim.create_task_config("json") -- or "yaml", "toml"- Create task configuration:
:DotnvimTaskInit json - Edit the generated
.nvim/tasks.jsonfile - Run tasks:
:DotnvimTaskRunor<leader>dt - Debug with automatic pre-debug tasks via DAP integration
Interactive code scaffolding for .NET projects with support for:
C# Model Generation
- Bootstraps a Model with default getter and setter properties
- Supports custom namespaces and inheritance
ASP.NET API Controllers
- Basic MVC controller scaffolding
- Full CRUD controller generation with:
- GET (single and all)
- POST (create)
- PUT (update)
- DELETE operations
Project compilation with intelligent project selection:
- Builds projects from solution root (where .sln exists)
last = trueuses previously selected project- Interactive project selection via Telescope or vim.ui.select
Hot reload development server:
- Starts
dotnet watchprocess on selected project - Persistent process management with restart capabilities
- Output logging to dedicated buffer
Multi-source NuGet authentication:
- Configurable authentication commands per source
- Support for AWS CodeArtifact, Azure DevOps, and private feeds
- Batch authentication for multiple sources
dotnvim provides a comprehensive task execution system with dependency resolution and DAP integration:
require('dotnvim').run_task(task_name)- Execute specific taskrequire('dotnvim').run_tasks(task_names)- Execute multiple tasksrequire('dotnvim').get_available_tasks()- List configured tasksrequire('dotnvim').task_status()- Get execution statusrequire('dotnvim').cancel_tasks()- Stop running tasksrequire('dotnvim').create_task_config(format)- Initialize task configuration
- Multiple formats: JSON, YAML, TOML
- Variable substitution: VSCode-style
${workspaceFolder}variables - Dependency resolution: Automatic task ordering with
previousarray - Environment variables: Per-task environment configuration
- Custom working directories: Task-specific
cwdsettings
- Pre-debug task execution: Automatic task running before debug sessions
- Configurable timeout: Task execution limits with failure handling
- Block on failure: Optional debug session blocking for failed tasks
- Auto-discovery: Automatic detection of
pre-debug,debug-preptasks
Enhanced debugging experience with nvim-dap integration:
.vscode/launch.jsoncompatibility- Plugin-based DAP configurations
- Automatic adapter setup for netcoredbg
-- Automatic execution before debugging
{
tasks = {
dap_integration = {
enabled = true,
pre_debug_tasks = {"build", "pre-debug"}, -- or nil for auto-discovery
block_on_failure = true,
timeout_seconds = 300
}
}
}{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/MyApp/bin/Debug/net8.0/MyApp.dll",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "https://localhost:5001;http://localhost:5000"
}
}
]
}require('dotnvim').restart_watch()- Restart development serverrequire('dotnvim').shutdown_watch()- Clean process termination- Background PID tracking and cleanup
require('dotnvim').query_last_ran_csproj()- Get last used project- Persistent project selection across sessions
- Smart project root detection
dotnvim provides several Neovim commands for easy access:
:DotnvimTaskRun [task_name]- Run a task (with autocomplete):DotnvimTaskStatus- Show task system status in dedicated buffer:DotnvimTaskCancel- Cancel currently running tasks:DotnvimTaskInit [format]- Create example task configuration (json/yaml/toml):DotnvimNugetAuth- Authenticate NuGet sources:DotnvimLog- Open the plugin log file for troubleshooting
require('dotnvim').show_config()- Display current configurationrequire('dotnvim').show_config_section(section)- Show specific config section- Centralized configuration management with validation
- State persistence across Neovim sessions
- Comprehensive debug logging to
~/.local/share/nvim/dotnvim.log - Configurable log levels and file rotation
- Real-time task execution monitoring
- DAP hook state tracking
dotnet- .NET CLI (required for all functionality)fd- File finder utility (required for project discovery)
netcoredbg- .NET Core debugger (required for debugging support)
Note
NuGet authentication uses the dotnet CLI internally, so no separate nuget executable is required.
plenarynvim-treesitter
nvim-dap
telescopenui.nvim
Thank you! please see CONTRIBUTING and check out the Issues
Here's a complete configuration example showing all available options with their default values and detailed explanations:
{
'adamkali/dotnvim',
ft = { 'cs', 'vb', 'csproj', 'sln', 'slnx', 'props', 'csx', 'targets' },
keys = {
-- Core functionality
{ '<leader>ds', function() require('dotnvim').bootstrap() end, desc = 'Bootstrap Class' },
{ '<leader>db', function() require('dotnvim').build(true) end, desc = 'Build Last Project' },
{ '<leader>dw', function() require('dotnvim').watch(true) end, desc = 'Watch Last Project' },
-- Process management
{ '<F10>', function() require('dotnvim').restart_watch() end, desc = 'Restart Watch Job'},
{ '<F34>', function() require('dotnvim').shutdown_watch() end, desc = 'Shutdown Watch Job'},
-- NuGet authentication
{ '<leader>dna', function() require('dotnvim').nuget_auth() end, desc = 'Authenticate Nuget Sources' },
-- Task system
{ '<leader>dt', ':DotnvimTaskRun<CR>', desc = 'Run Task' },
{ '<leader>dts', ':DotnvimTaskStatus<CR>', desc = 'Task Status' },
{ '<leader>dtc', ':DotnvimTaskCancel<CR>', desc = 'Cancel Tasks' },
{ '<leader>dti', ':DotnvimTaskInit<CR>', desc = 'Initialize Tasks' },
-- Configuration and debugging
{ '<leader>dc', function() require('dotnvim').show_config() end, desc = 'Show Configuration' },
{ '<leader>dl', ':DotnvimLog<CR>', desc = 'Open Log File' },
{ '<leader>dh', ':checkhealth dotnvim<CR>', desc = 'Health Check' },
},
opts = {
-- ============================================================================
-- BUILDER CONFIGURATION
-- ============================================================================
builders = {
-- Optional callback function that receives build output
-- Useful for custom parsing or notifications
build_output_callback = function(output)
-- Example: Parse and show warnings/errors in quickfix
-- vim.fn.setqflist({}, 'r', { title = 'Build Output', lines = output })
end,
-- Always use HTTPS in ASP.NET launch settings generation
-- When false, uses both HTTP and HTTPS endpoints
https_launch_setting_always = true,
},
-- ============================================================================
-- UI CONFIGURATION
-- ============================================================================
ui = {
-- Disable fancy UI components (Telescope, NUI)
-- Falls back to vim.ui.select for all selections
no_pretty_uis = false,
},
-- ============================================================================
-- DEBUG ADAPTER PROTOCOL (DAP) CONFIGURATION
-- ============================================================================
dap = {
-- netcoredbg adapter configuration
adapter = {
type = 'executable',
command = "netcoredbg", -- Must be in PATH or provide full path
args = { '--interpreter=vscode' },
},
-- Optional: Custom DAP configurations
-- Alternative to .vscode/launch.json
configurations = {
{
type = "coreclr",
name = "Launch Console App",
request = "launch",
program = function()
-- Dynamic program selection
return vim.fn.input('Path to dll: ', vim.fn.getcwd() .. '/bin/Debug/', 'file')
end,
cwd = "${workspaceFolder}",
stopAtEntry = false,
env = {
ASPNETCORE_ENVIRONMENT = "Development"
}
},
{
type = "coreclr",
name = "Launch Web App",
request = "launch",
program = "${workspaceFolder}/MyWebApp/bin/Debug/net8.0/MyWebApp.dll",
cwd = "${workspaceFolder}/MyWebApp",
stopAtEntry = false,
env = {
ASPNETCORE_ENVIRONMENT = "Development",
ASPNETCORE_URLS = "https://localhost:5001;http://localhost:5000"
},
-- Optional: browser launch
serverReadyAction = {
action = "openExternally",
pattern = "\\bNow listening on:\\s+(https?://\\S+)"
}
}
}
},
-- ============================================================================
-- NUGET AUTHENTICATION
-- ============================================================================
nuget = {
-- List of NuGet source names to authenticate
-- These should match the names in your nuget.config
sources = {
"MyCompanyFeed",
"AzureDevOps",
"AWSCodeArtifact"
},
-- Authentication commands for each source
-- Commands are executed in order for each source
authenticators = {
-- AWS CodeArtifact example
{
cmd = "aws",
args = {
"codeartifact", "login",
"--tool", "dotnet",
"--domain", "my-domain",
"--domain-owner", "123456789012",
"--repository", "my-repo",
"--region", "us-east-1"
}
},
-- Azure DevOps example
{
cmd = "az",
args = {
"artifacts", "universal", "download",
"--organization", "https://dev.azure.com/myorg/",
"--feed", "my-feed",
"--name", "auth-token",
"--version", "*",
"--path", "/tmp/"
}
},
-- Simple API key example
{
cmd = "dotnet",
args = {
"nuget", "setapikey",
"${NUGET_API_KEY}", -- Environment variable
"--source", "MyPrivateFeed"
}
},
-- Custom authentication script
{
cmd = "/path/to/custom-auth-script.sh",
args = { "MyCompanyFeed" }
}
},
},
-- ============================================================================
-- TASK SYSTEM CONFIGURATION
-- ============================================================================
tasks = {
-- Enable/disable the entire task system
enabled = true,
-- Task execution mode:
-- "sequential": Execute tasks in specified order
-- "dependency_aware": Resolve and execute dependencies automatically
execution_mode = "dependency_aware",
-- DAP integration for pre-debug tasks
dap_integration = {
-- Enable automatic pre-debug task execution
enabled = true,
-- Specific tasks to run before debugging
-- nil = auto-discover tasks named: pre-debug, debug-prep, prepare-debug, before-debug
-- array = specific task names to execute
pre_debug_tasks = nil, -- or {"restore", "build", "pre-debug"}
-- Block debugging if pre-debug tasks fail
block_on_failure = true,
-- Maximum time to wait for tasks to complete (seconds)
timeout_seconds = 300,
}
},
-- ============================================================================
-- DEBUG LOGGING
-- ============================================================================
debug = {
-- Enable comprehensive debug logging
-- Logs detailed information about task execution, DAP hooks, etc.
enabled = false, -- Set to true for troubleshooting
-- Custom log file path
-- nil = use default: ~/.local/share/nvim/dotnvim.log
log_file_path = nil, -- or "/path/to/custom/dotnvim.log"
},
-- ============================================================================
-- HEALTH CHECK CONFIGURATION
-- ============================================================================
health = {
-- Custom executable paths (if not in PATH)
executables = {
dotnet = "dotnet", -- or "/usr/local/share/dotnet/dotnet"
fd = "fd", -- or "/usr/local/bin/fd"
netcoredbg = "netcoredbg", -- or "/path/to/netcoredbg"
}
}
}
}dotnvim respects several environment variables for configuration:
# NuGet authentication
export NUGET_API_KEY="your-api-key-here"
export AZURE_DEVOPS_EXT_PAT="your-pat-token"
# AWS CodeArtifact
export AWS_PROFILE="your-aws-profile"
export AWS_REGION="us-east-1"
# Custom executable paths
export DOTNET_ROOT="/usr/local/share/dotnet"
export NETCOREDBG_PATH="/path/to/netcoredbg"
# Task system
export DOTNVIM_TASK_TIMEOUT="600" # seconds
export DOTNVIM_LOG_LEVEL="debug" # error, warn, info, debug
# Development
export DOTNVIM_DEBUG="1" # Enable debug modeIf you want the simplest possible setup:
{
'adamkali/dotnvim',
ft = { 'cs', 'csproj', 'sln' },
keys = {
{ '<leader>db', function() require('dotnvim').build() end },
{ '<leader>dw', function() require('dotnvim').watch() end },
},
opts = {} -- Use all defaults
}This minimal setup provides core build and watch functionality with sensible defaults.
- MoaidHathot: Inspiration for this project.
- nvim-dap-go For debugging bootstraps.
- tjdvrees: telescope 🔭
- folke: Code inspiration for... well everything!
- nui.nvim: For excellent UI components.
- Simba: My cat, for moral support. 🐱
