Skip to content

Commit c974bfb

Browse files
authored
feat(picker): support for fzf (#302)
1 parent 3a4e83e commit c974bfb

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

lua/notify/integrations/fzf.lua

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
local notify = require("notify")
2+
local time_format = notify._config().time_formats().notification
3+
4+
local builtin = require("fzf-lua.previewer.builtin")
5+
local fzf = require("fzf-lua")
6+
7+
local M = {}
8+
9+
---@alias NotifyMessage {id: number, message: notify.Record, texts: string[][]}
10+
---@alias NotifyEntry {ordinal: string, display: string}
11+
12+
---@param message NotifyMessage
13+
---@return NotifyEntry
14+
function M.entry(message)
15+
local display = message.id .. " " ---@type string
16+
local content = ""
17+
for _, text in ipairs(message.texts) do
18+
---@type string?
19+
local hl_group = text[2]
20+
display = display .. (hl_group and fzf.utils.ansi_from_hl(hl_group, text[1]) or text[1])
21+
content = content .. text[1]
22+
end
23+
24+
return {
25+
message = message.message,
26+
ordinal = content,
27+
display = display,
28+
}
29+
end
30+
31+
function M.find()
32+
local messages = notify.history()
33+
34+
---@type table<number, NotifyEntry>
35+
local ret = {}
36+
37+
for _, message in ipairs(messages) do
38+
ret[message.id] = M.entry({
39+
id = message.id,
40+
message = message,
41+
texts = {
42+
{ vim.fn.strftime(time_format, message.time) .. " ", "NotifyLogTime" },
43+
{ message.title[1] .. " ", "NotifyLogTitle" },
44+
{ message.icon .. " ", "Notify" .. message.level .. "Title" },
45+
{ message.level .. " ", "Notify" .. message.level .. "Title" },
46+
{ message.message[1], "Notify" .. message.level .. "Body" },
47+
},
48+
})
49+
end
50+
51+
return ret
52+
end
53+
54+
function M.parse_entry(messages, entry_str)
55+
local id = tonumber(entry_str:match("^%d+"))
56+
local entry = messages[id]
57+
return entry
58+
end
59+
60+
---@param messages table<number, NotifyEntry>
61+
function M.previewer(messages)
62+
local previewer = builtin.buffer_or_file:extend()
63+
64+
function previewer:new(o, opts, fzf_win)
65+
previewer.super.new(self, o, opts, fzf_win)
66+
self.title = "Message"
67+
setmetatable(self, previewer)
68+
return self
69+
end
70+
71+
function previewer:populate_preview_buf(entry_str)
72+
local buf = self:get_tmp_buffer()
73+
local entry = M.parse_entry(messages, entry_str)
74+
75+
if entry then
76+
local notification = entry.message
77+
notify.open(notification, { buffer = buf, max_width = 0 })
78+
end
79+
80+
self:set_preview_buf(buf)
81+
self.win:update_title(" Message ")
82+
self.win:update_scrollbar()
83+
self.win:set_winopts(self.win.preview_winid, { wrap = true })
84+
end
85+
86+
return previewer
87+
end
88+
89+
---@param opts? table<string, any>
90+
function M.open(opts)
91+
local messages = M.find()
92+
opts = vim.tbl_deep_extend("force", opts or {}, {
93+
prompt = false,
94+
winopts = {
95+
title = " Filter Notifications ",
96+
title_pos = "center",
97+
preview = {
98+
title = " Message ",
99+
title_pos = "center",
100+
},
101+
},
102+
previewer = M.previewer(messages),
103+
fzf_opts = {
104+
["--no-multi"] = "",
105+
["--with-nth"] = "2..",
106+
},
107+
actions = {
108+
default = function(selected)
109+
if #selected == 0 then
110+
return
111+
end
112+
local notification = M.parse_entry(messages, selected[1]).message
113+
114+
local opened_buffer = notify.open(notification)
115+
116+
local lines = vim.opt.lines:get()
117+
local cols = vim.opt.columns:get()
118+
119+
local win = vim.api.nvim_open_win(opened_buffer.buffer, true, {
120+
relative = "editor",
121+
row = (lines - opened_buffer.height) / 2,
122+
col = (cols - opened_buffer.width) / 2,
123+
height = opened_buffer.height,
124+
width = opened_buffer.width,
125+
border = "rounded",
126+
style = "minimal",
127+
})
128+
-- vim.wo does not behave like setlocal, thus we use setwinvar to set local
129+
-- only options. Otherwise our changes would affect subsequently opened
130+
-- windows.
131+
-- see e.g. neovim#14595
132+
vim.fn.setwinvar(
133+
win,
134+
"&winhl",
135+
"Normal:"
136+
.. opened_buffer.highlights.body
137+
.. ",FloatBorder:"
138+
.. opened_buffer.highlights.border
139+
)
140+
vim.fn.setwinvar(win, "&wrap", 0)
141+
end,
142+
},
143+
})
144+
local lines = vim.tbl_map(function(entry)
145+
return entry.display
146+
end, vim.tbl_values(messages))
147+
return fzf.fzf_exec(lines, opts)
148+
end
149+
150+
return M

lua/notify/integrations/init.lua

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
local M = {}
2+
3+
function M.pick()
4+
if pcall(_G.require, "telescope.config") then
5+
require("telescope").extensions.notify.noitfy({})
6+
elseif pcall(_G.require, "fzf-lua") then
7+
require("notify.integrations.fzf").open({})
8+
else
9+
error("No picker available")
10+
end
11+
end
12+
return M

0 commit comments

Comments
 (0)