Skip to content

Instantly share code, notes, and snippets.

@Calvindd2f
Last active August 18, 2025 22:13
Show Gist options
  • Select an option

  • Save Calvindd2f/7c99a169026f0dbb751d6aa6859da7b2 to your computer and use it in GitHub Desktop.

Select an option

Save Calvindd2f/7c99a169026f0dbb751d6aa6859da7b2 to your computer and use it in GitHub Desktop.
Calvins Neovim Configuration
-- lua/config/autocmds.lua
-- Autocommands for various functionality
-- Create augroup for our commands
local augroup = vim.api.nvim_create_augroup("UserConfig", { clear = true })
-- Highlight text on yank
vim.api.nvim_create_autocmd("TextYankPost", {
group = augroup,
callback = function()
vim.highlight.on_yank({ timeout = 200 })
end,
desc = "Highlight text on yank",
})
-- Remove trailing whitespace on save
vim.api.nvim_create_autocmd("BufWritePre", {
group = augroup,
pattern = "*",
callback = function()
local save_cursor = vim.fn.getpos(".")
vim.cmd([[%s/\s\+$//e]])
vim.fn.setpos(".", save_cursor)
end,
desc = "Remove trailing whitespace on save",
})
-- Automatically create directories when saving a file
vim.api.nvim_create_autocmd("BufWritePre", {
group = augroup,
callback = function()
local dir = vim.fn.expand("<afile>:p:h")
if vim.fn.isdirectory(dir) == 0 then
vim.fn.mkdir(dir, "p")
end
end,
desc = "Create directory if it doesn't exist when saving",
})
-- Set PowerShell-specific options
vim.api.nvim_create_autocmd("FileType", {
group = augroup,
pattern = "ps1",
callback = function()
-- Set comment string for PowerShell files
vim.bo.commentstring = "# %s"
-- Set indentation for PowerShell files
vim.bo.tabstop = 4
vim.bo.shiftwidth = 4
vim.bo.expandtab = true
-- Enable word wrap for PowerShell documentation
vim.wo.wrap = true
vim.wo.linebreak = true
-- Set PowerShell-specific formatting options
vim.bo.formatoptions = vim.bo.formatoptions
+ "r" -- Continue comments after hitting <Enter>
+ "o" -- Continue comments after hitting 'o' or 'O'
+ "q" -- Allow formatting of comments with 'gq'
+ "l" -- Don't break long lines in insert mode
- "t" -- Don't auto-wrap text
-- Enable spell checking for comments and strings
vim.wo.spell = true
vim.bo.spelllang = "en_us"
end,
desc = "Set PowerShell-specific options",
})
-- Auto-reload files when changed externally
vim.api.nvim_create_autocmd({ "FocusGained", "BufEnter", "CursorHold", "CursorHoldI" }, {
group = augroup,
pattern = "*",
callback = function()
if vim.fn.mode() ~= "c" then
vim.cmd("checktime")
end
end,
desc = "Auto-reload files when changed externally",
})
-- Restore cursor position when reopening files
vim.api.nvim_create_autocmd("BufReadPost", {
group = augroup,
callback = function()
local mark = vim.api.nvim_buf_get_mark(0, '"')
local lcount = vim.api.nvim_buf_line_count(0)
if mark[1] > 0 and mark[1] <= lcount then
pcall(vim.api.nvim_win_set_cursor, 0, mark)
end
end,
desc = "Restore cursor position when reopening files",
})
-- init.lua
-- Main configuration file for Neovim
-- Set up leader key early before lazy.nvim loads
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Basic editor settings for a better experience
vim.opt.number = true -- Show line numbers
vim.opt.relativenumber = true -- Show relative line numbers
vim.opt.mouse = 'a' -- Enable mouse support
vim.opt.ignorecase = true -- Ignore case in search
vim.opt.smartcase = true -- But don't ignore it when using upper case
vim.opt.hlsearch = false -- Don't highlight all search results
vim.opt.wrap = false -- Don't wrap lines
vim.opt.breakindent = true -- Maintain indent when wrapping indented lines
vim.opt.tabstop = 4 -- Number of spaces tabs count for
vim.opt.shiftwidth = 4 -- Size of an indent
vim.opt.expandtab = true -- Use spaces instead of tabs
vim.opt.undofile = true -- Save undo history
vim.opt.updatetime = 250 -- Decrease update time
vim.opt.signcolumn = 'yes' -- Always show sign column
vim.opt.termguicolors = true -- Enable 24-bit RGB colors
-- Bootstrap lazy.nvim package manager
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",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
-- Configure and load plugins
require("lazy").setup({
-- Import plugin specifications from separate files
{ import = "plugins" },
}, {
install = {
-- Try to load a colorscheme when installing plugins
colorscheme = { "tokyonight" },
},
checker = {
enabled = true, -- Check for plugin updates
notify = false, -- Don't notify about updates
},
change_detection = {
notify = false, -- Don't notify about config changes
},
})
-- Load keymaps and autocommands
require("config.keymaps")
require("config.autocmds")
-- lua/config/keymaps.lua
-- Custom key mappings for enhanced productivity
-- Utility function for easier mapping
local function map(mode, lhs, rhs, opts)
local options = { noremap = true, silent = true }
if opts then
options = vim.tbl_extend("force", options, opts)
end
vim.keymap.set(mode, lhs, rhs, options)
end
-- Better window navigation
map("n", "<C-h>", "<C-w>h", { desc = "Move to left window" })
map("n", "<C-j>", "<C-w>j", { desc = "Move to lower window" })
map("n", "<C-k>", "<C-w>k", { desc = "Move to upper window" })
map("n", "<C-l>", "<C-w>l", { desc = "Move to right window" })
-- Resize windows with arrows
map("n", "<C-Up>", ":resize +2<CR>")
map("n", "<C-Down>", ":resize -2<CR>")
map("n", "<C-Left>", ":vertical resize -2<CR>")
map("n", "<C-Right>", ":vertical resize +2<CR>")
-- Better indenting
map("v", "<", "<gv")
map("v", ">", ">gv")
-- Move selected lines up and down
map("v", "J", ":m '>+1<CR>gv=gv")
map("v", "K", ":m '<-2<CR>gv=gv")
-- LSP related mappings
-- These will only take effect when an LSP is attached to the buffer
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('UserLspConfig', {}),
callback = function(ev)
local opts = { buffer = ev.buf }
-- Go to definition
map('n', 'gd', vim.lsp.buf.definition, opts)
-- Hover documentation
map('n', 'K', vim.lsp.buf.hover, opts)
-- Workspace symbol search
map('n', '<leader>ws', vim.lsp.buf.workspace_symbol, opts)
-- Code actions
map('n', '<leader>ca', vim.lsp.buf.code_action, opts)
-- Rename symbol
map('n', '<leader>rn', vim.lsp.buf.rename, opts)
-- References
map('n', 'gr', vim.lsp.buf.references, opts)
-- Signature help
map('n', '<C-k>', vim.lsp.buf.signature_help, opts)
end,
})
-- plugins/lsp.lua
-- Configuration for Language Server Protocol support
return {
{
'neovim/nvim-lspconfig',
dependencies = {
-- Package manager for LSP servers, DAP servers, linters, and formatters
"williamboman/mason.nvim",
-- Bridges mason.nvim with the lspconfig plugin
"williamboman/mason-lspconfig.nvim",
-- Autocompletion plugins
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"hrsh7th/cmp-cmdline",
"hrsh7th/nvim-cmp",
-- Snippet engine required for LSP completions
"L3MON4D3/LuaSnip",
"saadparwaiz1/cmp_luasnip",
-- LSP status updates
"j-hui/fidget.nvim",
-- Uncomment for additional snippets
-- "rafamadriz/friendly-snippets",
},
config = function()
-- Set up completion
local cmp = require('cmp')
local cmp_lsp = require('cmp_nvim_lsp')
-- Merge LSP capabilities with completion capabilities
local capabilities = vim.tbl_deep_extend(
'force',
{},
vim.lsp.protocol.make_client_capabilities(),
cmp_lsp.default_capabilities()
)
-- Configure LSP status updates
require('fidget').setup({})
-- Set up mason for managing LSP servers
require('mason').setup()
-- Configure mason-lspconfig
require('mason-lspconfig').setup({
-- Let mason-lspconfig install LSP servers automatically
ensure_installed = {
"lua_ls", -- Lua language server
},
handlers = {
-- Default handler for LSP servers
function(server_name)
require('lspconfig')[server_name].setup {
capabilities = capabilities,
}
end,
-- Custom handler for PowerShell LSP
powershell_es = function()
local lspconfig = require('lspconfig')
lspconfig.powershell_es.setup{
-- Path to PowerShell Editor Services
bundle_path = vim.fn.stdpath("config") .. "/customLsp",
-- Set up omnifunc for buffer-local completion
on_attach = function(client, bufnr)
vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
end,
-- PowerShell formatting settings
settings = {
powershell = {
codeFormatting = {
Preset = 'OTBS' -- One True Brace Style
}
}
}
}
end
}
})
-- Configure completion behavior
cmp.setup({
snippet = {
expand = function(args)
require('luasnip').lsp_expand(args.body)
end,
},
-- Key mappings for completion
mapping = cmp.mapping.preset.insert({
['<C-p>'] = cmp.mapping.select_prev_item(),
['<C-n>'] = cmp.mapping.select_next_item(),
['<C-y>'] = cmp.mapping.confirm({ select = true }),
['<C-Space>'] = cmp.mapping.complete(),
}),
-- Configure completion sources
sources = cmp.config.sources({
{ name = 'nvim_lsp' }, -- LSP completion
{ name = 'luasnip' }, -- Snippets
}, {
{ name = 'buffer' }, -- Buffer words
})
})
-- Configure diagnostic display
vim.diagnostic.config({
float = {
focusable = false,
style = 'minimal',
border = 'rounded',
source = 'always',
header = '',
prefix = '',
},
})
end
}
}
# PowerShell Neovim Development Environment Setup Script
# This script installs and configures all necessary components for a PowerShell Neovim development environment
# Ensure script is running with administrator privileges
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Error "Please run this script as Administrator"
exit 1
}
# Function to check if a command exists
function Test-CommandExists {
param ($command)
$oldPreference = $ErrorActionPreference
$ErrorActionPreference = 'stop'
try {
if (Get-Command $command) { return $true }
}
catch { return $false }
finally { $ErrorActionPreference = $oldPreference }
}
# Create necessary directories
$ConfigPaths = @{
"NvimConfig" = "$env:LOCALAPPDATA\nvim"
"NvimData" = "$env:LOCALAPPDATA\nvim-data"
"NvimCustomLsp" = "$env:LOCALAPPDATA\nvim\customLsp"
"NvimTsParsers" = "$env:LOCALAPPDATA\nvim\tsparsers"
}
foreach ($path in $ConfigPaths.GetEnumerator()) {
if (-not (Test-Path $path.Value)) {
New-Item -ItemType Directory -Path $path.Value -Force
Write-Host "Created directory: $($path.Value)"
}
}
# Install required packages using winget
$WingetPackages = @(
"Python.Python.3.11",
"Git.Git",
"Microsoft.PowerShell",
"Microsoft.VisualStudioCode", # Useful for comparison and debugging
"Microsoft.VisualStudio.2022.BuildTools" # For C++ build tools
)
foreach ($package in $WingetPackages) {
Write-Host "Installing $package..."
winget install -e --id $package --accept-package-agreements --accept-source-agreements
}
# Install Node.js using winget (required for some Neovim plugins)
if (-not (Test-CommandExists "node")) {
Write-Host "Installing Node.js..."
winget install -e --id OpenJS.NodeJS
refreshenv
}
# Download and install Neovim
$NvimLatestRelease = "https://github.com/neovim/neovim/releases/download/stable/nvim-win64.zip"
$NvimZip = "$env:TEMP\nvim-win64.zip"
$NvimInstallPath = "C:\Program Files\Neovim"
if (-not (Test-Path $NvimInstallPath)) {
Write-Host "Downloading Neovim..."
Invoke-WebRequest -Uri $NvimLatestRelease -OutFile $NvimZip
Expand-Archive -Path $NvimZip -DestinationPath "C:\Program Files" -Force
Remove-Item $NvimZip
}
# Add Neovim to PATH if not already present
$NvimBinPath = "$NvimInstallPath\bin"
$CurrentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if (-not $CurrentPath.Contains($NvimBinPath)) {
[Environment]::SetEnvironmentVariable("Path", "$CurrentPath;$NvimBinPath", "Machine")
Write-Host "Added Neovim to PATH"
}
# Clone PowerShell TreeSitter parser
$TreeSitterPath = "$($ConfigPaths.NvimTsParsers)\tree-sitter-powershell"
if (-not (Test-Path $TreeSitterPath)) {
Write-Host "Cloning PowerShell TreeSitter parser..."
git clone https://github.com/airbus-cert/tree-sitter-powershell.git $TreeSitterPath
}
# Download PowerShell Editor Services
$PsesRelease = "https://github.com/PowerShell/PowerShellEditorServices/releases/latest/download/PowerShellEditorServices.zip"
$PsesZip = "$env:TEMP\PowerShellEditorServices.zip"
$PsesPath = $ConfigPaths.NvimCustomLsp
Write-Host "Downloading PowerShell Editor Services..."
Invoke-WebRequest -Uri $PsesRelease -OutFile $PsesZip
Expand-Archive -Path $PsesZip -DestinationPath $PsesPath -Force
Remove-Item $PsesZip
# Install pnpm (for better Node.js package management)
if (-not (Test-CommandExists "pnpm")) {
Write-Host "Installing pnpm..."
npm install -g pnpm
}
# Install global development tools
npm install -g tree-sitter-cli
pip install pynvim
# Set up Lazy package manager for Neovim
$LazyPath = "$($ConfigPaths.NvimData)\lazy\lazy.nvim"
if (-not (Test-Path $LazyPath)) {
Write-Host "Setting up Lazy package manager..."
git clone https://github.com/folke/lazy.nvim.git $LazyPath
}
Write-Host "`nSetup completed successfully!"
Write-Host "Please restart your terminal for all changes to take effect."
Write-Host "Remember to set up your Neovim configuration files in $($ConfigPaths.NvimConfig)"
Write-Host "Refer to the blog post for specific Neovim configuration details."

