Files
gitlab.nvim/lua/gitlab/discussions.lua
2023-04-23 14:32:19 -04:00

207 lines
6.0 KiB
Lua

local u = require("gitlab.utils")
local NuiTree = require("nui.tree")
local notify = require("notify")
local state = require("gitlab.state")
local Job = require("plenary.job")
local Popup = require("nui.popup")
local keymaps = require("gitlab.keymaps")
local M = {}
local replyPopup = Popup(u.create_popup_state("Reply", "80%", "80%"))
M.reply = function()
if u.base_invalid() then return end
replyPopup:mount()
keymaps.set_popup_keymaps(replyPopup, M.send_reply)
end
M.send_reply = function(text)
Job:new({
command = state.BIN,
args = {
"reply",
state.PROJECT_ID,
state.ACTIVE_DISCUSSION,
text,
},
on_stdout = function(_, line)
local note = vim.json.decode(line)
if note == nil then
notify("There was an issue creating the note", "error")
return
end
local note_node = M.build_note(note)
note_node:expand()
state.tree:add_node(note_node, "-" .. state.ACTIVE_DISCUSSION)
vim.schedule(function()
state.tree:render()
local buf = vim.api.nvim_get_current_buf()
u.darken_metadata(buf, '')
notify("Sent reply!")
end)
end,
on_stderr = u.print_error
}):start()
end
-- Places all of the discussions into a readable list
M.list_discussions = function()
if u.base_invalid() then return end
Job:new({
command = state.BIN,
args = { "listDiscussions", state.PROJECT_ID },
on_stdout = function(_, line)
local discussions = vim.json.decode(line)
if (type(discussions) == 'userdata') then
notify("No discussions found for this MR", "warn")
return
end
M.discussions = discussions
vim.schedule(function()
vim.cmd.tabnew()
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_command("vsplit")
vim.api.nvim_buf_set_option(buf, 'filetype', 'markdown')
vim.api.nvim_set_current_buf(buf)
local allDiscussions = {}
for i, discussion in ipairs(discussions) do
local discussionChildren = {}
for _, note in ipairs(discussion.notes) do
local note_node = M.build_note(note)
if i == 1 then
note_node:expand()
end
table.insert(discussionChildren, note_node)
end
local discussionNode = NuiTree.Node({
text = discussion.id,
id = discussion.id,
is_discussion = true
},
discussionChildren)
if i == 1 then
discussionNode:expand()
end
table.insert(allDiscussions, discussionNode)
end
state.tree = NuiTree({ nodes = allDiscussions, bufnr = buf })
M.set_tree_keymaps(buf)
state.tree:render()
vim.api.nvim_buf_set_option(buf, 'filetype', 'markdown')
u.darken_metadata(buf, '')
M.jump_to_file()
end)
end,
on_stderr = u.print_error,
}):start()
end
M.jump_to_file = function()
local node = state.tree:get_node()
if node == nil then return end
local childrenIds = node:get_child_ids()
-- We have selected a note node
if node.file_name ~= nil then
u.jump_to_file(node.file_name, node.line_number)
elseif node.is_body then
local parentId = node:get_parent_id()
local parent = state.tree:get_node(parentId)
if parent == nil then return end
u.jump_to_file(parent.file_name, parent.line_number)
else
local firstChild = state.tree:get_node(childrenIds[1])
if firstChild == nil then return end
u.jump_to_file(firstChild.file_name, firstChild.line_number)
end
end
M.set_tree_keymaps = function(buf)
-- Jump to file location where comment was left
vim.keymap.set('n', state.keymaps.discussion_tree.jump_to_location, function()
M.jump_to_file()
end, { buffer = true })
vim.keymap.set('n', state.keymaps.discussion_tree.edit_comment, function()
require("gitlab.comment").edit_comment()
end, { buffer = true })
vim.keymap.set('n', state.keymaps.discussion_tree.delete_comment, function()
require("gitlab.comment").delete_comment()
end)
-- Expand/collapse the current node
vim.keymap.set('n', state.keymaps.discussion_tree.toggle_node, function()
local node = state.tree:get_node()
if node == nil then return end
local children = node:get_child_ids()
if node == nil then return end
if node:is_expanded() then
node:collapse()
for _, child in ipairs(children) do
state.tree:get_node(child):collapse()
end
else
for _, child in ipairs(children) do
state.tree:get_node(child):expand()
end
node:expand()
end
state.tree:render()
u.darken_metadata(buf, '')
end,
{ buffer = true })
vim.keymap.set('n', 'r', function()
local node = state.tree:get_node()
if node == nil then return end
-- Get closest discussion parent
if node.is_body then
local parentId = node:get_parent_id()
local parent = state.tree:get_node(parentId)
if parent == nil then return end
parentId = parent:get_parent_id()
parent = state.tree:get_node(parentId)
if parent == nil then return end
node = parent
elseif node.is_note then
local parentId = node:get_parent_id()
local parent = state.tree:get_node(parentId)
if parent == nil then return end
node = parent
end
state.ACTIVE_DISCUSSION = node.id
M.reply()
end, { buffer = true })
end
M.build_note = function(note)
local noteTextNodes = {}
for bodyLine in note.body:gmatch("[^\n]+") do
table.insert(noteTextNodes, NuiTree.Node({ text = bodyLine, is_body = true }, {}))
end
local noteHeader = "@" ..
note.author.username .. " on " .. u.format_date(note.created_at)
local note_node = NuiTree.Node(
{
text = noteHeader,
id = note.id,
file_name = note.position.new_path,
line_number = note.position.new_line,
is_note = true
}, noteTextNodes)
return note_node
end
return M