diff --git a/README.md b/README.md index d380ca76..e79b73ac 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,9 @@ Install the plugin with your preferred package manager: use({ "folke/noice.nvim", config = function() - require("noice").setup() + require("noice").setup({ + -- add any options here + }) end, requires = { -- if you lazy-load any plugin below, make sure to add proper `module="..."` entries @@ -57,6 +59,30 @@ use({ }) ``` +Suggested setup: + +```lua +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, + }, + }, + -- 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 + cmdline_output_to_split = false, -- send the output of a command you executed in the cmdline to a split + }, +}) +``` + It's a good idea to run `:checkhealth noice` after installing to check for common issues.
vim-plug @@ -260,6 +286,7 @@ Check the [wiki](https://github.com/folke/noice.nvim/wiki/Configuration-Recipes) 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 + cmdline_output_to_split = false, -- send the output of a command you executed in the cmdline to a split }, throttle = 1000 / 30, -- how frequently does Noice need to check for ui updates? This has no effect when in blocking mode. ---@type NoiceConfigViews @@ -299,22 +326,24 @@ Check the [wiki](https://github.com/folke/noice.nvim/wiki/Configuration-Recipes) | 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 | +| **any** | `filter[]` | checks that at least one of the filters matches | | **blocking** | `boolean` | are we in blocking mode? | -| **event** | `string` or `string[]` | any of the events from `ext_messages` or `cmdline`. See [:h ui-messages](https://neovim.io/doc/user/ui.html#ui-messages) | -| **kind** | `string` or `string[]` | any of the kinds from `ext_messages`. See [:h ui-messages](https://neovim.io/doc/user/ui.html#ui-messages) | +| **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` | -| **warning** | `boolean` | all warning-like kinds from `ext_messages` | +| **event** | `string` or `string[]` | any of the events from `ext_messages` or `cmdline`. See [:h ui-messages](https://neovim.io/doc/user/ui.html#ui-messages) | | **find** | `string` | uses lua `string.find` to match the pattern | -| **min_height** | `number` | minimum height of the message | +| **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](https://neovim.io/doc/user/ui.html#ui-messages) | | **max_height** | `number` | maximum height of the message | -| **min_width** | `number` | minimum width 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) | -| **max_length** | `number` | maximum 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 wether the filter matches or not | -| **any** | `filter[]` | checks that at least one of the filters matches | +| **warning** | `boolean` | all warning-like kinds from `ext_messages` |
Example: @@ -340,20 +369,25 @@ local filter = { - **notify**: powered by [nvim-notify](https://github.com/rcarriga/nvim-notify) - **virtualtext**: shows the message as virtualtext (for example for `search_count`) - **mini**: similar to [notifier.nvim](https://github.com/vigoux/notifier.nvim) & [fidget.nvim](https://github.com/j-hui/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=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** | +| 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](https://github.com/folke/noice.nvim/blob/main/lua/noice/config/views.lua) to see the options. @@ -411,12 +445,12 @@ String or can also be a table like: ### Notify Options -| 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. | +| 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. | ### Virtual Text Options @@ -437,6 +471,10 @@ For a list of the defaults, please refer to [config.format](https://github.com/f - **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 to `vim.notify` Formatters are used in `format` definitions. **Noice** includes the following built-in formats: @@ -451,13 +489,16 @@ Formatters are used in `format` definitions. **Noice** includes the following bu "{level} ", "{date} ", "{event}", - { "{kind}", before = { ".", hl_group = "Comment" } }, + { "{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 } ``` diff --git a/lua/noice/config/cmdline.lua b/lua/noice/config/cmdline.lua index f143f781..4a64e701 100644 --- a/lua/noice/config/cmdline.lua +++ b/lua/noice/config/cmdline.lua @@ -25,9 +25,9 @@ function M.setup() kind = kind, icon_hl_group = "Noice" .. hl_group_icon, view = Config.options.cmdline.view, + lang = format.lang or format.ft, opts = { ---@diagnostic disable-next-line: undefined-field - lang = format.lang or format.ft, border = { text = { top = format.title or (" " .. kind_cc .. " "), diff --git a/lua/noice/config/format.lua b/lua/noice/config/format.lua index 80b08604..88f517e9 100644 --- a/lua/noice/config/format.lua +++ b/lua/noice/config/format.lua @@ -11,6 +11,7 @@ M.builtin = { { "{kind}", before = { ".", hl_group = "NoiceFormatKind" } }, " ", "{title} ", + "{cmdline} ", "{message}", }, telescope = { @@ -55,6 +56,8 @@ M.defaults = { debug = { enabled = true, }, + ---@class NoiceFormatOptions.cmdline + cmdline = {}, ---@class NoiceFormatOptions.level level = { hl_group = { diff --git a/lua/noice/config/init.lua b/lua/noice/config/init.lua index bb7b6f0c..efb2c512 100644 --- a/lua/noice/config/init.lua +++ b/lua/noice/config/init.lua @@ -186,6 +186,7 @@ function M.defaults() 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 + cmdline_output_to_split = false, -- send the output of a command you executed in the cmdline to a split }, throttle = 1000 / 30, -- how frequently does Noice need to check for ui updates? This has no effect when in blocking mode. ---@type NoiceConfigViews diff --git a/lua/noice/config/preset.lua b/lua/noice/config/preset.lua index 7fbb1963..000fd104 100644 --- a/lua/noice/config/preset.lua +++ b/lua/noice/config/preset.lua @@ -100,8 +100,7 @@ M.presets = { routes = { { filter = { event = "msg_show", min_height = 20 }, - view = "split", - opts = { enter = true }, + view = "cmdline_output", }, }, }, @@ -121,6 +120,14 @@ M.presets = { }, }, }, + cmdline_output_to_split = { + routes = { + { + view = "cmdline_output", + filter = { cmdline = "^:" }, + }, + }, + }, } return M diff --git a/lua/noice/config/views.lua b/lua/noice/config/views.lua index 3c8c05a0..445389d8 100644 --- a/lua/noice/config/views.lua +++ b/lua/noice/config/views.lua @@ -76,6 +76,10 @@ M.defaults = { wrap = true, }, }, + cmdline_output = { + format = "details", + view = "split", + }, messages = { view = "split", enter = true, diff --git a/lua/noice/message/filter.lua b/lua/noice/message/filter.lua index d8c00e6d..4fc2302b 100644 --- a/lua/noice/message/filter.lua +++ b/lua/noice/message/filter.lua @@ -8,24 +8,25 @@ local M = {} ---@alias NoiceFilterFun fun(message: NoiceMessage, ...): boolean ---@class NoiceFilter +---@field any? NoiceFilter[] +---@field blocking? boolean +---@field cleared? boolean +---@field cmdline? string|boolean +---@field error? boolean ---@field event? NoiceEvent|NoiceEvent[] +---@field find? string +---@field has? boolean ---@field kind? NoiceKind|NoiceKind[] ----@field message? NoiceMessage|NoiceMessage[] ----@field any? NoiceFilter[] ----@field not? NoiceFilter ----@field min_height? integer ---@field max_height? integer ----@field min_width? integer +---@field max_length? integer ---@field max_width? integer +---@field message? NoiceMessage|NoiceMessage[] +---@field min_height? integer ---@field min_length? integer ----@field max_length? integer ----@field find? string ----@field error? boolean ----@field has? boolean ----@field warning? boolean +---@field min_width? integer ---@field mode? string ----@field blocking? boolean ----@field cleared? boolean +---@field not? NoiceFilter +---@field warning? boolean -----@type table M.filters = { @@ -53,6 +54,18 @@ M.filters = { kind = type(kind) == "table" and kind or { kind } return vim.tbl_contains(kind, message.kind) end, + cmdline = function(message, cmdline) + ---@cast message NoiceMessage + ---@cast cmdline string|boolean + if type(cmdline) == "boolean" then + return (message.cmdline ~= nil) == cmdline + end + if message.cmdline then + local str = message.cmdline.state.firstc .. message.cmdline:get() + return str:find(cmdline) + end + return false + end, message = function(message, other) ---@cast message NoiceMessage other = vim.tbl_islist(other) and other or { other } diff --git a/lua/noice/message/init.lua b/lua/noice/message/init.lua index 64d73fa8..437fe894 100644 --- a/lua/noice/message/init.lua +++ b/lua/noice/message/init.lua @@ -14,6 +14,7 @@ local _id = 0 ---@field tick number ---@field level? NotifyLevel ---@field kind? NoiceKind +---@field cmdline? NoiceCmdline ---@field _debug? boolean ---@field opts table ---@overload fun(event: NoiceEvent, kind?: NoiceKind, content?: NoiceContent|NoiceContent[]): NoiceMessage diff --git a/lua/noice/text/block.lua b/lua/noice/text/block.lua index 567f3f73..49941777 100644 --- a/lua/noice/text/block.lua +++ b/lua/noice/text/block.lua @@ -8,7 +8,7 @@ local Object = require("nui.object") ---@alias NoiceContent string|NoiceChunk|NuiLine|NuiText|NoiceBlock ---@class NoiceBlock ----@field private _lines NuiLine[] +---@field _lines NuiLine[] ---@overload fun(content?: NoiceContent|NoiceContent[], highlight?: string|table): NoiceBlock local Block = Object("Block") diff --git a/lua/noice/text/format/formatters.lua b/lua/noice/text/format/formatters.lua index 471c0399..59aaec53 100644 --- a/lua/noice/text/format/formatters.lua +++ b/lua/noice/text/format/formatters.lua @@ -126,7 +126,7 @@ function M.debug(message, opts) vim.tbl_filter( ---@param t string function(t) - return t + return t ~= nil end, debug ), @@ -154,6 +154,14 @@ function M.spinner(message, opts) message:append(require("noice.util.spinners").spin(opts.name), opts.hl_group) end +---@param message NoiceMessage +---@param _opts NoiceFormatOptions.cmdline +function M.cmdline(message, _opts) + if message.cmdline then + message.cmdline:format(message, true) + end +end + ---@param message NoiceMessage ---@param input NoiceMessage ---@param opts NoiceFormatOptions.confirm diff --git a/lua/noice/ui/cmdline.lua b/lua/noice/ui/cmdline.lua index 5d211edc..0242c3ec 100644 --- a/lua/noice/ui/cmdline.lua +++ b/lua/noice/ui/cmdline.lua @@ -22,6 +22,9 @@ M.events = { block_hide = "cmdline_block_hide", } +---@type NoiceCmdline? +M.active = nil + ---@alias NoiceCmdlineFormatter fun(cmdline: NoiceCmdline): {icon?:string, offset?:number, view?:NoiceViewOptions} ---@class CmdlineState @@ -72,6 +75,7 @@ function Cmdline:get_format() end local line = self.state.firstc .. self:get() + ---@type table local formats = vim.tbl_values(vim.tbl_filter(function(f) return f.pattern end, Config.options.cmdline.format)) @@ -95,7 +99,8 @@ function Cmdline:get_format() end ---@param message NoiceMessage -function Cmdline:format(message) +---@param text_only? boolean +function Cmdline:format(message, text_only) local format = self:get_format() if format.icon then @@ -103,7 +108,9 @@ function Cmdline:format(message) message:append(" ") end - message.kind = format.kind + if not text_only then + message.kind = format.kind + end -- FIXME: prompt if self.state.prompt ~= "" then @@ -114,11 +121,19 @@ function Cmdline:format(message) message:append(self.state.firstc) end - message:append(self:get():sub(self.offset)) + local cmd = self:get():sub(self.offset) + + message:append(cmd) - local cursor = NoiceText.cursor(-self:length() + self.state.pos) - cursor.on_render = M.on_render - message:append(cursor) + if format.lang then + message:append(NoiceText.syntax(format.lang, 1, -vim.fn.strlen(cmd))) + end + + if not text_only then + local cursor = NoiceText.cursor(-self:length() + self.state.pos) + cursor.on_render = M.on_render + message:append(cursor) + end end function Cmdline:width() @@ -144,6 +159,7 @@ function M.on_show(event, content, pos, firstc, prompt, indent, level) }) local last = M.cmdlines[level] and M.cmdlines[level].state if not vim.deep_equal(c.state, last) then + M.active = c M.cmdlines[level] = c M.update() end @@ -152,6 +168,12 @@ end function M.on_hide(_, level) if M.cmdlines[level] then M.cmdlines[level] = nil + local active = M.active + vim.defer_fn(function() + if M.active == active then + M.active = nil + end + end, 100) M.update() end end diff --git a/lua/noice/ui/msg.lua b/lua/noice/ui/msg.lua index 99b536d3..77b5dad2 100644 --- a/lua/noice/ui/msg.lua +++ b/lua/noice/ui/msg.lua @@ -4,6 +4,7 @@ local Manager = require("noice.message.manager") local Message = require("noice.message") local Hacks = require("noice.util.hacks") local State = require("noice.ui.state") +local Cmdline = require("noice.ui.cmdline") local M = {} @@ -84,6 +85,7 @@ function M.on_show(event, kind, content, replace_last) Hacks.fix_nohlsearch() else message = Message(event, kind) + message.cmdline = Cmdline.active end message:set(content)