Let me explain the structure and how to set up these configuration files:

First, create the following directory structure in your Neovim config directory (typically ~/.config/nvim on Linux/WSL or %LOCALAPPDATA%\nvim on Windows):

nvim/
├── init.lua
├── lua/
│   └── config/
│       ├── keymaps.lua
│       └── autocmds.lua
└── plugins/
    ├── treesitter.lua
    ├── lsp.lua
    └── tools.lua

Each configuration file serves a specific purpose:

init.lua: The main configuration file that sets up basic editor settings and bootstraps the plugin manager lua/config/keymaps.lua: Defines all custom key mappings, including LSP-specific ones lua/config/autocmds.lua: Sets up automatic commands for various events plugins/treesitter.lua: Configures syntax highlighting and code parsing plugins/lsp.lua: Sets up the Language Server Protocol integration plugins/tools.lua: Configures additional development tools like Telescope, Git integration, and more

Key features of this setup:

Full PowerShell language support through TreeSitter and LSP Intelligent code completion with nvim-cmp Fuzzy finding with Telescope Git integration with fugitive Undo history visualization with undotree Status line with lualine Automatic pair matching with nvim-autopairs Enhanced PowerShell syntax highlighting Smart commenting system

After placing these files in their respective directories, start Neovim. The plugin manager (lazy.nvim) will automatically install all required plugins on the first run.

