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
- 📚
:Noicecommand to show a full message history - ⌨️ no more :h more-prompt
- 💻 fully customizable cmdline with icons
- 💅 syntax highlighting for
vimandluaon the cmdline - 🚥 statusline components
- 🔭 open message history in telescope.nvim
- Neovim >= 0.8.0
- nui.nvim: used for proper rendering and multiple views
- nvim-notify: notification view (optional)
- a Nerd Font (optional)
Install the plugin with your preferred package manager:
-- Packer
use({
"folke/noice.nvim",
event = "VimEnter",
config = function()
require("noice").setup()
end,
requires = {
-- 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",
}
})" 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.
{
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+", icon = "", lang = "lua" },
help = { pattern = "^:%s*h%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 = "split", -- 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
},
---@type table<string, NoiceCommand>
commands = {
history = {
-- options for the message history that you get with `:Noice`
view = "split",
opts = { enter = true, format = "details" },
filter = { event = { "msg_show", "notify" }, ["not"] = { kind = { "search_count", "echo" } } },
},
-- :Noice last
last = {
view = "popup",
opts = { enter = true, format = "details" },
filter = { event = { "msg_show", "notify" }, ["not"] = { kind = { "search_count", "echo" } } },
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",
},
hover = {
enabled = false,
view = nil, -- when nil, use defaults from documentation
---@type NoiceViewOptions
opts = {}, -- merged with defaults from documentation
},
signature = {
enabled = false,
auto_open = true, -- Automatically show signature help when typing a trigger character from the LSP
view = nil, -- when nil, use defaults from documentation
---@type NoiceViewOptions
opts = {}, -- merged with defaults from documentation
},
-- 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.
-- add any filetypes here, that shouldn't trigger smart move.
excluded_filetypes = { "cmp_menu", "cmp_docs", "notify" },
},
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 = "?" },
},
},
})Noice uses filters to route messages to specific views.
| Name | Type | Description |
|---|---|---|
| cleared | boolean |
checks if the message is cleared, meaning it's in the history |
| mode | string |
checks if vim.api.nvim_get_mode() contains the given mode |
| blocking | boolean |
are we in blocking mode? |
| event | string or string[] |
any of the events from ext_messages or cmdline. See :h ui-messages |
| kind | string or string[] |
any of the kinds from ext_messages. See :h ui-messages |
| error | boolean |
all error-like kinds from ext_messages |
| warning | boolean |
all warning-like kinds from ext_messages |
| find | string |
uses lua string.find to match the pattern |
| min_height | number |
minimum height of the message |
| max_height | number |
maximum height of the message |
| min_width | number |
minimum width of the message |
| max_width | number |
maximum width of the message |
| min_length | number |
minimum length of the message (total width of all the lines) |
| max_length | number |
maximum length of the message (total width of all the lines) |
| not | filter |
checks wether the filter matches or not |
| any | filter[] |
checks that at least one of the filters matches |
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
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=true, replace=true, merge=true |
| 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 |
| 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"
},
}
} |
| Option | Type | Default | Description |
|---|---|---|---|
| title | string |
nil |
title to be used for the notification. Uses Message.title if available. |
| replace | boolean |
true |
when true, messages routing to the same notify instance will replace existing messages instead of pushing a new notification every time |
| merge | boolean |
true |
Merge messages into one Notification or create separate notifications |
| level | number|string |
"info" |
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
iconandhl_groupper 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_groupto override message highlights - confirm: only useful for
confirmmessages. Will format the choices as buttons.
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 = "Comment" } },
" ",
"{title} ",
"{message}",
},
telescope = ..., -- formatter used to display telescope results
telescope_preview = ..., -- formatter used to preview telescope results
}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"):Noiceshows the message history:Noice disabledisables Noice:Noice enableenables Noice:Noice statsshows debugging stats:Noice telescopeopens message history in Telescope
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 |
| NoiceCmdlineIconCmdline | DiagnosticSignInfo | |
| NoiceCmdlineIconFilter | DiagnosticSignInfo | |
| NoiceCmdlineIconHelp | DiagnosticSignInfo | |
| NoiceCmdlineIconIncRename | DiagnosticSignInfo | |
| NoiceCmdlineIconInput | DiagnosticSignInfo | |
| NoiceCmdlineIconLua | DiagnosticSignInfo | |
| NoiceCmdlineIconSearch | DiagnosticSignWarn | Cmdline search icon (/ and ?) |
| NoiceCmdlinePopup | Normal | Normal for the cmdline popup |
| NoiceCmdlinePopupBorder | DiagnosticSignInfo | Cmdline popup border |
| NoiceCmdlinePopupBorderCmdline | DiagnosticSignInfo | |
| NoiceCmdlinePopupBorderFilter | DiagnosticSignInfo | |
| NoiceCmdlinePopupBorderHelp | DiagnosticSignInfo | |
| NoiceCmdlinePopupBorderIncRename | DiagnosticSignInfo | |
| NoiceCmdlinePopupBorderInput | DiagnosticSignInfo | |
| NoiceCmdlinePopupBorderLua | DiagnosticSignInfo | |
| NoiceCmdlinePopupBorderSearch | DiagnosticSignWarn | Cmdline popup border for search |
| 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 |
Noice is using the new experimental vim.ui_attach API, so issues are to be expected.
During setup, we apply a bunch of Hacks
to work around some of the current issues.
For more details, see this tracking issue
