feat: listeners for list actions

one thing to consider is if we want to add filtering to the listeners by
list?  or should we move the listeners to the list?
This commit is contained in:
mpaulson 2023-11-28 20:34:00 -07:00
parent b22cb4a873
commit 6fdff8bc41
5 changed files with 84 additions and 7 deletions

View File

@ -1,4 +1,6 @@
local utils = require("harpoon2.utils") local Listeners = require("harpoon2.listeners")
local listeners = Listeners.listeners
local M = {} local M = {}
---@alias HarpoonListItem {value: any, context: any} ---@alias HarpoonListItem {value: any, context: any}
@ -19,7 +21,6 @@ local M = {}
---@field width number ---@field width number
---@field height number ---@field height number
---notehunthoeunthoeunthoeunthoeunthoeunth ---notehunthoeunthoeunthoeunthoeunthoeunth
---@class HarpoonSettings ---@class HarpoonSettings
---@field save_on_toggle boolean defaults to true ---@field save_on_toggle boolean defaults to true
@ -31,7 +32,6 @@ local M = {}
---@field jump_to_file_location? boolean ---@field jump_to_file_location? boolean
---@field key? (fun(): string) ---@field key? (fun(): string)
---@class HarpoonConfig ---@class HarpoonConfig
---@field default HarpoonPartialConfigItem ---@field default HarpoonPartialConfigItem
---@field settings HarpoonSettings ---@field settings HarpoonSettings

View File

@ -2,6 +2,7 @@ local Ui = require("harpoon2.ui")
local Data = require("harpoon2.data") local Data = require("harpoon2.data")
local Config = require("harpoon2.config") local Config = require("harpoon2.config")
local List = require("harpoon2.list") local List = require("harpoon2.list")
local Listeners = require("harpoon2.listeners")
-- setup -- setup
-- read from a config file -- read from a config file
@ -14,6 +15,7 @@ local DEFAULT_LIST = "__harpoon_files"
---@class Harpoon ---@class Harpoon
---@field config HarpoonConfig ---@field config HarpoonConfig
---@field ui HarpoonUI ---@field ui HarpoonUI
---@field listeners HarpoonListeners
---@field data HarpoonData ---@field data HarpoonData
---@field lists {[string]: {[string]: HarpoonList}} ---@field lists {[string]: {[string]: HarpoonList}}
---@field hooks_setup boolean ---@field hooks_setup boolean
@ -29,6 +31,7 @@ function Harpoon:new()
config = config, config = config,
data = Data.Data:new(), data = Data.Data:new(),
ui = Ui:new(config.settings), ui = Ui:new(config.settings),
listeners = Listeners.listeners,
lists = {}, lists = {},
hooks_setup = false, hooks_setup = false,
}, self) }, self)

View File