# Setup-DevEnvironment.ps1
# Find the latest Visual Studio installation
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$vsPath = & $vswhere -latest -property installationPath
if (-not $vsPath) {
Write-Error "Visual Studio installation not found. Please ensure Visual Studio Build Tools are installed."
exit 1
}
# Get the path to the Developer Command Prompt configuration
$vcvarsall = Join-Path $vsPath "VC\Auxiliary\Build\vcvarsall.bat"
if (-not (Test-Path $vcvarsall)) {
Write-Error "vcvarsall.bat not found. Please ensure Visual Studio Build Tools are properly installed."
exit 1
}
# Create a script that will set up the environment
$setupScript = @"
@echo off
call "$vcvarsall" x64
set INCLUDE=%INCLUDE%;${env:SystemRoot}\SDK\Include
"@
# Save the script to a convenient location
$setupScriptPath = Join-Path $env:USERPROFILE "vsdev.bat"
$setupScript | Out-File -FilePath $setupScriptPath -Encoding ASCII
# Create a PowerShell function to set up the development environment
$profileContent = @"
function Initialize-DevEnvironment {
Write-Host "Initializing Visual Studio development environment..."
cmd /c "`"$setupScriptPath`" && set" | ForEach-Object {
if (`$_ -match '(.+?)=(.+)') {
`$name = `$matches[1]
`$value = `$matches[2]
[System.Environment]::SetEnvironmentVariable(`$name, `$value, 'Process')
}
}
Write-Host "Development environment initialized successfully."
}
"@
# Add the function to PowerShell profile
if (-not (Test-Path $PROFILE)) {
New-Item -Path $PROFILE -ItemType File -Force
}
Add-Content -Path $PROFILE -Value "`n$profileContent"
Write-Host "Setup complete. Please restart PowerShell and run Initialize-DevEnvironment before using Neovim."
-- plugins/tools.lua
-- Additional development tools and utilities
return {
-- Telescope for fuzzy finding
{
'nvim-telescope/telescope.nvim',
dependencies = {
'nvim-lua/plenary.nvim',
-- Fast file finding in C
{ 'nvim-telescope/telescope-fzf-native.nvim', build = 'make' }
},
config = function()
local telescope = require('telescope')
telescope.setup({
defaults = {
-- Configure file and text search behavior
path_display = { "truncate" },
sorting_strategy = "ascending",
layout_config = {
horizontal = {
prompt_position = "top",
preview_width = 0.55,
},
},
},
-- Configure file ignore patterns
pickers = {
find_files = {
-- Ignore common PowerShell artifacts
file_ignore_patterns = {
"*.dll", "*.pdb", "*.xml",
".git/", "node_modules/",
},
},
},
})
-- Load the FZF extension for better performance
telescope.load_extension('fzf')
-- Set up key mappings for Telescope
local map = vim.keymap.set
map('n', '<leader>ff', "<cmd>Telescope find_files<cr>", { desc = "Find files" })
map('n', '<leader>fg', "<cmd>Telescope live_grep<cr>", { desc = "Live grep" })
map('n', '<leader>fb', "<cmd>Telescope buffers<cr>", { desc = "Find buffers" })
map('n', '<leader>fh', "<cmd>Telescope help_tags<cr>", { desc = "Help tags" })
end,
},
-- Git integration
{
'tpope/vim-fugitive',
config = function()
-- Set up key mappings for common Git operations
local map = vim.keymap.set
map('n', '<leader>gs', vim.cmd.Git, { desc = "Git status" })
map('n', '<leader>gb', "<cmd>Git blame<cr>", { desc = "Git blame" })
end,
},
-- Undo history visualization
{
'mbbill/undotree',
config = function()
-- Configure UndoTree layout
vim.g.undotree_SetFocusWhenToggle = 1
vim.g.undotree_WindowLayout = 2
-- Set up key mapping for UndoTree
vim.keymap.set('n', '<leader>u', vim.cmd.UndotreeToggle, { desc = "Toggle UndoTree" })
end,
},
-- Status line
{
'nvim-lualine/lualine.nvim',
dependencies = { 'nvim-tree/nvim-web-devicons' },
config = function()
require('lualine').setup({
options = {
theme = 'auto',
component_separators = '|',
section_separators = '',
},
sections = {
lualine_a = {'mode'},
lualine_b = {
'branch',
{'diagnostics', sources = {'nvim_lsp'}},
},
lualine_c = {
{
'filename',
path = 1, -- Show relative path
symbols = {
modified = '',
readonly = ' ',
unnamed = '[No Name]',
}
}
},
lualine_x = {'encoding', 'fileformat', 'filetype'},
lualine_y = {'progress'},
lualine_z = {'location'}
},
})
end,
},
-- Auto-pairs for brackets and quotes
{
'windwp/nvim-autopairs',
event = "InsertEnter",
config = function()
require('nvim-autopairs').setup({
check_ts = true, -- Use treesitter to check for pairs
disable_filetype = { "TelescopePrompt" },
-- Configure PowerShell-specific pairs
pairs_map = {
["'"] = "'",
['"'] = '"',
['('] = ')',
['['] = ']',
['{'] = '}',
['@('] = ')', -- PowerShell array operator
['@{'] = '}', -- PowerShell hash table operator
},
})
end,
},
-- Better syntax highlighting for PowerShell
{
'PProvost/vim-ps1',
ft = 'ps1',
},
-- Comment toggling
{
'numToStr/Comment.nvim',
config = function()
require('Comment').setup({
-- Enable context-aware commenting
pre_hook = function(ctx)
local U = require('Comment.utils')
local location = nil
if ctx.ctype == U.ctype.block then
location = require('ts_context_commentstring.utils').get_cursor_location()
elseif ctx.cmotion == U.cmotion.v or ctx.cmotion == U.cmotion.V then
location = require('ts_context_commentstring.utils').get_visual_start_location()
end
return require('ts_context_commentstring.internal').calculate_commentstring {
key = ctx.ctype == U.ctype.line and '__default' or '__multiline',
location = location,
}
end,
})
end,
},
}
-- plugins/treesitter.lua
-- Configuration for syntax highlighting and code parsing
return {
{
'nvim-treesitter/nvim-treesitter',
build = ':TSUpdate',
config = function()
-- Configure TreeSitter with commonly used languages and features
require('nvim-treesitter.configs').setup({
-- Languages to install parsers for
ensure_installed = {
"vimdoc", -- For Neovim documentation
"lua", -- For Neovim configuration
"bash", -- For shell scripts
"markdown", -- For documentation
"json", -- For configuration files
"yaml", -- For configuration files
},
-- Don't install parsers synchronously
sync_install = false,
-- Automatically install parsers when needed
auto_install = true,
-- Enable indentation support
indent = {
enable = true,
},
-- Enable syntax highlighting
highlight = {
enable = true,
-- Disable vim's regex-based highlighting
additional_vim_regex_highlighting = false,
},
})
-- Configure custom PowerShell parser
local parser_config = require('nvim-treesitter.parsers').get_parser_configs()
parser_config.powershell = {
install_info = {
-- Path to the locally cloned PowerShell parser
url = vim.fn.stdpath("config") .. "/tsparsers/tree-sitter-powershell",
files = { "src/parser.c", "src/scanner.c" },
branch = "main",
generate_requires_npm = false,
requires_generate_from_grammar = false,
},
filetype = "ps1", -- Associate with PowerShell file extension
}
end,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment