mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-03 15:10:04 +08:00
208 lines
6.2 KiB
Lua
Vendored
208 lines
6.2 KiB
Lua
Vendored
local conf = require("telescope.config").values
|
|
local Path = require "plenary.path"
|
|
local utils = require "telescope.utils"
|
|
|
|
local uv = vim.loop
|
|
|
|
---@tag telescope.actions.history
|
|
---@config { ["module"] = "telescope.actions.history" }
|
|
|
|
---@brief [[
|
|
--- A base implementation of a prompt history that provides a simple history
|
|
--- and can be replaced with a custom implementation.
|
|
---
|
|
--- For example: We provide a extension for a smart history that uses sql.nvim
|
|
--- to map histories to metadata, like the calling picker or cwd.
|
|
---
|
|
--- So you have a history for:
|
|
--- - find_files project_1
|
|
--- - grep_string project_1
|
|
--- - live_grep project_1
|
|
--- - find_files project_2
|
|
--- - grep_string project_2
|
|
--- - live_grep project_2
|
|
--- - etc
|
|
---
|
|
--- See https://github.com/nvim-telescope/telescope-smart-history.nvim
|
|
---@brief ]]
|
|
|
|
-- TODO(conni2461): currently not present in plenary path only sync.
|
|
-- But sync is just unnecessary here
|
|
local write_async = function(path, txt, flag)
|
|
uv.fs_open(path, flag, 438, function(open_err, fd)
|
|
assert(not open_err, open_err)
|
|
uv.fs_write(fd, txt, -1, function(write_err)
|
|
assert(not write_err, write_err)
|
|
uv.fs_close(fd, function(close_err)
|
|
assert(not close_err, close_err)
|
|
end)
|
|
end)
|
|
end)
|
|
end
|
|
|
|
local append_async = function(path, txt)
|
|
write_async(path, txt, "a")
|
|
end
|
|
|
|
local histories = {}
|
|
|
|
--- Manages prompt history
|
|
---@class History @Manages prompt history
|
|
---@field enabled boolean: Will indicate if History is enabled or disabled
|
|
---@field path string: Will point to the location of the history file
|
|
---@field limit string: Will have the limit of the history. Can be nil, if limit is disabled.
|
|
---@field content table: History table. Needs to be filled by your own History implementation
|
|
---@field index number: Used to keep track of the next or previous index. Default is #content + 1
|
|
histories.History = {}
|
|
histories.History.__index = histories.History
|
|
|
|
--- Create a new History
|
|
---@param opts table: Defines the behavior of History
|
|
---@field init function: Will be called after handling configuration (required)
|
|
---@field append function: How to append a new prompt item (required)
|
|
---@field reset function: What happens on reset. Will be called when telescope closes (required)
|
|
---@field pre_get function: Will be called before a next or previous item will be returned (optional)
|
|
function histories.History:new(opts)
|
|
local obj = {}
|
|
if conf.history == false or type(conf.history) ~= "table" then
|
|
obj.enabled = false
|
|
return setmetatable(obj, self)
|
|
end
|
|
obj.enabled = true
|
|
if conf.history.limit then
|
|
obj.limit = conf.history.limit
|
|
end
|
|
obj.path = vim.fn.expand(conf.history.path)
|
|
obj.content = {}
|
|
obj.index = 1
|
|
|
|
opts.init(obj)
|
|
obj._reset = opts.reset
|
|
obj._append = opts.append
|
|
obj._pre_get = opts.pre_get
|
|
|
|
return setmetatable(obj, self)
|
|
end
|
|
|
|
--- Shorthand to create a new history
|
|
function histories.new(...)
|
|
return histories.History:new(...)
|
|
end
|
|
|
|
--- Will reset the history index to the default initial state. Will happen after the picker closed
|
|
function histories.History:reset()
|
|
if not self.enabled then
|
|
return
|
|
end
|
|
self._reset(self)
|
|
end
|
|
|
|
--- Append a new line to the history
|
|
---@param line string: current line that will be appended
|
|
---@param picker table: the current picker object
|
|
---@param no_reset boolean: On default it will reset the state at the end. If you don't want to do this set to true
|
|
function histories.History:append(line, picker, no_reset)
|
|
if not self.enabled then
|
|
return
|
|
end
|
|
self._append(self, line, picker, no_reset)
|
|
end
|
|
|
|
--- Will return the next history item. Can be nil if there are no next items
|
|
---@param line string: the current line
|
|
---@param picker table: the current picker object
|
|
---@return string: the next history item
|
|
function histories.History:get_next(line, picker)
|
|
if not self.enabled then
|
|
utils.notify("History:get_next", {
|
|
msg = "You are cycling to next the history item but history is disabled. Read ':help telescope.defaults.history'",
|
|
level = "WARN",
|
|
})
|
|
return false
|
|
end
|
|
if self._pre_get then
|
|
self._pre_get(self, line, picker)
|
|
end
|
|
|
|
local next_idx = self.index + 1
|
|
if next_idx <= #self.content then
|
|
self.index = next_idx
|
|
return self.content[next_idx]
|
|
end
|
|
self.index = #self.content + 1
|
|
return nil
|
|
end
|
|
|
|
--- Will return the previous history item. Can be nil if there are no previous items
|
|
---@param line string: the current line
|
|
---@param picker table: the current picker object
|
|
---@return string: the previous history item
|
|
function histories.History:get_prev(line, picker)
|
|
if not self.enabled then
|
|
utils.notify("History:get_prev", {
|
|
msg = "You are cycling to next the history item but history is disabled. Read ':help telescope.defaults.history'",
|
|
level = "WARN",
|
|
})
|
|
return false
|
|
end
|
|
if self._pre_get then
|
|
self._pre_get(self, line, picker)
|
|
end
|
|
|
|
local next_idx = self.index - 1
|
|
if self.index == #self.content + 1 then
|
|
if line ~= "" then
|
|
self:append(line, picker, true)
|
|
end
|
|
end
|
|
if next_idx >= 1 then
|
|
self.index = next_idx
|
|
return self.content[next_idx]
|
|
end
|
|
return nil
|
|
end
|
|
|
|
--- A simple implementation of history.
|
|
---
|
|
--- It will keep one unified history across all pickers.
|
|
histories.get_simple_history = function()
|
|
return histories.new {
|
|
init = function(obj)
|
|
local p = Path:new(obj.path)
|
|
if not p:exists() then
|
|
p:touch { parents = true }
|
|
end
|
|
|
|
obj.content = Path:new(obj.path):readlines()
|
|
obj.index = #obj.content
|
|
table.remove(obj.content, obj.index)
|
|
end,
|
|
reset = function(self)
|
|
self.index = #self.content + 1
|
|
end,
|
|
append = function(self, line, _, no_reset)
|
|
if line ~= "" then
|
|
if self.content[#self.content] ~= line then
|
|
table.insert(self.content, line)
|
|
|
|
local len = #self.content
|
|
if self.limit and len > self.limit then
|
|
local diff = len - self.limit
|
|
for i = diff, 1, -1 do
|
|
table.remove(self.content, i)
|
|
end
|
|
write_async(self.path, table.concat(self.content, "\n") .. "\n", "w")
|
|
else
|
|
append_async(self.path, line .. "\n")
|
|
end
|
|
end
|
|
end
|
|
if not no_reset then
|
|
self:reset()
|
|
end
|
|
end,
|
|
}
|
|
end
|
|
|
|
return histories
|