From ba89b73127ad9a88cfcdb0aa15cb153f4026d7a2 Mon Sep 17 00:00:00 2001 From: Brian Mayo Date: Tue, 21 Nov 2023 18:03:10 +0000 Subject: [PATCH 1/6] feat: add formatting options as a list --- lua/diffview/config.lua | 116 ++++----- .../scene/views/file_history/render.lua | 222 ++++++++++-------- .../unit/file_history_commit_format_spec.lua | 152 ++++++++++++ 3 files changed, 325 insertions(+), 165 deletions(-) create mode 100644 lua/diffview/tests/unit/file_history_commit_format_spec.lua diff --git a/lua/diffview/config.lua b/lua/diffview/config.lua index 86922fe1..734c3205 100644 --- a/lua/diffview/config.lua +++ b/lua/diffview/config.lua @@ -96,6 +96,16 @@ M.defaults = { multi_file = {}, }, }, + commit_format = { + 'status', + 'stats', + 'hash', + 'reflog', + 'ref', + 'subject', + 'author', + 'date', + }, win_config = { position = "bottom", height = 16, @@ -334,9 +344,7 @@ M.log_option_defaults = { ---@return DiffviewConfig function M.get_config() - if not setup_done then - M.setup() - end + if not setup_done then M.setup() end return M._config end @@ -349,7 +357,7 @@ function M.get_log_options(single_file, t, vcs) local log_options if single_file then - log_options = M._config.file_history_panel.log_options[vcs].single_file + log_options = M._config.file_history_panel.log_options[vcs].single_file else log_options = M._config.file_history_panel.log_options[vcs].multi_file end @@ -358,9 +366,7 @@ function M.get_log_options(single_file, t, vcs) log_options = vim.tbl_extend("force", log_options, t) for k, _ in pairs(log_options) do - if t[k] == "" then - log_options[k] = nil - end + if t[k] == "" then log_options[k] = nil end end end @@ -409,9 +415,7 @@ end function M.find_option_keymap(t) for _, mapping in ipairs(t) do - if mapping[3] and mapping[3] == actions.options then - return mapping - end + if mapping[3] and mapping[3] == actions.options then return mapping end end end @@ -427,9 +431,13 @@ end ---@param no_quote? boolean ---@return string local function fmt_enum(values, no_quote) - return table.concat(vim.tbl_map(function(v) - return (not no_quote and type(v) == "string") and ("'" .. v .. "'") or v - end, values), "|") + return table.concat( + vim.tbl_map( + function(v) return (not no_quote and type(v) == "string") and ("'" .. v .. "'") or v end, + values + ), + "|" + ) end ---@param ... table @@ -441,9 +449,7 @@ function M.extend_keymaps(...) for i = 1, argc do local cur = argv[i] - if type(cur) == "table" then - contexts[#contexts + 1] = { subject = cur, expanded = {} } - end + if type(cur) == "table" then contexts[#contexts + 1] = { subject = cur, expanded = {} } end end for _, ctx in ipairs(contexts) do @@ -461,20 +467,13 @@ function M.extend_keymaps(...) for _, map in ipairs(ctx.subject) do for _, mode in ipairs(type(map[1]) == "table" and map[1] or { map[1] }) do - ctx.expanded[mode .. " " .. map[2]] = utils.vec_join( - mode, - map[2], - utils.vec_slice(map, 3) - ) + ctx.expanded[mode .. " " .. map[2]] = utils.vec_join(mode, map[2], utils.vec_slice(map, 3)) end end end - local merged = vim.tbl_extend("force", unpack( - vim.tbl_map(function(v) - return v.expanded - end, contexts) - )) + local merged = + vim.tbl_extend("force", unpack(vim.tbl_map(function(v) return v.expanded end, contexts))) return vim.tbl_values(merged) end @@ -482,11 +481,7 @@ end function M.setup(user_config) user_config = user_config or {} - M._config = vim.tbl_deep_extend( - "force", - utils.tbl_deep_clone(M.defaults), - user_config - ) + M._config = vim.tbl_deep_extend("force", utils.tbl_deep_clone(M.defaults), user_config) ---@type EventEmitter M.user_emitter = EventEmitter() @@ -500,15 +495,17 @@ function M.setup(user_config) local old_win_config_spec = { "position", "width", "height" } for _, panel_name in ipairs({ "file_panel", "file_history_panel" }) do local panel_config = M._config[panel_name] - ---@cast panel_config table + ---@cast panel_config table local notified = false for _, option in ipairs(old_win_config_spec) do if panel_config[option] ~= nil then if not notified then utils.warn( - ("'%s.{%s}' has been deprecated. See ':h diffview.changelog-136'.") - :format(panel_name, fmt_enum(old_win_config_spec, true)) + ("'%s.{%s}' has been deprecated. See ':h diffview.changelog-136'."):format( + panel_name, + fmt_enum(old_win_config_spec, true) + ) ) notified = true end @@ -533,7 +530,9 @@ function M.setup(user_config) } for _, name in ipairs(top_options) do if user_log_options[name] ~= nil then - utils.warn("Global config of 'file_panel.log_options' has been deprecated. See ':h diffview.changelog-271'.") + utils.warn( + "Global config of 'file_panel.log_options' has been deprecated. See ':h diffview.changelog-271'." + ) end break end @@ -549,8 +548,9 @@ function M.setup(user_config) for _, name in ipairs(option_names) do if user_log_options[name] ~= nil then utils.warn( - ("'file_history_panel.log_options.{%s}' has been deprecated. See ':h diffview.changelog-151'.") - :format(fmt_enum(option_names, true)) + ("'file_history_panel.log_options.{%s}' has been deprecated. See ':h diffview.changelog-151'."):format( + fmt_enum(option_names, true) + ) ) break end @@ -559,9 +559,7 @@ function M.setup(user_config) --#endregion - if #M._config.git_cmd == 0 then - M._config.git_cmd = M.defaults.git_cmd - end + if #M._config.git_cmd == 0 then M._config.git_cmd = M.defaults.git_cmd end do -- Validate layouts @@ -573,7 +571,7 @@ function M.setup(user_config) "diff3_vertical", "diff3_mixed", "diff4_mixed", - -1 + -1, } local valid_layouts = { default = standard_layouts, @@ -583,11 +581,13 @@ function M.setup(user_config) for _, kind in ipairs(vim.tbl_keys(valid_layouts)) do if not vim.tbl_contains(valid_layouts[kind], view[kind].layout) then - utils.err(("Invalid layout name '%s' for 'view.%s'! Must be one of (%s)."):format( - view[kind].layout, - kind, - fmt_enum(valid_layouts[kind]) - )) + utils.err( + ("Invalid layout name '%s' for 'view.%s'! Must be one of (%s)."):format( + view[kind].layout, + kind, + fmt_enum(valid_layouts[kind]) + ) + ) view[kind].layout = M.defaults.view[kind].layout end end @@ -596,24 +596,16 @@ function M.setup(user_config) for _, name in ipairs({ "single_file", "multi_file" }) do for _, vcs in ipairs({ "git", "hg" }) do local t = M._config.file_history_panel.log_options[vcs] - t[name] = vim.tbl_extend( - "force", - M.log_option_defaults[vcs], - t[name] - ) + t[name] = vim.tbl_extend("force", M.log_option_defaults[vcs], t[name]) for k, _ in pairs(t[name]) do - if t[name][k] == "" then - t[name][k] = nil - end + if t[name][k] == "" then t[name][k] = nil end end end end for event, callback in pairs(M._config.hooks) do if type(callback) == "function" then - M.user_emitter:on(event, function (_, ...) - callback(...) - end) + M.user_emitter:on(event, function(_, ...) callback(...) end) end end @@ -630,10 +622,8 @@ function M.setup(user_config) -- Merge default and user keymaps for name, keymap in pairs(M._config.keymaps) do if type(name) == "string" and type(keymap) == "table" then - M._config.keymaps[name] = M.extend_keymaps( - keymap, - utils.tbl_access(user_config, { "keymaps", name }) or {} - ) + M._config.keymaps[name] = + M.extend_keymaps(keymap, utils.tbl_access(user_config, { "keymaps", name }) or {}) end end @@ -642,9 +632,7 @@ function M.setup(user_config) if type(name) == "string" and type(keymaps) == "table" then for i = #keymaps, 1, -1 do local v = keymaps[i] - if type(v) == "table" and not v[3] then - table.remove(keymaps, i) - end + if type(v) == "table" and not v[3] then table.remove(keymaps, i) end end end end diff --git a/lua/diffview/scene/views/file_history/render.lua b/lua/diffview/scene/views/file_history/render.lua index 24b13970..7fc88540 100644 --- a/lua/diffview/scene/views/file_history/render.lua +++ b/lua/diffview/scene/views/file_history/render.lua @@ -10,6 +10,103 @@ local pl = utils.path local cache = setmetatable({}, { __mode = "k" }) +local formatters = { + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + status = function(comp, entry, _) + if entry.status then + comp:add_text(entry.status, hl.get_git_hl(entry.status)) + else + comp:add_text("-", "DiffviewNonText") + end + end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + files = function(comp, entry, params) + if entry.single_file then return end + + local s_num_files = tostring(params.max_num_files) + + if entry.nulled then + comp:add_text(utils.str_center_pad("empty", #s_num_files + 7), "DiffviewFilePanelCounter") + else + comp:add_text( + fmt( + " %s file%s", + utils.str_left_pad(tostring(#entry.files), #s_num_files), + #entry.files > 1 and "s" or " " + ), + "DiffviewFilePanelCounter" + ) + end + end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + hash = function(comp, entry, _) + if entry.commit.hash then comp:add_text(" " .. entry.commit.hash:sub(1, 8), "DiffviewHash") end + end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + stats = function(comp, entry, params) + if params.max_len_stats == -1 then return end + + local adds = { "-", "DiffviewNonText" } + local dels = { "-", "DiffviewNonText" } + + if entry.stats and entry.stats.additions then + adds = { tostring(entry.stats.additions), "DiffviewFilePanelInsertions" } + end + + if entry.stats and entry.stats.deletions then + dels = { tostring(entry.stats.deletions), "DiffviewFilePanelDeletions" } + end + + comp:add_text(" | ", "DiffviewNonText") + comp:add_text(unpack(adds)) + comp:add_text(string.rep(" ", params.max_len_stats - (#adds[1] + #dels[1]))) + comp:add_text(unpack(dels)) + comp:add_text(" |", "DiffviewNonText") + end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + reflog = function(comp, entry, _) + local reflog_selector = (entry.commit --[[@as GitCommit ]]).reflog_selector + if reflog_selector then + comp:add_text((" %s"):format(reflog_selector), "DiffviewReflogSelector") + end + end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + ref = function(comp, entry, _) + if entry.commit.ref_names then + comp:add_text((" (%s)"):format(entry.commit.ref_names), "DiffviewReference") + end + end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + subject = function(comp, entry, params) + local subject = utils.str_trunc(entry.commit.subject, 72) + if subject == "" then subject = "[empty message]" end + comp:add_text( + " " .. subject, + params.panel.cur_item[1] == entry and "DiffviewFilePanelSelected" + or "DiffviewFilePanelFileName" + ) + end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + author = function(comp, entry, _) comp:add_text(" " .. entry.commit.author) end, + + ---@type fun(comp:RenderComponent, entry:LogEntry, params:table) + date = function(comp, entry, _) + -- 3 months + local date = ( + os.difftime(os.time(), entry.commit.time) > 60 * 60 * 24 * 30 * 3 and entry.commit.iso_date + or entry.commit.rel_date + ) + comp:add_text(" " .. date, "DiffviewFilePanelPath") + end, +} + ---@param comp RenderComponent ---@param files FileEntry[] local function render_files(comp, files) @@ -35,7 +132,10 @@ local function render_files(comp, files) comp:add_text(file.parent_path .. "/", "DiffviewFilePanelPath") end - comp:add_text(file.basename, file.active and "DiffviewFilePanelSelected" or "DiffviewFilePanelFileName") + comp:add_text( + file.basename, + file.active and "DiffviewFilePanelSelected" or "DiffviewFilePanelFileName" + ) if file.stats then comp:add_text(" " .. file.stats.additions, "DiffviewFilePanelInsertions") @@ -60,107 +160,38 @@ local function render_entries(panel, parent, entries, updating) local max_len_stats = -1 for _, entry in ipairs(entries) do - if #entry.files > max_num_files then - max_num_files = #entry.files - end + if #entry.files > max_num_files then max_num_files = #entry.files end if entry.stats then local adds = tostring(entry.stats.additions) local dels = tostring(entry.stats.deletions) local l = 7 local w = l - (#adds + #dels) - if w < 1 then - l = (#adds + #dels) - ((#adds + #dels) % 2) + 2 - end + if w < 1 then l = (#adds + #dels) - ((#adds + #dels) % 2) + 2 end max_len_stats = l > max_len_stats and l or max_len_stats end end for i, entry in ipairs(entries) do - if i > #parent or (updating and i > 128) then - break - end + if i > #parent or (updating and i > 128) then break end local entry_struct = parent[i] local comp = entry_struct.commit.comp if not entry.single_file then - comp:add_text((entry.folded and c.signs.fold_closed or c.signs.fold_open) .. " ", "CursorLineNr") - end - - if entry.status then - comp:add_text(entry.status, hl.get_git_hl(entry.status)) - else - comp:add_text("-", "DiffviewNonText") + comp:add_text( + (entry.folded and c.signs.fold_closed or c.signs.fold_open) .. " ", + "CursorLineNr" + ) end - if not entry.single_file then - local s_num_files = tostring(max_num_files) - - if entry.nulled then - comp:add_text(utils.str_center_pad("empty", #s_num_files + 7), "DiffviewFilePanelCounter") + for format in c.file_history_panel.commit_format do + local fn = formatters[format] + if fn then + fn(comp, entry, { max_len_stats, max_num_files, panel }) else - comp:add_text( - fmt( - " %s file%s", - utils.str_left_pad(tostring(#entry.files), #s_num_files), - #entry.files > 1 and "s" or " " - ), - "DiffviewFilePanelCounter" - ) - end - end - - if max_len_stats ~= -1 then - local adds = { "-", "DiffviewNonText" } - local dels = { "-", "DiffviewNonText" } - - if entry.stats and entry.stats.additions then - adds = { tostring(entry.stats.additions), "DiffviewFilePanelInsertions" } + logger:warn("[format] Unsopported commit format: " .. format) end - - if entry.stats and entry.stats.deletions then - dels = { tostring(entry.stats.deletions), "DiffviewFilePanelDeletions" } - end - - comp:add_text(" | ", "DiffviewNonText") - comp:add_text(unpack(adds)) - comp:add_text(string.rep(" ", max_len_stats - (#adds[1] + #dels[1]))) - comp:add_text(unpack(dels)) - comp:add_text(" |", "DiffviewNonText") - end - - if entry.commit.hash then - comp:add_text(" " .. entry.commit.hash:sub(1, 8), "DiffviewHash") - end - - if (entry.commit --[[@as GitCommit ]]).reflog_selector then - comp:add_text((" %s"):format((entry.commit --[[@as GitCommit ]]).reflog_selector), "DiffviewReflogSelector") - end - - if entry.commit.ref_names then - comp:add_text((" (%s)"):format(entry.commit.ref_names), "DiffviewReference") - end - - local subject = utils.str_trunc(entry.commit.subject, 72) - - if subject == "" then - subject = "[empty message]" - end - - comp:add_text( - " " .. subject, - panel.cur_item[1] == entry and "DiffviewFilePanelSelected" or "DiffviewFilePanelFileName" - ) - - if entry.commit then - -- 3 months - local date = ( - os.difftime(os.time(), entry.commit.time) > 60 * 60 * 24 * 30 * 3 - and entry.commit.iso_date - or entry.commit.rel_date - ) - comp:add_text(" " .. entry.commit.author .. ", " .. date, "DiffviewFilePanelPath") end comp:ln() @@ -177,27 +208,22 @@ local function prepare_panel_cache(panel) local c = {} cache[panel] = c c.root_path = panel.state.form == "column" - and pl:truncate( - pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~"), - panel:infer_width() - 6 - ) + and pl:truncate(pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~"), panel:infer_width() - 6) or pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~") c.args = table.concat(panel.log_options.single_file.path_args, " ") end return { + commit_formatters = formatters, + ---@param panel FileHistoryPanel file_history_panel = function(panel) - if not panel.render_data then - return - end + if not panel.render_data then return end perf:reset() panel.render_data:clear() - if not cache[panel] then - prepare_panel_cache(panel) - end + if not cache[panel] then prepare_panel_cache(panel) end local conf = config.get_config() local comp = panel.components.header.comp @@ -253,9 +279,7 @@ return { comp:add_text("File History ", "DiffviewFilePanelTitle") comp:add_text("(" .. #panel.entries .. ")", "DiffviewFilePanelCounter") - if panel.updating then - comp:add_text(" (Updating...)", "DiffviewDim1") - end + if panel.updating then comp:add_text(" (Updating...)", "DiffviewDim1") end comp:ln() perf:lap("header") @@ -270,9 +294,7 @@ return { ---@param panel FHOptionPanel fh_option_panel = function(panel) - if not panel.render_data then - return - end + if not panel.render_data then return end panel.render_data:clear() @@ -312,7 +334,5 @@ return { comp:ln() end end, - clear_cache = function(panel) - cache[panel] = nil - end, + clear_cache = function(panel) cache[panel] = nil end, } diff --git a/lua/diffview/tests/unit/file_history_commit_format_spec.lua b/lua/diffview/tests/unit/file_history_commit_format_spec.lua new file mode 100644 index 00000000..36e62527 --- /dev/null +++ b/lua/diffview/tests/unit/file_history_commit_format_spec.lua @@ -0,0 +1,152 @@ +local helpers = require("diffview.tests.helpers") + +local eq, neq = helpers.eq, helpers.neq +local formatters = require("diffview.scene.views.file_history.render").commit_formatters + +-- Windows path standards: +-- https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats + +describe("diffview.scenes.views.file_history.render.formatters", function() + local renderer = require("diffview.renderer") + + it("status()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.status(comp, { status = "M" }, {}) + comp:ln() + eq("M", comp.lines[1]) + + comp:clear() + formatters.status(comp, { status = nil }, {}) + comp:ln() + eq("-", comp.lines[1]) + + comp:destroy() + end) + + it("files()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.files(comp, { single_file = false, files = { "a file" } }, { max_num_files = 1 }) + comp:ln() + eq(" 1 file ", comp.lines[1]) + eq("DiffviewFilePanelCounter", comp.hl[1].group) + + comp:clear() + formatters.files( + comp, + { nulled = true, single_file = false, files = { "a file" } }, + { max_num_files = 1 } + ) + comp:ln() + eq(" empty ", comp.lines[1]) + + comp:clear() + formatters.files(comp, { single_file = true }, {}) + comp:ln() + eq("", comp.lines[1]) + + comp:destroy() + end) + + it("hash()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.hash( + comp, + { commit = { hash = "762489b5c8d74bf8bbfb211d49aed686" } }, + { max_num_files = 1 } + ) + comp:ln() + eq(" 762489b5", comp.lines[1]) + eq("DiffviewHash", comp.hl[1].group) + + comp:destroy() + end) + + it("stats()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.stats(comp, { stats = { additions = 10, deletions = 22 } }, { max_len_stats = 4 }) + comp:ln() + eq(" | 1022 |", comp.lines[1]) + eq("DiffviewNonText", comp.hl[1].group) + eq("DiffviewFilePanelInsertions", comp.hl[2].group) + eq("DiffviewFilePanelDeletions", comp.hl[3].group) + eq("DiffviewNonText", comp.hl[4].group) + + comp:destroy() + end) + + it("reflog()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.reflog(comp, { commit = { reflog_selector = "reflog" } }, {}) + comp:ln() + eq(" reflog", comp.lines[1]) + eq("DiffviewReflogSelector", comp.hl[1].group) + + comp:destroy() + end) + + it("ref()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.ref(comp, { commit = { ref_names = "main" } }, {}) + comp:ln() + eq(" (main)", comp.lines[1]) + eq("DiffviewReference", comp.hl[1].group) + + comp:destroy() + end) + + it("subject()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.subject( + comp, + { commit = { subject = "refactor: cleanup" } }, + { panel = { cur_item = { nil } } } + ) + comp:ln() + eq(" refactor: cleanup", comp.lines[1]) + eq("DiffviewFilePanelFileName", comp.hl[1].group) + + comp:clear() + formatters.subject(comp, { commit = { subject = "" } }, { panel = { cur_item = { nil } } }) + comp:ln() + eq(" [empty message]", comp.lines[1]) + eq("DiffviewFilePanelFileName", comp.hl[1].group) + + comp:clear() + local entry = { commit = { subject = "fix #1111" } } + formatters.subject(comp, entry, { panel = { cur_item = { entry } } }) + comp:ln() + eq(" fix #1111", comp.lines[1]) + eq("DiffviewFilePanelSelected", comp.hl[1].group) + + comp:destroy() + end) + + it("author()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + formatters.author(comp, { commit = { author = "Dale Cooper" } }, {}) + comp:ln() + eq(" Dale Cooper", comp.lines[1]) + + comp:destroy() + end) + + it("date()", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + local time = os.time({ year = 2023, month = 1, day = 1 }) + local iso = os.date("%FT%TZ", time) + formatters.date(comp, { commit = { time = time, iso_date = iso } }, {}) + comp:ln() + eq(" " .. iso, comp.lines[1]) + + comp:destroy() + end) +end) From 1d133f28f1441750640a70a31df01cbe96155907 Mon Sep 17 00:00:00 2001 From: Brian Mayo Date: Tue, 21 Nov 2023 18:20:09 +0000 Subject: [PATCH 2/6] docs: default config for file history pannel commit format --- doc/diffview_defaults.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/diffview_defaults.txt b/doc/diffview_defaults.txt index 1a89b468..2b55f00f 100644 --- a/doc/diffview_defaults.txt +++ b/doc/diffview_defaults.txt @@ -21,7 +21,7 @@ DEFAULT CONFIG *diffview.defaults* }, view = { -- Configure the layout and behavior of different types of views. - -- Available layouts: + -- Available layouts: -- 'diff1_plain' -- |'diff2_horizontal' -- |'diff2_vertical' @@ -74,6 +74,16 @@ DEFAULT CONFIG *diffview.defaults* multi_file = {}, }, }, + commit_format = { + 'status', + 'stats', + 'hash', + 'reflog', + 'ref', + 'subject', + 'author', + 'date', + }, win_config = { -- See |diffview-config-win_config| position = "bottom", height = 16, From c45146c6f6da24d0a9db46a405dd8bc4bfc487c8 Mon Sep 17 00:00:00 2001 From: Brian Mayo Date: Tue, 21 Nov 2023 19:38:16 +0000 Subject: [PATCH 3/6] test: all format components --- .../unit/file_history_commit_format_spec.lua | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lua/diffview/tests/unit/file_history_commit_format_spec.lua b/lua/diffview/tests/unit/file_history_commit_format_spec.lua index 36e62527..89f37281 100644 --- a/lua/diffview/tests/unit/file_history_commit_format_spec.lua +++ b/lua/diffview/tests/unit/file_history_commit_format_spec.lua @@ -1,4 +1,5 @@ local helpers = require("diffview.tests.helpers") +local config = require("diffview.config") local eq, neq = helpers.eq, helpers.neq local formatters = require("diffview.scene.views.file_history.render").commit_formatters @@ -149,4 +150,39 @@ describe("diffview.scenes.views.file_history.render.formatters", function() comp:destroy() end) + + it("default config format", function() + --- @type RenderComponent + local comp = renderer.RenderComponent.create_static_component(nil) + local c = config.get_config() + local time = os.time({ year = 2023, month = 1, day = 1 }) + local iso = os.date("%FT%TZ", time) + local entry = { + stats = { additions = 121, deletions = 101 }, + status = "M", + commit = { + time = time, + iso_date = iso, + hash = "ba89b7310101", + subject = "fix #1", + author = "Dale Cooper", + }, + } + + local params = { + panel = { cur_item = { nil } }, + max_num_files = 1, + max_len_stats = 7, + } + + for _, f in ipairs(c.file_history_panel.commit_format) do + formatters[f](comp, entry, params) + end + + comp:ln() + local expected = string.format("M | 121 101 | ba89b731 fix #1 Dale Cooper %s", iso) + eq(expected, table.concat(comp.lines, " ")) + + comp:destroy() + end) end) From 53d2539fc777c49dae562516605bf75eec107ec4 Mon Sep 17 00:00:00 2001 From: Brian Mayo Date: Sun, 3 Dec 2023 01:46:40 +0000 Subject: [PATCH 4/6] revert formatting --- lua/diffview/config.lua | 102 +++++++++++------- .../scene/views/file_history/render.lua | 47 ++++---- 2 files changed, 91 insertions(+), 58 deletions(-) diff --git a/lua/diffview/config.lua b/lua/diffview/config.lua index 734c3205..7bfe1169 100644 --- a/lua/diffview/config.lua +++ b/lua/diffview/config.lua @@ -344,7 +344,9 @@ M.log_option_defaults = { ---@return DiffviewConfig function M.get_config() - if not setup_done then M.setup() end + if not setup_done then + M.setup() + end return M._config end @@ -366,7 +368,9 @@ function M.get_log_options(single_file, t, vcs) log_options = vim.tbl_extend("force", log_options, t) for k, _ in pairs(log_options) do - if t[k] == "" then log_options[k] = nil end + if t[k] == "" then + log_options[k] = nil + end end end @@ -415,7 +419,9 @@ end function M.find_option_keymap(t) for _, mapping in ipairs(t) do - if mapping[3] and mapping[3] == actions.options then return mapping end + if mapping[3] and mapping[3] == actions.options then + return mapping + end end end @@ -431,13 +437,9 @@ end ---@param no_quote? boolean ---@return string local function fmt_enum(values, no_quote) - return table.concat( - vim.tbl_map( - function(v) return (not no_quote and type(v) == "string") and ("'" .. v .. "'") or v end, - values - ), - "|" - ) + return table.concat(vim.tbl_map(function(v) + return (not no_quote and type(v) == "string") and ("'" .. v .. "'") or v + end, values), "|") end ---@param ... table @@ -449,7 +451,9 @@ function M.extend_keymaps(...) for i = 1, argc do local cur = argv[i] - if type(cur) == "table" then contexts[#contexts + 1] = { subject = cur, expanded = {} } end + if type(cur) == "table" then + contexts[#contexts + 1] = { subject = cur, expanded = {} } + end end for _, ctx in ipairs(contexts) do @@ -467,13 +471,20 @@ function M.extend_keymaps(...) for _, map in ipairs(ctx.subject) do for _, mode in ipairs(type(map[1]) == "table" and map[1] or { map[1] }) do - ctx.expanded[mode .. " " .. map[2]] = utils.vec_join(mode, map[2], utils.vec_slice(map, 3)) + ctx.expanded[mode .. " " .. map[2]] = utils.vec_join( + mode, + map[2], + utils.vec_slice(map, 3) + ) end end end - local merged = - vim.tbl_extend("force", unpack(vim.tbl_map(function(v) return v.expanded end, contexts))) + local merged = vim.tbl_extend("force", unpack( + vim.tbl_map(function(v) + return v.expanded + end, contexts) + )) return vim.tbl_values(merged) end @@ -481,7 +492,11 @@ end function M.setup(user_config) user_config = user_config or {} - M._config = vim.tbl_deep_extend("force", utils.tbl_deep_clone(M.defaults), user_config) + M._config = vim.tbl_deep_extend( + "force", + utils.tbl_deep_clone(M.defaults), + user_config + ) ---@type EventEmitter M.user_emitter = EventEmitter() @@ -502,10 +517,8 @@ function M.setup(user_config) if panel_config[option] ~= nil then if not notified then utils.warn( - ("'%s.{%s}' has been deprecated. See ':h diffview.changelog-136'."):format( - panel_name, - fmt_enum(old_win_config_spec, true) - ) + ("'%s.{%s}' has been deprecated. See ':h diffview.changelog-136'.") + :format( panel_name, fmt_enum(old_win_config_spec, true)) ) notified = true end @@ -530,9 +543,7 @@ function M.setup(user_config) } for _, name in ipairs(top_options) do if user_log_options[name] ~= nil then - utils.warn( - "Global config of 'file_panel.log_options' has been deprecated. See ':h diffview.changelog-271'." - ) + utils.warn( "Global config of 'file_panel.log_options' has been deprecated. See ':h diffview.changelog-271'.") end break end @@ -548,9 +559,8 @@ function M.setup(user_config) for _, name in ipairs(option_names) do if user_log_options[name] ~= nil then utils.warn( - ("'file_history_panel.log_options.{%s}' has been deprecated. See ':h diffview.changelog-151'."):format( - fmt_enum(option_names, true) - ) + ("'file_history_panel.log_options.{%s}' has been deprecated. See ':h diffview.changelog-151'.") + :format( fmt_enum(option_names, true)) ) break end @@ -559,7 +569,9 @@ function M.setup(user_config) --#endregion - if #M._config.git_cmd == 0 then M._config.git_cmd = M.defaults.git_cmd end + if #M._config.git_cmd == 0 then + M._config.git_cmd = M.defaults.git_cmd + end do -- Validate layouts @@ -571,7 +583,7 @@ function M.setup(user_config) "diff3_vertical", "diff3_mixed", "diff4_mixed", - -1, + -1 } local valid_layouts = { default = standard_layouts, @@ -581,13 +593,11 @@ function M.setup(user_config) for _, kind in ipairs(vim.tbl_keys(valid_layouts)) do if not vim.tbl_contains(valid_layouts[kind], view[kind].layout) then - utils.err( - ("Invalid layout name '%s' for 'view.%s'! Must be one of (%s)."):format( - view[kind].layout, - kind, - fmt_enum(valid_layouts[kind]) - ) - ) + utils.err( ("Invalid layout name '%s' for 'view.%s'! Must be one of (%s)."):format( + view[kind].layout, + kind, + fmt_enum(valid_layouts[kind]) + )) view[kind].layout = M.defaults.view[kind].layout end end @@ -596,16 +606,24 @@ function M.setup(user_config) for _, name in ipairs({ "single_file", "multi_file" }) do for _, vcs in ipairs({ "git", "hg" }) do local t = M._config.file_history_panel.log_options[vcs] - t[name] = vim.tbl_extend("force", M.log_option_defaults[vcs], t[name]) + t[name] = vim.tbl_extend( + "force", + M.log_option_defaults[vcs], + t[name] + ) for k, _ in pairs(t[name]) do - if t[name][k] == "" then t[name][k] = nil end + if t[name][k] == "" + then t[name][k] = nil + end end end end for event, callback in pairs(M._config.hooks) do if type(callback) == "function" then - M.user_emitter:on(event, function(_, ...) callback(...) end) + M.user_emitter:on(event, function(_, ...) + callback(...) + end) end end @@ -622,8 +640,10 @@ function M.setup(user_config) -- Merge default and user keymaps for name, keymap in pairs(M._config.keymaps) do if type(name) == "string" and type(keymap) == "table" then - M._config.keymaps[name] = - M.extend_keymaps(keymap, utils.tbl_access(user_config, { "keymaps", name }) or {}) + M._config.keymaps[name] = M.extend_keymaps( + keymap, + utils.tbl_access(user_config, { "keymaps", name }) or {} + ) end end @@ -632,7 +652,9 @@ function M.setup(user_config) if type(name) == "string" and type(keymaps) == "table" then for i = #keymaps, 1, -1 do local v = keymaps[i] - if type(v) == "table" and not v[3] then table.remove(keymaps, i) end + if type(v) == "table" and not v[3] then + table.remove(keymaps, i) + end end end end diff --git a/lua/diffview/scene/views/file_history/render.lua b/lua/diffview/scene/views/file_history/render.lua index 7fc88540..1652df35 100644 --- a/lua/diffview/scene/views/file_history/render.lua +++ b/lua/diffview/scene/views/file_history/render.lua @@ -89,7 +89,7 @@ local formatters = { comp:add_text( " " .. subject, params.panel.cur_item[1] == entry and "DiffviewFilePanelSelected" - or "DiffviewFilePanelFileName" + or "DiffviewFilePanelFileName" ) end, @@ -132,10 +132,7 @@ local function render_files(comp, files) comp:add_text(file.parent_path .. "/", "DiffviewFilePanelPath") end - comp:add_text( - file.basename, - file.active and "DiffviewFilePanelSelected" or "DiffviewFilePanelFileName" - ) + comp:add_text(file.basename, file.active and "DiffviewFilePanelSelected" or "DiffviewFilePanelFileName") if file.stats then comp:add_text(" " .. file.stats.additions, "DiffviewFilePanelInsertions") @@ -160,7 +157,9 @@ local function render_entries(panel, parent, entries, updating) local max_len_stats = -1 for _, entry in ipairs(entries) do - if #entry.files > max_num_files then max_num_files = #entry.files end + if #entry.files > max_num_files then + max_num_files = #entry.files + end if entry.stats then local adds = tostring(entry.stats.additions) @@ -173,16 +172,15 @@ local function render_entries(panel, parent, entries, updating) end for i, entry in ipairs(entries) do - if i > #parent or (updating and i > 128) then break end + if i > #parent or (updating and i > 128) then + break + end local entry_struct = parent[i] local comp = entry_struct.commit.comp if not entry.single_file then - comp:add_text( - (entry.folded and c.signs.fold_closed or c.signs.fold_open) .. " ", - "CursorLineNr" - ) + comp:add_text((entry.folded and c.signs.fold_closed or c.signs.fold_open) .. " ", "CursorLineNr") end for format in c.file_history_panel.commit_format do @@ -208,8 +206,11 @@ local function prepare_panel_cache(panel) local c = {} cache[panel] = c c.root_path = panel.state.form == "column" - and pl:truncate(pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~"), panel:infer_width() - 6) - or pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~") + and pl:truncate( + pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~"), + panel:infer_width() - 6 + ) + or pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~") c.args = table.concat(panel.log_options.single_file.path_args, " ") end @@ -218,12 +219,16 @@ return { ---@param panel FileHistoryPanel file_history_panel = function(panel) - if not panel.render_data then return end + if not panel.render_data then + return + end perf:reset() panel.render_data:clear() - if not cache[panel] then prepare_panel_cache(panel) end + if not cache[panel] then + prepare_panel_cache(panel) + end local conf = config.get_config() local comp = panel.components.header.comp @@ -279,7 +284,9 @@ return { comp:add_text("File History ", "DiffviewFilePanelTitle") comp:add_text("(" .. #panel.entries .. ")", "DiffviewFilePanelCounter") - if panel.updating then comp:add_text(" (Updating...)", "DiffviewDim1") end + if panel.updating then + comp:add_text(" (Updating...)", "DiffviewDim1") + end comp:ln() perf:lap("header") @@ -294,7 +301,9 @@ return { ---@param panel FHOptionPanel fh_option_panel = function(panel) - if not panel.render_data then return end + if not panel.render_data then + return + end panel.render_data:clear() @@ -334,5 +343,7 @@ return { comp:ln() end end, - clear_cache = function(panel) cache[panel] = nil end, + clear_cache = function(panel) + cache[panel] = nil + end, } From b39df42a91e34f6a061c144ec9ea63d8f666d35d Mon Sep 17 00:00:00 2001 From: Brian Mayo Date: Sun, 3 Dec 2023 01:58:40 +0000 Subject: [PATCH 5/6] test: monkey patch os.difftime to cover commit relative date --- .../tests/unit/file_history_commit_format_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lua/diffview/tests/unit/file_history_commit_format_spec.lua b/lua/diffview/tests/unit/file_history_commit_format_spec.lua index 89f37281..b51d3cfa 100644 --- a/lua/diffview/tests/unit/file_history_commit_format_spec.lua +++ b/lua/diffview/tests/unit/file_history_commit_format_spec.lua @@ -148,7 +148,19 @@ describe("diffview.scenes.views.file_history.render.formatters", function() comp:ln() eq(" " .. iso, comp.lines[1]) + comp:clear() + local tmp_diff_time = os.difftime + os.difftime = function() + return 1 + end + + formatters.date(comp, { commit = { time = time, iso_date = iso, rel_date = '1 day' } }, {}) + comp:ln() + eq(" 1 day", comp.lines[1]) + comp:destroy() + + os.difftime = tmp_diff_time end) it("default config format", function() From 065435b5dfa113a9affc94bb2fab77929a040b74 Mon Sep 17 00:00:00 2001 From: Brian Mayo Date: Sun, 3 Dec 2023 02:02:59 +0000 Subject: [PATCH 6/6] style format --- lua/diffview/config.lua | 20 +++++++++---------- .../scene/views/file_history/render.lua | 6 ++++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lua/diffview/config.lua b/lua/diffview/config.lua index 7bfe1169..195cf329 100644 --- a/lua/diffview/config.lua +++ b/lua/diffview/config.lua @@ -481,9 +481,9 @@ function M.extend_keymaps(...) end local merged = vim.tbl_extend("force", unpack( - vim.tbl_map(function(v) - return v.expanded - end, contexts) + vim.tbl_map(function(v) + return v.expanded + end, contexts) )) return vim.tbl_values(merged) @@ -518,7 +518,7 @@ function M.setup(user_config) if not notified then utils.warn( ("'%s.{%s}' has been deprecated. See ':h diffview.changelog-136'.") - :format( panel_name, fmt_enum(old_win_config_spec, true)) + :format(panel_name, fmt_enum(old_win_config_spec, true)) ) notified = true end @@ -543,7 +543,7 @@ function M.setup(user_config) } for _, name in ipairs(top_options) do if user_log_options[name] ~= nil then - utils.warn( "Global config of 'file_panel.log_options' has been deprecated. See ':h diffview.changelog-271'.") + utils.warn("Global config of 'file_panel.log_options' has been deprecated. See ':h diffview.changelog-271'.") end break end @@ -560,7 +560,7 @@ function M.setup(user_config) if user_log_options[name] ~= nil then utils.warn( ("'file_history_panel.log_options.{%s}' has been deprecated. See ':h diffview.changelog-151'.") - :format( fmt_enum(option_names, true)) + :format(fmt_enum(option_names, true)) ) break end @@ -593,7 +593,7 @@ function M.setup(user_config) for _, kind in ipairs(vim.tbl_keys(valid_layouts)) do if not vim.tbl_contains(valid_layouts[kind], view[kind].layout) then - utils.err( ("Invalid layout name '%s' for 'view.%s'! Must be one of (%s)."):format( + utils.err(("Invalid layout name '%s' for 'view.%s'! Must be one of (%s)."):format( view[kind].layout, kind, fmt_enum(valid_layouts[kind]) @@ -612,8 +612,8 @@ function M.setup(user_config) t[name] ) for k, _ in pairs(t[name]) do - if t[name][k] == "" - then t[name][k] = nil + if t[name][k] == "" then + t[name][k] = nil end end end @@ -621,7 +621,7 @@ function M.setup(user_config) for event, callback in pairs(M._config.hooks) do if type(callback) == "function" then - M.user_emitter:on(event, function(_, ...) + M.user_emitter:on(event, function (_, ...) callback(...) end) end diff --git a/lua/diffview/scene/views/file_history/render.lua b/lua/diffview/scene/views/file_history/render.lua index 1652df35..5620c321 100644 --- a/lua/diffview/scene/views/file_history/render.lua +++ b/lua/diffview/scene/views/file_history/render.lua @@ -166,7 +166,9 @@ local function render_entries(panel, parent, entries, updating) local dels = tostring(entry.stats.deletions) local l = 7 local w = l - (#adds + #dels) - if w < 1 then l = (#adds + #dels) - ((#adds + #dels) % 2) + 2 end + if w < 1 then + l = (#adds + #dels) - ((#adds + #dels) % 2) + 2 + end max_len_stats = l > max_len_stats and l or max_len_stats end end @@ -210,7 +212,7 @@ local function prepare_panel_cache(panel) pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~"), panel:infer_width() - 6 ) - or pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~") + or pl:vim_fnamemodify(panel.adapter.ctx.toplevel, ":~") c.args = table.concat(panel.log_options.single_file.path_args, " ") end