Multiline comment and suggestion (#66)

This MR adds the ability to leave multi-line comments and suggested changes to an MR. The features are only supported for `diffview` because we plan to deprecate `delta` as a reviewer soon.
This commit is contained in:
johnybx
2023-10-31 02:58:53 +01:00
committed by GitHub
parent f853c2f940
commit 3a67424fec
11 changed files with 689 additions and 161 deletions

View File

@@ -1,22 +1,23 @@
-- This Module contains all of the code specific to the Diffview reviewer.
local state = require("gitlab.state")
local u = require("gitlab.utils")
local state = require("gitlab.state")
local async_ok, async = pcall(require, "diffview.async")
local M = {
local M = {
bufnr = nil,
tabnr = nil
tabnr = nil,
}
-- Public Functions
-- These functions are exposed externally and are used
-- when the reviewer is consumed by other code. They must follow the specification
-- outlined in the reviewer/init.lua file
M.open = function()
M.open = function()
vim.api.nvim_command(string.format("DiffviewOpen %s", state.INFO.target_branch))
M.tabnr = vim.api.nvim_get_current_tabpage()
end
M.jump = function(file_name, new_line, old_line)
M.jump = function(file_name, new_line, old_line)
if M.tabnr == nil then
vim.notify("Can't jump to Diffvew. Is it open?", vim.log.levels.ERROR)
return
@@ -49,12 +50,25 @@ M.jump = function(file_name, new_line, old_line)
end
end
M.get_location = function()
if M.tabnr == nil then return nil, nil, "Diffview reviewer must be initialized first" end
---Get the location of a line within the diffview. If range is specified, then also the location
---of the lines in range.
---@param range LineRange | nil Line range to get location for
---@return ReviewerInfo | nil nil is returned only if error was encountered
M.get_location = function(range)
if M.tabnr == nil then
vim.notify("Diffview reviewer must be initialized first")
return
end
local bufnr = vim.api.nvim_get_current_buf()
local current_line = vim.api.nvim_win_get_cursor(0)[1]
-- check if we are in the diffview tab
local tabnr = vim.api.nvim_get_current_tabpage()
if tabnr ~= M.tabnr then return nil, nil, "Line location can only be determined within reviewer window" end
if tabnr ~= M.tabnr then
vim.notify("Line location can only be determined within reviewer window")
return
end
-- check if we are in the diffview buffer
local view = require("diffview.lib").get_current_view()
if view == nil then
@@ -62,18 +76,81 @@ M.get_location = function()
return
end
local layout = view.cur_layout
local file_name = nil
local current_line_changes = nil
local result = {}
local type
local is_new
if layout.a.file.bufnr == bufnr then
file_name = layout.a.file.path
current_line_changes = { new_line = nil, old_line = vim.api.nvim_win_get_cursor(0)[1] }
return file_name, current_line_changes
result.file_name = layout.a.file.path
result.old_line = current_line
type = "old"
is_new = false
elseif layout.b.file.bufnr == bufnr then
file_name = layout.b.file.path
current_line_changes = { new_line = vim.api.nvim_win_get_cursor(0)[1], old_line = nil }
return file_name, current_line_changes
result.file_name = layout.b.file.path
result.new_line = current_line
type = "new"
is_new = true
else
vim.notify("Line location can only be determined within reviewer window")
return
end
return nil, nil, "Line location can only be determined within reviewer window"
local hunks = u.parse_hunk_headers(result.file_name, state.INFO.target_branch)
if hunks == nil then
vim.notify("Could not parse hunks", vim.log.levels.ERROR)
return
end
local current_line_info
if is_new then
current_line_info = u.get_lines_from_hunks(hunks, result.new_line, is_new)
else
current_line_info = u.get_lines_from_hunks(hunks, result.old_line, is_new)
end
-- If single line comment is outside of changed lines then we need to specify both new line and old line
-- otherwise the API returns error.
-- https://docs.gitlab.com/ee/api/discussions.html#create-a-new-thread-in-the-merge-request-diff
if not current_line_info.in_hunk then
result.old_line = current_line_info.old_line
result.new_line = current_line_info.new_line
end
if range == nil then
return result
end
result.range_info = { start = {}, ["end"] = {} }
if current_line == range.start_line then
result.range_info.start.old_line = current_line_info.old_line
result.range_info.start.new_line = current_line_info.new_line
result.range_info.start.type = type
else
local start_line_info = u.get_lines_from_hunks(hunks, range.start_line, is_new)
result.range_info.start.old_line = start_line_info.old_line
result.range_info.start.new_line = start_line_info.new_line
result.range_info.start.type = type
end
if current_line == range.end_line then
result.range_info["end"].old_line = current_line_info.old_line
result.range_info["end"].new_line = current_line_info.new_line
result.range_info["end"].type = type
else
local end_line_info = u.get_lines_from_hunks(hunks, range.end_line, is_new)
result.range_info["end"].old_line = end_line_info.old_line
result.range_info["end"].new_line = end_line_info.new_line
result.range_info["end"].type = type
end
return result
end
---Return content between start_line and end_line
---@param start_line integer
---@param end_line integer
---@return string[]
M.get_lines = function(start_line, end_line)
return vim.api.nvim_buf_get_lines(0, start_line - 1, end_line, false)
end
return M