Highly experimental plugin that completely replaces the UI for messages
, cmdline
and the popupmenu
.
- π fully configurable views like nvim-notify, splits, popups, virtual text, ..
- π use filters to route messages to different views
- π message highlights are preserved in the views (like the colors of
:hi
) - π command output like :messages is shown in normal buffers, which makes it much easier to work with
- π
:Noice
command to show a full message history - β¨οΈ no more :h more-prompt
- π» fully customizable cmdline with icons
- π
syntax highlighting for
vim
andlua
on the cmdline - π₯ statusline components
- π open message history in telescope.nvim
Noice is using the new experimental vim.ui_attach
API, so issues are to be expected.
It is highly recommended to use Neovim nightly, since a bunch of issues have already been fixed upstream.
Check this tracking issue for a list of known issues.
- Neovim >= 0.8.0 (nightly highly recommended)
- nui.nvim: used for proper rendering and multiple views
- nvim-notify: notification view (optional)
- a Nerd Font (optional)
- nvim-treesitter (optional, but highly recommended)
used for highlighting the cmdline and lsp docs. Make sure to install the parsers for
vim
,regex
,lua
,bash
,markdown
andmarkdown_inline
Install the plugin with your preferred package manager:
-- lazy.nvim
{
"folke/noice.nvim",
event = "VeryLazy",
opts = {
-- add any options here
},
dependencies = {
-- if you lazy-load any plugin below, make sure to add proper `module="..."` entries
"MunifTanjim/nui.nvim",
-- OPTIONAL:
-- `nvim-notify` is only needed, if you want to use the notification view.
-- If not available, we use `mini` as the fallback
"rcarriga/nvim-notify",
}
}
Suggested setup:
require("noice").setup({
lsp = {
-- override markdown rendering so that **cmp** and other plugins use **Treesitter**
override = {
["vim.lsp.util.convert_input_to_markdown_lines"] = true,
["vim.lsp.util.stylize_markdown"] = true,
["cmp.entry.get_documentation"] = true, -- requires hrsh7th/nvim-cmp
},
},
-- you can enable a preset for easier configuration
presets = {
bottom_search = true, -- use a classic bottom cmdline for search
command_palette = true, -- position the cmdline and popupmenu together
long_message_to_split = true, -- long messages will be sent to a split
inc_rename = false, -- enables an input dialog for inc-rename.nvim
lsp_doc_border = false, -- add a border to hover docs and signature help
},
})
It's a good idea to run :checkhealth noice
after installing to check for common issues.
vim-plug
" vim-plug
call plug#begin()
Plug 'folke/noice.nvim'
Plug 'MunifTanjim/nui.nvim'
call plug#end()
lua require("noice").setup()
noice.nvim comes with the following defaults:
Check the wiki for configuration recipes.
{
cmdline = {
enabled = true, -- enables the Noice cmdline UI
view = "cmdline_popup", -- view for rendering the cmdline. Change to `cmdline` to get a classic cmdline at the bottom
opts = {}, -- global options for the cmdline. See section on views
---@type table<string, CmdlineFormat>
format = {
-- conceal: (default=true) This will hide the text in the cmdline that matches the pattern.
-- view: (default is cmdline view)
-- opts: any options passed to the view
-- icon_hl_group: optional hl_group for the icon
-- title: set to anything or empty string to hide
cmdline = { pattern = "^:", icon = "ο", lang = "vim" },
search_down = { kind = "search", pattern = "^/", icon = "ο ο", lang = "regex" },
search_up = { kind = "search", pattern = "^%?", icon = "ο ο", lang = "regex" },
filter = { pattern = "^:%s*!", icon = "$", lang = "bash" },
lua = { pattern = { "^:%s*lua%s+", "^:%s*lua%s*=%s*", "^:%s*=%s*" }, icon = "ξ ", lang = "lua" },
help = { pattern = "^:%s*he?l?p?%s+", icon = "ο" },
input = {}, -- Used by input()
-- lua = false, -- to disable a format, set to `false`
},
},
messages = {
-- NOTE: If you enable messages, then the cmdline is enabled automatically.
-- This is a current Neovim limitation.
enabled = true, -- enables the Noice messages UI
view = "notify", -- default view for messages
view_error = "notify", -- view for errors
view_warn = "notify", -- view for warnings
view_history = "messages", -- view for :messages
view_search = "virtualtext", -- view for search count messages. Set to `false` to disable
},
popupmenu = {
enabled = true, -- enables the Noice popupmenu UI
---@type 'nui'|'cmp'
backend = "nui", -- backend to use to show regular cmdline completions
---@type NoicePopupmenuItemKind|false
-- Icons for completion item kinds (see defaults at noice.config.icons.kinds)
kind_icons = {}, -- set to `false` to disable icons
},
-- default options for require('noice').redirect
-- see the section on Command Redirection
---@type NoiceRouteConfig
redirect = {
view = "popup",
filter = { event = "msg_show" },
},
-- You can add any custom commands below that will be available with `:Noice command`
---@type table<string, NoiceCommand>
commands = {
history = {
-- options for the message history that you get with `:Noice`
view = "split",
opts = { enter = true, format = "details" },
filter = {
any = {
{ event = "notify" },
{ error = true },
{ warning = true },
{ event = "msg_show", kind = { "" } },
{ event = "lsp", kind = "message" },
},
},
},
-- :Noice last
last = {
view = "popup",
opts = { enter = true, format = "details" },
filter = {
any = {
{ event = "notify" },
{ error = true },
{ warning = true },
{ event = "msg_show", kind = { "" } },
{ event = "lsp", kind = "message" },
},
},
filter_opts = { count = 1 },
},
-- :Noice errors
errors = {
-- options for the message history that you get with `:Noice`
view = "popup",
opts = { enter = true, format = "details" },
filter = { error = true },
filter_opts = { reverse = true },
},
},
notify = {
-- Noice can be used as `vim.notify` so you can route any notification like other messages
-- Notification messages have their level and other properties set.
-- event is always "notify" and kind can be any log level as a string
-- The default routes will forward notifications to nvim-notify
-- Benefit of using Noice for this is the routing and consistent history view
enabled = true,
view = "notify",
},
lsp = {
progress = {
enabled = true,
-- Lsp Progress is formatted using the builtins for lsp_progress. See config.format.builtin
-- See the section on formatting for more details on how to customize.
--- @type NoiceFormat|string
format = "lsp_progress",
--- @type NoiceFormat|string
format_done = "lsp_progress_done",
throttle = 1000 / 30, -- frequency to update lsp progress message
view = "mini",
},
override = {
-- override the default lsp markdown formatter with Noice
["vim.lsp.util.convert_input_to_markdown_lines"] = false,
-- override the lsp markdown formatter with Noice
["vim.lsp.util.stylize_markdown"] = false,
-- override cmp documentation with Noice (needs the other options to work)
["cmp.entry.get_documentation"] = false,
},
hover = {
enabled = true,
silent = false, -- set to true to not show a message if hover is not available
view = nil, -- when nil, use defaults from documentation
---@type NoiceViewOptions
opts = {}, -- merged with defaults from documentation
},
signature = {
enabled = true,
auto_open = {
enabled = true,
trigger = true, -- Automatically show signature help when typing a trigger character from the LSP
luasnip = true, -- Will open signature help when jumping to Luasnip insert nodes
throttle = 50, -- Debounce lsp signature help request by 50ms
},
view = nil, -- when nil, use defaults from documentation
---@type NoiceViewOptions
opts = {}, -- merged with defaults from documentation
},
message = {
-- Messages shown by lsp servers
enabled = true,
view = "notify",
opts = {},
},
-- defaults for hover and signature help
documentation = {
view = "hover",
---@type NoiceViewOptions
opts = {
lang = "markdown",
replace = true,
render = "plain",
format = { "{message}" },
win_options = { concealcursor = "n", conceallevel = 3 },
},
},
},
markdown = {
hover = {
["|(%S-)|"] = vim.cmd.help, -- vim help links
["%[.-%]%((%S-)%)"] = require("noice.util").open, -- markdown links
},
highlights = {
["|%S-|"] = "@text.reference",
["@%S+"] = "@parameter",
["^%s*(Parameters:)"] = "@text.title",
["^%s*(Return:)"] = "@text.title",
["^%s*(See also:)"] = "@text.title",
["{%S-}"] = "@parameter",
},
},
health = {
checker = true, -- Disable if you don't want health checks to run
},
smart_move = {
-- noice tries to move out of the way of existing floating windows.
enabled = true, -- you can disable this behaviour here
-- add any filetypes here, that shouldn't trigger smart move.
excluded_filetypes = { "cmp_menu", "cmp_docs", "notify" },
},
---@type NoicePresets
presets = {
-- you can enable a preset by setting it to true, or a table that will override the preset config
-- you can also add custom presets that you can enable/disable with enabled=true
bottom_search = false, -- use a classic bottom cmdline for search
command_palette = false, -- position the cmdline and popupmenu together
long_message_to_split = false, -- long messages will be sent to a split
inc_rename = false, -- enables an input dialog for inc-rename.nvim
lsp_doc_border = false, -- add a border to hover docs and signature help
},
throttle = 1000 / 30, -- how frequently does Noice need to check for ui updates? This has no effect when in blocking mode.
---@type NoiceConfigViews
views = {}, ---@see section on views
---@type NoiceRouteConfig[]
routes = {}, --- @see section on routes
---@type table<string, NoiceFilter>
status = {}, --- @see section on statusline components
---@type NoiceFormatOptions
format = {}, --- @see section on formatting
}
If you don't want to use a Nerd Font, you can replace the icons with Unicode symbols.
require("noice").setup({
cmdline = {
format = {
cmdline = { icon = ">" },
search_down = { icon = "πβ" },
search_up = { icon = "πβ" },
filter = { icon = "$" },
lua = { icon = "βΎ" },
help = { icon = "?" },
},
},
format = {
level = {
icons = {
error = "β",
warn = "βΌ",
info = "β",
},
},
},
popupmenu = {
kind_icons = false,
},
inc_rename = {
cmdline = {
format = {
IncRename = { icon = "β³" },
},
},
},
})
Noice uses filters to route messages to specific views.
Name | Type | Description |
---|---|---|
any | filter[] |
checks that at least one of the filters matches |
blocking | boolean |
are we in blocking mode? |
cleared | boolean |
checks if the message is cleared, meaning it's in the history |
cmdline | boolean or string |
checks if the message was generated by executing a cmdline. When string , then it is used as a pattern |
error | boolean |
all error-like kinds from ext_messages |
event | string or string[] |
any of the events from ext_messages or cmdline . See :h ui-messages |
find | string |
uses lua string.find to match the pattern |
has | boolean |
checks if the message is exists, meaning it's in the history |
kind | string or string[] |
any of the kinds from ext_messages . See :h ui-messages |
max_height | number |
maximum height of the message |
max_length | number |
maximum length of the message (total width of all the lines) |
max_width | number |
maximum width of the message |
min_height | number |
minimum height of the message |
min_length | number |
minimum length of the message (total width of all the lines) |
min_width | number |
minimum width of the message |
mode | string |
checks if vim.api.nvim_get_mode() contains the given mode |
not | filter |
checks whether the filter matches or not |
warning | boolean |
all warning-like kinds from ext_messages |
Example:
-- all messages over 10 lines, excluding echo and search_count
local filter = {
event = "msg_show",
min_height = 10,
["not"] = { kind = { "search_count", "echo" } },
}
Noice comes with the following built-in backends:
- popup: powered by nui.nvim
- split: powered by nui.nvim
- notify: powered by nvim-notify
- virtualtext: shows the message as virtualtext (for example for
search_count
) - mini: similar to notifier.nvim & fidget.nvim
- notify_send: generate a desktop notification
A View (config.views
) is a combination of a backend
and options.
Noice comes with the following built-in views with sane defaults:
View | Backend | Description |
---|---|---|
notify | notify |
nvim-notify with level=nil , replace=false , merge=false |
split | split |
horizontal split |
vsplit | split |
vertical split |
popup | popup |
simple popup |
mini | mini |
minimal view, by default bottom right, right-aligned |
cmdline | popup |
bottom line, similar to the classic cmdline |
cmdline_popup | popup |
fancy cmdline popup, with different styles according to the cmdline mode |
cmdline_output | split |
split used by config.presets.cmdline_output_to_split |
messages | split |
split used for :messages |
confirm | popup |
popup used for confirm events |
hover | popup |
popup used for lsp signature help and hover |
popupmenu | nui.menu |
special view with the options used to render the popupmenu when backend is nui |
Please refer to noice.config.views
to see the options.
Any options passed to existing views in config.views
, will override those options only.
You can configure completely new views and use them in custom routes.
Example:
-- override the default split view to always enter the split when it opens
require("noice").setup({
views = {
split = {
enter = true,
},
},
})
All built-in Noice views have the filetype
noice
See the Nui documentation for Popup and Split.
Option | Description |
size, position | Size, position and their constituents can additionally be specified as "auto", to use the message height and width. |
win_options.winhighlight |
String or can also be a table like:
{
win_options = {
winhighlight = {
Normal = "NormalFloat",
FloatBorder = "FloatBorder"
},
}
} |
scrollbar | Set to false to hide the scrollbar. |
Option | Type | Default | Description |
---|---|---|---|
title | string |
"Notification" |
title to be used for the notification. Uses Message.title if available. |
replace | boolean |
false |
when true, messages routing to the same notify instance will replace existing messages instead of pushing a new notification every time |
merge | boolean |
false |
Merge messages into one Notification or create separate notifications |
level | number|string |
nil |
notification level. Uses Message.level if available. |
Right now there's only an option to set the hl_group
used to render the virtual text.
Formatting options can be specified with config.format
.
For a list of the defaults, please refer to config.format
Noice includes the following formatters:
- level: message level with optional
icon
andhl_group
per level - text: any text with optional
hl_group
- title: message title with optional
hl_group
- event: message event with optional
hl_group
- kind: message kind with optional
hl_group
- date: formatted date with optional date format string
- message: message content itself with optional
hl_group
to override message highlights - confirm: only useful for
confirm
messages. Will format the choices as buttons. - cmdline: will render the cmdline in the message that generated the message.
- progress: progress bar used by lsp progress
- spinner: spinners used by lsp progress
- data: render any custom data from
Message.opts
. Useful in combination with the opts passed tovim.notify
Formatters are used in format
definitions. Noice includes the following built-in formats:
{
-- default format
default = { "{level} ", "{title} ", "{message}" },
-- default format for vim.notify views
notify = { "{message}" },
-- default format for the history
details = {
"{level} ",
"{date} ",
"{event}",
{ "{kind}", before = { ".", hl_group = "NoiceFormatKind" } },
" ",
"{title} ",
"{cmdline} ",
"{message}",
},
telescope = ..., -- formatter used to display telescope results
telescope_preview = ..., -- formatter used to preview telescope results
lsp_progress = ..., -- formatter used by lsp progress
lsp_progress_done = ..., -- formatter used by lsp progress
}
Text before/after the formatter or in the before/after options, will only be rendered if the formatter itself rendered something.
The format
view option, can be either a string
(one of the built-in formats), or a table with a custom format definition.
To align text, you can use the align
option for a view. Can be center
, left
or right
.
A route has a filter
, view
and optional opts
attribute.
- view: one of the views (built-in or custom)
- filter a filter for messages matching this route
- opts: options for the view and the route
Route options can be any of the view options above, or one of:
Option | Type | Default | Description |
---|---|---|---|
skip | boolean |
false |
messages matching this filter will be skipped and not shown in any views |
stop | boolean |
true |
When false and a route matches the filter, then other routes can still process the message too. Useful if you want certain messages to be shown in multiple views. |
Please refer to noice.config.routes
for an overview of the default routes.
Routes passed to setup()
will be prepended to the default routes.
Example
-- skip search_count messages instead of showing them as virtual text
require("noice").setup({
routes = {
{
filter = { event = "msg_show", kind = "search_count" },
opts = { skip = true },
},
},
})
-- always route any messages with more than 20 lines to the split view
require("noice").setup({
routes = {
{
view = "split",
filter = { event = "msg_show", min_height = 20 },
},
},
})
Noice comes with the following statusline components:
- ruler
- message: last line of the last message (
event=show_msg
) - command:
showcmd
- mode:
showmode
(@recording messages) - search: search count messages
See noice.config.status for the default config.
You can add custom statusline components in setup under the status
key.
Statusline components have the following methods:
- get: gets the content of the message without highlights
- get_hl: gets the content of the message with highlights
- has: checks if the component is available
Example of configuring lualine.nvim
require("lualine").setup({
sections = {
lualine_x = {
{
require("noice").api.status.message.get_hl,
cond = require("noice").api.status.message.has,
},
{
require("noice").api.status.command.get,
cond = require("noice").api.status.command.has,
color = { fg = "#ff9e64" },
},
{
require("noice").api.status.mode.get,
cond = require("noice").api.status.mode.has,
color = { fg = "#ff9e64" },
},
{
require("noice").api.status.search.get,
cond = require("noice").api.status.search.has,
color = { fg = "#ff9e64" },
},
},
},
})
In order to use Noice in Telescope, you can either do :Noice telescope
,
or register the extension and use :Telescope noice
.
The results panel is formatted using config.format.formatters.telescope
. The preview is formatted with config.format.formatters.telescope_preview
require("telescope").load_extension("noice")
:Noice
or:Noice history
shows the message history:Noice last
shows the last message in a popup:Noice dismiss
dismiss all visible messages:Noice errors
shows the error messages in a split. Last errors on top:Noice disable
disables Noice:Noice enable
enables Noice:Noice stats
shows debugging stats:Noice telescope
opens message history in Telescope
Alternatively, all commands also exist as a full name like :NoiceLast
, :NoiceDisable
.
You can also use Lua
equivalents.
vim.keymap.set("n", "<leader>nl", function()
require("noice").cmd("last")
end)
vim.keymap.set("n", "<leader>nh", function()
require("noice").cmd("history")
end)
You can add custom commands with
config.commands
Sometimes it's useful to redirect the messages generated by a command or function to a different view. That can be easily achieved with command redirection.
The redirect API can taken an optional routes
parameter, which defaults to {config.redirect}
.
-- redirect ":hi"
require("noice").redirect("hi")
-- redirect some function
require("noice").redirect(function()
print("test")
end)
Adding the following keymap, will redirect the active cmdline when pressing <S-Enter>
.
The cmdline stays open, so you can change the command and execute it again.
When exiting the cmdline, the popup window will be focused.
vim.keymap.set("c", "<S-Enter>", function()
require("noice").redirect(vim.fn.getcmdline())
end, { desc = "Redirect Cmdline" })
vim.keymap.set({ "n", "i", "s" }, "<c-f>", function()
if not require("noice.lsp").scroll(4) then
return "<c-f>"
end
end, { silent = true, expr = true })
vim.keymap.set({ "n", "i", "s" }, "<c-b>", function()
if not require("noice.lsp").scroll(-4) then
return "<c-b>"
end
end, { silent = true, expr = true })
Click to see all highlight groups
Highlight Group | Default Group | Description |
---|---|---|
NoiceCmdline | MsgArea | Normal for the classic cmdline area at the bottom" |
NoiceCmdlineIcon | DiagnosticSignInfo | Cmdline icon |
NoiceCmdlineIconCalculator | NoiceCmdlineIcon | |
NoiceCmdlineIconCmdline | NoiceCmdlineIcon | |
NoiceCmdlineIconFilter | NoiceCmdlineIcon | |
NoiceCmdlineIconHelp | NoiceCmdlineIcon | |
NoiceCmdlineIconIncRename | NoiceCmdlineIcon | |
NoiceCmdlineIconInput | NoiceCmdlineIcon | |
NoiceCmdlineIconLua | NoiceCmdlineIcon | |
NoiceCmdlineIconSearch | DiagnosticSignWarn | Cmdline search icon (/ and ? ) |
NoiceCmdlinePopup | Normal | Normal for the cmdline popup |
NoiceCmdlinePopupBorder | DiagnosticSignInfo | Cmdline popup border |
NoiceCmdlinePopupBorderCalculator | NoiceCmdlinePopupBorder | |
NoiceCmdlinePopupBorderCmdline | NoiceCmdlinePopupBorder | |
NoiceCmdlinePopupBorderFilter | NoiceCmdlinePopupBorder | |
NoiceCmdlinePopupBorderHelp | NoiceCmdlinePopupBorder | |
NoiceCmdlinePopupBorderIncRename | NoiceCmdlinePopupBorder | |
NoiceCmdlinePopupBorderInput | NoiceCmdlinePopupBorder | |
NoiceCmdlinePopupBorderLua | NoiceCmdlinePopupBorder | |
NoiceCmdlinePopupBorderSearch | DiagnosticSignWarn | Cmdline popup border for search |
NoiceCmdlinePopupTitle | DiagnosticSignInfo | Cmdline popup border |
NoiceCmdlinePrompt | Title | prompt for input() |
NoiceCompletionItemKindClass | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindColor | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindConstant | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindConstructor | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindDefault | Special | |
NoiceCompletionItemKindEnum | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindEnumMember | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindField | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindFile | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindFolder | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindFunction | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindInterface | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindKeyword | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindMethod | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindModule | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindProperty | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindSnippet | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindStruct | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindText | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindUnit | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindValue | NoiceCompletionItemKindDefault | |
NoiceCompletionItemKindVariable | NoiceCompletionItemKindDefault | |
NoiceCompletionItemMenu | none | Normal for the popupmenu |
NoiceCompletionItemWord | none | Normal for the popupmenu |
NoiceConfirm | Normal | Normal for the confirm view |
NoiceConfirmBorder | DiagnosticSignInfo | Border for the confirm view |
NoiceCursor | Cursor | Fake Cursor |
NoiceFormatConfirm | CursorLine | |
NoiceFormatConfirmDefault | Visual | |
NoiceFormatDate | Special | |
NoiceFormatEvent | NonText | |
NoiceFormatKind | NonText | |
NoiceFormatLevelDebug | NonText | |
NoiceFormatLevelError | DiagnosticVirtualTextError | |
NoiceFormatLevelInfo | DiagnosticVirtualTextInfo | |
NoiceFormatLevelOff | NonText | |
NoiceFormatLevelTrace | NonText | |
NoiceFormatLevelWarn | DiagnosticVirtualTextWarn | |
NoiceFormatProgressDone | Search | Progress bar done |
NoiceFormatProgressTodo | CursorLine | progress bar todo |
NoiceFormatTitle | Title | |
NoiceLspProgressClient | Title | Lsp progress client name |
NoiceLspProgressSpinner | Constant | Lsp progress spinner |
NoiceLspProgressTitle | NonText | Lsp progress title |
NoiceMini | MsgArea | Normal for mini view |
NoicePopup | NormalFloat | Normal for popup views |
NoicePopupBorder | FloatBorder | Border for popup views |
NoicePopupmenu | Pmenu | Normal for the popupmenu |
NoicePopupmenuBorder | FloatBorder | Popupmenu border |
NoicePopupmenuMatch | Special | Part of the item that matches the input |
NoicePopupmenuSelected | PmenuSel | Selected item in the popupmenu |
NoiceScrollbar | PmenuSbar | Normal for scrollbar |
NoiceScrollbarThumb | PmenuThumb | Scrollbar thumb |
NoiceSplit | NormalFloat | Normal for split views |
NoiceSplitBorder | FloatBorder | Border for split views |
NoiceVirtualText | DiagnosticVirtualTextInfo | Default hl group for virtualtext views |