Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ These `keymaps` are active in the discussion tree window.
| `dd` | Delete comment |
| `e` | Edit comment |
| `r` | Reply to comment |
| `se` | Edit comment with suggestion preview in a new tab |
| `sr` | Reply to comment with a suggestion preview in a new tab |
| `sa` | Apply the suggestion to the local file with a preview in a new tab |
| `-` | Toggle the resolved status of the whole discussion |
| `o` | Jump to comment location in file |
| `a` | Jump to the comment location in the reviewer window |
Expand All @@ -233,11 +236,12 @@ These `keymaps` are active in the discussion tree window.

These `keymaps` are active in the reviewer window (the diff view).

| Keys | Action |
| ---- | ------------------------------------------------------------------------ |
| `c` | Create a comment for the lines that the following {motion} moves over |
| `s` | Create a suggestion for the lines that the following {motion} moves over |
| `a` | Jump to the comment in the discussion tree |
| Keys | Action |
| ---- | -------------------------------------------------------------------------------------------------- |
| `c` | Create a comment for the lines that the following {motion} moves over |
| `s` | Create a suggestion for the lines that the following {motion} moves over |
| `S` | Create a suggestion with preview in a new tab for the lines that the following {motion} moves over |
| `a` | Jump to the comment in the discussion tree |

## Contributing

Expand Down
4 changes: 2 additions & 2 deletions cmd/app/comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type DeleteCommentRequest struct {
DiscussionId string `json:"discussion_id" validate:"required"`
}

/* deleteComment deletes a note, multiline comment, or comment, which are all considered discussion notes. */
/* deleteComment deletes a note or comment, which are all considered discussion notes. */
func (a commentService) deleteComment(w http.ResponseWriter, r *http.Request) {
payload := r.Context().Value(payload("payload")).(*DeleteCommentRequest)

Expand Down Expand Up @@ -81,7 +81,7 @@ func (comment CommentWithPosition) GetPositionData() PositionData {
return comment.PositionData
}

/* postComment creates a note, multiline comment, or comment. */
/* postComment creates a note or comment. */
func (a commentService) postComment(w http.ResponseWriter, r *http.Request) {
payload := r.Context().Value(payload("payload")).(*PostCommentRequest)

Expand Down
93 changes: 48 additions & 45 deletions doc/gitlab.nvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -291,11 +291,22 @@ you call this function with no values the defaults will be used:
toggle_unresolved_discussions = "U", -- Open or close all unresolved discussions
refresh_data = "<C-R>", -- Refresh the data in the view by hitting Gitlab's APIs again
print_node = "<leader>p", -- Print the current node (for debugging)
edit_suggestion = "se", -- Edit comment with suggestion preview in a new tab
reply_with_suggestion = "sr", -- Reply to comment with a suggestion preview in a new tab
apply_suggestion = "sa", -- Apply the suggestion to the local file with a preview in a new tab
},
suggestion_preview = {
apply_changes = "ZZ", -- Close suggestion preview tab, and post comment to Gitlab (discarding changes to local file). In "apply mode", accept suggestion, commit changes, then push to remote and resolve thread
discard_changes = "ZQ", -- Close suggestion preview tab and discard changes in local file
attach_file = "ZA", -- Attach a file from the `settings.attachment_dir`
apply_changes_locally = "Zz", -- Only in "apply mode", close suggestion preview tab and write suggestion buffer to local file (no changes posted to Gitlab)
paste_default_suggestion = "glS", -- Paste the default suggestion below the cursor (overrides default "glS" (start review) keybinding for the "Note" buffer)
},
reviewer = {
disable_all = false, -- Disable all default mappings for the reviewer windows
create_comment = "c", -- Create a comment for the lines that the following {motion} moves over. Repeat the key(s) for creating comment for the current line
create_suggestion = "s", -- Create a suggestion for the lines that the following {motion} moves over. Repeat the key(s) for creating comment for the current line
create_suggestion_with_preview = "S", -- In a new tab create a suggestion with a diff preview for the lines that the following {motion} moves over. Repeat the key(s) for creating comment for the current line
move_to_discussion_tree = "a", -- Jump to the comment in the discussion tree
},
},
Expand Down Expand Up @@ -512,23 +523,19 @@ configuration for more information.

