diff --git a/lua/noice/config/init.lua b/lua/noice/config/init.lua index 1c242b8..b025177 100644 --- a/lua/noice/config/init.lua +++ b/lua/noice/config/init.lua @@ -78,11 +78,14 @@ M.defaults = { hover = { enabled = false, view = "notify", + ---@type NoiceViewOptions opts = { lang = "markdown", replace = true, render = "plain", + format = { "{message}" }, buf_options = { iskeyword = '!-~,^*,^|,^",192-255', keywordprg = ":help" }, + win_options = { concealcursor = "n", conceallevel = 3 }, }, }, hl_patterns = { diff --git a/lua/noice/config/views.lua b/lua/noice/config/views.lua index eedeb78..7865ec2 100644 --- a/lua/noice/config/views.lua +++ b/lua/noice/config/views.lua @@ -87,7 +87,7 @@ M.defaults = { backend = "popup", close = { events = { "BufLeave" }, - keys = { "q", "" }, + keys = { "q" }, }, enter = true, border = { @@ -102,6 +102,17 @@ M.defaults = { winhighlight = { Normal = "NoicePopup", FloatBorder = "NoicePopupBorder" }, }, }, + hover = { + view = "popup", + relative = "cursor", + enter = false, + size = "auto", + border = { + style = "none", + padding = { 0, 2 }, + }, + position = { row = 1, col = 0 }, + }, cmdline = { backend = "popup", relative = "editor", diff --git a/lua/noice/source/lsp/format.lua b/lua/noice/source/lsp/format.lua index 78ba793..4c9fe9c 100644 --- a/lua/noice/source/lsp/format.lua +++ b/lua/noice/source/lsp/format.lua @@ -6,6 +6,17 @@ local Config = require("noice.config") local M = {} +---@type NoiceMessage[] +M._messages = {} + +function M.get(kind) + if not M._messages[kind] then + M._messages[kind] = Message("lsp", kind) + end + M._messages[kind]:clear() + return M._messages[kind] +end + ---@alias MarkedString string | { language: string; value: string } ---@alias MarkupContent { kind: ('plaintext' | 'markdown'), value: string} ---@alias MarkupContents MarkedString | MarkedString[] | MarkupContent @@ -43,8 +54,8 @@ function M.format(contents, kind) width = math.max(width, vim.api.nvim_strwidth(line)) end - local message = Message(M.event, kind) - message.once = true + local message = M.get(kind) + -- message.once = true message.opts.title = kind for _, line in ipairs(lines) do diff --git a/lua/noice/source/lsp/init.lua b/lua/noice/source/lsp/init.lua index 9342261..995d767 100644 --- a/lua/noice/source/lsp/init.lua +++ b/lua/noice/source/lsp/init.lua @@ -3,6 +3,7 @@ local require = require("noice.util.lazy") local Manager = require("noice.message.manager") local Config = require("noice.config") local Format = require("noice.source.lsp.format") +local Util = require("noice.util") local M = {} @@ -17,7 +18,7 @@ M.kinds = { function M.setup() if Config.options.lsp.hover.enabled then - vim.lsp.handlers["textDocument/hover"] = M.hover + vim.lsp.handlers["textDocument/hover"] = Util.protect(M.hover) end if Config.options.lsp.progress.enabled then require("noice.source.lsp.progress").setup() @@ -25,20 +26,42 @@ function M.setup() end ---@param message NoiceMessage -function M.close_on_move(message) +function M.auto_close(message) local open = true message.opts.timeout = 100 message.opts.keep = function() return open end - vim.api.nvim_create_autocmd("CursorMoved", { + + local group = vim.api.nvim_create_augroup("noice_lsp_" .. message.id, { + clear = true, + }) + + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI", "InsertCharPre" }, { + group = group, callback = function() - open = false + if not Util.buf_has_message(vim.api.nvim_get_current_buf(), message) then + pcall(vim.api.nvim_del_augroup_by_id, group) + Manager.remove(message) + open = false + end end, - once = true, }) end +---@param message NoiceMessage +function M.try_enter(message) + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if Util.buf_has_message(buf, message) then + local win = vim.fn.bufwinid(buf) + if win ~= -1 then + vim.api.nvim_set_current_win(win) + return true + end + end + end +end + function M.hover(_, result) if not (result and result.contents) then vim.notify("No information available") @@ -46,8 +69,10 @@ function M.hover(_, result) end local message = Format.format(result.contents, "hover") - M.close_on_move(message) - Manager.add(message) + if not M.try_enter(message) then + M.auto_close(message) + Manager.add(message) + end end return M diff --git a/lua/noice/types/nui.lua b/lua/noice/types/nui.lua index 9b19869..fa59c4d 100644 --- a/lua/noice/types/nui.lua +++ b/lua/noice/types/nui.lua @@ -21,8 +21,8 @@ ---@field timeout? number ---@field min_size? number ---@field max_size? number ----@field buf_options? table ----@field win_options? table +---@field buf_options? vim.bo +---@field win_options? vim.wo ---@field close? {events?:string[], keys?:string[]} ---@class NuiBaseOptions: _.NuiBaseOptions diff --git a/lua/noice/util/init.lua b/lua/noice/util/init.lua index 20f22ed..fd59bff 100644 --- a/lua/noice/util/init.lua +++ b/lua/noice/util/init.lua @@ -21,6 +21,11 @@ function M.once(fn) end end +---@param message NoiceMessage +function M.buf_has_message(buf, message) + return vim.b[buf].messages and vim.tbl_contains(vim.b[buf].messages, message.id) +end + function M.tag(buf, tag) local ft = vim.api.nvim_buf_get_option(buf, "filetype") diff --git a/lua/noice/view/backend/notify.lua b/lua/noice/view/backend/notify.lua index aa75c12..cdaf56e 100644 --- a/lua/noice/view/backend/notify.lua +++ b/lua/noice/view/backend/notify.lua @@ -132,7 +132,7 @@ function NotifyView:_notify(msg) return Util.is_blocking() end, on_open = function(win) - vim.api.nvim_win_set_option(win, "foldenable", false) + self:set_win_options(win) if self._opts.merge then self.win = win end diff --git a/lua/noice/view/init.lua b/lua/noice/view/init.lua index 5e60213..1e748b3 100644 --- a/lua/noice/view/init.lua +++ b/lua/noice/view/init.lua @@ -190,17 +190,20 @@ function View:content() ) end +function View:set_win_options(win) + vim.api.nvim_win_set_option(win, "winbar", "") + vim.api.nvim_win_set_option(win, "foldenable", false) + if self._opts.win_options then + require("nui.utils")._.set_win_options(win, self._opts.win_options) + end +end + ---@param buf number buffer number ---@param opts? {offset: number, highlight: boolean, messages?: NoiceMessage[]} line number (1-indexed), if `highlight`, then only highlight function View:render(buf, opts) opts = opts or {} local linenr = opts.offset or 1 - local win = vim.fn.bufwinid(buf) - if win ~= -1 then - vim.api.nvim_win_set_option(win, "winbar", "") - end - if self._opts.buf_options then require("nui.utils")._.set_buf_options(buf, self._opts.buf_options) end @@ -217,7 +220,12 @@ function View:render(buf, opts) vim.api.nvim_buf_set_lines(buf, linenr - 1, -1, false, {}) end + local buf_messages = vim.b[buf].messages or {} + for _, m in ipairs(opts.messages or self._messages) do + if not vim.tbl_contains(buf_messages, m.id) then + table.insert(buf_messages, m.id) + end if opts.highlight then m:highlight(buf, Config.ns, linenr) else @@ -225,6 +233,7 @@ function View:render(buf, opts) end linenr = linenr + m:height() end + vim.b[buf].messages = buf_messages end return View diff --git a/lua/noice/view/nui.lua b/lua/noice/view/nui.lua index e762823..19b11fd 100644 --- a/lua/noice/view/nui.lua +++ b/lua/noice/view/nui.lua @@ -184,6 +184,7 @@ function NuiView:show() end self._nui:show() + self:set_win_options(self._nui.winid) if not self._visible then self._nui:update_layout(self:get_layout()) self:smart_move()