Powerful navigation, completion, and inline value display for Laravel projects in Neovim.
Jump between controllers, routes, config files, Blade views, components, Inertia pages, and localization files with gf. See resolved config, env, and translation values as virtual text. Get smart completions for every Laravel construct.
blade-nav.mp4
Place your cursor on any reference and press gf:
| Context | Supported patterns |
|---|---|
| Blade directives | @include, @extends, @component, @each, @includeIf, @includeWhen, @includeUnless, @includeFirst |
| Blade components | <x-button />, <x-input.date /> |
| Livewire | <livewire:name />, @livewire('name') |
| Routes | route('name'), to_route('name') |
| Views | view('name'), View::make('name'), Route::view('url', 'name') |
| Inertia | inertia('Page/Name'), Inertia::render('Page/Name') |
| Config | config('app.key'), Config::get('key'), Config::set('key') |
| Environment | env('APP_KEY') |
| Translations | __('messages.welcome'), trans('messages.welcome') |
| Vue imports | <MyComponent /> (resolves from <script> imports in .vue files) |
Falls back to standard Neovim gf for unrecognized patterns.
Smart completion items for nvim-cmp, blink.cmp, and coq.nvim:
| Trigger | What completes |
|---|---|
@include(', @extends(', @component(' |
Blade view names |
<x- |
Component names |
<livewire:, @livewire(' |
Livewire component names |
route(', to_route(' |
Route names |
view(', View::make(', Route::view(' |
View names |
inertia(', Inertia::render(' |
Inertia page names |
config(', Config::get(', Config::set(' |
Config keys |
env(' |
Environment variable names |
__(', trans(' |
Translation keys |
Resolved values for config(), env(), __(), trans(), Config::get(), and Config::set() displayed as virtual text next to each call.
Works in PHP, Blade, and embedded JavaScript contexts.
Commands:
| Command | Description |
|---|---|
:BladeNavToggleShowValues |
Toggle virtual text annotations on/off |
:BladeNavClearCache |
Clear all cached config, env, and translation maps |
Keymaps (when annotations.create_keymaps = true, the default):
| Key | Action |
|---|---|
K |
Show resolved value in floating window (with LSP fallback) |
<leader>bv |
Toggle annotations |
<leader>bcc |
Clear cache |
For __() and trans() calls, K opens a floating window showing the translation across all locales.
Requires Neovim >= 0.11 and nvim-treesitter with php, blade, vue, and html parsers.
{
'ricardoramirezr/blade-nav.nvim',
dependencies = { -- optional, for nvim-cmp integration
'hrsh7th/nvim-cmp',
},
ft = { 'blade', 'php' },
opts = {},
}For blink.cmp users, no dependency is needed. See blink.cmp configuration below.
call plug#begin()
Plug 'hrsh7th/nvim-cmp' " optional
Plug 'ricardoramirezr/blade-nav.nvim', { 'for': ['blade', 'php'] }
call plug#end()
lua require("blade-nav").setup()use {
'ricardoramirezr/blade-nav.nvim',
requires = {
'hrsh7th/nvim-cmp', -- optional
},
ft = { 'blade', 'php' },
config = function()
require('blade-nav').setup()
end,
}Works out of the box. All options and their defaults:
require('blade-nav').setup({
-- Master switch. Auto-disabled outside Laravel unless force_enable = true.
enable = true,
force_enable = false,
cache_timeout = 50000, -- Cache TTL in ms
debug = false,
-- Completion behavior (applies to nvim-cmp, blink.cmp, and coq.nvim)
close_tag_on_complete = true,
include_routes_in_cmp = true,
-- Inertia
inertia_pages_path = nil, -- nil = "Pages" (default)
inertia_extensions = { 'vue', 'tsx', 'jsx', 'ts', 'js' },
-- Vue
jsconfig_path = './jsconfig.json',
-- Extra directories for <x-component> resolution
laravel_components_paths = {},
-- Navigation targets (gf)
handlers = {
directive = true,
view = true,
livewire = true,
route = true,
config = true,
component = true,
inertia = true,
vue = true,
lang = true,
},
-- Completion/integration sources
integrations = {
gf = true,
cmp = true,
coq = true,
},
-- Inline value annotations
annotations = {
show = false, -- Start with annotations visible
hl = 'Comment', -- Highlight group for virtual text
prefix = ' ⟶ ', -- Prefix before each value
max_len = 160, -- Max display length before truncation
debounce_ms = 120, -- Debounce for re-rendering on edits
show_on_load = true, -- Render annotations when a buffer loads
create_keymaps = true, -- Create K, <leader>bv, <leader>bcc maps
},
})A project is detected as Laravel if any of these are true:
artisanfile existsroutes/web.phpexistsresources/views/directory existscomposer.jsonrequireslaravel/frameworkorlaravel/lumen-framework
Set force_enable = true to skip detection.
local kind_icons = {
BladeNav = "",
}
require('cmp').setup({
formatting = {
format = function(entry, item)
if kind_icons[item.kind] then
item.kind = string.format('%s %s', kind_icons[item.kind], item.kind)
end
return item
end,
},
})Register blade-nav as a source provider in your blink.cmp config:
require('blink.cmp').setup({
sources = {
default = { 'lsp', 'blade-nav', 'snippets', 'path', 'buffer' },
providers = {
['blade-nav'] = {
name = 'blade-nav',
module = 'blade-nav.integrations.blink',
},
},
},
})To customize the icon:
completion = {
menu = {
draw = {
components = {
kind_icon = {
text = function(ctx)
if ctx.source_name == 'blade-nav' then
return ' '
end
return ctx.kind_icon
end,
highlight = function(ctx)
if ctx.source_name == 'blade-nav' then
return 'BlinkCmpKindBladeNav'
end
return 'BlinkCmpKind' .. ctx.kind
end,
},
},
},
},
}require('blade-nav').setup({
laravel_components_paths = {
'app/View/Components/',
'resources/views/common',
},
})If your autopairs plugin closes tags automatically:
require('blade-nav').setup({
close_tag_on_complete = false,
})| Command | Description |
|---|---|
:BladeNavToggleShowValues |
Toggle inline config/env/translation annotations |
:BladeNavClearCache |
Clear all caches (config, env, translations, routes, views) |
:BladeNavInstallArtisanCommand |
Install the BladeNav artisan command into your Laravel project |
:checkhealth blade-nav |
Diagnose setup issues |
Run :checkhealth blade-nav to verify:
- Treesitter parsers installed
- Laravel project detected
- PHP and artisan available
- Integration status (cmp, blink, coq)
- Handler configuration
Issues and pull requests welcome at GitHub.
MIT. See LICENSE.