Fixes: https://www.reddit.com/r/neovim/comments/14irqwt/comment/jphw2cx/?utm_source=share&utm_medium=web2x&context=3
201 lines
6.3 KiB
Lua
201 lines
6.3 KiB
Lua
local u = require("gitlab.utils")
|
|
local NuiTree = require("nui.tree")
|
|
local job = require("gitlab.job")
|
|
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)
|
|
local escapedText = string.gsub(text, "\n", "\\n")
|
|
local json = string.format('{"discussion_id": "%s", "reply": "%s"}', state.ACTIVE_DISCUSSION, escapedText)
|
|
job.run_job("reply", "POST", json, function(data)
|
|
local note_node = M.build_note(data.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, '')
|
|
vim.notify("Sent reply!", vim.log.levels.INFO)
|
|
end)
|
|
end)
|
|
end
|
|
|
|
-- Places all of the discussions into a readable list
|
|
M.list_discussions = function()
|
|
if u.base_invalid() then return end
|
|
Job:new({
|
|
command = "curl",
|
|
args = { "-s", string.format("localhost:%s/discussions", state.PORT) },
|
|
on_stdout = function(_, output)
|
|
local data_ok, data = pcall(vim.json.decode, output)
|
|
if data_ok and data ~= nil then
|
|
local status = (data.status >= 200 and data.status < 300) and "success" or "error"
|
|
if status == "error" then
|
|
vim.notify("Could not fetch discussions!", vim.log.levels.ERROR)
|
|
return
|
|
end
|
|
M.discussions = data.discussions
|
|
vim.schedule(function()
|
|
vim.cmd.tabnew()
|
|
local buf = vim.api.nvim_create_buf(false, true)
|
|
vim.api.nvim_command("aboveleft vsplit")
|
|
vim.api.nvim_buf_set_option(buf, 'filetype', 'markdown')
|
|
vim.api.nvim_set_current_buf(buf)
|
|
local allDiscussions = {}
|
|
for i, discussion in ipairs(data.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
|
|
end,
|
|
on_stderr = function(_, output)
|
|
vim.notify("Could not run approve command!", vim.log.levels.ERROR)
|
|
error(output)
|
|
end,
|
|
}):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 line_number = note.position.new_line or note.position.old_line
|
|
local note_node = NuiTree.Node(
|
|
{
|
|
text = noteHeader,
|
|
id = note.id,
|
|
file_name = note.position.new_path,
|
|
line_number = line_number,
|
|
is_note = true
|
|
}, noteTextNodes)
|
|
|
|
return note_node
|
|
end
|
|
|
|
return M
|