Regenerate nvim config
This commit is contained in:
@ -0,0 +1,84 @@
|
||||
local actions = require("telescope.actions")
|
||||
local actions_state = require("telescope.actions.state")
|
||||
|
||||
local function _get_default_register()
|
||||
local clipboardFlags = vim.split(vim.api.nvim_get_option("clipboard"), ",")
|
||||
if vim.tbl_contains(clipboardFlags, "unnamedplus") then
|
||||
return "+"
|
||||
end
|
||||
if vim.tbl_contains(clipboardFlags, "unnamed") then
|
||||
return "*"
|
||||
end
|
||||
return '"'
|
||||
end
|
||||
|
||||
-- TODO maybe provide actions for the following:
|
||||
-- * yank to arbitrary registers
|
||||
-- * open state in new file
|
||||
-- * rewind to last saved state
|
||||
-- * goto lastest undo state
|
||||
-- * something with git staging?
|
||||
local myactions = {}
|
||||
|
||||
-- these actions are returning named functions with the prompt_bufnr en-closured so that their metatable contains a name that telescope which-key can use
|
||||
myactions.restore = function(prompt_bufnr)
|
||||
local function restore()
|
||||
-- makes the selected undo state the buffers current state
|
||||
local entry = actions_state.get_selected_entry()
|
||||
if entry ~= nil then
|
||||
vim.api.nvim_buf_call(entry.value.bufnr, function()
|
||||
vim.cmd("undo " .. entry.value.seq)
|
||||
end)
|
||||
actions.close(prompt_bufnr)
|
||||
end
|
||||
end
|
||||
return restore
|
||||
end
|
||||
|
||||
myactions.yank_deletions = function(prompt_bufnr)
|
||||
local function yank_deletions()
|
||||
-- yanks the deletions from the currently selected undo state into the default register
|
||||
local entry = actions_state.get_selected_entry()
|
||||
if entry ~= nil then
|
||||
vim.fn.setreg(_get_default_register(), entry.value.deletions, (#entry.value.deletions > 1) and "V" or "v")
|
||||
actions.close(prompt_bufnr)
|
||||
return entry.value.deletions
|
||||
end
|
||||
end
|
||||
return yank_deletions
|
||||
end
|
||||
|
||||
myactions.yank_additions = function(prompt_bufnr)
|
||||
local function yank_additions()
|
||||
-- yanks the additions from the currently selected undo state into the default register
|
||||
local entry = actions_state.get_selected_entry()
|
||||
if entry ~= nil then
|
||||
vim.fn.setreg(_get_default_register(), entry.value.additions, (#entry.value.additions > 1) and "V" or "v")
|
||||
actions.close(prompt_bufnr)
|
||||
return entry.value.additions
|
||||
end
|
||||
end
|
||||
return yank_additions
|
||||
end
|
||||
|
||||
myactions.yank_larger = function(prompt_bufnr)
|
||||
local function yank_larger()
|
||||
-- yanks the additions from the currently selected undo state into the default register
|
||||
local entry = actions_state.get_selected_entry()
|
||||
if entry == nil then
|
||||
return
|
||||
end
|
||||
if #entry.value.additions >= #entry.value.deletions then
|
||||
vim.fn.setreg(_get_default_register(), entry.value.additions, (#entry.value.additions > 1) and "V" or "v")
|
||||
actions.close(prompt_bufnr)
|
||||
return entry.value.additions
|
||||
else
|
||||
vim.fn.setreg(_get_default_register(), entry.value.deletions, (#entry.value.deletions > 1) and "V" or "v")
|
||||
actions.close(prompt_bufnr)
|
||||
return entry.value.deletions
|
||||
end
|
||||
end
|
||||
return yank_larger
|
||||
end
|
||||
|
||||
return myactions
|
||||
@ -0,0 +1,172 @@
|
||||
local finders = require("telescope.finders")
|
||||
local pickers = require("telescope.pickers")
|
||||
local conf = require("telescope.config").values
|
||||
|
||||
require("telescope-undo.previewer")
|
||||
require("telescope-undo.actions")
|
||||
require("telescope-undo.lua-timeago")
|
||||
|
||||
local function _traverse_undotree(opts, entries, level)
|
||||
local undolist = {}
|
||||
-- create diffs for each entry in our undotree
|
||||
for i = #entries, 1, -1 do
|
||||
if opts.saved_only ~= nil and opts.saved_only and entries[i].save == nil then
|
||||
goto continue
|
||||
end
|
||||
-- grab the buffer as it is after this iteration's undo state
|
||||
vim.cmd("silent undo " .. entries[i].seq)
|
||||
local buffer_after_lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) or {}
|
||||
local buffer_after = table.concat(buffer_after_lines, "\n")
|
||||
|
||||
-- grab the buffer as it is after this undo state's parent
|
||||
vim.cmd("silent undo")
|
||||
local buffer_before_lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) or {}
|
||||
local buffer_before = table.concat(buffer_before_lines, "\n")
|
||||
|
||||
-- build diff header so that delta can go ahead and syntax highlight
|
||||
local filename = vim.fn.expand("%")
|
||||
local header = filename .. "\n--- " .. filename .. "\n+++ " .. filename .. "\n"
|
||||
|
||||
-- do the diff using our internal diff function
|
||||
local diff = vim.diff(buffer_before, buffer_after, {
|
||||
algorithm = "patience",
|
||||
ctxlen = opts.diff_context_lines or 0,
|
||||
})
|
||||
|
||||
-- extract data for yanking and searching
|
||||
local ordinal = ""
|
||||
local additions = {}
|
||||
local deletions = {}
|
||||
for line in (diff .. "\n"):gmatch("(.-)\n") do
|
||||
if line:sub(1, 1) == "+" then
|
||||
local content = line:sub(2, -1)
|
||||
table.insert(additions, content)
|
||||
ordinal = ordinal .. content
|
||||
elseif line:sub(1, 1) == "-" then
|
||||
local content = line:sub(2, -1)
|
||||
table.insert(deletions, content)
|
||||
ordinal = ordinal .. content
|
||||
end
|
||||
end
|
||||
|
||||
-- use the data we just created to feed into our finder later
|
||||
table.insert(undolist, {
|
||||
seq = entries[i].seq, -- save state number, used in display and to restore
|
||||
alt = level, -- current level, i.e. how deep into alt branches are we, used to graph
|
||||
first = i == #entries, -- whether this is the first node in this branch, used to graph
|
||||
time = entries[i].time, -- save state time, used in display
|
||||
ordinal = ordinal, -- a long string of all additions and deletions, used for search
|
||||
diff = header .. diff, -- the proper diff, used for preview
|
||||
additions = additions, -- all additions, used to yank a result
|
||||
deletions = deletions, -- all deletions, used to yank a result
|
||||
bufnr = vim.api.nvim_get_current_buf(), -- for which buffer this telescope was invoked, used to restore
|
||||
})
|
||||
|
||||
-- descend recursively into alternate histories of undo states
|
||||
if entries[i].alt ~= nil then
|
||||
local alt_undolist = _traverse_undotree(opts, entries[i].alt, level + 1)
|
||||
-- pretend these results are our results
|
||||
for _, elem in pairs(alt_undolist) do
|
||||
table.insert(undolist, elem)
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
return undolist
|
||||
end
|
||||
|
||||
local function build_undolist(opts)
|
||||
-- save our current cursor
|
||||
local cursor = vim.api.nvim_win_get_cursor(0)
|
||||
|
||||
-- get all diffs
|
||||
local ut = vim.fn.undotree()
|
||||
|
||||
-- TODO: maybe use this opportunity to limit the number of root nodes we process overall, to ensure good performance
|
||||
local undolist = _traverse_undotree(opts, ut.entries, 0)
|
||||
|
||||
-- restore everything after all diffs have been created
|
||||
-- BUG: `gi` (last insert location) is being killed by our method, we should save that as well
|
||||
vim.cmd("silent undo " .. ut.seq_cur)
|
||||
vim.api.nvim_win_set_cursor(0, cursor)
|
||||
|
||||
return undolist
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
M.undo = function(opts)
|
||||
if not vim.api.nvim_buf_get_option(0, "modifiable") then
|
||||
print("telescope-undo.nvim: Current buffer is not modifiable.")
|
||||
return
|
||||
end
|
||||
opts = opts or {}
|
||||
pickers
|
||||
.new(opts, {
|
||||
prompt_title = "Undo History",
|
||||
finder = finders.new_table({
|
||||
results = build_undolist(opts),
|
||||
entry_maker = function(undo)
|
||||
local order = require("telescope.config").values.sorting_strategy
|
||||
|
||||
-- TODO: show a table instead of a list
|
||||
if #undo.additions + #undo.deletions == 0 then
|
||||
-- skip empty changes, vim has these sometimes...
|
||||
return nil
|
||||
end
|
||||
-- the following prefix should work out to this graph structure:
|
||||
-- state #1
|
||||
-- └─state #2
|
||||
-- state #3
|
||||
-- ├─state #4
|
||||
-- └─state #5
|
||||
-- state #6
|
||||
-- ├─state #7
|
||||
-- ┆ ├─state #8
|
||||
-- ┆ └─state #9
|
||||
-- └─state #10
|
||||
local prefix = ""
|
||||
if undo.alt > 0 then
|
||||
prefix = string.rep("┆ ", undo.alt - 1)
|
||||
if undo.first then
|
||||
local corner = order == "ascending" and "┌" or "└"
|
||||
prefix = prefix .. corner .. "╴"
|
||||
else
|
||||
prefix = prefix .. "├╴"
|
||||
end
|
||||
end
|
||||
local diffstat = ""
|
||||
if #undo.additions > 0 then
|
||||
diffstat = "+" .. #undo.additions
|
||||
end
|
||||
if #undo.deletions > 0 then
|
||||
if diffstat ~= "" then
|
||||
diffstat = diffstat .. " "
|
||||
end
|
||||
diffstat = "-" .. #undo.deletions
|
||||
end
|
||||
local formatted_time = opts.time_format == "" and timeago(undo.time) or os.date(opts.time_format, undo.time)
|
||||
return {
|
||||
value = undo,
|
||||
display = prefix
|
||||
.. opts.entry_format:gsub("$ID", undo.seq):gsub("$STAT", diffstat):gsub("$TIME", formatted_time),
|
||||
ordinal = undo.ordinal,
|
||||
}
|
||||
end,
|
||||
}),
|
||||
previewer = get_previewer(opts),
|
||||
sorter = conf.generic_sorter(opts),
|
||||
attach_mappings = function(prompt_bufnr, map)
|
||||
for _, mode in pairs({ "i", "n" }) do
|
||||
for key, get_action in pairs(opts.mappings[mode] or {}) do
|
||||
map(mode, key, get_action(prompt_bufnr))
|
||||
end
|
||||
end
|
||||
-- TODO: provide means to filter for time frames
|
||||
return true -- include defaults as well
|
||||
end,
|
||||
})
|
||||
:find()
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,72 @@
|
||||
-- This file is subject to LGPL-2.1 and installed from:
|
||||
-- https://github.com/f-person/lua-timeago
|
||||
--
|
||||
-- TODO: Understand lua require weirdness and properly include this as a git submodule
|
||||
|
||||
local language = {
|
||||
justnow = "just now",
|
||||
minute = { singular = "a minute ago", plural = "minutes ago" },
|
||||
hour = { singular = "an hour ago", plural = "hours ago" },
|
||||
day = { singular = "a day ago", plural = "days ago" },
|
||||
week = { singular = "a week ago", plural = "weeks ago" },
|
||||
month = { singular = "a month ago", plural = "months ago" },
|
||||
year = { singular = "a year ago", plural = "years ago" },
|
||||
}
|
||||
|
||||
local function round(num)
|
||||
return math.floor(num + 0.5)
|
||||
end
|
||||
|
||||
function timeago(time)
|
||||
local now = os.time()
|
||||
local diff_seconds = os.difftime(now, time)
|
||||
if diff_seconds < 45 then
|
||||
return language.justnow
|
||||
end
|
||||
|
||||
local diff_minutes = diff_seconds / 60
|
||||
if diff_minutes < 1.5 then
|
||||
return language.minute.singular
|
||||
end
|
||||
if diff_minutes < 59.5 then
|
||||
return round(diff_minutes) .. " " .. language.minute.plural
|
||||
end
|
||||
|
||||
local diff_hours = diff_minutes / 60
|
||||
if diff_hours < 1.5 then
|
||||
return language.hour.singular
|
||||
end
|
||||
if diff_hours < 23.5 then
|
||||
return round(diff_hours) .. " " .. language.hour.plural
|
||||
end
|
||||
|
||||
local diff_days = diff_hours / 24
|
||||
if diff_days < 1.5 then
|
||||
return language.day.singular
|
||||
end
|
||||
if diff_days < 7.5 then
|
||||
return round(diff_days) .. " " .. language.day.plural
|
||||
end
|
||||
|
||||
local diff_weeks = diff_days / 7
|
||||
if diff_weeks < 1.5 then
|
||||
return language.week.singular
|
||||
end
|
||||
if diff_weeks < 4.5 then
|
||||
return round(diff_weeks) .. " " .. language.week.plural
|
||||
end
|
||||
|
||||
local diff_months = diff_days / 30
|
||||
if diff_months < 1.5 then
|
||||
return language.month.singular
|
||||
end
|
||||
if diff_months < 11.5 then
|
||||
return round(diff_months) .. " " .. language.month.plural
|
||||
end
|
||||
|
||||
local diff_years = diff_days / 365.25
|
||||
if diff_years < 1.5 then
|
||||
return language.year.singular
|
||||
end
|
||||
return round(diff_years) .. " " .. language.year.plural
|
||||
end
|
||||
@ -0,0 +1,57 @@
|
||||
local previewers = require("telescope.previewers")
|
||||
local is_wsl = (function()
|
||||
local output = vim.fn.systemlist("uname -r")
|
||||
return not not string.find(output[1] or "", "WSL")
|
||||
end)()
|
||||
function get_previewer(opts)
|
||||
if opts.use_custom_command ~= nil then
|
||||
return previewers.new_termopen_previewer({
|
||||
get_command = function(entry, status)
|
||||
local difftext = entry.value.diff:gsub("'", [['"'"']])
|
||||
local shlexed = {}
|
||||
for i, part in ipairs(opts.use_custom_command) do
|
||||
shlexed[i] = part:gsub("$DIFF", difftext)
|
||||
end
|
||||
return shlexed
|
||||
end,
|
||||
})
|
||||
end
|
||||
local has_powershell = vim.fn.executable("powershell") == 1
|
||||
local has_bash = vim.fn.executable("bash") == 1
|
||||
if opts.use_delta and not is_wsl and (has_powershell or has_bash) and vim.fn.executable("delta") == 1 then
|
||||
return previewers.new_termopen_previewer({
|
||||
get_command = function(entry, status)
|
||||
local append = ""
|
||||
if opts.side_by_side == true then
|
||||
append = append .. " -s"
|
||||
end
|
||||
if has_powershell then
|
||||
return {
|
||||
"powershell",
|
||||
"-Command",
|
||||
"echo '" .. entry.value.diff:gsub([[']], [['']]) .. "' | delta" .. append,
|
||||
}
|
||||
elseif has_bash then
|
||||
return {
|
||||
"bash",
|
||||
"-c",
|
||||
"echo '" .. entry.value.diff:gsub("'", [['"'"']]) .. "' | delta" .. append,
|
||||
-- HACK: check out this escape method -----^
|
||||
}
|
||||
end
|
||||
end,
|
||||
})
|
||||
else
|
||||
return previewers.new_buffer_previewer({
|
||||
-- this is not the prettiest preview...
|
||||
define_preview = function(self, entry, status)
|
||||
vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, true, vim.split(entry.value.diff, "\n"))
|
||||
require("telescope.previewers.utils").highlighter(
|
||||
self.state.bufnr,
|
||||
"diff",
|
||||
{ preview = { treesitter = { enable = {} } } }
|
||||
)
|
||||
end,
|
||||
})
|
||||
end
|
||||
end
|
||||
@ -0,0 +1,57 @@
|
||||
local has_telescope, telescope = pcall(require, "telescope")
|
||||
if not has_telescope then
|
||||
error("telescope_undo.nvim requires telescope.nvim - https://github.com/nvim-telescope/telescope.nvim")
|
||||
end
|
||||
|
||||
-- full list of available config items and their defaults
|
||||
local defaults = {
|
||||
use_delta = true,
|
||||
use_custom_command = nil, -- should be in this format: { "bash", "-c", "echo '$DIFF' | delta" }
|
||||
side_by_side = false,
|
||||
diff_context_lines = vim.o.scrolloff,
|
||||
entry_format = "state #$ID, $STAT, $TIME",
|
||||
time_format = "",
|
||||
saved_only = false,
|
||||
mappings = {
|
||||
i = {
|
||||
["<cr>"] = require("telescope-undo.actions").yank_additions,
|
||||
["<S-cr>"] = require("telescope-undo.actions").yank_deletions,
|
||||
["<C-cr>"] = require("telescope-undo.actions").restore,
|
||||
-- alternative defaults, for users whose terminals do questionable things with modified <cr>
|
||||
["<C-y>"] = require("telescope-undo.actions").yank_deletions,
|
||||
["<C-r>"] = require("telescope-undo.actions").restore,
|
||||
},
|
||||
n = {
|
||||
["y"] = require("telescope-undo.actions").yank_additions,
|
||||
["Y"] = require("telescope-undo.actions").yank_deletions,
|
||||
["u"] = require("telescope-undo.actions").restore,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local M = {
|
||||
exports = {},
|
||||
}
|
||||
|
||||
M.exports.undo = function(config)
|
||||
config = vim.tbl_deep_extend("force", M.config, config or {})
|
||||
if config.theme then
|
||||
config = require("telescope.themes")["get_" .. config.theme](config)
|
||||
end
|
||||
require("telescope-undo").undo(config)
|
||||
end
|
||||
|
||||
M.setup = function(extension_config, telescope_config)
|
||||
M.config = vim.tbl_deep_extend("force", defaults, extension_config)
|
||||
-- Remove default keymaps that have been disabled by the user.
|
||||
for _, mode in ipairs({ "i", "n" }) do
|
||||
M.config.mappings[mode] = vim.tbl_map(function(val)
|
||||
return val ~= false and val or nil
|
||||
end, M.config.mappings[mode])
|
||||
end
|
||||
if M.config["side_by_side"] and not M.config["use_delta"] then
|
||||
error("telescope_undo.nvim: setting side_by_side but not use_delta will have no effect")
|
||||
end
|
||||
end
|
||||
|
||||
return telescope.register_extension(M)
|
||||
Reference in New Issue
Block a user