@@ -17,31 +17,53 @@ local M = {
1717 current_win = nil ,
1818 start_line = nil ,
1919 end_line = nil ,
20+ draft_popup = nil ,
21+ comment_popup = nil ,
2022}
2123
2224--- Fires the API that sends the comment data to the Go server, called when you "confirm" creation
2325--- via the M.settings.popup.perform_action keybinding
2426--- @param text string comment text
2527--- @param visual_range LineRange | nil range of visual selection or nil
26- --- @param unlinked boolean | nil if true , the comment is not linked to a line
27- local confirm_create_comment = function (text , visual_range , unlinked )
28+ --- @param unlinked boolean if true , the comment is not linked to a line
29+ --- @param discussion_id string | nil The ID of the discussion to which the reply is responding , nil if not a reply
30+ local confirm_create_comment = function (text , visual_range , unlinked , discussion_id )
2831 if text == nil then
2932 u .notify (" Reviewer did not provide text of change" , vim .log .levels .ERROR )
3033 return
3134 end
3235
3336 local is_draft = M .draft_popup and u .string_to_bool (u .get_buffer_text (M .draft_popup .bufnr ))
34- if unlinked then
37+
38+ -- Creating a normal reply to a discussion
39+ if discussion_id ~= nil and not is_draft then
40+ local body = { discussion_id = discussion_id , reply = text , draft = is_draft }
41+ job .run_job (" /mr/reply" , " POST" , body , function ()
42+ u .notify (" Sent reply!" , vim .log .levels .INFO )
43+ if is_draft then
44+ draft_notes .load_draft_notes (function ()
45+ discussions .rebuild_view (unlinked )
46+ end )
47+ else
48+ discussions .rebuild_view (unlinked )
49+ end
50+ end )
51+ return
52+ end
53+
54+ -- Creating a note (unlinked comment)
55+ if unlinked and discussion_id == nil then
3556 local body = { comment = text }
3657 local endpoint = is_draft and " /mr/draft_notes/" or " /mr/comment"
37- job .run_job (endpoint , " POST" , body , function (data )
58+ job .run_job (endpoint , " POST" , body , function ()
3859 u .notify (is_draft and " Draft note created!" or " Note created!" , vim .log .levels .INFO )
3960 if is_draft then
40- draft_notes .add_draft_note ({ draft_note = data .draft_note , unlinked = true })
61+ draft_notes .load_draft_notes (function ()
62+ discussions .rebuild_view (unlinked )
63+ end )
4164 else
42- discussions .add_discussion ({ data = data , unlinked = true } )
65+ discussions .rebuild_view ( unlinked )
4366 end
44- discussions .refresh ()
4567 end )
4668 return
4769 end
@@ -61,9 +83,7 @@ local confirm_create_comment = function(text, visual_range, unlinked)
6183 end
6284
6385 local revision = state .MR_REVISIONS [1 ]
64- local body = {
65- type = " text" ,
66- comment = text ,
86+ local position_data = {
6787 file_name = reviewer_data .file_name ,
6888 base_commit_sha = revision .base_commit_sha ,
6989 start_commit_sha = revision .start_commit_sha ,
@@ -73,34 +93,84 @@ local confirm_create_comment = function(text, visual_range, unlinked)
7393 line_range = location_data .line_range ,
7494 }
7595
96+ -- Creating a draft reply, in response to a discussion ID
97+ if discussion_id ~= nil and is_draft then
98+ local body = { comment = text , discussion_id = discussion_id , position = position_data }
99+ job .run_job (" /mr/draft_notes/" , " POST" , body , function ()
100+ u .notify (" Draft reply created!" , vim .log .levels .INFO )
101+ draft_notes .load_draft_notes (function ()
102+ discussions .rebuild_view (false , true )
103+ end )
104+ end )
105+ return
106+ end
107+
108+ -- Creating a new comment (linked to specific changes)
109+ local body = u .merge ({ type = " text" , comment = text }, position_data )
76110 local endpoint = is_draft and " /mr/draft_notes/" or " /mr/comment"
77- job .run_job (endpoint , " POST" , body , function (data )
111+ job .run_job (endpoint , " POST" , body , function ()
78112 u .notify (is_draft and " Draft comment created!" or " Comment created!" , vim .log .levels .INFO )
79113 if is_draft then
80- draft_notes .add_draft_note ({ draft_note = data .draft_note , unlinked = false })
114+ draft_notes .load_draft_notes (function ()
115+ discussions .rebuild_view (unlinked )
116+ end )
81117 else
82- discussions .add_discussion ({ data = data , has_position = true } )
118+ discussions .rebuild_view ( unlinked )
83119 end
84- discussions .refresh ()
85120 end )
86121end
87122
123+ -- This function will actually send the deletion to Gitlab when you make a selection,
124+ -- and re-render the tree
125+ --- @param note_id integer
126+ --- @param discussion_id string
127+ --- @param unlinked boolean
128+ M .confirm_delete_comment = function (note_id , discussion_id , unlinked )
129+ local body = { discussion_id = discussion_id , note_id = tonumber (note_id ) }
130+ job .run_job (" /mr/comment" , " DELETE" , body , function (data )
131+ u .notify (data .message , vim .log .levels .INFO )
132+ discussions .rebuild_view (unlinked )
133+ end )
134+ end
135+
136+ --- This function sends the edited comment to the Go server
137+ --- @param discussion_id string
138+ --- @param note_id integer
139+ --- @param unlinked boolean
140+ M .confirm_edit_comment = function (discussion_id , note_id , unlinked )
141+ return function (text )
142+ local body = {
143+ discussion_id = discussion_id ,
144+ note_id = note_id ,
145+ comment = text ,
146+ }
147+ job .run_job (" /mr/comment" , " PATCH" , body , function (data )
148+ u .notify (data .message , vim .log .levels .INFO )
149+ discussions .rebuild_view (unlinked )
150+ end )
151+ end
152+ end
153+
88154--- @class LayoutOpts
89155--- @field ranged boolean
156+ --- @field discussion_id string | nil
90157--- @field unlinked boolean
91158
92159--- This function sets up the layout and popups needed to create a comment, note and
93160--- multi-line comment. It also sets up the basic keybindings for switching between
94161--- window panes, and for the non-primary sections.
95162--- @param opts LayoutOpts | nil
96163--- @return NuiLayout
97- local function create_comment_layout (opts )
164+ M . create_comment_layout = function (opts )
98165 if opts == nil then
99166 opts = {}
100167 end
101168
169+ local title = opts .discussion_id and " Reply" or " Comment"
170+ local settings = opts .discussion_id ~= nil and state .settings .popup .reply or state .settings .popup .comment
171+
102172 M .current_win = vim .api .nvim_get_current_win ()
103- M .comment_popup = Popup (u .create_popup_state (" Comment " , state . settings . popup . comment ))
173+ M .comment_popup = Popup (u .create_popup_state (title , settings ))
104174 M .draft_popup = Popup (u .create_box_popup_state (" Draft" , false ))
105175 M .start_line , M .end_line = u .get_visual_selection_boundaries ()
106176
@@ -128,14 +198,16 @@ local function create_comment_layout(opts)
128198 local range = opts .ranged and { start_line = M .start_line , end_line = M .end_line } or nil
129199 local unlinked = opts .unlinked or false
130200
201+ --- Keybinding for focus on text section
131202 state .set_popup_keymaps (M .draft_popup , function ()
132203 local text = u .get_buffer_text (M .comment_popup .bufnr )
133- confirm_create_comment (text , range , unlinked )
204+ confirm_create_comment (text , range , unlinked , opts . discussion_id )
134205 vim .api .nvim_set_current_win (M .current_win )
135206 end , miscellaneous .toggle_bool , popup_opts )
136207
208+ --- Keybinding for focus on draft section
137209 state .set_popup_keymaps (M .comment_popup , function (text )
138- confirm_create_comment (text , range , unlinked )
210+ confirm_create_comment (text , range , unlinked , opts . discussion_id )
139211 vim .api .nvim_set_current_win (M .current_win )
140212 end , miscellaneous .attach_file , popup_opts )
141213
@@ -144,6 +216,14 @@ local function create_comment_layout(opts)
144216 vim .api .nvim_buf_set_lines (M .draft_popup .bufnr , 0 , - 1 , false , { u .bool_to_string (draft_mode ) })
145217 end )
146218
219+ -- Send back to previous window on close
220+ vim .api .nvim_create_autocmd (" BufHidden" , {
221+ buffer = M .draft_popup .bufnr ,
222+ callback = function ()
223+ vim .api .nvim_set_current_win (M .current_win )
224+ end ,
225+ })
226+
147227 return layout
148228end
149229
@@ -167,7 +247,7 @@ M.create_comment = function()
167247 return
168248 end
169249
170- local layout = create_comment_layout ()
250+ local layout = M . create_comment_layout ({ ranged = false , unlinked = false } )
171251 layout :mount ()
172252end
173253
@@ -181,14 +261,14 @@ M.create_multiline_comment = function()
181261 return
182262 end
183263
184- local layout = create_comment_layout ({ ranged = true , unlinked = false })
264+ local layout = M . create_comment_layout ({ ranged = true , unlinked = false })
185265 layout :mount ()
186266end
187267
188268--- This function will open a a popup to create a "note" (e.g. unlinked comment)
189269--- on the changed/updated line in the current MR
190270M .create_note = function ()
191- local layout = create_comment_layout ({ ranged = false , unlinked = true })
271+ local layout = M . create_comment_layout ({ ranged = false , unlinked = true })
192272 layout :mount ()
193273end
194274
@@ -204,8 +284,8 @@ local build_suggestion = function()
204284 local backticks = " ```"
205285 local selected_lines = u .get_lines (M .start_line , M .end_line )
206286
207- for line in ipairs (selected_lines ) do
208- if string.match (line , " ^```$" ) then
287+ for _ , line in ipairs (selected_lines ) do
288+ if string.match (line , " ^```%S* $" ) then
209289 backticks = " ````"
210290 break
211291 end
@@ -243,7 +323,7 @@ M.create_comment_suggestion = function()
243323
244324 local suggestion_lines , range_length = build_suggestion ()
245325
246- local layout = create_comment_layout ({ ranged = range_length > 0 , unlinked = false })
326+ local layout = M . create_comment_layout ({ ranged = range_length > 0 , unlinked = false })
247327 layout :mount ()
248328 vim .schedule (function ()
249329 if suggestion_lines then
0 commit comments