@ -1,3 +1,5 @@
local Listeners = require("harpoon2.listeners")
local function index_of(items, element, config) local function index_of(items, element, config)
local equals = config and config.equals or function(a, b) return a == b end local equals = config and config.equals or function(a, b) return a == b end
local index = -1 local index = -1
@ -43,6 +45,7 @@ function HarpoonList:append(item)
local index = index_of(self.items, item, self.config) local index = index_of(self.items, item, self.config)
if index == -1 then if index == -1 then
Listeners.listeners:emit(Listeners.event_names.ADD, {list = self, item = item, idx = #self.items + 1})
table.insert(self.items, item) table.insert(self.items, item)
end end
@ -54,6 +57,7 @@ function HarpoonList:prepend(item)
item = item or self.config.add() item = item or self.config.add()
local index = index_of(self.items, item, self.config) local index = index_of(self.items, item, self.config)
if index == -1 then if index == -1 then
Listeners.listeners:emit(Listeners.event_names.ADD, {list = self, item = item, idx = 1})
table.insert(self.items, 1, item) table.insert(self.items, 1, item)
end end
@ -64,6 +68,7 @@ end
function HarpoonList:remove(item) function HarpoonList:remove(item)
for i, v in ipairs(self.items) do for i, v in ipairs(self.items) do
if self.config.equals(v, item) then if self.config.equals(v, item) then
Listeners.listeners:emit(Listeners.event_names.REMOVE, {list = self, item = item, idx = i})
table.remove(self.items, i) table.remove(self.items, i)
break break
end end
@ -73,6 +78,7 @@ end
---@return HarpoonList ---@return HarpoonList
function HarpoonList:removeAt(index) function HarpoonList:removeAt(index)
Listeners.listeners:emit(Listeners.event_names.REMOVE, {list = self, item = self.items[index], idx = index})
table.remove(self.items, index) table.remove(self.items, index)
return self return self
end end
@ -97,17 +103,25 @@ function HarpoonList:resolve_displayed(displayed)
local new_list = {} local new_list = {}
local list_displayed = self:display() local list_displayed = self:display()
for i, v in ipairs(list_displayed) do
local index = index_of(list_displayed, v)
if index == -1 then
Listeners.listeners:emit(Listeners.event_names.REMOVE, {list = self, item = v, idx = i})
end
end
for i, v in ipairs(displayed) do for i, v in ipairs(displayed) do
local index = index_of(list_displayed, v) local index = index_of(list_displayed, v)
if index == -1 then if index == -1 then
table.insert(new_list, self.config.add(v)) Listeners.listeners:emit(Listeners.event_names.ADD, {list = self, item = v, idx = i})
new_list[i] = self.config.add(v)
else else
local index_in_new_list = index_of(new_list, self.items[index], self.config) local index_in_new_list = index_of(new_list, self.items[index], self.config)
if index_in_new_list == -1 then if index_in_new_list == -1 then
table.insert(new_list, self.items[index]) new_list[i] = self.items[index]
end end
end end
end end
self.items = new_list self.items = new_list
@ -116,6 +130,7 @@ end
function HarpoonList:select(index, options) function HarpoonList:select(index, options)
local item = self.items[index] local item = self.items[index]
if item then if item then
Listeners.listeners:emit(Listeners.event_names.SELECT, {list = self, item = item, idx = index})
self.config.select(item, options) self.config.select(item, options)
end end
end end

View File

@ -0,0 +1,57 @@
---@alias HarpoonListener fun(type: string, args: any[] | any | nil): nil
---@class HarpoonListeners
---@field listeners (HarpoonListener)[]
---@field listenersByType (table<string, HarpoonListener>)[]
local HarpoonListeners = {}
HarpoonListeners.__index = HarpoonListeners
function HarpoonListeners:new()
return setmetatable({
listeners = {},
listenersByType = {}
}, self)
end
---@param cbOrType HarpoonListener | string
---@param cbOrNil HarpoonListener | string
function HarpoonListeners:add_listener(cbOrType, cbOrNil)
if (type(cbOrType) == "string") then
if not self.listenersByType[cbOrType] then
self.listenersByType[cbOrType] = {}
end
table.insert(self.listenersByType[cbOrType], cbOrNil)
else
table.insert(self.listeners, cbOrType)
end
end
function HarpoonListeners:clear_listeners()
self.listeners = {}
end
---@param type string
---@param args any[] | any | nil
function HarpoonListeners:emit(type, args)
for _, cb in ipairs(self.listeners) do
cb(type, args)
end
local listeners = self.listenersByType[type]
if listeners ~= nil then
for _, cb in ipairs(listeners) do
cb(type, args)
end
end
end
return {
listeners = HarpoonListeners:new(),
event_names = {
ADD = "ADD",
SELECT = "SELECT",
REMOVE = "REMOVE",
},
}

View File

@ -13,6 +13,9 @@ describe("harpoon", function()
local bufnr = harpoon.ui.bufnr local bufnr = harpoon.ui.bufnr
local win_id = harpoon.ui.win_id local win_id = harpoon.ui.win_id
eq(vim.api.nvim_buf_is_valid(bufnr), true)
eq(vim.api.nvim_win_is_valid(win_id), true)
harpoon.ui:toggle_quick_menu() harpoon.ui:toggle_quick_menu()
eq(vim.api.nvim_buf_is_valid(bufnr), false) eq(vim.api.nvim_buf_is_valid(bufnr), false)
@ -20,7 +23,6 @@ describe("harpoon", function()
eq(harpoon.ui.bufnr, nil) eq(harpoon.ui.bufnr, nil)
eq(harpoon.ui.win_id, nil) eq(harpoon.ui.win_id, nil)
end) end)
end) end)