diff --git a/doc/gitlab.nvim.txt b/doc/gitlab.nvim.txt index 523afa20..c6e6bc79 100644 --- a/doc/gitlab.nvim.txt +++ b/doc/gitlab.nvim.txt @@ -235,16 +235,20 @@ you call this function with no values the defaults will be used: }, }, popup = { -- The popup for comment creation, editing, and replying - width = "40%", - height = "60%", + width = "40%", -- Can be a percentage (string or decimal, "40%" = 0.4) of editor screen width, or an integer (number of columns) + height = "60%", -- Can be a percentage (string or decimal, "60%" = 0.6) of editor screen width, or an integer (number of rows) + position = "50%", -- Position (from the top left corner), either a number or percentage string that applies to both horizontal and vertical position, or a table that specifies them separately, e.g., { row = "90%", col = "100%" } places popups in the bottom right corner while leaving the status line visible border = "rounded", -- One of "rounded", "single", "double", "solid" opacity = 1.0, -- From 0.0 (fully transparent) to 1.0 (fully opaque) comment = nil, -- Individual popup overrides, e.g. { width = "60%", height = "80%", border = "single", opacity = 0.85 }, edit = nil, note = nil, - pipeline = nil, + help = nil, -- Width and height are calculated automatically and cannot be overridden + pipeline = nil, -- Width and height are calculated automatically and cannot be overridden reply = nil, squash_message = nil, + create_mr = { width = "95%", height = "95%" }, + summary = { width = "95%", height = "95%" }, temp_registers = {}, -- List of registers for backing up popup content (see `:h gitlab.nvim.temp-registers`) }, discussion_tree = { -- The discussion tree that holds all comments diff --git a/lua/gitlab/actions/comment.lua b/lua/gitlab/actions/comment.lua index fbc3ad01..08e11da8 100644 --- a/lua/gitlab/actions/comment.lua +++ b/lua/gitlab/actions/comment.lua @@ -7,6 +7,7 @@ local diffview_lib = require("diffview.lib") local state = require("gitlab.state") local job = require("gitlab.job") local u = require("gitlab.utils") +local popup = require("gitlab.popup") local git = require("gitlab.git") local discussions = require("gitlab.actions.discussions") local draft_notes = require("gitlab.actions.draft_notes") @@ -197,12 +198,24 @@ M.create_comment_layout = function(opts) end end - local title = opts.discussion_id and "Reply" or "Comment" - local settings = opts.discussion_id ~= nil and state.settings.popup.reply or state.settings.popup.comment + local popup_settings = state.settings.popup + local title + local user_settings + if opts.discussion_id ~= nil then + title = "Reply" + user_settings = popup_settings.reply + elseif opts.unlinked then + title = "Note" + user_settings = popup_settings.note + else + title = "Comment" + user_settings = popup_settings.comment + end + local settings = u.merge(popup_settings, user_settings or {}) M.current_win = vim.api.nvim_get_current_win() - M.comment_popup = Popup(u.create_popup_state(title, settings)) - M.draft_popup = Popup(u.create_box_popup_state("Draft", false)) + M.comment_popup = Popup(popup.create_popup_state(title, settings)) + M.draft_popup = Popup(popup.create_box_popup_state("Draft", false, settings)) M.start_line, M.end_line = u.get_visual_selection_boundaries() local internal_layout = Layout.Box({ @@ -211,45 +224,38 @@ M.create_comment_layout = function(opts) }, { dir = "col" }) local layout = Layout({ - position = "50%", + position = settings.position, relative = "editor", size = { - width = "50%", - height = "55%", + width = settings.width, + height = settings.height, }, }, internal_layout) - miscellaneous.set_cycle_popups_keymaps({ M.comment_popup, M.draft_popup }) + popup.set_cycle_popups_keymaps({ M.comment_popup, M.draft_popup }) + popup.set_up_autocommands(M.comment_popup, layout, M.current_win) local range = opts.ranged and { start_line = M.start_line, end_line = M.end_line } or nil local unlinked = opts.unlinked or false ---Keybinding for focus on draft section - state.set_popup_keymaps(M.draft_popup, function() + popup.set_popup_keymaps(M.draft_popup, function() local text = u.get_buffer_text(M.comment_popup.bufnr) confirm_create_comment(text, range, unlinked, opts.discussion_id) vim.api.nvim_set_current_win(M.current_win) - end, miscellaneous.toggle_bool, miscellaneous.non_editable_popup_opts) + end, miscellaneous.toggle_bool, popup.non_editable_popup_opts) ---Keybinding for focus on text section - state.set_popup_keymaps(M.comment_popup, function(text) + popup.set_popup_keymaps(M.comment_popup, function(text) confirm_create_comment(text, range, unlinked, opts.discussion_id) vim.api.nvim_set_current_win(M.current_win) - end, miscellaneous.attach_file, miscellaneous.editable_popup_opts) + end, miscellaneous.attach_file, popup.editable_popup_opts) vim.schedule(function() local draft_mode = state.settings.discussion_tree.draft_mode vim.api.nvim_buf_set_lines(M.draft_popup.bufnr, 0, -1, false, { u.bool_to_string(draft_mode) }) end) - --Send back to previous window on close - vim.api.nvim_create_autocmd("BufHidden", { - buffer = M.draft_popup.bufnr, - callback = function() - vim.api.nvim_set_current_win(M.current_win) - end, - }) - return layout end diff --git a/lua/gitlab/actions/create_mr.lua b/lua/gitlab/actions/create_mr.lua index 2e366946..7e6f35d4 100644 --- a/lua/gitlab/actions/create_mr.lua +++ b/lua/gitlab/actions/create_mr.lua @@ -5,6 +5,7 @@ local Input = require("nui.input") local Popup = require("nui.popup") local job = require("gitlab.job") local u = require("gitlab.utils") +local popup = require("gitlab.popup") local git = require("gitlab.git") local state = require("gitlab.state") local common = require("gitlab.actions.common") @@ -277,13 +278,13 @@ M.open_confirmation_popup = function(mr) action_before_exit = true, } - state.set_popup_keymaps(description_popup, M.create_mr, miscellaneous.attach_file, popup_opts) - state.set_popup_keymaps(title_popup, M.create_mr, nil, popup_opts) - state.set_popup_keymaps(target_popup, M.create_mr, M.select_new_target, popup_opts) - state.set_popup_keymaps(delete_branch_popup, M.create_mr, miscellaneous.toggle_bool, popup_opts) - state.set_popup_keymaps(squash_popup, M.create_mr, miscellaneous.toggle_bool, popup_opts) - state.set_popup_keymaps(forked_project_id_popup, M.create_mr, nil, popup_opts) - miscellaneous.set_cycle_popups_keymaps(popups) + popup.set_popup_keymaps(description_popup, M.create_mr, miscellaneous.attach_file, popup_opts) + popup.set_popup_keymaps(title_popup, M.create_mr, nil, popup_opts) + popup.set_popup_keymaps(target_popup, M.create_mr, M.select_new_target, popup_opts) + popup.set_popup_keymaps(delete_branch_popup, M.create_mr, miscellaneous.toggle_bool, popup_opts) + popup.set_popup_keymaps(squash_popup, M.create_mr, miscellaneous.toggle_bool, popup_opts) + popup.set_popup_keymaps(forked_project_id_popup, M.create_mr, nil, popup_opts) + popup.set_cycle_popups_keymaps(popups) vim.api.nvim_set_current_buf(M.description_bufnr) end) @@ -328,19 +329,20 @@ M.create_mr = function() end M.create_layout = function() - local title_popup = Popup(u.create_box_popup_state("Title", false)) + local settings = u.merge(state.settings.popup, state.settings.popup.create_mr or {}) + local title_popup = Popup(popup.create_box_popup_state("Title", false, settings)) M.title_bufnr = title_popup.bufnr - local description_popup = Popup(u.create_box_popup_state("Description", true)) + local description_popup = Popup(popup.create_popup_state("Description", settings)) M.description_bufnr = description_popup.bufnr - local target_branch_popup = Popup(u.create_box_popup_state("Target branch", false)) + local target_branch_popup = Popup(popup.create_box_popup_state("Target branch", false, settings)) M.target_bufnr = target_branch_popup.bufnr local delete_title = vim.o.columns > 110 and "Delete source branch" or "Delete source" - local delete_branch_popup = Popup(u.create_box_popup_state(delete_title, false)) + local delete_branch_popup = Popup(popup.create_box_popup_state(delete_title, false, settings)) M.delete_branch_bufnr = delete_branch_popup.bufnr local squash_title = vim.o.columns > 110 and "Squash commits" or "Squash" - local squash_popup = Popup(u.create_box_popup_state(squash_title, false)) + local squash_popup = Popup(popup.create_box_popup_state(squash_title, false, settings)) M.squash_bufnr = squash_popup.bufnr - local forked_project_id_popup = Popup(u.create_box_popup_state("Forked Project ID", false)) + local forked_project_id_popup = Popup(popup.create_box_popup_state("Forked Project ID", false, settings)) M.forked_project_id_bufnr = forked_project_id_popup.bufnr local boxes = {} @@ -360,14 +362,16 @@ M.create_layout = function() }, { dir = "col" }) local layout = Layout({ - position = "50%", + position = settings.position, relative = "editor", size = { - width = "95%", - height = "95%", + width = settings.width, + height = settings.height, }, }, internal_layout) + popup.set_up_autocommands(description_popup, layout, vim.api.nvim_get_current_win()) + layout:mount() return layout, diff --git a/lua/gitlab/actions/discussions/init.lua b/lua/gitlab/actions/discussions/init.lua index aaa4d48f..1825c9ad 100644 --- a/lua/gitlab/actions/discussions/init.lua +++ b/lua/gitlab/actions/discussions/init.lua @@ -7,12 +7,12 @@ local Popup = require("nui.popup") local NuiTree = require("nui.tree") local job = require("gitlab.job") local u = require("gitlab.utils") +local popup = require("gitlab.popup") local state = require("gitlab.state") local reviewer = require("gitlab.reviewer") local common = require("gitlab.actions.common") local List = require("gitlab.utils.list") local tree_utils = require("gitlab.actions.discussions.tree") -local miscellaneous = require("gitlab.actions.miscellaneous") local discussions_tree = require("gitlab.actions.discussions.tree") local draft_notes = require("gitlab.actions.draft_notes") local diffview_lib = require("diffview.lib") @@ -284,7 +284,7 @@ end -- This function (settings.keymaps.discussion_tree.edit_comment) will open the edit popup for the current comment in the discussion tree M.edit_comment = function(tree, unlinked) - local edit_popup = Popup(u.create_popup_state("Edit Comment", state.settings.popup.edit)) + local edit_popup = Popup(popup.create_popup_state("Edit Comment", state.settings.popup.edit)) local current_node = tree:get_node() local note_node = common.get_note_node(tree, current_node) local root_node = common.get_root_node(tree, current_node) @@ -293,6 +293,8 @@ M.edit_comment = function(tree, unlinked) return end + popup.set_up_autocommands(edit_popup, nil, vim.api.nvim_get_current_win()) + edit_popup:mount() -- Gather all lines from immediate children that aren't note nodes @@ -310,19 +312,19 @@ M.edit_comment = function(tree, unlinked) -- Draft notes module handles edits for draft notes if M.is_draft_note(tree) then - state.set_popup_keymaps( + popup.set_popup_keymaps( edit_popup, draft_notes.confirm_edit_draft_note(note_node.id, unlinked), nil, - miscellaneous.editable_popup_opts + popup.editable_popup_opts ) else local comment = require("gitlab.actions.comment") - state.set_popup_keymaps( + popup.set_popup_keymaps( edit_popup, comment.confirm_edit_comment(tostring(root_node.id), tonumber(note_node.root_note_id or note_node.id), unlinked), nil, - miscellaneous.editable_popup_opts + popup.editable_popup_opts ) end end diff --git a/lua/gitlab/actions/help.lua b/lua/gitlab/actions/help.lua index d76c7b5e..edbe5afc 100644 --- a/lua/gitlab/actions/help.lua +++ b/lua/gitlab/actions/help.lua @@ -1,6 +1,7 @@ local M = {} local u = require("gitlab.utils") +local popup = require("gitlab.popup") local event = require("nui.utils.autocmd").event local state = require("gitlab.state") local List = require("gitlab.utils.list") @@ -16,15 +17,20 @@ M.open = function() end return agg end, {}) + local longest_line = u.get_longest_string(help_content_lines) - local help_popup = - Popup(u.create_popup_state("Help", state.settings.popup.help, longest_line + 3, #help_content_lines + 3, 60)) + local opts = { "Help", state.settings.popup.help, longest_line + 3, #help_content_lines, 70 } + local help_popup = Popup(popup.create_popup_state(unpack(opts))) + help_popup:on(event.BufLeave, function() help_popup:unmount() end) + + popup.set_up_autocommands(help_popup, nil, vim.api.nvim_get_current_win(), opts) + help_popup:mount() - state.set_popup_keymaps(help_popup, "Help", nil) + popup.set_popup_keymaps(help_popup, "Help", nil) local currentBuffer = vim.api.nvim_get_current_buf() vim.api.nvim_buf_set_lines(currentBuffer, 0, #help_content_lines, false, help_content_lines) u.switch_can_edit_buf(currentBuffer, false) diff --git a/lua/gitlab/actions/merge.lua b/lua/gitlab/actions/merge.lua index 81d23846..81eed3f6 100644 --- a/lua/gitlab/actions/merge.lua +++ b/lua/gitlab/actions/merge.lua @@ -1,14 +1,14 @@ local u = require("gitlab.utils") +local popup = require("gitlab.popup") local Popup = require("nui.popup") local state = require("gitlab.state") local job = require("gitlab.job") local reviewer = require("gitlab.reviewer") -local miscellaneous = require("gitlab.actions.miscellaneous") local M = {} local function create_squash_message_popup() - return Popup(u.create_popup_state("Squash Commit Message", state.settings.popup.squash_message)) + return Popup(popup.create_popup_state("Squash Commit Message", state.settings.popup.squash_message)) end ---@class MergeOpts @@ -31,10 +31,11 @@ M.merge = function(opts) if merge_body.squash then local squash_message_popup = create_squash_message_popup() + popup.set_up_autocommands(squash_message_popup, nil, vim.api.nvim_get_current_win()) squash_message_popup:mount() - state.set_popup_keymaps(squash_message_popup, function(text) + popup.set_popup_keymaps(squash_message_popup, function(text) M.confirm_merge(merge_body, text) - end, nil, miscellaneous.editable_popup_opts) + end, nil, popup.editable_popup_opts) else M.confirm_merge(merge_body) end diff --git a/lua/gitlab/actions/miscellaneous.lua b/lua/gitlab/actions/miscellaneous.lua index df080665..368c198b 100644 --- a/lua/gitlab/actions/miscellaneous.lua +++ b/lua/gitlab/actions/miscellaneous.lua @@ -34,70 +34,6 @@ M.attach_file = function() end) end -M.editable_popup_opts = { - action_before_close = true, - action_before_exit = false, - save_to_temp_register = true, -} - -M.non_editable_popup_opts = { - action_before_close = true, - action_before_exit = false, - save_to_temp_register = false, -} - --- Get the index of the next popup when cycling forward -local function next_index(i, n, count) - count = count > 0 and count or 1 - for _ = 1, count do - if i < n then - i = i + 1 - elseif i == n then - i = 1 - end - end - return i -end - ----Get the index of the previous popup when cycling backward ----@param i integer The current index ----@param n integer The total number of popups ----@param count integer The count used with the keymap (replaced with 1 if no count was given) -local function prev_index(i, n, count) - count = count > 0 and count or 1 - for _ = 1, count do - if i > 1 then - i = i - 1 - elseif i == 1 then - i = n - end - end - return i -end - ----Setup keymaps for cycling popups. The keymap accepts count. ----@param popups table Table of Popups -M.set_cycle_popups_keymaps = function(popups) - local keymaps = require("gitlab.state").settings.keymaps - if keymaps.disable_all or keymaps.popup.disable_all then - return - end - - local number_of_popups = #popups - for i, popup in ipairs(popups) do - if keymaps.popup.next_field then - popup:map("n", keymaps.popup.next_field, function() - vim.api.nvim_set_current_win(popups[next_index(i, number_of_popups, vim.v.count)].winid) - end, { desc = "Go to next field (accepts count)", nowait = keymaps.popup.next_field_nowait }) - end - if keymaps.popup.prev_field then - popup:map("n", keymaps.popup.prev_field, function() - vim.api.nvim_set_current_win(popups[prev_index(i, number_of_popups, vim.v.count)].winid) - end, { desc = "Go to previous field (accepts count)", nowait = keymaps.popup.prev_field_nowait }) - end - end -end - ---Toggle the value in a "Boolean buffer" M.toggle_bool = function() local bufnr = vim.api.nvim_get_current_buf() diff --git a/lua/gitlab/actions/pipeline.lua b/lua/gitlab/actions/pipeline.lua index bddc1949..00dc5c29 100644 --- a/lua/gitlab/actions/pipeline.lua +++ b/lua/gitlab/actions/pipeline.lua @@ -5,6 +5,7 @@ local Popup = require("nui.popup") local state = require("gitlab.state") local job = require("gitlab.job") local u = require("gitlab.utils") +local popup = require("gitlab.popup") local M = { pipeline_jobs = nil, latest_pipeline = nil, @@ -40,7 +41,8 @@ M.open = function() local height = 6 + #M.pipeline_jobs + 3 local pipeline_popup = - Popup(u.create_popup_state("Loading Pipeline...", state.settings.popup.pipeline, width, height, 60)) + Popup(popup.create_popup_state("Loading Pipeline...", state.settings.popup.pipeline, width, height, 60)) + popup.set_up_autocommands(pipeline_popup, nil, vim.api.nvim_get_current_win()) M.pipeline_popup = pipeline_popup pipeline_popup:mount() @@ -91,7 +93,7 @@ M.open = function() end pipeline_popup.border:set_text("top", "Pipeline Status", "center") - state.set_popup_keymaps(pipeline_popup, M.retrigger, M.see_logs) + popup.set_popup_keymaps(pipeline_popup, M.retrigger, M.see_logs) u.switch_can_edit_buf(bufnr, false) end) end diff --git a/lua/gitlab/actions/summary.lua b/lua/gitlab/actions/summary.lua index 6d034be1..9f75ca7d 100644 --- a/lua/gitlab/actions/summary.lua +++ b/lua/gitlab/actions/summary.lua @@ -7,6 +7,7 @@ local git = require("gitlab.git") local job = require("gitlab.job") local common = require("gitlab.actions.common") local u = require("gitlab.utils") +local popup = require("gitlab.popup") local List = require("gitlab.utils.list") local state = require("gitlab.state") local miscellaneous = require("gitlab.actions.miscellaneous") @@ -59,25 +60,25 @@ M.summary = function() M.color_details(info_popup.bufnr) -- Color values in details popup end - state.set_popup_keymaps( + popup.set_popup_keymaps( description_popup, M.edit_summary, miscellaneous.attach_file, { cb = exit, action_before_close = true, action_before_exit = true, save_to_temp_register = true } ) - state.set_popup_keymaps( + popup.set_popup_keymaps( title_popup, M.edit_summary, nil, { cb = exit, action_before_close = true, action_before_exit = true } ) - state.set_popup_keymaps( + popup.set_popup_keymaps( info_popup, M.edit_summary, nil, { cb = exit, action_before_close = true, action_before_exit = true } ) - miscellaneous.set_cycle_popups_keymaps(popups) + popup.set_cycle_popups_keymaps(popups) vim.api.nvim_set_current_buf(description_popup.bufnr) end) @@ -166,15 +167,16 @@ M.edit_summary = function() end M.create_layout = function(info_lines) - local title_popup = Popup(u.create_box_popup_state(nil, false)) + local settings = u.merge(state.settings.popup, state.settings.popup.summary or {}) + local title_popup = Popup(popup.create_box_popup_state(nil, false, settings)) M.title_bufnr = title_popup.bufnr - local description_popup = Popup(u.create_box_popup_state("Description", true)) + local description_popup = Popup(popup.create_popup_state("Description", settings)) M.description_bufnr = description_popup.bufnr local details_popup local internal_layout if state.settings.info.enabled then - details_popup = Popup(u.create_box_popup_state("Details", false)) + details_popup = Popup(popup.create_box_popup_state("Details", false, settings)) if state.settings.info.horizontal then local longest_line = u.get_longest_string(info_lines) internal_layout = Layout.Box({ @@ -199,14 +201,16 @@ M.create_layout = function(info_lines) end local layout = Layout({ - position = "50%", + position = settings.position, relative = "editor", size = { - width = "95%", - height = "95%", + width = settings.width, + height = settings.height, }, }, internal_layout) + popup.set_up_autocommands(description_popup, layout, vim.api.nvim_get_current_win()) + layout:mount() return layout, title_popup, description_popup, details_popup end diff --git a/lua/gitlab/popup.lua b/lua/gitlab/popup.lua new file mode 100644 index 00000000..8ab0b513 --- /dev/null +++ b/lua/gitlab/popup.lua @@ -0,0 +1,239 @@ +local u = require("gitlab.utils") + +local M = {} + +---Get the popup view_opts +---@param title string The string to appear on top of the popup +---@param user_settings table|nil User-defined popup settings +---@param width number? Override default width +---@param height number? Override default height +---@param zindex number? Override default zindex +---@return table +M.create_popup_state = function(title, user_settings, width, height, zindex) + local settings = u.merge(require("gitlab.state").settings.popup, user_settings or {}) + local view_opts = { + buf_options = { + filetype = "markdown", + }, + relative = "editor", + enter = true, + focusable = true, + zindex = zindex or 50, + border = { + style = settings.border, + text = { + top = title, + }, + }, + position = settings.position, + size = { + width = width and math.min(width, vim.o.columns - 2) or settings.width, + height = height and math.min(height, vim.o.lines - 3) or settings.height, + }, + opacity = settings.opacity, + } + + return view_opts +end + +---Create view_opts for Box popups used inside popup Layouts +---@param title string|nil The string to appear on top of the popup +---@param enter boolean Whether the pop should be focused after creation +---@param settings table User defined popup settings +---@return table +M.create_box_popup_state = function(title, enter, settings) + return { + buf_options = { + filetype = "markdown", + }, + enter = enter or false, + focusable = true, + border = { + style = settings.border, + text = { + top = title, + }, + }, + opacity = settings.opacity, + } +end + +local function exit(popup, opts) + if opts.action_before_exit and opts.cb ~= nil then + opts.cb() + popup:unmount() + else + popup:unmount() + if opts.cb ~= nil then + opts.cb() + end + end +end + +-- These keymaps are buffer specific and are set dynamically when popups mount +M.set_popup_keymaps = function(popup, action, linewise_action, opts) + local settings = require("gitlab.state").settings + if settings.keymaps.disable_all or settings.keymaps.popup.disable_all then + return + end + + if opts == nil then + opts = {} + end + if action ~= "Help" and settings.keymaps.help then -- Don't show help on the help popup + vim.keymap.set("n", settings.keymaps.help, function() + local help = require("gitlab.actions.help") + help.open() + end, { buffer = popup.bufnr, desc = "Open help", nowait = settings.keymaps.help_nowait }) + end + if action ~= nil and settings.keymaps.popup.perform_action then + vim.keymap.set("n", settings.keymaps.popup.perform_action, function() + local text = u.get_buffer_text(popup.bufnr) + if opts.action_before_close then + action(text, popup.bufnr) + exit(popup, opts) + else + exit(popup, opts) + action(text, popup.bufnr) + end + end, { buffer = popup.bufnr, desc = "Perform action", nowait = settings.keymaps.popup.perform_action_nowait }) + end + + if linewise_action ~= nil and settings.keymaps.popup.perform_action then + vim.keymap.set("n", settings.keymaps.popup.perform_linewise_action, function() + local bufnr = vim.api.nvim_get_current_buf() + local linnr = vim.api.nvim_win_get_cursor(0)[1] + local text = u.get_line_content(bufnr, linnr) + linewise_action(text) + end, { + buffer = popup.bufnr, + desc = "Perform linewise action", + nowait = settings.keymaps.popup.perform_linewise_action_nowait, + }) + end + + if settings.keymaps.popup.discard_changes then + vim.keymap.set("n", settings.keymaps.popup.discard_changes, function() + local temp_registers = settings.popup.temp_registers + settings.popup.temp_registers = {} + vim.cmd("quit!") + settings.popup.temp_registers = temp_registers + end, { + buffer = popup.bufnr, + desc = "Quit discarding changes", + nowait = settings.keymaps.popup.discard_changes_nowait, + }) + end + + if opts.save_to_temp_register then + vim.api.nvim_create_autocmd("BufWinLeave", { + buffer = popup.bufnr, + callback = function() + local text = u.get_buffer_text(popup.bufnr) + for _, register in ipairs(settings.popup.temp_registers) do + vim.fn.setreg(register, text) + end + end, + }) + end + + if opts.action_before_exit then + vim.api.nvim_create_autocmd("BufWinLeave", { + buffer = popup.bufnr, + callback = function() + exit(popup, opts) + end, + }) + end +end + +--- Setup autocommands for the popup +--- @param popup NuiPopup +--- @param layout NuiLayout|nil +--- @param previous_window number|nil Number of window active before the popup was opened +--- @param opts table|nil Table with options for updating the popup +M.set_up_autocommands = function(popup, layout, previous_window, opts) + -- Make the popup/layout resizable + popup:on("VimResized", function() + if layout ~= nil then + layout:update() + else + popup:update_layout(opts and M.create_popup_state(unpack(opts))) + end + end) + + -- After closing the popup, refocus the previously active window + if previous_window ~= nil then + popup:on("BufHidden", function() + vim.schedule(function() + vim.api.nvim_set_current_win(previous_window) + end) + end) + end +end + +M.editable_popup_opts = { + action_before_close = true, + action_before_exit = false, + save_to_temp_register = true, +} + +M.non_editable_popup_opts = { + action_before_close = true, + action_before_exit = false, + save_to_temp_register = false, +} + +-- Get the index of the next popup when cycling forward +local function next_index(i, n, count) + count = count > 0 and count or 1 + for _ = 1, count do + if i < n then + i = i + 1 + elseif i == n then + i = 1 + end + end + return i +end + +---Get the index of the previous popup when cycling backward +---@param i integer The current index +---@param n integer The total number of popups +---@param count integer The count used with the keymap (replaced with 1 if no count was given) +local function prev_index(i, n, count) + count = count > 0 and count or 1 + for _ = 1, count do + if i > 1 then + i = i - 1 + elseif i == 1 then + i = n + end + end + return i +end + +---Setup keymaps for cycling popups. The keymap accepts count. +---@param popups table Table of Popups +M.set_cycle_popups_keymaps = function(popups) + local keymaps = require("gitlab.state").settings.keymaps + if keymaps.disable_all or keymaps.popup.disable_all then + return + end + + local number_of_popups = #popups + for i, popup in ipairs(popups) do + if keymaps.popup.next_field then + popup:map("n", keymaps.popup.next_field, function() + vim.api.nvim_set_current_win(popups[next_index(i, number_of_popups, vim.v.count)].winid) + end, { desc = "Go to next field (accepts count)", nowait = keymaps.popup.next_field_nowait }) + end + if keymaps.popup.prev_field then + popup:map("n", keymaps.popup.prev_field, function() + vim.api.nvim_set_current_win(popups[prev_index(i, number_of_popups, vim.v.count)].winid) + end, { desc = "Go to previous field (accepts count)", nowait = keymaps.popup.prev_field_nowait }) + end + end +end + +return M diff --git a/lua/gitlab/state.lua b/lua/gitlab/state.lua index 22278c67..c276af41 100644 --- a/lua/gitlab/state.lua +++ b/lua/gitlab/state.lua @@ -134,15 +134,18 @@ M.settings = { popup = { width = "40%", height = "60%", + position = "50%", border = "rounded", opacity = 1.0, - edit = nil, comment = nil, + edit = nil, note = nil, help = nil, pipeline = nil, reply = nil, squash_message = nil, + create_mr = { width = "95%", height = "95%" }, + summary = { width = "95%", height = "95%" }, temp_registers = {}, }, discussion_tree = { @@ -432,94 +435,6 @@ M.setPluginConfiguration = function() return true end -local function exit(popup, opts) - if opts.action_before_exit and opts.cb ~= nil then - opts.cb() - popup:unmount() - else - popup:unmount() - if opts.cb ~= nil then - opts.cb() - end - end -end - --- These keymaps are buffer specific and are set dynamically when popups mount -M.set_popup_keymaps = function(popup, action, linewise_action, opts) - if M.settings.keymaps.disable_all or M.settings.keymaps.popup.disable_all then - return - end - - if opts == nil then - opts = {} - end - if action ~= "Help" and M.settings.keymaps.help then -- Don't show help on the help popup - vim.keymap.set("n", M.settings.keymaps.help, function() - local help = require("gitlab.actions.help") - help.open() - end, { buffer = popup.bufnr, desc = "Open help", nowait = M.settings.keymaps.help_nowait }) - end - if action ~= nil and M.settings.keymaps.popup.perform_action then - vim.keymap.set("n", M.settings.keymaps.popup.perform_action, function() - local text = u.get_buffer_text(popup.bufnr) - if opts.action_before_close then - action(text, popup.bufnr) - exit(popup, opts) - else - exit(popup, opts) - action(text, popup.bufnr) - end - end, { buffer = popup.bufnr, desc = "Perform action", nowait = M.settings.keymaps.popup.perform_action_nowait }) - end - - if linewise_action ~= nil and M.settings.keymaps.popup.perform_action then - vim.keymap.set("n", M.settings.keymaps.popup.perform_linewise_action, function() - local bufnr = vim.api.nvim_get_current_buf() - local linnr = vim.api.nvim_win_get_cursor(0)[1] - local text = u.get_line_content(bufnr, linnr) - linewise_action(text) - end, { - buffer = popup.bufnr, - desc = "Perform linewise action", - nowait = M.settings.keymaps.popup.perform_linewise_action_nowait, - }) - end - - if M.settings.keymaps.popup.discard_changes then - vim.keymap.set("n", M.settings.keymaps.popup.discard_changes, function() - local temp_registers = M.settings.popup.temp_registers - M.settings.popup.temp_registers = {} - vim.cmd("quit!") - M.settings.popup.temp_registers = temp_registers - end, { - buffer = popup.bufnr, - desc = "Quit discarding changes", - nowait = M.settings.keymaps.popup.discard_changes_nowait, - }) - end - - if opts.save_to_temp_register then - vim.api.nvim_create_autocmd("BufWinLeave", { - buffer = popup.bufnr, - callback = function() - local text = u.get_buffer_text(popup.bufnr) - for _, register in ipairs(M.settings.popup.temp_registers) do - vim.fn.setreg(register, text) - end - end, - }) - end - - if opts.action_before_exit then - vim.api.nvim_create_autocmd("BufWinLeave", { - buffer = popup.bufnr, - callback = function() - exit(popup, opts) - end, - }) - end -end - -- Dependencies -- These tables are passed to the async.sequence function, which calls them in sequence -- before calling an action. They are used to set global state that's required diff --git a/lua/gitlab/utils/init.lua b/lua/gitlab/utils/init.lua index aa71136b..776f05f0 100644 --- a/lua/gitlab/utils/init.lua +++ b/lua/gitlab/utils/init.lua @@ -480,62 +480,6 @@ M.difference = function(a, b) return not_included end ----Get the popup view_opts ----@param title string The string to appear on top of the popup ----@param settings table|nil User defined popup settings ----@param width number? Override default width ----@param height number? Override default height ----@return table -M.create_popup_state = function(title, settings, width, height, zindex) - local default_settings = require("gitlab.state").settings.popup - local user_settings = settings or {} - local view_opts = { - buf_options = { - filetype = "markdown", - }, - relative = "editor", - enter = true, - focusable = true, - zindex = zindex or 50, - border = { - style = user_settings.border or default_settings.border, - text = { - top = title, - }, - }, - position = "50%", - size = { - width = user_settings.width or width or default_settings.width, - height = user_settings.height or height or default_settings.height, - }, - opacity = user_settings.opacity or default_settings.opacity, - } - - return view_opts -end - ----Create view_opts for Box popups used inside popup Layouts ----@param title string|nil The string to appear on top of the popup ----@param enter boolean Whether the pop should be focused after creation ----@return table -M.create_box_popup_state = function(title, enter) - local settings = require("gitlab.state").settings.popup - return { - buf_options = { - filetype = "markdown", - }, - enter = enter or false, - focusable = true, - border = { - style = settings.border, - text = { - top = title, - }, - }, - opacity = settings.opacity, - } -end - M.read_file = function(file_path, opts) local file = io.open(file_path, "r") if file == nil then