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
This commit is contained in:
parent
42ada741e3
commit
149a9df9e8
16 changed files with 460 additions and 36 deletions
|
@ -13,6 +13,7 @@ import (
|
|||
"html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
|
@ -56,15 +57,42 @@ const (
|
|||
DiffFileRename
|
||||
)
|
||||
|
||||
// DiffLineExpandDirection represents the DiffLineSection expand direction
|
||||
type DiffLineExpandDirection uint8
|
||||
|
||||
// DiffLineExpandDirection possible values.
|
||||
const (
|
||||
DiffLineExpandNone DiffLineExpandDirection = iota + 1
|
||||
DiffLineExpandSingle
|
||||
DiffLineExpandUpDown
|
||||
DiffLineExpandUp
|
||||
DiffLineExpandDown
|
||||
)
|
||||
|
||||
// DiffLine represents a line difference in a DiffSection.
|
||||
type DiffLine struct {
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
Type DiffLineType
|
||||
Content string
|
||||
Comments []*models.Comment
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
Type DiffLineType
|
||||
Content string
|
||||
Comments []*models.Comment
|
||||
SectionInfo *DiffLineSectionInfo
|
||||
}
|
||||
|
||||
// DiffLineSectionInfo represents diff line section meta data
|
||||
type DiffLineSectionInfo struct {
|
||||
Path string
|
||||
LastLeftIdx int
|
||||
LastRightIdx int
|
||||
LeftIdx int
|
||||
RightIdx int
|
||||
LeftHunkSize int
|
||||
RightHunkSize int
|
||||
}
|
||||
|
||||
// BlobExceprtChunkSize represent max lines of excerpt
|
||||
const BlobExceprtChunkSize = 20
|
||||
|
||||
// GetType returns the type of a DiffLine.
|
||||
func (d *DiffLine) GetType() int {
|
||||
return int(d.Type)
|
||||
|
@ -91,6 +119,71 @@ func (d *DiffLine) GetLineTypeMarker() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// GetBlobExcerptQuery builds query string to get blob excerpt
|
||||
func (d *DiffLine) GetBlobExcerptQuery() string {
|
||||
query := fmt.Sprintf(
|
||||
"last_left=%d&last_right=%d&"+
|
||||
"left=%d&right=%d&"+
|
||||
"left_hunk_size=%d&right_hunk_size=%d&"+
|
||||
"path=%s",
|
||||
d.SectionInfo.LastLeftIdx, d.SectionInfo.LastRightIdx,
|
||||
d.SectionInfo.LeftIdx, d.SectionInfo.RightIdx,
|
||||
d.SectionInfo.LeftHunkSize, d.SectionInfo.RightHunkSize,
|
||||
url.QueryEscape(d.SectionInfo.Path))
|
||||
return query
|
||||
}
|
||||
|
||||
// GetExpandDirection gets DiffLineExpandDirection
|
||||
func (d *DiffLine) GetExpandDirection() DiffLineExpandDirection {
|
||||
if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 {
|
||||
return DiffLineExpandNone
|
||||
}
|
||||
if d.SectionInfo.LastLeftIdx <= 0 && d.SectionInfo.LastRightIdx <= 0 {
|
||||
return DiffLineExpandUp
|
||||
} else if d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx > BlobExceprtChunkSize && d.SectionInfo.RightHunkSize > 0 {
|
||||
return DiffLineExpandUpDown
|
||||
} else if d.SectionInfo.LeftHunkSize <= 0 && d.SectionInfo.RightHunkSize <= 0 {
|
||||
return DiffLineExpandDown
|
||||
}
|
||||
return DiffLineExpandSingle
|
||||
}
|
||||
|
||||
func getDiffLineSectionInfo(curFile *DiffFile, line string, lastLeftIdx, lastRightIdx int) *DiffLineSectionInfo {
|
||||
var (
|
||||
leftLine int
|
||||
leftHunk int
|
||||
rightLine int
|
||||
righHunk int
|
||||
)
|
||||
ss := strings.Split(line, "@@")
|
||||
ranges := strings.Split(ss[1][1:], " ")
|
||||
leftRange := strings.Split(ranges[0], ",")
|
||||
leftLine, _ = com.StrTo(leftRange[0][1:]).Int()
|
||||
if len(leftRange) > 1 {
|
||||
leftHunk, _ = com.StrTo(leftRange[1]).Int()
|
||||
}
|
||||
if len(ranges) > 1 {
|
||||
rightRange := strings.Split(ranges[1], ",")
|
||||
rightLine, _ = com.StrTo(rightRange[0]).Int()
|
||||
if len(rightRange) > 1 {
|
||||
righHunk, _ = com.StrTo(rightRange[1]).Int()
|
||||
}
|
||||
} else {
|
||||
log.Warn("Parse line number failed: %v", line)
|
||||
rightLine = leftLine
|
||||
righHunk = leftHunk
|
||||
}
|
||||
return &DiffLineSectionInfo{
|
||||
Path: curFile.Name,
|
||||
LastLeftIdx: lastLeftIdx,
|
||||
LastRightIdx: lastRightIdx,
|
||||
LeftIdx: leftLine,
|
||||
RightIdx: rightLine,
|
||||
LeftHunkSize: leftHunk,
|
||||
RightHunkSize: righHunk,
|
||||
}
|
||||
}
|
||||
|
||||
// escape a line's content or return <br> needed for copy/paste purposes
|
||||
func getLineContent(content string) string {
|
||||
if len(content) > 0 {
|
||||
|
@ -248,6 +341,53 @@ func (diffFile *DiffFile) GetHighlightClass() string {
|
|||
return highlight.FileNameToHighlightClass(diffFile.Name)
|
||||
}
|
||||
|
||||
// GetTailSection creates a fake DiffLineSection if the last section is not the end of the file
|
||||
func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection {
|
||||
if diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile {
|
||||
return nil
|
||||
}
|
||||
leftCommit, err := gitRepo.GetCommit(leftCommitID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
rightCommit, err := gitRepo.GetCommit(rightCommitID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
lastSection := diffFile.Sections[len(diffFile.Sections)-1]
|
||||
lastLine := lastSection.Lines[len(lastSection.Lines)-1]
|
||||
leftLineCount := getCommitFileLineCount(leftCommit, diffFile.Name)
|
||||
rightLineCount := getCommitFileLineCount(rightCommit, diffFile.Name)
|
||||
if leftLineCount <= lastLine.LeftIdx || rightLineCount <= lastLine.RightIdx {
|
||||
return nil
|
||||
}
|
||||
tailDiffLine := &DiffLine{
|
||||
Type: DiffLineSection,
|
||||
Content: " ",
|
||||
SectionInfo: &DiffLineSectionInfo{
|
||||
Path: diffFile.Name,
|
||||
LastLeftIdx: lastLine.LeftIdx,
|
||||
LastRightIdx: lastLine.RightIdx,
|
||||
LeftIdx: leftLineCount,
|
||||
RightIdx: rightLineCount,
|
||||
}}
|
||||
tailSection := &DiffSection{Lines: []*DiffLine{tailDiffLine}}
|
||||
return tailSection
|
||||
|
||||
}
|
||||
|
||||
func getCommitFileLineCount(commit *git.Commit, filePath string) int {
|
||||
blob, err := commit.GetBlobByPath(filePath)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
lineCount, err := blob.GetBlobLineCount()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return lineCount
|
||||
}
|
||||
|
||||
// Diff represents a difference between two git trees.
|
||||
type Diff struct {
|
||||
TotalAddition, TotalDeletion int
|
||||
|
@ -510,19 +650,16 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
|||
case line[0] == '@':
|
||||
curSection = &DiffSection{}
|
||||
curFile.Sections = append(curFile.Sections, curSection)
|
||||
ss := strings.Split(line, "@@")
|
||||
diffLine := &DiffLine{Type: DiffLineSection, Content: line}
|
||||
curSection.Lines = append(curSection.Lines, diffLine)
|
||||
|
||||
// Parse line number.
|
||||
ranges := strings.Split(ss[1][1:], " ")
|
||||
leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
|
||||
if len(ranges) > 1 {
|
||||
rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int()
|
||||
} else {
|
||||
log.Warn("Parse line number failed: %v", line)
|
||||
rightLine = leftLine
|
||||
lineSectionInfo := getDiffLineSectionInfo(curFile, line, leftLine-1, rightLine-1)
|
||||
diffLine := &DiffLine{
|
||||
Type: DiffLineSection,
|
||||
Content: line,
|
||||
SectionInfo: lineSectionInfo,
|
||||
}
|
||||
curSection.Lines = append(curSection.Lines, diffLine)
|
||||
// update line number.
|
||||
leftLine = lineSectionInfo.LeftIdx
|
||||
rightLine = lineSectionInfo.RightIdx
|
||||
continue
|
||||
case line[0] == '+':
|
||||
curFile.Addition++
|
||||
|
@ -599,6 +736,8 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
|
|||
break
|
||||
}
|
||||
curFileLinesCount = 0
|
||||
leftLine = 1
|
||||
rightLine = 1
|
||||
curFileLFSPrefix = false
|
||||
|
||||
// Check file diff type and is submodule.
|
||||
|
@ -701,6 +840,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
|
|||
diffArgs = append(diffArgs, actualBeforeCommitID)
|
||||
diffArgs = append(diffArgs, afterCommitID)
|
||||
cmd = exec.Command(git.GitExecutable, diffArgs...)
|
||||
beforeCommitID = actualBeforeCommitID
|
||||
}
|
||||
cmd.Dir = repoPath
|
||||
cmd.Stderr = os.Stderr
|
||||
|
@ -721,6 +861,12 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("ParsePatch: %v", err)
|
||||
}
|
||||
for _, diffFile := range diff.Files {
|
||||
tailSection := diffFile.GetTailSection(gitRepo, beforeCommitID, afterCommitID)
|
||||
if tailSection != nil {
|
||||
diffFile.Sections = append(diffFile.Sections, tailSection)
|
||||
}
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("Wait: %v", err)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue