A sophisticated Neovim plugin for managing LSP diagnostic display with per-severity control, multiple display modes, and focus capabilities.
xray.mp4
- Per-severity control: Toggle ERROR, WARN, INFO, and HINT diagnostics independently
- Dual display modes: Switch between virtual text (inline) and virtual lines (multiline) for each severity
- Focus mode: Show diagnostics only on the current cursor line
- State persistence: All settings automatically saved and restored across sessions
- Which-key integration: Intuitive menu-driven interface
- Neovim >= 0.8.0
- which-key.nvim
- LSP server configured
Using lazy.nvim
{
"sfn101/xray.nvim",
dependencies = {
"folke/which-key.nvim",
},
config = function()
require("xray").setup()
end,
}Using packer.nvim
use {
"sfn101/xray.nvim",
requires = { "folke/which-key.nvim" },
config = function()
require("xray").setup()
end,
}require("xray").setup({
-- Default state file location
state_file = vim.fn.stdpath("data") .. "/xray_state.json",
-- Default keymaps prefix
keymap_prefix = "gl",
-- Auto-setup keymaps (set to false to define your own)
setup_keymaps = true,
})If you prefer to define your own keymaps, disable auto-setup:
require("xray").setup({
setup_keymaps = false,
})
-- Define your own keymaps
vim.keymap.set("n", "<leader>da", require("xray").toggle_all, { desc = "Toggle all diagnostics" })All keymaps use the gl prefix by default (customizable via keymap_prefix option).
| Key | Action |
|---|---|
gla |
Toggle all diagnostics on/off |
gle |
Toggle ERROR diagnostics on/off |
glw |
Toggle WARN/INFO/HINT diagnostics on/off together |
| Key | Action |
|---|---|
glse |
Toggle ERROR display mode (virtual text ↔ virtual lines) |
glsw |
Toggle WARN display mode (virtual text ↔ virtual lines) |
glsi |
Toggle INFO display mode (virtual text ↔ virtual lines) |
glsh |
Toggle HINT display mode (virtual text ↔ virtual lines) |
glsc |
Reset all severities to virtual text mode (default) |
| Key | Action |
|---|---|
glf |
Toggle focus mode (show diagnostics only on current line) |
glsf |
Toggle focus mode as default on startup (persisted) |
| Key | Action |
|---|---|
glr |
Manually refresh diagnostics for current buffer |
Virtual Text Mode (default):
- Diagnostics appear inline at the end of the line
- Compact and non-intrusive
- Good for quick scanning
Virtual Lines Mode:
- Diagnostics appear on separate lines below the code
- More detailed and readable
- Better for long messages
Focus mode is a special display mode that:
- Shows diagnostics only on the current cursor line
- Updates automatically as you move the cursor
- Respects current virtual text/lines settings for each severity
- Respects enabled/disabled state for each severity
- Perfect for reducing visual noise while working
Usage Example:
- Press
glfto enter focus mode - Move your cursor - diagnostics follow
- Press
glfagain to exit and see all diagnostics - Use
glsfto make focus mode your default at startup
All settings are automatically saved to ~/.local/share/nvim/xray_state.json and restored when you restart Neovim. This includes:
- Display mode for each severity (text vs lines)
- Enabled/disabled state for each severity
- Focus mode default preference
- Press
glwto hide WARN/INFO/HINT - Only errors remain visible
- Press
glseuntil errors use virtual lines - Keep other severities in virtual text mode
- Press
glfto enter focus mode - Work with minimal distraction
- See diagnostics only where your cursor is
Press glsc to reset all severities to default virtual text mode
Press glr to manually refresh diagnostics for the current buffer. This is useful if:
- Another plugin's config is interfering with xray settings
- Diagnostics appear duplicated or glitchy
- You want to force-reapply xray's configuration
Note: xray automatically refreshes diagnostics when you open or switch to a buffer, so manual refresh is rarely needed.
lua/xray/init.lua: Main plugin logic and keymap setuplua/xray/config.lua: Configuration managementlua/xray/state.lua: State persistence (load/save JSON)plugin/xray.lua: Plugin initialization guard
Focus mode uses a custom namespace to display filtered diagnostics:
- Global diagnostics are hidden
- Custom namespace is configured with same display settings
- CursorMoved/CursorMovedI autocmds update filtered diagnostics
- Only diagnostics on current line are shown in custom namespace
xray automatically refreshes diagnostics when you enter a buffer to ensure:
- xray's configuration takes precedence over other plugins
- No duplicate or conflicting diagnostic displays
- Consistent behavior across all buffers
The refresh happens with a 50ms delay to allow other plugins (like LazyVim) to apply their configs first, then xray overrides with your preferred settings.
State is serialized to JSON with descriptive labels:
{
"modes": {
"ERROR": true,
"WARN": true,
"INFO": false,
"HINT": false
},
"enabled": {
"ERROR": true,
"WARN": true,
"INFO": true,
"HINT": true
},
"focus_default": false
}- Check LSP is attached:
:LspInfo - Reset to defaults:
glsc - Check state file:
~/.local/share/nvim/xray_state.json
- Exit and re-enter focus mode with
glf - Check CursorMoved autocmds:
:au CursorMoved
- Verify which-key is installed
- Check keymap prefix in setup options
- Try
:map glto see registered keymaps
Contributions welcome! Please open an issue or PR.
MIT License - see LICENSE file for details
Inspired by the need for granular diagnostic control in modern LSP workflows.