This MR simplifies the plugin quite a bit by only attempting to start the Go server after you specifically try to run a command. This streamlines working on feature branches and removes the need for a `base_branch` property entirely.
234 lines
7.2 KiB
Lua
234 lines
7.2 KiB
Lua
local Menu = require("nui.menu")
|
|
local NuiTree = require("nui.tree")
|
|
local Popup = require("nui.popup")
|
|
local job = require("gitlab.job")
|
|
local state = require("gitlab.state")
|
|
local u = require("gitlab.utils")
|
|
local discussions = require("gitlab.discussions")
|
|
local keymaps = require("gitlab.keymaps")
|
|
local M = {}
|
|
|
|
local comment_popup = Popup(u.create_popup_state("Comment", "40%", "60%"))
|
|
local edit_popup = Popup(u.create_popup_state("Edit Comment", "80%", "80%"))
|
|
|
|
-- Function that fires to open the comment popup
|
|
M.create_comment = function()
|
|
comment_popup:mount()
|
|
keymaps.set_popup_keymaps(comment_popup, M.confirm_create_comment)
|
|
end
|
|
|
|
-- Actually sends the comment to Gitlab
|
|
M.confirm_create_comment = function(text)
|
|
local relative_file_path = u.get_relative_file_path()
|
|
local current_line_number = u.get_current_line_number()
|
|
if relative_file_path == nil then return end
|
|
|
|
-- If leaving a comment on a deleted line, get hash value + proper filename
|
|
local sha = ""
|
|
local is_base_file = relative_file_path:find(".git")
|
|
if is_base_file then -- We are looking at a deletion.
|
|
local _, path = u.split_diff_view_filename(relative_file_path)
|
|
relative_file_path = path
|
|
sha = M.find_deletion_commit(path)
|
|
if sha == "" then
|
|
return
|
|
end
|
|
end
|
|
|
|
local jsonTable = { line_number = current_line_number, file_name = relative_file_path, comment = text }
|
|
local json = vim.json.encode(jsonTable)
|
|
|
|
job.run_job("comment", "POST", json, function(data)
|
|
vim.notify("Comment created")
|
|
discussions.refresh_tree()
|
|
end)
|
|
end
|
|
|
|
-- Function to open the deletion popup
|
|
M.delete_comment = function()
|
|
local menu = Menu({
|
|
position = "50%",
|
|
size = {
|
|
width = 25,
|
|
},
|
|
border = {
|
|
style = "single",
|
|
text = {
|
|
top = "Delete Comment?",
|
|
top_align = "center",
|
|
},
|
|
},
|
|
win_options = {
|
|
winhighlight = "Normal:Normal,FloatBorder:Normal",
|
|
},
|
|
}, {
|
|
lines = {
|
|
Menu.item("Confirm"),
|
|
Menu.item("Cancel"),
|
|
},
|
|
max_width = 20,
|
|
keymap = {
|
|
focus_next = state.keymaps.dialogue.focus_next,
|
|
focus_prev = state.keymaps.dialogue.focus_prev,
|
|
close = state.keymaps.dialogue.close,
|
|
submit = state.keymaps.dialogue.submit,
|
|
},
|
|
on_submit = M.send_deletion
|
|
})
|
|
menu:mount()
|
|
end
|
|
|
|
-- Function to actually send the deletion to Gitlab
|
|
M.send_deletion = function(item)
|
|
if item.text == "Confirm" then
|
|
local current_node = state.tree:get_node()
|
|
|
|
local note_node = discussions.get_note_node(current_node)
|
|
local root_node = discussions.get_root_node(current_node)
|
|
local note_id = note_node.is_root and root_node.root_note_id or note_node.id
|
|
|
|
local jsonTable = { discussion_id = root_node.id, note_id = note_id }
|
|
local json = vim.json.encode(jsonTable)
|
|
|
|
job.run_job("comment", "DELETE", json, function(data)
|
|
vim.notify(data.message, vim.log.levels.INFO)
|
|
if not note_node.is_root then
|
|
state.tree:remove_node("-" .. note_id)
|
|
state.tree:render()
|
|
else
|
|
-- We are removing the root node of the discussion,
|
|
-- we need to move all the children around, the easiest way
|
|
-- to do this is to just re-render the whole tree 🤷
|
|
discussions.refresh_tree()
|
|
note_node:expand()
|
|
end
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- Function that opens the edit popup from the discussion tree
|
|
M.edit_comment = function()
|
|
local current_node = state.tree:get_node()
|
|
local note_node = discussions.get_note_node(current_node)
|
|
local root_node = discussions.get_root_node(current_node)
|
|
|
|
edit_popup:mount()
|
|
|
|
local lines = {} -- Gather all lines from immediate children that aren't note nodes
|
|
local children_ids = note_node:get_child_ids()
|
|
for _, child_id in ipairs(children_ids) do
|
|
local child_node = state.tree:get_node(child_id)
|
|
if (not child_node:has_children()) then
|
|
local line = state.tree:get_node(child_id).text
|
|
table.insert(lines, line)
|
|
end
|
|
end
|
|
|
|
local currentBuffer = vim.api.nvim_get_current_buf()
|
|
vim.api.nvim_buf_set_lines(currentBuffer, 0, -1, false, lines)
|
|
keymaps.set_popup_keymaps(edit_popup, M.send_edits(tostring(root_node.id), note_node.root_note_id or note_node.id))
|
|
end
|
|
|
|
-- Function that actually makes the API call
|
|
M.send_edits = function(discussion_id, note_id)
|
|
return function(text)
|
|
local json_table = {
|
|
discussion_id = discussion_id,
|
|
note_id = note_id,
|
|
comment = text
|
|
}
|
|
local json = vim.json.encode(json_table)
|
|
job.run_job("comment", "PATCH", json, function(data)
|
|
vim.notify(data.message, vim.log.levels.INFO)
|
|
M.redraw_text(text)
|
|
end)
|
|
end
|
|
end
|
|
|
|
M.toggle_resolved = function()
|
|
local note = state.tree:get_node()
|
|
if not note.resolvable then return end
|
|
|
|
local json_table = {
|
|
discussion_id = note.id,
|
|
note_id = note.root_note_id,
|
|
resolved = not note.resolved,
|
|
}
|
|
|
|
local json = vim.json.encode(json_table)
|
|
job.run_job("comment", "PATCH", json, function(data)
|
|
vim.notify(data.message, vim.log.levels.INFO)
|
|
M.update_resolved_status(note, not note.resolved)
|
|
end)
|
|
end
|
|
|
|
-- Helpers
|
|
M.find_deletion_commit = function(file)
|
|
local current_line = vim.api.nvim_get_current_line()
|
|
local command = string.format("git log -S '%s' %s", current_line, file)
|
|
local handle = io.popen(command)
|
|
local output = handle:read("*line")
|
|
if output == nil then
|
|
vim.notify("Error reading SHA of deletion commit", vim.log.levels.ERROR)
|
|
return ""
|
|
end
|
|
handle:close()
|
|
local words = {}
|
|
for word in output:gmatch("%S+") do
|
|
table.insert(words, word)
|
|
end
|
|
|
|
return words[2]
|
|
end
|
|
|
|
M.update_resolved_status = function(note, mark_resolved)
|
|
local current_text = state.tree.nodes.by_id["-" .. note.id].text
|
|
local target = mark_resolved and 'resolved' or 'unresolved'
|
|
local current = mark_resolved and 'unresolved' or 'resolved'
|
|
|
|
local function set_property(key, val)
|
|
state.tree.nodes.by_id["-" .. note.id][key] = val
|
|
end
|
|
|
|
local has_symbol = function(s)
|
|
return state.SYMBOLS[s] ~= nil and state.SYMBOLS[s] ~= ''
|
|
end
|
|
|
|
set_property('resolved', mark_resolved)
|
|
|
|
if not has_symbol(current) and not has_symbol(target) then return end
|
|
|
|
if not has_symbol(current) and has_symbol(target) then
|
|
set_property('text', (current_text .. " " .. state.SYMBOLS[target]))
|
|
elseif has_symbol(current) and not has_symbol(target) then
|
|
set_property('text', u.remove_last_chunk(current_text))
|
|
else
|
|
set_property('text', (u.remove_last_chunk(current_text) .. " " .. state.SYMBOLS[target]))
|
|
end
|
|
|
|
state.tree:render()
|
|
end
|
|
|
|
M.redraw_text = function(text)
|
|
local current_node = state.tree:get_node()
|
|
local note_node = discussions.get_note_node(current_node)
|
|
|
|
local childrenIds = note_node:get_child_ids()
|
|
for _, value in ipairs(childrenIds) do
|
|
state.tree:remove_node(value)
|
|
end
|
|
|
|
local newNoteTextNodes = {}
|
|
for bodyLine in text:gmatch("[^\n]+") do
|
|
table.insert(newNoteTextNodes, NuiTree.Node({ text = bodyLine, is_body = true }, {}))
|
|
end
|
|
|
|
state.tree:set_nodes(newNoteTextNodes, "-" .. note_node.id)
|
|
|
|
state.tree:render()
|
|
local buf = vim.api.nvim_get_current_buf()
|
|
u.darken_metadata(buf, '')
|
|
end
|
|
|
|
return M
|