REVIEWING AN MR *gitlab.nvim.reviewing-an-mr*

The `review` action will open a diff of the changes. You can leave comments
using the `create_comment` action. In visual mode, add multiline comments with
the `create_multiline_comment` command, and add suggested changes with the
`create_comment_suggestion` command:
The `review` action opens a diff of the changes (see |gitlab.nvim.review|).
Alternatively, use `choose_merge_request` for more flexibility in choosing the
MR (see |gitlab.nvim.choose_merge_request|).
>lua
require("gitlab").review()
require("gitlab").create_comment()
require("gitlab").create_multiline_comment()
require("gitlab").create_comment_suggestion()
require("gitlab").choose_merge_request({ labels = {"include_mrs_with_label"} })
<
For suggesting changes you can use `create_comment_suggestion` in visual mode
which works similar to `create_multiline_comment` but prefills the comment
window with Gitlab’s suggest changes
<https://docs.gitlab.com/ee/user/project/merge_requests/reviews/suggestions.html>
code block with prefilled code from the visual selection. Just like the
summary, all the different kinds of comments are saved via the
`keymaps.popup.perform_action` keybinding.
You can leave comments in the reviewer windows using the `keymaps.reviewer`
keybindings which in normal mode work as operators and in visual mode they
create comments on the selected lines. Alternatively, you can use the
`create_comment` API in your custom mappings (see
|gitlab.nvim.create_comment|). See `settings.keymaps.popup` for the
keybindings available in the popup windows.


DRAFT NOTES *gitlab.nvim.draft-comments*
Expand Down Expand Up @@ -658,9 +665,11 @@ https://{GITLAB_URL}/-/emojis/{VERSION}/emojis.json.
UPLOADING FILES *gitlab.nvim.uploading-files*

To attach a file to an MR description, reply, comment, and so forth use the
`keymaps.popup.perform_linewise_action` keybinding when the popup is open.
This will open a picker that will look for files in the directory you specify
in the `settings.attachment_dir` folder (this must be an absolute path).
`keymaps.popup.perform_linewise_action` keybinding when the popup is open (or
the `keymaps.suggestion_preview.attach_file` in the comment buffer of the
suggestion preview). This will open a picker that will look for files in the
directory you specify in the `settings.attachment_dir` folder (this must be an
absolute path).

When you have picked the file, it will be added to the current buffer at the
current line.
Expand Down Expand Up @@ -966,35 +975,29 @@ have permission or has not previously approved the MR.
*gitlab.nvim.create_comment*
gitlab.create_comment() ~

Opens a popup to create a comment on the current line. Must be called when focused on the
reviewer pane (see the gitlab.nvim.review command), otherwise it will error.
Opens a popup to create a comment on the selected line(s) in the current
buffer. Must be called when focused on the reviewer pane (see the
|gitlab.nvim.review| command). In normal mode comments on the current line. In
visual mode comments on the selected lines:
>lua
require("gitlab").create_comment()

After the comment is typed, submit it to Gitlab via the
`keymaps.popup.perform_action` keybinding, by default `ZZ`.

*gitlab.nvim.create_multiline_comment*
gitlab.create_multiline_comment() ~

Opens a popup to create a multi-line comment. May only be called in visual
mode, and will use the currently selected lines.
>lua
require("gitlab").create_multiline_comment()

After the comment is typed, submit it to Gitlab via the
`keymaps.popup.perform_linewise_action` keybinding, by default `ZA`.

*gitlab.nvim.create_comment_suggestion*
gitlab.create_comment_suggestion() ~

Opens a popup to create a comment suggestion (aka a comment that makes a committable
change suggestion to the currently selected lines).
>lua
require("gitlab").create_multiline_comment()

After the comment is typed, submit it to Gitlab via the
`keymaps.popup.perform_linewise_action` keybinding, by default `ZA`.
require("gitlab").create_comment({ with_suggestion = true })
<
Parameters: ~
• {opts}: (table|nil) Keyword arguments that can be used to include
a suggestion in the comment.
• {with_suggestion} (boolean) When true, pastes into the comment
buffer Gitlab’s suggestion code block prefilled with the
original text from the visual selection. See
https://docs.gitlab.com/ee/user/project/merge_requests/reviews/suggestions.html.

