The Vanilla Neovim LSP Journey: From “Dull” to “IDE” Without a Package Manager
How I learned the hard way that Native LSP isn’t enough — and the missing piece that changes everything.
The Vanilla Neovim LSP Journey: From “Dull” to “IDE” Without a Package Manager
How I learned the hard way that Native LSP isn’t enough — and the missing piece that changes everything.
I used to use Lazy vim for easy package download , But I want make clear without black box, then we first encounter with Neovim’s native LSP will feel like a punch to the face.
Recently, I set out to configure PowerShell LSP on Neovim 0.12 — without using a single package manager. No Lazy. No Mason. Just raw Lua and Git.
lHere is the story of how I went from a dull, broken auto-complete to a fully-fledged IDE experience, and why the tool you use to render your LSP matters more than you think.
Phase 1: The “Dull” Native Reality
I started with the bleeding-edge Neovim 0.12 native API. I downloaded the PowerShell LSP server manually via curl, placed it in my ~/.local/share/nvim/lsp-servers/, and wired it up natively in my init.lua:
vim.lsp.enable('powershell_es')
Then, I turned on native auto-triggering:
- Native auto-complete trigger
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if client and client:supports_method("textDocument/completion") then
vim.lsp.completion.enable(true, client.id, args.buf, { autotrigger = true })
end
end,
})
The LSP attached. :LspInfo there is no such a command and I try to find what is wrong about that was dropped a long time ago by nvim-Ispconfig from Neovim 0.12 onwards. Only 0.11 and prior versions still
: checkhealth vim. lsp
When I typed $env:, I didn’t get a nice dropdown menu. I got a clunky, horizontal text list at the bottom of the screen. Arrow keys didn't work to navigate it. Worse, whenever I typed $, the LSP tried to be helpful and forcefully converted it into ${$}, completely breaking my workflow.
The native LSP was working, but the user experience was dull, jarring, and frustrating.
Phase 2: Understanding the Gap
What went wrong? I had to understand the architecture.
LSP (Language Server Protocol) is just a data pipe. The PowerShell Editor Services (PSES) was doing its job perfectly — it was sending a list of completions and snippets over the wire.
The problem was Neovim’s native completion engine. It is intentionally barebones. It doesn’t know how to draw a pretty floating menu, and it certainly doesn’t know how to parse LSP Snippets (like ${1:variable}). It just takes the raw text from the LSP and dumbly pastes it onto the screen.
To get the IDE experience, you need a Completion Engine — a UI layer that sits between the LSP data pipe and your screen.
Phase 3: The nvim-cmp Revolution
Enter nvim-cmp. It is the industry standard completion engine for Neovim. But since I was on a strict No Package Manager diet, I couldn’t just run :Lazy install. I had to install it manually using Neovim’s built-in pack feature:
# Create the native plugin directory
mkdir -p ~/.config/nvim/pack/manual/start
# Clone the engine and its helpers
cd ~/.config/nvim/pack/manual/start
git clone https://github.com/hrsh7th/nvim-cmp.git
git clone https://github.com/hrsh7th/cmp-nvim-lsp.git # The bridge
git clone https://github.com/hrsh7th/vim-vsnip.git # Snippet parser
git clone https://github.com/hrsh7th/cmp-vsnip.git
Then, the magic happened in the Lua config. I replaced the dull vim.lsp.completion.enable with the nvim-cmp setup:
local cmp = require('cmp')
cmp.setup({
- Tell cmp how to parse snippets (FIXES THE ${$} BUG!)
snippet = {
expand = function(args)
vim.fn["vsnip#anonymous"](args.body)
end,
},
- IDE-Style Keybindings
mapping = cmp.mapping.preset.insert({
['<Down>'] = cmp.mapping.select_next_item(),
['<Up>'] = cmp.mapping.select_prev_item(),
['<CR>'] = cmp.mapping.confirm({ select = true }),
}),
- Where the suggestions come from
sources = cmp.config.sources({
{ name = 'nvim_lsp' },
{ name = 'vsnip' },
})
})
The Secret Sauce: capabilities
There was one final, crucial step. I had to tell the PowerShell LSP that Neovim was now smart enough to handle snippets. In the native LSP config file (~/.config/nvim/lsp/powershell_es.lua), I added this single line:
capabilities = require('cmp_nvim_lsp').default_capabilities(),
This line transforms the communication. Instead of the LSP sending raw, broken text, nvim-cmp tells the LSP: "Hey, I understand advanced snippets and floating windows. Send me the good stuff."
🏠 YOUR MAC HOME DIRECTORY (~)
│
│
├── 📁 .config/nvim/ ─────────────────────────────── [NEOVIM CONFIG ROOT]
│ │
│ ├── 📄 init.lua ─────────────────────────────── 🧠 THE BRAIN
│ │ (Tells Neovim to enable the LSP and setup nvim-cmp)
│ │
│ ├── 📁 lsp/ ─────────────────────────────────── 🍳 THE KITCHEN (Native 0.12 API)
│ │ └── 📄 powershell_es.lua
│ │ (Tells Neovim HOW to start the Microsoft LSP process.
│ │ Contains the 'capabilities' bridge to the Waiter.)
│ │
│ └── 📁 pack/manual/start/ ───────────────────── 🤵 THE WAITER (Manual Plugins)
│ │
│ │ (Neovim auto-loads anything inside 'start/')
│ │
│ ├── 📁 nvim-cmp/ (Draws the pretty dropdown menu)
│ ├── 📁 cmp-nvim-lsp/ (🤝 THE BRIDGE: Connects Kitchen to Waiter)
│ ├── 📁 vim-vsnip/ (Parses snippets so $ doesn't become ${$})
│ └── 📁 cmp-vsnip/ (Feeds snippets into the menu)
│
│
└── 📁 .local/share/nvim/ ─────────────────────────── [NEOVIM DATA ROOT]
│
└── 📁 lsp-servers/ ─────────────────────────── 🧠 THE CHEF (Manual Binaries)
│
└── 📁 powershell-editor-services/
(The actual program downloaded via 'curl' from GitHub.
It does the heavy lifting of reading your PowerShell code.)
The Result: Night and Day
The difference was instantaneous.
When I open a .ps1 file now and type $env::
- A beautiful, bordered, floating dropdown menu appears instantly.
- I can navigate it with Up/Down arrow keys.
- I can hit Enter to confirm.
- Typing
$no longer creates the${$}monster—it correctly suggests variables with proper snippet placeholders.
The Takeaway
Neovim’s native LSP is an incredible foundation. It handles the heavy lifting of talking to language servers. But do not confuse the data layer with the presentation layer.
If you’re coming from an IDE, the native vim.lsp.completion will only disappoint you. You need nvim-cmp.
And the best part? You don’t need a bloated package manager to get it. A few git clone commands into pack/manual/start/ and some clean Lua config, and you have an IDE-grade experience with 100% control over your editor.
No black boxes. No magic. Just pure, vanilla Neovim.
메타데이터
- post_id
- 73f8a5d885fc
- slug
- the-vanilla-neovim-lsp-journey-from-dull-to-ide-without-a-package-manager-73f8a5d885fc
- url
- https://medium.com/@ethan_june/the-vanilla-neovim-lsp-journey-from-dull-to-ide-without-a-package-manager-73f8a5d885fc
- canonical_url
- https://medium.com/@ethan_june/the-vanilla-neovim-lsp-journey-from-dull-to-ide-without-a-package-manager-73f8a5d885fc
- author_url
- https://medium.com/@ethan_june
- status
- ok
- fetched_at
- 2026-06-11 22:20:54