2.0.0 (#196)
This MR is a #MAJOR breaking change to the plugin. While the plugin will continue to work for users with their existing settings, they will be informed of outdated configuration (diagnostics and signs have been simplified) the next time they open the reviewer. Fix: Trim trailing slash from custom URLs Update: .github/CONTRIBUTING.md, .github/ISSUE_TEMPLATE/bug_report.md Feat: Improve discussion tree toggling (#192) Fix: Toggle modified notes (#188) Fix: Toggle discussion nodes correctly Feat: Show Help keymap in discussion tree winbar Fix: Enable toggling nodes from the note body Fix: Enable toggling resolved status from child nodes Fix: Only try to show emoji popup on note nodes Feat: Add keymap for toggling tree type Fix: Disable tree type toggling in Notes Fix Multi Line Issues (Large Refactor) (#197) Fix: Multi-line discussions. The calculation of a range for a multiline comment has been consolidated and moved into the location.lua file. This does not attempt to fix diagnostics. Refactor: It refactors the discussions code to split hunk parsing and management into a separate module Fix: Don't allow comments on modified buffers #194 by preventing comments on the reviewer when using --imply-local and when the working tree is dirty entirely. Refactor: It introduces a new List class for data aggregation, filtering, etc. Fix: It removes redundant API calls and refreshes from the discussion pane Fix: Location provider (#198) Fix: add nil check for Diffview performance issue (#199) Fix: Switch Tabs During Comment Creation (#200) Fix: Check if file is modified (#201) Fix: Off-By-One Issue in Old SHA (#202) Fix: Rebuild Diagnostics + Signs (#203) Fix: Off-By-One Issue in New SHA (#205) Fix: Reviewer Jumps to wrong location (#206) BREAKING CHANGE: Changes configuration of diagnostics and signs in the setup call.
This commit is contained in:
committed by
GitHub
parent
f6a5238d4b
commit
b5b475ce8b
73
lua/gitlab/indicators/common.lua
Normal file
73
lua/gitlab/indicators/common.lua
Normal file
@@ -0,0 +1,73 @@
|
||||
local u = require("gitlab.utils")
|
||||
local state = require("gitlab.state")
|
||||
local reviewer = require("gitlab.reviewer")
|
||||
local List = require("gitlab.utils.list")
|
||||
|
||||
local M = {}
|
||||
|
||||
---Filter all discussions which are relevant for currently visible signs and diagnostics.
|
||||
---@return Discussion[]
|
||||
M.filter_placeable_discussions = function(all_discussions)
|
||||
if type(all_discussions) ~= "table" then
|
||||
return {}
|
||||
end
|
||||
local file = reviewer.get_current_file()
|
||||
if not file then
|
||||
return {}
|
||||
end
|
||||
return List.new(all_discussions):filter(function(discussion)
|
||||
local first_note = discussion.notes[1]
|
||||
return type(first_note.position) == "table"
|
||||
--Do not include unlinked notes
|
||||
and (first_note.position.new_path == file or first_note.position.old_path == file)
|
||||
--Skip resolved discussions if user wants to
|
||||
and not (state.settings.discussion_signs.skip_resolved_discussion and first_note.resolvable and first_note.resolved)
|
||||
--Skip discussions from old revisions
|
||||
and not (
|
||||
state.settings.discussion_signs.skip_old_revision_discussion
|
||||
and u.from_iso_format_date_to_timestamp(first_note.created_at)
|
||||
<= u.from_iso_format_date_to_timestamp(state.MR_REVISIONS[1].created_at)
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
M.parse_line_code = function(line_code)
|
||||
local line_code_regex = "%w+_(%d+)_(%d+)"
|
||||
local old_line, new_line = line_code:match(line_code_regex)
|
||||
return tonumber(old_line), tonumber(new_line)
|
||||
end
|
||||
|
||||
---@param discussion Discussion
|
||||
---@return boolean
|
||||
M.is_old_sha = function(discussion)
|
||||
local first_note = discussion.notes[1]
|
||||
return first_note.position.old_line ~= nil
|
||||
end
|
||||
|
||||
---@param discussion Discussion
|
||||
---@return boolean
|
||||
M.is_new_sha = function(discussion)
|
||||
return not M.is_old_sha(discussion)
|
||||
end
|
||||
|
||||
---@param discussion Discussion
|
||||
---@return boolean
|
||||
M.is_single_line = function(discussion)
|
||||
local first_note = discussion.notes[1]
|
||||
local line_range = first_note.position.line_range
|
||||
return line_range == nil
|
||||
end
|
||||
|
||||
---@param discussion Discussion
|
||||
---@return boolean
|
||||
M.is_multi_line = function(discussion)
|
||||
return not M.is_single_line(discussion)
|
||||
end
|
||||
|
||||
---@param discussion Discussion
|
||||
---@return Note
|
||||
M.get_first_note = function(discussion)
|
||||
return discussion.notes[1]
|
||||
end
|
||||
|
||||
return M
|
||||
152
lua/gitlab/indicators/diagnostics.lua
Normal file
152
lua/gitlab/indicators/diagnostics.lua
Normal file
@@ -0,0 +1,152 @@
|
||||
local u = require("gitlab.utils")
|
||||
local diffview_lib = require("diffview.lib")
|
||||
local discussion_tree = require("gitlab.actions.discussions.tree")
|
||||
local common = require("gitlab.indicators.common")
|
||||
local List = require("gitlab.utils.list")
|
||||
local state = require("gitlab.state")
|
||||
local discussion_sign_name = "gitlab_discussion"
|
||||
|
||||
local M = {}
|
||||
local diagnostics_namespace = vim.api.nvim_create_namespace(discussion_sign_name)
|
||||
M.diagnostics_namespace = diagnostics_namespace
|
||||
M.discussion_sign_name = discussion_sign_name
|
||||
M.clear_diagnostics = function()
|
||||
vim.diagnostic.reset(diagnostics_namespace)
|
||||
end
|
||||
|
||||
-- Display options for the diagnostic
|
||||
local display_opts = {
|
||||
virtual_text = state.settings.discussion_signs.virtual_text,
|
||||
severity_sort = true,
|
||||
underline = false,
|
||||
}
|
||||
|
||||
---Takes some range information and data about a discussion
|
||||
---and creates a diagnostic to be placed in the reviewer
|
||||
---@param range_info table
|
||||
---@param discussion Discussion
|
||||
---@return Diagnostic
|
||||
local function create_diagnostic(range_info, discussion)
|
||||
local message = ""
|
||||
for _, note in ipairs(discussion.notes) do
|
||||
message = message .. discussion_tree.build_note_header(note) .. "\n" .. note.body .. "\n"
|
||||
end
|
||||
|
||||
local diagnostic = {
|
||||
message = message,
|
||||
col = 0,
|
||||
severity = state.settings.discussion_signs.severity,
|
||||
user_data = { discussion_id = discussion.id, header = discussion_tree.build_note_header(discussion.notes[1]) },
|
||||
source = "gitlab",
|
||||
code = "gitlab.nvim",
|
||||
}
|
||||
return vim.tbl_deep_extend("force", diagnostic, range_info)
|
||||
end
|
||||
|
||||
---Creates a single line diagnostic
|
||||
---@param discussion Discussion
|
||||
---@return Diagnostic
|
||||
local create_single_line_diagnostic = function(discussion)
|
||||
local first_note = discussion.notes[1]
|
||||
return create_diagnostic({
|
||||
lnum = first_note.position.new_line - 1,
|
||||
}, discussion)
|
||||
end
|
||||
|
||||
---Creates a mutli-line line diagnostic
|
||||
---@param discussion Discussion
|
||||
---@return Diagnostic
|
||||
local create_multiline_diagnostic = function(discussion)
|
||||
local first_note = discussion.notes[1]
|
||||
local line_range = first_note.position.line_range
|
||||
if line_range == nil then
|
||||
error("Parsing multi-line comment but note does not contain line range")
|
||||
end
|
||||
|
||||
local start_old_line, start_new_line = common.parse_line_code(line_range.start.line_code)
|
||||
|
||||
if common.is_new_sha(discussion) then
|
||||
return create_diagnostic({
|
||||
lnum = start_new_line - 1,
|
||||
end_lnum = first_note.position.new_line - 1,
|
||||
}, discussion)
|
||||
else
|
||||
return create_diagnostic({
|
||||
lnum = start_old_line - 1,
|
||||
end_lnum = first_note.position.old_line - 1,
|
||||
}, discussion)
|
||||
end
|
||||
end
|
||||
|
||||
---Set diagnostics in currently new SHA.
|
||||
---@param namespace number namespace for diagnostics
|
||||
---@param diagnostics table see :h vim.diagnostic.set
|
||||
---@param opts table? see :h vim.diagnostic.set
|
||||
local set_diagnostics_in_new_sha = function(namespace, diagnostics, opts)
|
||||
local view = diffview_lib.get_current_view()
|
||||
if not view then
|
||||
return
|
||||
end
|
||||
vim.diagnostic.set(namespace, view.cur_layout.b.file.bufnr, diagnostics, opts)
|
||||
require("gitlab.indicators.signs").set_signs(diagnostics, view.cur_layout.b.file.bufnr)
|
||||
end
|
||||
|
||||
---Set diagnostics in old SHA.
|
||||
---@param namespace number namespace for diagnostics
|
||||
---@param diagnostics table see :h vim.diagnostic.set
|
||||
---@param opts table? see :h vim.diagnostic.set
|
||||
local set_diagnostics_in_old_sha = function(namespace, diagnostics, opts)
|
||||
local view = diffview_lib.get_current_view()
|
||||
if not view then
|
||||
return
|
||||
end
|
||||
vim.diagnostic.set(namespace, view.cur_layout.a.file.bufnr, diagnostics, opts)
|
||||
require("gitlab.indicators.signs").set_signs(diagnostics, view.cur_layout.a.file.bufnr)
|
||||
end
|
||||
|
||||
---Refresh the diagnostics for the currently reviewed file
|
||||
---@param discussions Discussion[]
|
||||
M.refresh_diagnostics = function(discussions)
|
||||
local ok, err = pcall(function()
|
||||
require("gitlab.indicators.signs").clear_signs()
|
||||
M.clear_diagnostics()
|
||||
local filtered_discussions = common.filter_placeable_discussions(discussions)
|
||||
if filtered_discussions == nil then
|
||||
return
|
||||
end
|
||||
|
||||
local new_diagnostics = M.parse_new_diagnostics(filtered_discussions)
|
||||
set_diagnostics_in_new_sha(diagnostics_namespace, new_diagnostics, display_opts)
|
||||
|
||||
local old_diagnostics = M.parse_old_diagnostics(filtered_discussions)
|
||||
set_diagnostics_in_old_sha(diagnostics_namespace, old_diagnostics, display_opts)
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
u.notify(string.format("Error setting diagnostics: %s", err), vim.log.levels.ERROR)
|
||||
end
|
||||
end
|
||||
|
||||
---Iterates over each discussion and returns a list of tables with sign
|
||||
---data, for instance group, priority, line number etc for the new SHA
|
||||
---@param discussions Discussion[]
|
||||
---@return DiagnosticTable[]
|
||||
M.parse_new_diagnostics = function(discussions)
|
||||
local new_diagnostics = List.new(discussions):filter(common.is_new_sha)
|
||||
local single_line = new_diagnostics:filter(common.is_single_line):map(create_single_line_diagnostic)
|
||||
local multi_line = new_diagnostics:filter(common.is_multi_line):map(create_multiline_diagnostic)
|
||||
return u.combine(single_line, multi_line)
|
||||
end
|
||||
|
||||
---Iterates over each discussion and returns a list of tables with sign
|
||||
---data, for instance group, priority, line number etc for the old SHA
|
||||
---@param discussions Discussion[]
|
||||
---@return DiagnosticTable[]
|
||||
M.parse_old_diagnostics = function(discussions)
|
||||
local old_diagnostics = List.new(discussions):filter(common.is_old_sha)
|
||||
local single_line = old_diagnostics:filter(common.is_single_line):map(create_single_line_diagnostic)
|
||||
local multi_line = old_diagnostics:filter(common.is_multi_line):map(create_multiline_diagnostic)
|
||||
return u.combine(single_line, multi_line)
|
||||
end
|
||||
|
||||
return M
|
||||
96
lua/gitlab/indicators/signs.lua
Normal file
96
lua/gitlab/indicators/signs.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
local u = require("gitlab.utils")
|
||||
local state = require("gitlab.state")
|
||||
local List = require("gitlab.utils.list")
|
||||
local discussion_sign_name = require("gitlab.indicators.diagnostics").discussion_sign_name
|
||||
local namespace = require("gitlab.indicators.diagnostics").diagnostics_namespace
|
||||
|
||||
local M = {}
|
||||
M.clear_signs = function()
|
||||
vim.fn.sign_unplace(discussion_sign_name)
|
||||
end
|
||||
|
||||
local gitlab_comment = "GitlabComment"
|
||||
local gitlab_range = "GitlabRange"
|
||||
|
||||
local severity_map = {
|
||||
"Error",
|
||||
"Warn",
|
||||
"Info",
|
||||
"Hint",
|
||||
}
|
||||
|
||||
---Refresh the discussion signs for currently loaded file in reviewer For convinience we use same
|
||||
---string for sign name and sign group ( currently there is only one sign needed)
|
||||
---@param diagnostics Diagnostic[]
|
||||
---@param bufnr number
|
||||
M.set_signs = function(diagnostics, bufnr)
|
||||
if not state.settings.discussion_sign.enabled then
|
||||
return
|
||||
end
|
||||
|
||||
-- Filter diagnostics from the 'gitlab' source and apply custom signs
|
||||
for _, diagnostic in ipairs(diagnostics) do
|
||||
---@type SignTable[]
|
||||
local existing_signs =
|
||||
vim.fn.sign_getplaced(vim.api.nvim_get_current_buf(), { group = "gitlab_discussion" })[1].signs
|
||||
|
||||
local sign_id = string.format("%s__%d", namespace, diagnostic.lnum)
|
||||
if diagnostic.end_lnum then
|
||||
local linenr = diagnostic.lnum + 1
|
||||
while linenr <= diagnostic.end_lnum do
|
||||
linenr = linenr + 1
|
||||
local conflicting_comment_sign = List.new(existing_signs):find(function(sign)
|
||||
return u.ends_with(sign.name, gitlab_comment) and sign.lnum == linenr
|
||||
end)
|
||||
if conflicting_comment_sign == nil then
|
||||
vim.fn.sign_place(
|
||||
sign_id,
|
||||
discussion_sign_name,
|
||||
"DiagnosticSign" .. M.severity .. gitlab_range,
|
||||
bufnr,
|
||||
{ lnum = linenr, priority = state.settings.discussion_signs.priority }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vim.fn.sign_place(
|
||||
sign_id,
|
||||
discussion_sign_name,
|
||||
"DiagnosticSign" .. M.severity .. gitlab_comment,
|
||||
bufnr,
|
||||
{ lnum = diagnostic.lnum + 1, priority = state.settings.discussion_signs.priority }
|
||||
)
|
||||
|
||||
-- TODO: Detect whether diagnostic is ranged and set helper signs
|
||||
end
|
||||
end
|
||||
|
||||
---Define signs for discussions
|
||||
M.setup_signs = function()
|
||||
local discussion_sign_settings = state.settings.discussion_signs
|
||||
local comment_icon = discussion_sign_settings.icons.comment
|
||||
local range_icon = discussion_sign_settings.icons.range
|
||||
M.severity = severity_map[state.settings.discussion_signs.severity]
|
||||
local signs = { "Error", "Warn", "Hint", "Info" }
|
||||
for _, type in ipairs(signs) do
|
||||
-- Define comment highlight group
|
||||
local hl = "DiagnosticSign" .. type
|
||||
local comment_hl = hl .. gitlab_comment
|
||||
vim.fn.sign_define(comment_hl, {
|
||||
text = comment_icon,
|
||||
texthl = comment_hl,
|
||||
})
|
||||
vim.cmd(string.format("highlight link %s %s", comment_hl, hl))
|
||||
|
||||
-- Define range highlight group
|
||||
local range_hl = hl .. gitlab_range
|
||||
vim.fn.sign_define(range_hl, {
|
||||
text = range_icon,
|
||||
texthl = range_hl,
|
||||
})
|
||||
vim.cmd(string.format("highlight link %s %s", range_hl, hl))
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user