In the popup, you can use the `keymaps.popup.perform_linewise_action`
keybinding (default: `ZA`) to attach a file to the comment. After the comment
is typed, submit it to Gitlab via the `keymaps.popup.perform_action`
keybinding, (default: `ZZ`). Discard the comment with
`keymaps.popup.discard_changes` (default: `ZQ`). Otherwise, if you close the
popup with something like `<c-w>q`, the comment contents are saved to the
temporary register(s) (|gitlab.nvim.temp-registers|).

*gitlab.nvim.create_mr*
gitlab.create_mr({opts}) ~
Expand Down Expand Up @@ -1054,7 +1057,7 @@ tied to specific changes in an MR.
require("gitlab").create_note()

After the comment is typed, submit it to Gitlab via the
`keymaps.popup.perform_action` keybinding, by default `ZZ`.
`keymaps.popup.perform_action` keybinding (default: `ZZ`).

*gitlab.nvim.toggle_discussions*
gitlab.toggle_discussions() ~
Expand Down
128 changes: 59 additions & 69 deletions lua/gitlab/actions/comment.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,31 @@ local M = {
comment_popup = nil,
}

---Decide if the comment is a draft based on the draft popup field.
---@return boolean? is_draft True if the draft popup exists and the string it contains converts to `true`. If the draft popup does not exist, return nil.
local get_draft_value_from_popup = function()
local buf_is_valid = M.draft_popup and M.draft_popup.bufnr and vim.api.nvim_buf_is_valid(M.draft_popup.bufnr)
if buf_is_valid then
return u.string_to_bool(u.get_buffer_text(M.draft_popup.bufnr))
else
return nil
end
end

---Fire the API to send the comment data to the Go server.
---@param text string comment text
---@param unlinked boolean if true, the comment is not linked to a line
---@param discussion_id? string The ID of the discussion when replying in a thread, otherwise nil
local confirm_create_comment = function(text, unlinked, discussion_id)
M.confirm_create_comment = function(text, unlinked, discussion_id)
if text == nil then
u.notify("Reviewer did not provide text of change", vim.log.levels.ERROR)
return
end

local is_draft = M.draft_popup and u.string_to_bool(u.get_buffer_text(M.draft_popup.bufnr))
local is_draft = get_draft_value_from_popup()
if is_draft == nil then
is_draft = state.settings.discussion_tree.draft_mode
end

-- Creating a normal reply to a discussion
if discussion_id ~= nil and not is_draft then
Expand Down Expand Up @@ -186,13 +200,13 @@ M.create_comment_layout = function(opts)
---Keybinding for focus on draft section
popup.set_popup_keymaps(M.draft_popup, function()
local text = u.get_buffer_text(M.comment_popup.bufnr)
confirm_create_comment(text, unlinked, opts.discussion_id)
M.confirm_create_comment(text, unlinked, opts.discussion_id)
vim.api.nvim_set_current_win(current_win)
end, miscellaneous.toggle_bool, popup.non_editable_popup_opts)

---Keybinding for focus on text section
popup.set_popup_keymaps(M.comment_popup, function(text)
confirm_create_comment(text, unlinked, opts.discussion_id)
M.confirm_create_comment(text, unlinked, opts.discussion_id)
vim.api.nvim_set_current_win(current_win)
end, miscellaneous.attach_file, popup.editable_popup_opts)

Expand All @@ -204,92 +218,68 @@ M.create_comment_layout = function(opts)
return layout
end

---Open a comment popup in order to create a comment on the changed/updated line in the
---current MR.
M.create_comment = function()
---@class CreateCommentsOpts Options for the create_comment function.
---@field with_suggestion boolean When true, paste the default suggestion into the comment buffer.

---Open a popup to create a comment on the current line(s) in the reviwer.
---In normal mode comments on the current line.
---In visual mode comments on the whole selection.
---@param opts CreateCommentsOpts?
M.create_comment = function(opts)
opts = opts or {}
M.location = Location.new()
if not M.can_create_comment(false) then
return
end

