diff --git a/models/issues/comment_code.go b/models/issues/comment_code.go index 67a77ceb13f36..fdba7dca25310 100644 --- a/models/issues/comment_code.go +++ b/models/issues/comment_code.go @@ -18,11 +18,11 @@ import ( type CodeComments map[string]map[int64][]*Comment // FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line -func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User, showOutdatedComments bool) (CodeComments, error) { - return fetchCodeCommentsByReview(ctx, issue, currentUser, nil, showOutdatedComments) +func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User, showOutdatedComments bool, filePath *string) (CodeComments, error) { + return fetchCodeCommentsByReview(ctx, issue, currentUser, nil, showOutdatedComments, filePath) } -func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *user_model.User, review *Review, showOutdatedComments bool) (CodeComments, error) { +func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *user_model.User, review *Review, showOutdatedComments bool, filePath *string) (CodeComments, error) { pathToLineToComment := make(CodeComments) if review == nil { review = &Review{ID: 0} @@ -33,6 +33,15 @@ func fetchCodeCommentsByReview(ctx context.Context, issue *Issue, currentUser *u ReviewID: review.ID, } + if filePath != nil { + opts = FindCommentsOptions{ + Type: CommentTypeCode, + IssueID: issue.ID, + ReviewID: review.ID, + TreePath: *filePath, + } + } + comments, err := findCodeComments(ctx, opts, issue, currentUser, review, showOutdatedComments) if err != nil { return nil, err diff --git a/models/issues/comment_test.go b/models/issues/comment_test.go index c5bbfdedc28ec..10a4558639e8f 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -50,7 +50,7 @@ func TestFetchCodeComments(t *testing.T) { issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - res, err := issues_model.FetchCodeComments(db.DefaultContext, issue, user, false) + res, err := issues_model.FetchCodeComments(db.DefaultContext, issue, user, false, nil) assert.NoError(t, err) assert.Contains(t, res, "README.md") assert.Contains(t, res["README.md"], int64(4)) @@ -58,7 +58,7 @@ func TestFetchCodeComments(t *testing.T) { assert.Equal(t, int64(4), res["README.md"][4][0].ID) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - res, err = issues_model.FetchCodeComments(db.DefaultContext, issue, user2, false) + res, err = issues_model.FetchCodeComments(db.DefaultContext, issue, user2, false, nil) assert.NoError(t, err) assert.Len(t, res, 1) } diff --git a/models/issues/review.go b/models/issues/review.go index 8b345e5fd8002..12425172617f9 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -158,7 +158,7 @@ func (r *Review) LoadCodeComments(ctx context.Context) (err error) { if err = r.LoadIssue(ctx); err != nil { return err } - r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false) + r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false, nil) return err } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 278974bec3ecf..4cd2f1006aa7d 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -14,6 +14,7 @@ import ( "net/http" "net/url" "path/filepath" + "sort" "strings" "code.gitea.io/gitea/models/db" @@ -39,6 +40,7 @@ import ( "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/context/upload" "code.gitea.io/gitea/services/gitdiff" + user_service "code.gitea.io/gitea/services/user" ) const ( @@ -863,6 +865,10 @@ func ExcerptBlob(ctx *context.Context) { direction := ctx.FormString("direction") filePath := ctx.FormString("path") gitRepo := ctx.Repo.GitRepo + if ctx.FormBool("pull") { + ctx.Data["PageIsPullFiles"] = true + } + if ctx.FormBool("wiki") { var err error gitRepo, err = gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository) @@ -881,6 +887,7 @@ func ExcerptBlob(ctx *context.Context) { section := &gitdiff.DiffSection{ FileName: filePath, Name: filePath, + Lines: []*gitdiff.DiffLine{}, } if direction == "up" && (idxLeft-lastLeft) > chunkSize { idxLeft -= chunkSize @@ -924,7 +931,9 @@ func ExcerptBlob(ctx *context.Context) { RightIdx: idxRight, LeftHunkSize: leftHunkSize, RightHunkSize: rightHunkSize, + HasComments: false, }, + Comments: nil, } if direction == "up" { section.Lines = append([]*gitdiff.DiffLine{lineSection}, section.Lines...) @@ -932,10 +941,69 @@ func ExcerptBlob(ctx *context.Context) { section.Lines = append(section.Lines, lineSection) } } + issueIndex := ctx.FormInt64("issue_index") + if ctx.FormBool("pull") && issueIndex > 0 { + issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, issueIndex) + if err != nil { + ctx.ServerError("GetIssueByIndex", err) + return + } + allComments, err := issues_model.FetchCodeComments(ctx, issue, ctx.Doer, false, &filePath) + if err != nil { + ctx.ServerError("FetchCodeComments", err) + return + } + lineCommits := allComments[filePath] + for index, line := range section.Lines { + if line.SectionInfo != nil && line.Type == 4 && !(line.SectionInfo.LastRightIdx == 0 && index+1 == len(section.Lines)) { + start := int64(line.SectionInfo.LastRightIdx + 1) + end := int64(line.SectionInfo.RightIdx - 1) + for start <= end { + if _, ok := lineCommits[start]; ok { + if !line.SectionInfo.HasComments { + line.SectionInfo.HasComments = true + break + } + } + start++ + } + } + if comments, ok := lineCommits[int64(line.LeftIdx*-1)]; ok { + line.Comments = append(line.Comments, comments...) + } + if comments, ok := lineCommits[int64(line.RightIdx)]; ok { + line.Comments = append(line.Comments, comments...) + } + + sort.SliceStable(line.Comments, func(i, j int) bool { + return line.Comments[i].CreatedUnix < line.Comments[j].CreatedUnix + }) + } + for _, line := range section.Lines { + for _, comment := range line.Comments { + if err := comment.LoadAttachments(ctx); err != nil { + ctx.ServerError("LoadAttachments", err) + return + } + } + } + ctx.Data["Issue"] = issue + ctx.Data["IssueIndex"] = issue.Index + } ctx.Data["section"] = section ctx.Data["FileNameHash"] = git.HashFilePathForWebUI(filePath) ctx.Data["AfterCommitID"] = commitID ctx.Data["Anchor"] = anchor + ctx.Data["CanBlockUser"] = func(blocker, blockee *user_model.User) bool { + return user_service.CanBlockUser(ctx, ctx.Doer, blocker, blockee) + } + if ctx.Data["SignedUserID"] == nil { + ctx.Data["SignedUserID"] = ctx.Doer.ID + } + ctx.Data["SignedUser"] = ctx.Doer + ctx.Data["IsSigned"] = ctx.Doer != nil + ctx.Data["Repository"] = ctx.Repo.Repository + ctx.Data["Permission"] = &ctx.Repo.Permission ctx.HTML(http.StatusOK, tplBlobExcerpt) } @@ -964,6 +1032,7 @@ func getExcerptLines(commit *git.Commit, filePath string, idxLeft, idxRight, chu RightIdx: line + 1, Type: gitdiff.DiffLinePlain, Content: " " + lineText, + Comments: []*issues_model.Comment{}, } diffLines = append(diffLines, diffLine) } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 9694ae845b1b9..609dfc0517aea 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -128,6 +128,7 @@ func getPullInfo(ctx *context.Context) (issue *issues_model.Issue, ok bool) { } ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, emoji.ReplaceAliases(issue.Title)) ctx.Data["Issue"] = issue + ctx.Data["IssueIndex"] = issue.Index if !issue.IsPull { ctx.NotFound("ViewPullCommits", nil) diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index bb1722039e19d..9cc1cc15a35a6 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -93,6 +93,7 @@ type DiffLineSectionInfo struct { RightIdx int LeftHunkSize int RightHunkSize int + HasComments bool } // BlobExcerptChunkSize represent max lines of excerpt @@ -177,6 +178,7 @@ func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int RightIdx: rightLine, LeftHunkSize: leftHunk, RightHunkSize: righHunk, + HasComments: false, } } @@ -401,6 +403,7 @@ func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommit, ri LastRightIdx: lastLine.RightIdx, LeftIdx: leftLineCount, RightIdx: rightLineCount, + HasComments: false, }, } tailSection := &DiffSection{FileName: diffFile.Name, Lines: []*DiffLine{tailDiffLine}} @@ -460,14 +463,28 @@ type Diff struct { // LoadComments loads comments into each line func (diff *Diff) LoadComments(ctx context.Context, issue *issues_model.Issue, currentUser *user_model.User, showOutdatedComments bool) error { - allComments, err := issues_model.FetchCodeComments(ctx, issue, currentUser, showOutdatedComments) + allComments, err := issues_model.FetchCodeComments(ctx, issue, currentUser, showOutdatedComments, nil) if err != nil { return err } + for _, file := range diff.Files { if lineCommits, ok := allComments[file.Name]; ok { for _, section := range file.Sections { - for _, line := range section.Lines { + for index, line := range section.Lines { + if line.SectionInfo != nil && line.Type == 4 && !(line.SectionInfo.LastRightIdx == 0 && index+1 == len(section.Lines)) { + start := int64(line.SectionInfo.LastRightIdx + 1) + end := int64(line.SectionInfo.RightIdx - 1) + for start <= end { + if _, ok := lineCommits[start]; ok { + if !line.SectionInfo.HasComments { + line.SectionInfo.HasComments = true + break + } + } + start++ + } + } if comments, ok := lineCommits[int64(line.LeftIdx*-1)]; ok { line.Comments = append(line.Comments, comments...) } diff --git a/services/repository/files/diff_test.go b/services/repository/files/diff_test.go index ea6ffe60c3f88..c698c8389265a 100644 --- a/services/repository/files/diff_test.go +++ b/services/repository/files/diff_test.go @@ -66,6 +66,7 @@ func TestGetDiffPreview(t *testing.T) { RightIdx: 1, LeftHunkSize: 3, RightHunkSize: 4, + HasComments: false, }, }, { diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index cc2237029bd68..ba4e29ad43eb2 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -1,35 +1,49 @@ {{if $.IsSplitStyle}} {{range $k, $line := $.section.Lines}} + {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}}
{{/*
*/}}{{end}}{{/*
@@ -38,45 +52,87 @@
{{/*
*/}}{{end}}{{/*
*/}}{{$inlineDiff.Content}}
{{$inlineDiff.Content}}
+