Inline error diagnostics for native Vim 9.0+
inspired by rachartier/tiny-inline-diagnostic.nvim
rebuilt from scratch on Vim 9's text-property virtual text (prop_add() with text_align) since Vim has no extmarks API.
Inline diagnostics in native Vim have a long lineage - Syntastic (sign-column errors), ALE and Neomake (async linting), and pure-Vimscript LSP clients like vim-lsp and vim-lsc; vimline-errors builds on that history with a zero-setup, compiler-driven source and one-keystroke fix-its.
Feel free to contribute!
Most diagnostic plugins need you to install a linter or language server per
language. vimline-errors doesn't. By default it runs the language's own
compiler/interpreter in check-only mode - gcc -fsyntax-only,
python3 compile(), node --check, bash -n, tools you already have if
you write in that language.
It catches errors - It is not a style/lint tool, for that, point it at ALE instead (see Rich linting via ALE).
Each works only if that language's runtime is present (it usually is, if you're editing that language). Missing runtime → that filetype silently shows nothing.
| Filetype | Uses | Catches |
|---|---|---|
python |
python3 (compile()) |
syntax errors |
c |
gcc -fsyntax-only |
syntax + semantic (undeclared, type) |
cpp |
g++ -fsyntax-only |
syntax + semantic |
javascript |
node --check |
syntax errors |
sh / bash |
bash -n |
syntax errors |
perl |
perl -c |
syntax errors |
lua |
luac -p |
syntax errors |
Adding a language is a few lines in autoload/vimline_errors/checkers.vim
(a command + an output-parsing regex).
- Vim 9.0.0297+ compiled with
+textprop- that's when text-property virtual text landed. There is no fallback for older Vim or Vim 8. Check with:echo has('patch-9.0.0297')(should print1). - The compiler/interpreter for whichever languages you want checked (already present if you write them). Nothing else.
call plug#begin('~/.vim/plugged')
Plug 'Joekrry/vimline-errors'
call plug#end()Then :PlugInstall.
git clone https://github.com/Joekrry/vimline-errors ~/.vim/pack/plugins/start/vimline-errorsThen generate help tags once from inside Vim:
:helptags ~/.vim/pack/plugins/start/vimline-errors/docThat's it. Open a file in a supported language and errors appear inline as you type, and clear as soon as you fix them.
Zero config required. To customize, set g:vimline_errors_config before the
plugin loads (or call vimline_errors#Setup(...) any time after):
let g:vimline_errors_config = {
\ 'source': 'builtin',
\ 'preset': 'modern',
\ 'enabled': v:true,
\ 'cursor_only': v:false,
\ 'show_all_diags_on_cursorline': v:true,
\ 'multilines': {'enabled': v:true},
\ 'add_messages': {'display_count': v:true},
\ 'overflow': {'mode': 'truncate', 'padding': 2},
\ 'severity': ['E', 'W', 'I'],
\ 'signs': {},
\ 'hi': {
\ 'error': 'VimlineError',
\ 'warn': 'VimlineWarn',
\ 'info': 'VimlineInfo',
\ 'arrow': 'VimlineArrow',
\ },
\ 'throttle': 20,
\ 'check_delay': 300,
\ 'disabled_ft': [],
\ }Key options (:help vimline-errors-config for the rest):
source-'builtin'(default, self-contained) or'ale'(see below).cursor_only-v:false(default) annotates every line that has an error so they stay visible until fixed;v:trueannotates only the cursor's line.check_delay- ms to debounce running the checker while you type.throttle- ms to debounce re-rendering on cursor movement.disabled_ft- filetypes to never check.
Every built-in language exposes an inline fix action. For gcc/g++ (C/C++),
vimline-errors uses the precise machine-applicable fix-it emitted by the
compiler: insert a missing token, rename to a "did you mean" suggestion, or
remove a token. Other language runtimes do not emit structured edits, so their
explicit fallback is comment out line; native compiler edits always win.
A diagnostic that carries a fix advertises it inline with a wrench glyph and a short label:
❯ expected ';' before '}' token insert ";"
Put the cursor on that line and run :VimlineErrors fix, or bind the provided
mapping (no default key is taken):
nmap <leader>f <Plug>(vimline-errors-fix)The recommended fix-it keybinding is therefore <leader>f. With Vim's
default leader (\), press \f. If you set mapleader (for example to
Space), press that leader followed by f. The plugin intentionally does not
create this binding automatically, so add the line above to your vimrc.
The fix is applied against the buffer snapshot the checker last ran on. If
you've edited since that check, the apply is refused and a fresh check runs
instead - a stale column can never corrupt the buffer. Only single-line fixes
are applied for now (the common case: insert ;/), rename an identifier);
multi-line fixes are reported but skipped.
Rust (rustc --error-format=json) and clang JSON fix-its are natural next steps.
The built-in checkers report errors. If you want full linting (style, warnings, deep semantics) for some language, install ALE plus a linter/LSP and switch the source:
let g:vimline_errors_config = { 'source': 'ale' }In ale mode vimline-errors renders ALE's loclist instead of running its own
checkers, and takes over g:ale_virtualtext_cursor to avoid duplicate display
(restored on :VimlineErrors disable; opt out with
'manage_ale_virtualtext': v:false).
| preset | look |
|---|---|
modern |
nerdfont icons, ❯ arrow, │/└ connectors, `` fix glyph |
simple |
ASCII E:/W:/I: labels, > arrow, |/`- connectors, [fix] |
minimal |
just the message text, no icons, arrow, or fix hint |
Set the fix glyph empty to hide the inline fix-it hint (the fix still applies
via :VimlineErrors fix).
Override individual glyphs without a preset:
let g:vimline_errors_config = {
\ 'signs': {'arrow': '->', 'vertical': '|', 'vertical_end': '`-',
\ 'error': 'E', 'warn': 'W', 'info': 'I', 'fix': '[fix]'},
\ }VimlineError, VimlineWarn, VimlineInfo, and VimlineArrow are defined
with highlight default, so your colorscheme or vimrc can override them:
highlight VimlineError guifg=#ff5555 ctermfg=203:VimlineErrors enable
:VimlineErrors disable
:VimlineErrors toggle
:VimlineErrors toggle_cursor_only
:VimlineErrors toggle_all_diags_on_cursorline
:VimlineErrors fix
:VimlineErrors resetnnoremap <leader>de <Cmd>VimlineErrors enable<CR>
nnoremap <leader>dt <Cmd>VimlineErrors toggle<CR>
nmap <leader>f <Plug>(vimline-errors-fix)call vimline_errors#Setup({config})
call vimline_errors#Enable() | #Disable() | #Toggle()
call vimline_errors#ToggleCursorOnly() | #ToggleAllDiagsOnCursorline()
call vimline_errors#RunCheck(bufnr('%')) " force a re-check (builtin source)
call vimline_errors#RenderBuffer(bufnr('%')) " force a re-render
call vimline_errors#ApplyFix() " apply the fix-it under the cursor
echo vimline_errors#GetConfig()
echo vimline_errors#GetDiagnosticUnderCursor()These will be developed as I continue building it. For now, feel free to contribute to this project!
- Errors, not lint. Built-in mode catches errors the compiler/interpreter
reports; it doesn't do style/warning linting (use
source: 'ale'for that). - Structured fix-its are gcc/g++ only (C/C++). Other built-in languages
offer a clearly labelled
comment out linefallback. Fixes are single-line and use byte columns. - Syntax errors are one-at-a-time for interpreted languages (the parser stops at the first). Compiled languages (C/C++) report several at once.
- EOF errors (e.g. a missing
fi/}reported "at end of file") land on a line past the buffer and are skipped - the fix is usually obvious anyway. - Text properties are buffer-scoped, so the same buffer in two split windows shares one render state.
- No background-color blending (terminal highlight groups are flat foreground).
See :help vimline-errors for full documentation.
MIT