Release (#440)
* Feat: Enable sorting discussions by original comment (#422) * Feat: Improve popup UX (#426) * Feat: Automatically update MR summary details (#427) * Feat: Show update progress in winbar (#432) * Feat: Abbreviate winbar (#439) * Fix: Note Creation Bug (#441) * Fix: Checking whether comment can be created (#434) * Fix: Syntax in discussion tree (#433) * fix: improve indication of resolved threads and drafts (#442) * Docs: Various minor improvements (#445) --------- Co-authored-by: Jakub F. Bortlík <jakub.bortlik@proton.me>
This commit is contained in:
committed by
GitHub
parent
be027331e1
commit
495e64c8bc
@@ -7,12 +7,12 @@ local Popup = require("nui.popup")
|
||||
local NuiTree = require("nui.tree")
|
||||
local job = require("gitlab.job")
|
||||
local u = require("gitlab.utils")
|
||||
local popup = require("gitlab.popup")
|
||||
local state = require("gitlab.state")
|
||||
local reviewer = require("gitlab.reviewer")
|
||||
local common = require("gitlab.actions.common")
|
||||
local List = require("gitlab.utils.list")
|
||||
local tree_utils = require("gitlab.actions.discussions.tree")
|
||||
local miscellaneous = require("gitlab.actions.miscellaneous")
|
||||
local discussions_tree = require("gitlab.actions.discussions.tree")
|
||||
local draft_notes = require("gitlab.actions.draft_notes")
|
||||
local diffview_lib = require("diffview.lib")
|
||||
@@ -48,13 +48,15 @@ M.rebuild_view = function(unlinked, all)
|
||||
else
|
||||
M.rebuild_discussion_tree()
|
||||
end
|
||||
M.refresh_diagnostics_and_winbar()
|
||||
state.discussion_tree.last_updated = os.time()
|
||||
M.refresh_diagnostics()
|
||||
end)
|
||||
end
|
||||
|
||||
---Makes API call to get the discussion data, stores it in the state, and calls the callback
|
||||
---@param callback function|nil
|
||||
M.load_discussions = function(callback)
|
||||
state.discussion_tree.last_updated = nil
|
||||
state.load_new_state("discussion_data", function(data)
|
||||
if not state.DISCUSSION_DATA then
|
||||
state.DISCUSSION_DATA = {}
|
||||
@@ -70,9 +72,10 @@ end
|
||||
|
||||
---Initialize everything for discussions like setup of signs, callbacks for reviewer, etc.
|
||||
M.initialize_discussions = function()
|
||||
state.discussion_tree.last_updated = os.time()
|
||||
signs.setup_signs()
|
||||
reviewer.set_callback_for_file_changed(function()
|
||||
M.refresh_diagnostics_and_winbar()
|
||||
M.refresh_diagnostics()
|
||||
M.modifiable(false)
|
||||
reviewer.set_reviewer_keymaps()
|
||||
end)
|
||||
@@ -102,11 +105,10 @@ M.modifiable = function(bool)
|
||||
end
|
||||
|
||||
--- Take existing data and refresh the diagnostics, the winbar, and the signs
|
||||
M.refresh_diagnostics_and_winbar = function()
|
||||
M.refresh_diagnostics = function()
|
||||
if state.settings.discussion_signs.enabled then
|
||||
diagnostics.refresh_diagnostics()
|
||||
end
|
||||
winbar.update_winbar()
|
||||
common.add_empty_titles()
|
||||
end
|
||||
|
||||
@@ -154,7 +156,7 @@ M.open = function(callback)
|
||||
end
|
||||
|
||||
vim.schedule(function()
|
||||
M.refresh_diagnostics_and_winbar()
|
||||
M.refresh_diagnostics()
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -251,9 +253,7 @@ M.reply = function(tree)
|
||||
reply = true,
|
||||
})
|
||||
|
||||
if layout then
|
||||
layout:mount()
|
||||
end
|
||||
layout:mount()
|
||||
end
|
||||
|
||||
-- This function (settings.keymaps.discussion_tree.delete_comment) will trigger a popup prompting you to delete the current comment
|
||||
@@ -284,7 +284,7 @@ end
|
||||
|
||||
-- This function (settings.keymaps.discussion_tree.edit_comment) will open the edit popup for the current comment in the discussion tree
|
||||
M.edit_comment = function(tree, unlinked)
|
||||
local edit_popup = Popup(u.create_popup_state("Edit Comment", state.settings.popup.edit))
|
||||
local edit_popup = Popup(popup.create_popup_state("Edit Comment", state.settings.popup.edit))
|
||||
local current_node = tree:get_node()
|
||||
local note_node = common.get_note_node(tree, current_node)
|
||||
local root_node = common.get_root_node(tree, current_node)
|
||||
@@ -293,6 +293,8 @@ M.edit_comment = function(tree, unlinked)
|
||||
return
|
||||
end
|
||||
|
||||
popup.set_up_autocommands(edit_popup, nil, vim.api.nvim_get_current_win())
|
||||
|
||||
edit_popup:mount()
|
||||
|
||||
-- Gather all lines from immediate children that aren't note nodes
|
||||
@@ -310,19 +312,19 @@ M.edit_comment = function(tree, unlinked)
|
||||
|
||||
-- Draft notes module handles edits for draft notes
|
||||
if M.is_draft_note(tree) then
|
||||
state.set_popup_keymaps(
|
||||
popup.set_popup_keymaps(
|
||||
edit_popup,
|
||||
draft_notes.confirm_edit_draft_note(note_node.id, unlinked),
|
||||
nil,
|
||||
miscellaneous.editable_popup_opts
|
||||
popup.editable_popup_opts
|
||||
)
|
||||
else
|
||||
local comment = require("gitlab.actions.comment")
|
||||
state.set_popup_keymaps(
|
||||
popup.set_popup_keymaps(
|
||||
edit_popup,
|
||||
comment.confirm_edit_comment(tostring(root_node.id), tonumber(note_node.root_note_id or note_node.id), unlinked),
|
||||
nil,
|
||||
miscellaneous.editable_popup_opts
|
||||
popup.editable_popup_opts
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -585,7 +587,7 @@ M.set_tree_keymaps = function(tree, bufnr, unlinked)
|
||||
if keymaps.discussion_tree.jump_to_reviewer then
|
||||
vim.keymap.set("n", keymaps.discussion_tree.jump_to_reviewer, function()
|
||||
if M.is_current_node_note(tree) then
|
||||
common.jump_to_reviewer(tree, M.refresh_diagnostics_and_winbar)
|
||||
common.jump_to_reviewer(tree, M.refresh_diagnostics)
|
||||
end
|
||||
end, { buffer = bufnr, desc = "Jump to reviewer", nowait = keymaps.discussion_tree.jump_to_reviewer_nowait })
|
||||
end
|
||||
@@ -603,7 +605,6 @@ M.set_tree_keymaps = function(tree, bufnr, unlinked)
|
||||
|
||||
if keymaps.discussion_tree.refresh_data then
|
||||
vim.keymap.set("n", keymaps.discussion_tree.refresh_data, function()
|
||||
u.notify("Refreshing data...", vim.log.levels.INFO)
|
||||
draft_notes.rebuild_view(unlinked, false)
|
||||
end, {
|
||||
buffer = bufnr,
|
||||
@@ -646,6 +647,16 @@ M.set_tree_keymaps = function(tree, bufnr, unlinked)
|
||||
})
|
||||
end
|
||||
|
||||
if keymaps.discussion_tree.toggle_sort_method then
|
||||
vim.keymap.set("n", keymaps.discussion_tree.toggle_sort_method, function()
|
||||
M.toggle_sort_method()
|
||||
end, {
|
||||
buffer = bufnr,
|
||||
desc = "Toggle sort method",
|
||||
nowait = keymaps.discussion_tree.toggle_sort_method_nowait,
|
||||
})
|
||||
end
|
||||
|
||||
if keymaps.discussion_tree.toggle_resolved then
|
||||
vim.keymap.set("n", keymaps.discussion_tree.toggle_resolved, function()
|
||||
if M.is_current_node_note(tree) and not M.is_draft_note(tree) then
|
||||
@@ -746,16 +757,6 @@ M.set_tree_keymaps = function(tree, bufnr, unlinked)
|
||||
})
|
||||
end
|
||||
|
||||
if keymaps.discussion_tree.print_node then
|
||||
vim.keymap.set("n", keymaps.discussion_tree.print_node, function()
|
||||
common.print_node(tree)
|
||||
end, {
|
||||
buffer = bufnr,
|
||||
desc = "Print current node (for debugging)",
|
||||
nowait = keymaps.discussion_tree.print_node_nowait,
|
||||
})
|
||||
end
|
||||
|
||||
if keymaps.discussion_tree.add_emoji then
|
||||
vim.keymap.set("n", keymaps.discussion_tree.add_emoji, function()
|
||||
M.add_emoji_to_note(tree, unlinked)
|
||||
@@ -792,7 +793,18 @@ end
|
||||
---Toggle between draft mode (comments posted as drafts) and live mode (comments are posted immediately)
|
||||
M.toggle_draft_mode = function()
|
||||
state.settings.discussion_tree.draft_mode = not state.settings.discussion_tree.draft_mode
|
||||
end
|
||||
|
||||
---Toggle between sorting by "original comment" (oldest at the top) or "latest reply" (newest at the
|
||||
---top).
|
||||
M.toggle_sort_method = function()
|
||||
if state.settings.discussion_tree.sort_by == "original_comment" then
|
||||
state.settings.discussion_tree.sort_by = "latest_reply"
|
||||
else
|
||||
state.settings.discussion_tree.sort_by = "original_comment"
|
||||
end
|
||||
winbar.update_winbar()
|
||||
M.rebuild_view(false, true)
|
||||
end
|
||||
|
||||
---Indicates whether the node under the cursor is a draft note or not
|
||||
|
||||
@@ -277,13 +277,16 @@ local function build_note_body(note, resolve_info)
|
||||
)
|
||||
end
|
||||
|
||||
local resolve_symbol = ""
|
||||
local symbol = ""
|
||||
local is_draft = note.note ~= nil
|
||||
if resolve_info ~= nil and resolve_info.resolvable then
|
||||
resolve_symbol = resolve_info.resolved and state.settings.discussion_tree.resolved
|
||||
symbol = resolve_info.resolved and state.settings.discussion_tree.resolved
|
||||
or state.settings.discussion_tree.unresolved
|
||||
elseif not is_draft and resolve_info and not resolve_info.resolvable then
|
||||
symbol = state.settings.discussion_tree.unlinked
|
||||
end
|
||||
|
||||
local noteHeader = common.build_note_header(note) .. " " .. resolve_symbol
|
||||
local noteHeader = common.build_note_header(note) .. " " .. symbol
|
||||
|
||||
return noteHeader, text_nodes
|
||||
end
|
||||
@@ -454,7 +457,9 @@ M.restore_cursor_position = function(winid, tree, original_node, root_node)
|
||||
end
|
||||
end
|
||||
if line_number ~= nil then
|
||||
vim.api.nvim_win_set_cursor(winid, { line_number, 0 })
|
||||
if vim.api.nvim_win_is_valid(winid) then
|
||||
vim.api.nvim_win_set_cursor(winid, { line_number, 0 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -54,7 +54,19 @@ local get_data = function(nodes)
|
||||
return total_resolvable, total_resolved, total_non_resolvable
|
||||
end
|
||||
|
||||
local spinner_index = 0
|
||||
state.discussion_tree.last_updated = nil
|
||||
|
||||
local function content()
|
||||
local updated
|
||||
if state.discussion_tree.last_updated then
|
||||
local last_update = tostring(os.date("!%Y-%m-%dT%H:%M:%S", state.discussion_tree.last_updated))
|
||||
updated = u.time_since(last_update) .. " ⟳"
|
||||
else
|
||||
spinner_index = (spinner_index % #state.settings.discussion_tree.spinner_chars) + 1
|
||||
updated = state.settings.discussion_tree.spinner_chars[spinner_index]
|
||||
end
|
||||
|
||||
local resolvable_discussions, resolved_discussions, non_resolvable_discussions =
|
||||
get_data(state.DISCUSSION_DATA.discussions)
|
||||
local resolvable_notes, resolved_notes, non_resolvable_notes = get_data(state.DISCUSSION_DATA.unlinked_discussions)
|
||||
@@ -82,9 +94,10 @@ local function content()
|
||||
resolved_notes = resolved_notes,
|
||||
non_resolvable_notes = non_resolvable_notes,
|
||||
help_keymap = state.settings.keymaps.help,
|
||||
updated = updated,
|
||||
}
|
||||
|
||||
return M.make_winbar(t)
|
||||
return state.settings.discussion_tree.winbar and state.settings.discussion_tree.winbar(t) or M.make_winbar(t)
|
||||
end
|
||||
|
||||
---This function updates the winbar
|
||||
@@ -108,7 +121,7 @@ M.update_winbar = function()
|
||||
end
|
||||
|
||||
local function get_connector(base_title)
|
||||
return string.match(base_title, "%($") and "" or "; "
|
||||
return string.match(base_title, "%($") and "" or " "
|
||||
end
|
||||
|
||||
---Builds the title string for both sections, using the count of resolvable and draft nodes
|
||||
@@ -116,84 +129,128 @@ end
|
||||
---@param resolvable_count integer
|
||||
---@param resolved_count integer
|
||||
---@param drafts_count integer
|
||||
---@param focused boolean
|
||||
---@return string
|
||||
local add_drafts_and_resolvable = function(
|
||||
base_title,
|
||||
resolvable_count,
|
||||
resolved_count,
|
||||
drafts_count,
|
||||
non_resolvable_count
|
||||
non_resolvable_count,
|
||||
focused
|
||||
)
|
||||
if resolvable_count == 0 and drafts_count == 0 and non_resolvable_count == 0 then
|
||||
return base_title
|
||||
end
|
||||
base_title = base_title .. " ("
|
||||
if non_resolvable_count ~= 0 then
|
||||
base_title = base_title .. u.pluralize(non_resolvable_count, "comment")
|
||||
end
|
||||
if resolvable_count ~= 0 then
|
||||
base_title = base_title
|
||||
.. get_connector(base_title)
|
||||
.. string.format("%d/%s", resolved_count, u.pluralize(resolvable_count, "thread"))
|
||||
base_title = base_title .. M.get_resolved_text(focused, resolved_count, resolvable_count)
|
||||
end
|
||||
if non_resolvable_count ~= 0 then
|
||||
base_title = base_title .. M.get_nonresolveable_text(base_title, non_resolvable_count, focused)
|
||||
end
|
||||
if drafts_count ~= 0 then
|
||||
base_title = base_title .. get_connector(base_title) .. u.pluralize(drafts_count, "draft")
|
||||
base_title = base_title .. M.get_drafts_text(base_title, drafts_count, focused)
|
||||
end
|
||||
base_title = base_title .. ")"
|
||||
return base_title
|
||||
end
|
||||
|
||||
---@param t WinbarTable
|
||||
M.make_winbar = function(t)
|
||||
local discussion_title = add_drafts_and_resolvable(
|
||||
"Inline Comments",
|
||||
local discussions_focused = M.current_view_type == "discussions"
|
||||
local discussion_text = add_drafts_and_resolvable(
|
||||
"Inline Comments:",
|
||||
t.resolvable_discussions,
|
||||
t.resolved_discussions,
|
||||
t.inline_draft_notes,
|
||||
t.non_resolvable_discussions
|
||||
t.non_resolvable_discussions,
|
||||
discussions_focused
|
||||
)
|
||||
local notes_title = add_drafts_and_resolvable(
|
||||
"Notes",
|
||||
local notes_text = add_drafts_and_resolvable(
|
||||
"Notes:",
|
||||
t.resolvable_notes,
|
||||
t.resolved_notes,
|
||||
t.unlinked_draft_notes,
|
||||
t.non_resolvable_notes
|
||||
t.non_resolvable_notes,
|
||||
not discussions_focused
|
||||
)
|
||||
|
||||
-- Colorize the active tab
|
||||
if M.current_view_type == "discussions" then
|
||||
discussion_title = "%#Text#" .. discussion_title
|
||||
notes_title = "%#Comment#" .. notes_title
|
||||
elseif M.current_view_type == "notes" then
|
||||
discussion_title = "%#Comment#" .. discussion_title
|
||||
notes_title = "%#Text#" .. notes_title
|
||||
if discussions_focused then
|
||||
discussion_text = "%#Text#" .. discussion_text
|
||||
notes_text = "%#Comment#" .. notes_text
|
||||
else
|
||||
discussion_text = "%#Comment#" .. discussion_text
|
||||
notes_text = "%#Text#" .. notes_text
|
||||
end
|
||||
|
||||
local sort_method = M.get_sort_method()
|
||||
local mode = M.get_mode()
|
||||
|
||||
-- Join everything together and return it
|
||||
local separator = "%#Comment#|"
|
||||
local end_section = "%="
|
||||
local updated = "%#Text#" .. t.updated
|
||||
local help = "%#Comment#Help: " .. (t.help_keymap and t.help_keymap:gsub(" ", "<space>") .. " " or "unmapped")
|
||||
return string.format(
|
||||
" %s %s %s %s %s %s %s",
|
||||
discussion_title,
|
||||
" %s %s %s %s %s %s %s %s %s %s %s",
|
||||
discussion_text,
|
||||
separator,
|
||||
notes_title,
|
||||
notes_text,
|
||||
end_section,
|
||||
updated,
|
||||
separator,
|
||||
sort_method,
|
||||
separator,
|
||||
mode,
|
||||
separator,
|
||||
help
|
||||
)
|
||||
end
|
||||
|
||||
---Returns a string for the winbar indicating the sort method
|
||||
---@return string
|
||||
M.get_sort_method = function()
|
||||
local sort_method = state.settings.discussion_tree.sort_by == "original_comment" and "↓ by thread" or "↑ by reply"
|
||||
return "%#GitlabSortMethod#" .. sort_method .. "%#Comment#"
|
||||
end
|
||||
|
||||
M.get_resolved_text = function(focused, resolved_count, resolvable_count)
|
||||
local text = focused and ("%#GitlabResolved#" .. state.settings.discussion_tree.resolved .. "%#Text#")
|
||||
or state.settings.discussion_tree.resolved
|
||||
return " " .. string.format("%d%s/%d", resolved_count, text, resolvable_count)
|
||||
end
|
||||
|
||||
M.get_drafts_text = function(base_title, drafts_count, focused)
|
||||
return get_connector(base_title)
|
||||
.. string.format(
|
||||
"%d%s",
|
||||
drafts_count,
|
||||
(
|
||||
focused and ("%#GitlabDraft#" .. state.settings.discussion_tree.draft .. "%#Text#")
|
||||
or state.settings.discussion_tree.draft
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
M.get_nonresolveable_text = function(base_title, non_resolvable_count, focused)
|
||||
return get_connector(base_title)
|
||||
.. string.format(
|
||||
"%d%s",
|
||||
non_resolvable_count,
|
||||
(
|
||||
focused and ("%#GitlabUnlinked#" .. state.settings.discussion_tree.unlinked .. "%#Text#")
|
||||
or state.settings.discussion_tree.unlinked
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
---Returns a string for the winbar indicating the mode type, live or draft
|
||||
---@return string
|
||||
M.get_mode = function()
|
||||
if state.settings.discussion_tree.draft_mode then
|
||||
return "%#DiagnosticWarn#Draft Mode"
|
||||
return "%#GitlabDraftMode#Draft"
|
||||
else
|
||||
return "%#DiagnosticOK#Live Mode"
|
||||
return "%#GitlabLiveMode#Live"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -215,4 +272,8 @@ M.switch_view_type = function(override)
|
||||
M.update_winbar()
|
||||
end
|
||||
|
||||
-- Set up a timer to update the winbar periodically
|
||||
local timer = vim.uv.new_timer()
|
||||
timer:start(0, 100, vim.schedule_wrap(M.update_winbar))
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user