local suggestion_lines = require("gitlab.actions.suggestions").build_suggestion(
vim.api.nvim_buf_get_lines(0, 0, -1, false),
M.location.visual_range.start_line,
M.location.visual_range.end_line
)

local layout = M.create_comment_layout({ unlinked = false })
layout:mount()
end

---Open a multi-line comment popup in order to create a multi-line comment on the
---changed/updated line in the current MR.
M.create_multiline_comment = function()
M.location = Location.new()
if not M.can_create_comment(true) then
u.press_escape()
return
if opts.with_suggestion then
vim.schedule(function()
if suggestion_lines then
vim.api.nvim_buf_set_lines(M.comment_popup.bufnr, 0, -1, false, suggestion_lines)
end
end)
end

local layout = M.create_comment_layout({ unlinked = false })
layout:mount()
end

---Open a popup to create a "note" (e.g. unlinked comment) on the changed/updated line
---in the current MR.
---Open a popup to create a "note" (e.g. unlinked comment) for the current MR.
M.create_note = function()
local layout = M.create_comment_layout({ unlinked = true })
layout:mount()
end

---Given the current visually selected area of text, builds text to fill in the
---comment popup with a suggested change
---@return LineRange?
local build_suggestion = function()
local current_line = vim.api.nvim_win_get_cursor(0)[1]
local range_length = M.location.visual_range.end_line - M.location.visual_range.start_line
local backticks = "```"
local selected_lines = u.get_lines(M.location.visual_range.start_line, M.location.visual_range.end_line)

for _, line in ipairs(selected_lines) do
if string.match(line, "^```%S*$") then
backticks = "````"
break
end
end

local suggestion_start
if M.location.visual_range.start_line == current_line then
suggestion_start = backticks .. "suggestion:-0+" .. range_length
elseif M.location.visual_range.end_line == current_line then
suggestion_start = backticks .. "suggestion:-" .. range_length .. "+0"
else
--- This should never happen afaik
u.notify("Unexpected suggestion position", vim.log.levels.ERROR)
return nil
end
suggestion_start = suggestion_start
local suggestion_lines = {}
table.insert(suggestion_lines, suggestion_start)
vim.list_extend(suggestion_lines, selected_lines)
table.insert(suggestion_lines, backticks)

return suggestion_lines
end

---Open a popup to create a suggestion comment on the changed/updated line in the current MR
---See: https://docs.gitlab.com/ee/user/project/merge_requests/reviews/suggestions.html
M.create_comment_suggestion = function()
---Open new tab with a suggestion preview for the line(s) selected in the reviewer.
M.create_comment_with_suggestion = function()
M.location = Location.new()
if not M.can_create_comment(true) then
u.press_escape()
return
end

local suggestion_lines = build_suggestion()

local layout = M.create_comment_layout({ unlinked = false })
layout:mount()

vim.schedule(function()
if suggestion_lines then
vim.api.nvim_buf_set_lines(M.comment_popup.bufnr, 0, -1, false, suggestion_lines)
end
end)
local old_file_name = M.location.reviewer_data.old_file_name ~= "" and M.location.reviewer_data.old_file_name
or M.location.reviewer_data.file_name
local is_new_sha = M.location.reviewer_data.new_sha_focused

---@type ShowPreviewOpts
local opts = {
old_file_name = old_file_name,
new_file_name = M.location.reviewer_data.file_name,
start_line = M.location.visual_range.start_line,
end_line = M.location.visual_range.end_line,
is_new_sha = is_new_sha,
revision = is_new_sha and "HEAD" or require("gitlab.state").INFO.target_branch,
note_header = "comment",
comment_type = "new",
}
require("gitlab.actions.suggestions").show_preview(opts)
end

---Return true if it's possible to create an inline comment.
Expand Down Expand Up @@ -350,7 +340,7 @@ M.can_create_comment = function(must_be_visual)
return false
end

-- Check we're in visual mode for code suggestions and multiline comments
-- Check we're in visual mode for code suggestions
if must_be_visual and not u.check_visual_mode() then
return false
end
Expand Down
Loading
Loading