Files
gitlab.nvim/lua/gitlab/reviewer/location.lua
Harrison (Harry) Cramer be027331e1 Miscellaneous Bug Fixes (#423)
fix: Show non-resolvable notes in winbar (#417)
fix: add more emojis and make emoji picker configurable (#414)
fix: comment creation should not be possible for renamed and moved files (#416)
fix: color highlight groups are invalid (#421)
fix: plugin failing to build on Windows (#419)

---------

Co-authored-by: Jakub F. Bortlík <jakub.bortlik@proton.me>
2024-11-12 11:01:28 -05:00

236 lines
7.8 KiB
Lua
Executable File

local u = require("gitlab.utils")
local hunks = require("gitlab.hunks")
local state = require("gitlab.state")
---@class Location
---@field location_data LocationData
---@field reviewer_data DiffviewInfo
---@field run function
---@field build_location_data function
---@class ReviewerLineInfo
---@field old_line integer|nil
---@field new_line integer|nil
---@field type "new"|"old"
---@class ReviewerRangeInfo
---@field start ReviewerLineInfo
---@field end ReviewerLineInfo
local Location = {}
Location.__index = Location
---@param reviewer_data DiffviewInfo
---@param visual_range LineRange | nil
---@return Location
function Location.new(reviewer_data, visual_range)
local location = {}
local instance = setmetatable(location, Location)
instance.reviewer_data = reviewer_data
instance.visual_range = visual_range
instance.base_sha = state.INFO.diff_refs.base_sha
instance.head_sha = state.INFO.diff_refs.head_sha
return instance
end
---Takes in information about the current changes, such as the file name, modification type of the diff, and the line numbers
---and builds the appropriate payload when creating a comment.
function Location:build_location_data()
---@type DiffviewInfo
local reviewer_data = self.reviewer_data
---@type LineRange | nil
local visual_range = self.visual_range
---@type LocationData
local location_data = {
old_line = nil,
new_line = nil,
line_range = nil,
}
-- Comment on new line: Include only new_line in payload.
-- Comment on deleted line: Include only old_line in payload.
-- The line was not found in any hunks, send both lines.
if reviewer_data.modification_type == "added" then
location_data.old_line = nil
location_data.new_line = reviewer_data.new_line_from_buf
elseif reviewer_data.modification_type == "deleted" then
location_data.old_line = reviewer_data.old_line_from_buf
location_data.new_line = nil
elseif
reviewer_data.modification_type == "unmodified" or reviewer_data.modification_type == "bad_file_unmodified"
then
location_data.old_line = reviewer_data.old_line_from_buf
location_data.new_line = reviewer_data.new_line_from_buf
end
self.location_data = location_data
if visual_range == nil then
return
else
self.location_data.line_range = {
start = {},
["end"] = {},
}
end
self:set_start_range(visual_range)
self:set_end_range(visual_range)
-- Ranged comments should always use the end of the range.
-- Otherwise they will not highlight the full comment in Gitlab.
self.location_data.old_line = self.location_data.line_range["end"].old_line
self.location_data.new_line = self.location_data.line_range["end"].new_line
end
-- Helper methods 🤝
-- Returns the matching line from the new SHA.
-- For instance, line 12 in the new SHA may be scroll-linked
-- to line 10 in the old SHA.
---@param line number
---@return number|nil
function Location:get_line_number_from_new_sha(line)
local reviewer = require("gitlab.reviewer")
local is_current_sha_focused = reviewer.is_current_sha_focused()
if is_current_sha_focused then
return line
end
-- Otherwise we want to get the matching line in the opposite buffer
return hunks.calculate_matching_line_new(
self.base_sha,
self.head_sha,
self.reviewer_data.file_name,
self.reviewer_data.old_file_name,
line
)
end
-- Returns the matching line from the old SHA.
-- For instance, line 12 in the new SHA may be scroll-linked
-- to line 10 in the old SHA.
---@param line number
---@return number|nil
function Location:get_line_number_from_old_sha(line)
local reviewer = require("gitlab.reviewer")
local is_current_sha_focused = reviewer.is_current_sha_focused()
if not is_current_sha_focused then
return line
end
-- Otherwise we want to get the matching line in the opposite buffer
return hunks.calculate_matching_line_new(
self.head_sha,
self.base_sha,
self.reviewer_data.file_name,
self.reviewer_data.old_file_name,
line
)
end
-- Returns the current line number from whatever SHA (new or old)
-- the reviewer is focused in.
---@return number|nil
function Location:get_current_line()
local reviewer = require("gitlab.reviewer")
local win_id = reviewer.is_current_sha_focused() and self.reviewer_data.new_sha_win_id
or self.reviewer_data.old_sha_win_id
if win_id == nil then
return
end
local current_line = vim.api.nvim_win_get_cursor(win_id)[1]
return current_line
end
-- Given a new_line and old_line from the start of a ranged comment, returns the start
-- range information for the Gitlab payload
---@param visual_range LineRange
---@return ReviewerLineInfo|nil
function Location:set_start_range(visual_range)
local current_file = require("gitlab.reviewer").get_current_file_path()
if current_file == nil then
u.notify("Error getting current file from Diffview", vim.log.levels.ERROR)
return
end
local reviewer = require("gitlab.reviewer")
local is_current_sha_focused = reviewer.is_current_sha_focused()
local win_id = is_current_sha_focused and self.reviewer_data.new_sha_win_id or self.reviewer_data.old_sha_win_id
if win_id == nil then
u.notify("Error getting window number of SHA for start range", vim.log.levels.ERROR)
return
end
local current_line = self:get_current_line()
if current_line == nil then
u.notify("Error getting current line for start range", vim.log.levels.ERROR)
return
end
local new_line = self:get_line_number_from_new_sha(visual_range.start_line)
local old_line = self:get_line_number_from_old_sha(visual_range.start_line)
if
(new_line == nil and self.reviewer_data.modification_type ~= "deleted")
or (old_line == nil and self.reviewer_data.modification_type ~= "added")
then
u.notify("Error getting new or old line for start range", vim.log.levels.ERROR)
return
end
local modification_type = hunks.get_modification_type(old_line, new_line, is_current_sha_focused)
if modification_type == nil then
u.notify("Error getting modification type for start of range", vim.log.levels.ERROR)
return
end
self.location_data.line_range.start = {
new_line = modification_type ~= "deleted" and new_line or nil,
old_line = modification_type ~= "added" and old_line or nil,
type = modification_type == "added" and "new" or "old",
}
end
-- Given a modification type, a range, and the hunk data, returns the end range information
-- for the Gitlab payload
---@param visual_range LineRange
function Location:set_end_range(visual_range)
local current_file = require("gitlab.reviewer").get_current_file_path()
if current_file == nil then
u.notify("Error getting current file from Diffview", vim.log.levels.ERROR)
return
end
local current_line = self:get_current_line()
if current_line == nil then
u.notify("Error getting current line for end range", vim.log.levels.ERROR)
return
end
local new_line = self:get_line_number_from_new_sha(visual_range.end_line)
local old_line = self:get_line_number_from_old_sha(visual_range.end_line)
if
(new_line == nil and self.reviewer_data.modification_type ~= "deleted")
or (old_line == nil and self.reviewer_data.modification_type ~= "added")
then
u.notify("Error getting new or old line for end range", vim.log.levels.ERROR)
return
end
local reviewer = require("gitlab.reviewer")
local is_current_sha_focused = reviewer.is_current_sha_focused()
local modification_type = hunks.get_modification_type(old_line, new_line, is_current_sha_focused)
if modification_type == nil then
u.notify("Error getting modification type for end of range", vim.log.levels.ERROR)
return
end
self.location_data.line_range["end"] = {
new_line = modification_type ~= "deleted" and new_line or nil,
old_line = modification_type ~= "added" and old_line or nil,
type = modification_type == "added" and "new" or "old",
}
end
return Location