History

Expand/Collapse Files and Blob Excerpt while Reviewing/Comparing code (#8924)

* update #8659 fold/unfold code diffs * add fold button style * update #8659 implement expand up/down codes (blob excerpt) * fix golint errors * fix expand direction * remove debug message * update css style for blob exceprt * fix typo in comment * update style sheet with less * update expect diff (add SectionInfo) * update #8942 accept suggested change (fix typo) * close reader and check file type before get tail section * adjust button position and check file type before insert fold button * move index js to web_src * merge index.js with master * generate index.js * update js coding style

Benno committed 6 years ago

Commit 149a9df1 parent 42ada7416 files · +460 −36Browse files

Showing the changes to services/gitdiff/gitdiff.go (1 of 16 files). Show all

Unified · Split

services/gitdiff/gitdiff.go+163−17
@@ -13,6 +13,7 @@ import ( · 12 unmodified lines
1313 "html/template"
1414 "io"
1515 "io/ioutil"
16+ "net/url"
1617 "os"
1718 "os/exec"
1819 "regexp"
@@ -56,15 +57,42 @@ const ( · 37 unmodified lines
5657 DiffFileRename
5758 )
5859
60+// DiffLineExpandDirection represents the DiffLineSection expand direction
61+type DiffLineExpandDirection uint8
62+
63+// DiffLineExpandDirection possible values.
64+const (
65+ DiffLineExpandNone DiffLineExpandDirection = iota + 1
66+ DiffLineExpandSingle
67+ DiffLineExpandUpDown
68+ DiffLineExpandUp
69+ DiffLineExpandDown
70+)
71+
5972 // DiffLine represents a line difference in a DiffSection.
6073 type DiffLine struct {
61− LeftIdx int
62− RightIdx int
63− Type DiffLineType
64− Content string
65− Comments []*models.Comment
74+ LeftIdx int
75+ RightIdx int
76+ Type DiffLineType
77+ Content string
78+ Comments []*models.Comment
79+ SectionInfo *DiffLineSectionInfo
80+}
81+
82+// DiffLineSectionInfo represents diff line section meta data
83+type DiffLineSectionInfo struct {
84+ Path string
85+ LastLeftIdx int
86+ LastRightIdx int
87+ LeftIdx int
88+ RightIdx int
89+ LeftHunkSize int
90+ RightHunkSize int
6691 }
6792
93+// BlobExceprtChunkSize represent max lines of excerpt
94+const BlobExceprtChunkSize = 20
95+
6896 // GetType returns the type of a DiffLine.
6997 func (d *DiffLine) GetType() int {
7098 return int(d.Type)
@@ -91,6 +119,71 @@ func (d *DiffLine) GetLineTypeMarker() string { · 20 unmodified lines
91119 return ""
92120 }
93121
122+// GetBlobExcerptQuery builds query string to get blob excerpt
123+func (d *DiffLine) GetBlobExcerptQuery() string {
124+ query := fmt.Sprintf(
125+ "last_left=%d&last_right=%d&"+
126+ "left=%d&right=%d&"+
127+ "left_hunk_size=%d&right_hunk_size=%d&"+
128+ "path=%s",
129+ d.SectionInfo.LastLeftIdx, d.SectionInfo.LastRightIdx,
130+ d.SectionInfo.LeftIdx, d.SectionInfo.RightIdx,
131+ d.SectionInfo.LeftHunkSize, d.SectionInfo.RightHunkSize,
132+ url.QueryEscape(d.SectionInfo.Path))
133+ return query
134+}
135+
136+// GetExpandDirection gets DiffLineExpandDirection
137+func (d *DiffLine) GetExpandDirection() DiffLineExpandDirection {
138+ if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 {
139+ return DiffLineExpandNone
140+ }
141+ if d.SectionInfo.LastLeftIdx <= 0 && d.SectionInfo.LastRightIdx <= 0 {
142+ return DiffLineExpandUp
143+ } else if d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx > BlobExceprtChunkSize && d.SectionInfo.RightHunkSize > 0 {
144+ return DiffLineExpandUpDown
145+ } else if d.SectionInfo.LeftHunkSize <= 0 && d.SectionInfo.RightHunkSize <= 0 {
146+ return DiffLineExpandDown
147+ }
148+ return DiffLineExpandSingle
149+}
150+
151+func getDiffLineSectionInfo(curFile *DiffFile, line string, lastLeftIdx, lastRightIdx int) *DiffLineSectionInfo {
152+ var (
153+ leftLine int
154+ leftHunk int
155+ rightLine int
156+ righHunk int
157+ )
158+ ss := strings.Split(line, "@@")
159+ ranges := strings.Split(ss[1][1:], " ")
160+ leftRange := strings.Split(ranges[0], ",")
161+ leftLine, _ = com.StrTo(leftRange[0][1:]).Int()
162+ if len(leftRange) > 1 {
163+ leftHunk, _ = com.StrTo(leftRange[1]).Int()
164+ }
165+ if len(ranges) > 1 {
166+ rightRange := strings.Split(ranges[1], ",")
167+ rightLine, _ = com.StrTo(rightRange[0]).Int()
168+ if len(rightRange) > 1 {
169+ righHunk, _ = com.StrTo(rightRange[1]).Int()
170+ }
171+ } else {
172+ log.Warn("Parse line number failed: %v", line)
173+ rightLine = leftLine
174+ righHunk = leftHunk
175+ }
176+ return &DiffLineSectionInfo{
177+ Path: curFile.Name,
178+ LastLeftIdx: lastLeftIdx,
179+ LastRightIdx: lastRightIdx,
180+ LeftIdx: leftLine,
181+ RightIdx: rightLine,
182+ LeftHunkSize: leftHunk,
183+ RightHunkSize: righHunk,
184+ }
185+}
186+
94187 // escape a line's content or return <br> needed for copy/paste purposes
95188 func getLineContent(content string) string {
96189 if len(content) > 0 {
@@ -248,6 +341,53 @@ func (diffFile *DiffFile) GetHighlightClass() string { · 151 unmodified lines
248341 return highlight.FileNameToHighlightClass(diffFile.Name)
249342 }
250343
344+// GetTailSection creates a fake DiffLineSection if the last section is not the end of the file
345+func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection {
346+ if diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile {
347+ return nil
348+ }
349+ leftCommit, err := gitRepo.GetCommit(leftCommitID)
350+ if err != nil {
351+ return nil
352+ }
353+ rightCommit, err := gitRepo.GetCommit(rightCommitID)
354+ if err != nil {
355+ return nil
356+ }
357+ lastSection := diffFile.Sections[len(diffFile.Sections)-1]
358+ lastLine := lastSection.Lines[len(lastSection.Lines)-1]
359+ leftLineCount := getCommitFileLineCount(leftCommit, diffFile.Name)
360+ rightLineCount := getCommitFileLineCount(rightCommit, diffFile.Name)
361+ if leftLineCount <= lastLine.LeftIdx || rightLineCount <= lastLine.RightIdx {
362+ return nil
363+ }
364+ tailDiffLine := &DiffLine{
365+ Type: DiffLineSection,
366+ Content: " ",
367+ SectionInfo: &DiffLineSectionInfo{
368+ Path: diffFile.Name,
369+ LastLeftIdx: lastLine.LeftIdx,
370+ LastRightIdx: lastLine.RightIdx,
371+ LeftIdx: leftLineCount,
372+ RightIdx: rightLineCount,
373+ }}
374+ tailSection := &DiffSection{Lines: []*DiffLine{tailDiffLine}}
375+ return tailSection
376+
377+}
378+
379+func getCommitFileLineCount(commit *git.Commit, filePath string) int {
380+ blob, err := commit.GetBlobByPath(filePath)
381+ if err != nil {
382+ return 0
383+ }
384+ lineCount, err := blob.GetBlobLineCount()
385+ if err != nil {
386+ return 0
387+ }
388+ return lineCount
389+}
390+
251391 // Diff represents a difference between two git trees.
252392 type Diff struct {
253393 TotalAddition, TotalDeletion int
@@ -510,19 +650,16 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 256 unmodified lines
510650 case line[0] == '@':
511651 curSection = &DiffSection{}
512652 curFile.Sections = append(curFile.Sections, curSection)
513− ss := strings.Split(line, "@@")
514− diffLine := &DiffLine{Type: DiffLineSection, Content: line}
515− curSection.Lines = append(curSection.Lines, diffLine)
516−
517− // Parse line number.
518− ranges := strings.Split(ss[1][1:], " ")
519− leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
520− if len(ranges) > 1 {
521− rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int()
522− } else {
523− log.Warn("Parse line number failed: %v", line)
524− rightLine = leftLine
653+ lineSectionInfo := getDiffLineSectionInfo(curFile, line, leftLine-1, rightLine-1)
654+ diffLine := &DiffLine{
655+ Type: DiffLineSection,
656+ Content: line,
657+ SectionInfo: lineSectionInfo,
525658 }
659+ curSection.Lines = append(curSection.Lines, diffLine)
660+ // update line number.
661+ leftLine = lineSectionInfo.LeftIdx
662+ rightLine = lineSectionInfo.RightIdx
526663 continue
527664 case line[0] == '+':
528665 curFile.Addition++
@@ -599,6 +736,8 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 70 unmodified lines
599736 break
600737 }
601738 curFileLinesCount = 0
739+ leftLine = 1
740+ rightLine = 1
602741 curFileLFSPrefix = false
603742
604743 // Check file diff type and is submodule.
@@ -701,6 +840,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID · 96 unmodified lines
701840 diffArgs = append(diffArgs, actualBeforeCommitID)
702841 diffArgs = append(diffArgs, afterCommitID)
703842 cmd = exec.Command(git.GitExecutable, diffArgs...)
843+ beforeCommitID = actualBeforeCommitID
704844 }
705845 cmd.Dir = repoPath
706846 cmd.Stderr = os.Stderr
@@ -721,6 +861,12 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID · 14 unmodified lines
721861 if err != nil {
722862 return nil, fmt.Errorf("ParsePatch: %v", err)
723863 }
864+ for _, diffFile := range diff.Files {
865+ tailSection := diffFile.GetTailSection(gitRepo, beforeCommitID, afterCommitID)
866+ if tailSection != nil {
867+ diffFile.Sections = append(diffFile.Sections, tailSection)
868+ }
869+ }
724870
725871 if err = cmd.Wait(); err != nil {
726872 return nil, fmt.Errorf("Wait: %v", err)