6060 :group 'github-review
6161 :type 'string )
6262
63+ (defcustom github-review-view-comments-in-code-lines nil
64+ " Flag to enable displaying comments in code lines."
65+ :group 'github-review )
66+
67+ (defcustom github-review-view-comments-in-code-lines-outdated nil
68+ " Flag to enable displaying outdated comments in code lines."
69+ :group 'github-review )
70+
6371(defconst github-review-diffheader '((" Accept" . " application/vnd.github.v3.diff" ))
6472 " Header for requesting diffs from GitHub." )
6573
@@ -119,8 +127,26 @@ return a deferred object"
119127 nodes { author { login } bodyText state }
120128 } }
121129 }
130+ } " .repo .owner .num))
131+ (query-with-comments (format " query {
132+ repository(name: \" %s \" , owner: \" %s \" ) {
133+ pullRequest(number: %s ){
134+ headRef { target{ oid } }
135+ title
136+ bodyText
137+ comments(first:50) {
138+ nodes { author { login } bodyText }
139+ }
140+ reviews(first: 50) {
141+ nodes { author { login } bodyText state
142+ comments(first: 50)
143+ { nodes { bodyText originalPosition position outdated path} }}
144+ } }
145+ }
122146} " .repo .owner .num)))
123- (ghub-graphql query
147+ (ghub-graphql (if github-review-view-comments-in-code-lines
148+ query-with-comments
149+ query)
124150 '()
125151 :auth 'github-review
126152 :host (github-review-api-host pr-alist)
@@ -340,7 +366,82 @@ This function infers the PR name based on the current filename"
340366(defun github-review-format-review (review )
341367 " Format a REVIEW object to string."
342368 (let-alist review
343- (format " Reviewed by @%s [%s ]: %s " .author.login .state .bodyText)))
369+ (if (not (string-empty-p .bodyText))
370+ (format " Reviewed by @%s [%s ]: %s " .author.login .state .bodyText)
371+ " " )))
372+
373+ (defvar github-review-comment-pos ()
374+ " Variable to count how many comments in code lines were added in the diff.
375+ This is necessary to adjust the new comments to the correct position in the diff given that
376+ Github API provides only the originalPosition in the query." )
377+
378+ (defun github-review--get-how-many-comments-written (path )
379+ (or (a-get github-review-comment-pos path) 0 ))
380+
381+ (defun github-review-place-review-comments (gitdiff review )
382+ (if (not (a-get-in review (list 'comments 'nodes )))
383+ gitdiff
384+ (let* ((at (a-get-in review (list 'author 'login )))
385+ (body (a-get review 'bodyText ))
386+ (body-lines (split-string body " \n " ))
387+ (state (a-get review 'state ))
388+
389+ (comments (a-get-in review (list 'comments 'nodes )))
390+ (default-shift-pos 1 ))
391+ (-reduce-from
392+ (lambda (acc-diff comment )
393+ (if (and (not github-review-view-comments-in-code-lines-outdated)
394+ (a-get comment 'outdated ))
395+ acc-diff
396+ (let* ((path (a-get comment 'path ))
397+ (original-pos (a-get comment 'originalPosition ))
398+ (-position (a-get comment 'position ))
399+ (position (when (numberp -position) -position))
400+ (adjusted-pos (+ (or position original-pos)
401+ default-shift-pos
402+ (github-review--get-how-many-comments-written path)))
403+ (comment-lines (split-string (a-get comment 'bodyText ) " \n " ))
404+
405+ ; ; get diff lines specific for the current path
406+ (gitdiff-path (s-concat " +++ b/" path " \n " ))
407+ (gitdiff-splitted-on-path (split-string acc-diff gitdiff-path))
408+ (gitdiff-on-path-lines (split-string (-second-item gitdiff-splitted-on-path) " \n " ))
409+ (gitdiff-on-path-splitted (-split-at adjusted-pos gitdiff-on-path-lines)))
410+
411+ ; ; save how many lines of comments was written in the buffer for this path
412+ (setf (alist-get path github-review-comment-pos nil nil 'equal )
413+ (+ (github-review--get-how-many-comments-written path)
414+ (length comment-lines)
415+ (if (string-empty-p body)
416+ 0
417+ (length body-lines))))
418+
419+ ; ; include comments on buffer for this path
420+ (let* ((result
421+ (-concat
422+ (-first-item gitdiff-on-path-splitted)
423+ (list (format " ~ Reviewed by @%s [%s ]: %s " at state
424+ (if (string-empty-p body)
425+ (-first-item comment-lines)
426+ (-first-item body-lines))))
427+ (-map
428+ (lambda (commentLine ) (s-concat " ~ " (s-trim-left commentLine)))
429+ (-concat
430+ (-drop 1 body-lines)
431+ (if (string-empty-p body)
432+ (-drop 1 comment-lines)
433+ comment-lines)))
434+ (-second-item gitdiff-on-path-splitted)))
435+ (gitdiff-on-path-new (s-concat
436+ gitdiff-path
437+ (s-join " \n " result))))
438+
439+ ; ; join this path with beginning of the diff
440+ (s-concat
441+ (-first-item gitdiff-splitted-on-path)
442+ gitdiff-on-path-new)))))
443+ gitdiff
444+ comments))))
344445
345446(defun github-review-format-diff (gitdiff pr )
346447 " Formats a GITDIFF and PR to save it for review."
@@ -366,7 +467,15 @@ This function infers the PR name based on the current filename"
366467 #'github-review-to-comments
367468 (-map #'github-review-format-review reviews)))
368469 " \n " ))
369- (a-get gitdiff 'message ))))
470+ (if github-review-view-comments-in-code-lines
471+ (progn
472+ (setq github-review-comment-pos ())
473+ (-reduce-from
474+ (lambda (acc-gitdiff node )
475+ (github-review-place-review-comments acc-gitdiff node))
476+ (a-get gitdiff 'message )
477+ .reviews.nodes))
478+ (a-get gitdiff 'message )))))
370479
371480; ;;;;;;;;;;;;;;;;;;;;
372481; ; User facing API ;;
0 commit comments