mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 20:21:47 +01:00 
			
		
		
		
	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
					
				| @ -6,6 +6,7 @@ | ||||
| package git | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/base64" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| @ -50,6 +51,28 @@ func (b *Blob) GetBlobContent() (string, error) { | ||||
| 	return string(buf), nil | ||||
| } | ||||
| 
 | ||||
| // GetBlobLineCount gets line count of lob as raw text | ||||
| func (b *Blob) GetBlobLineCount() (int, error) { | ||||
| 	reader, err := b.DataAsync() | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	defer reader.Close() | ||||
| 	buf := make([]byte, 32*1024) | ||||
| 	count := 0 | ||||
| 	lineSep := []byte{'\n'} | ||||
| 	for { | ||||
| 		c, err := reader.Read(buf) | ||||
| 		count += bytes.Count(buf[:c], lineSep) | ||||
| 		switch { | ||||
| 		case err == io.EOF: | ||||
| 			return count, nil | ||||
| 		case err != nil: | ||||
| 			return count, err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string | ||||
| func (b *Blob) GetBlobContentBase64() (string, error) { | ||||
| 	dataRc, err := b.DataAsync() | ||||
|  | ||||
| @ -55,6 +55,15 @@ func TestGetDiffPreview(t *testing.T) { | ||||
| 								Type:     4, | ||||
| 								Content:  "@@ -1,3 +1,4 @@", | ||||
| 								Comments: nil, | ||||
| 								SectionInfo: &gitdiff.DiffLineSectionInfo{ | ||||
| 									Path:          "README.md", | ||||
| 									LastLeftIdx:   0, | ||||
| 									LastRightIdx:  0, | ||||
| 									LeftIdx:       1, | ||||
| 									RightIdx:      1, | ||||
| 									LeftHunkSize:  3, | ||||
| 									RightHunkSize: 4, | ||||
| 								}, | ||||
| 							}, | ||||
| 							{ | ||||
| 								LeftIdx:  1, | ||||
|  | ||||
| @ -898,6 +898,7 @@ tbody.commit-list{vertical-align:baseline} | ||||
| .repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important} | ||||
| .repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important} | ||||
| .tag-code,.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} | ||||
| td.blob-excerpt{background-color:#fafafa} | ||||
| .issue-keyword{border-bottom:1px dotted #959da5;display:inline-block} | ||||
| .file-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px!important} | ||||
| .file-info{display:flex;align-items:center} | ||||
| @ -1068,4 +1069,8 @@ tbody.commit-list{vertical-align:baseline} | ||||
| .comment-code-cloud .footer:after{clear:both;content:"";display:block} | ||||
| .comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em} | ||||
| .comment-code-cloud form.comment-form-reply{margin:0 0 0 4em} | ||||
| .file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} | ||||
| .file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} | ||||
| .ui.fold-code{margin-right:1em;padding-left:5px;cursor:pointer;width:22px;font-size:12px} | ||||
| .ui.fold-code:hover{color:#428bca} | ||||
| .ui.blob-excerpt{display:block;line-height:20px;font-size:16px;cursor:pointer} | ||||
| .ui.blob-excerpt:hover{color:#428bca} | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -245,6 +245,7 @@ func Diff(ctx *context.Context) { | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["CommitID"] = commitID | ||||
| 	ctx.Data["AfterCommitID"] = commitID | ||||
| 	ctx.Data["Username"] = userName | ||||
| 	ctx.Data["Reponame"] = repoName | ||||
| 
 | ||||
|  | ||||
| @ -5,21 +5,26 @@ | ||||
| package repo | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"html" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/base" | ||||
| 	"code.gitea.io/gitea/modules/context" | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/highlight" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/services/gitdiff" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	tplCompare base.TplName = "repo/diff/compare" | ||||
| 	tplCompare     base.TplName = "repo/diff/compare" | ||||
| 	tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt" | ||||
| ) | ||||
| 
 | ||||
| // setPathsCompareContext sets context data for source and raw paths | ||||
| @ -434,3 +439,109 @@ func CompareDiff(ctx *context.Context) { | ||||
| 
 | ||||
| 	ctx.HTML(200, tplCompare) | ||||
| } | ||||
| 
 | ||||
| // ExcerptBlob render blob excerpt contents | ||||
| func ExcerptBlob(ctx *context.Context) { | ||||
| 	commitID := ctx.Params("sha") | ||||
| 	lastLeft := ctx.QueryInt("last_left") | ||||
| 	lastRight := ctx.QueryInt("last_right") | ||||
| 	idxLeft := ctx.QueryInt("left") | ||||
| 	idxRight := ctx.QueryInt("right") | ||||
| 	leftHunkSize := ctx.QueryInt("left_hunk_size") | ||||
| 	rightHunkSize := ctx.QueryInt("right_hunk_size") | ||||
| 	anchor := ctx.Query("anchor") | ||||
| 	direction := ctx.Query("direction") | ||||
| 	filePath := ctx.Query("path") | ||||
| 	gitRepo := ctx.Repo.GitRepo | ||||
| 	chunkSize := gitdiff.BlobExceprtChunkSize | ||||
| 	commit, err := gitRepo.GetCommit(commitID) | ||||
| 	if err != nil { | ||||
| 		ctx.Error(500, "GetCommit") | ||||
| 		return | ||||
| 	} | ||||
| 	section := &gitdiff.DiffSection{ | ||||
| 		Name: filePath, | ||||
| 	} | ||||
| 	if direction == "up" && (idxLeft-lastLeft) > chunkSize { | ||||
| 		idxLeft -= chunkSize | ||||
| 		idxRight -= chunkSize | ||||
| 		leftHunkSize += chunkSize | ||||
| 		rightHunkSize += chunkSize | ||||
| 		section.Lines, err = getExcerptLines(commit, filePath, idxLeft-1, idxRight-1, chunkSize) | ||||
| 	} else if direction == "down" && (idxLeft-lastLeft) > chunkSize { | ||||
| 		section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, chunkSize) | ||||
| 		lastLeft += chunkSize | ||||
| 		lastRight += chunkSize | ||||
| 	} else { | ||||
| 		section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, idxRight-lastRight-1) | ||||
| 		leftHunkSize = 0 | ||||
| 		rightHunkSize = 0 | ||||
| 		idxLeft = lastLeft | ||||
| 		idxRight = lastRight | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		ctx.Error(500, "getExcerptLines") | ||||
| 		return | ||||
| 	} | ||||
| 	if idxRight > lastRight { | ||||
| 		lineText := " " | ||||
| 		if rightHunkSize > 0 || leftHunkSize > 0 { | ||||
| 			lineText = fmt.Sprintf("@@ -%d,%d +%d,%d @@\n", idxLeft, leftHunkSize, idxRight, rightHunkSize) | ||||
| 		} | ||||
| 		lineText = html.EscapeString(lineText) | ||||
| 		lineSection := &gitdiff.DiffLine{ | ||||
| 			Type:    gitdiff.DiffLineSection, | ||||
| 			Content: lineText, | ||||
| 			SectionInfo: &gitdiff.DiffLineSectionInfo{ | ||||
| 				Path:          filePath, | ||||
| 				LastLeftIdx:   lastLeft, | ||||
| 				LastRightIdx:  lastRight, | ||||
| 				LeftIdx:       idxLeft, | ||||
| 				RightIdx:      idxRight, | ||||
| 				LeftHunkSize:  leftHunkSize, | ||||
| 				RightHunkSize: rightHunkSize, | ||||
| 			}} | ||||
| 		if direction == "up" { | ||||
| 			section.Lines = append([]*gitdiff.DiffLine{lineSection}, section.Lines...) | ||||
| 		} else if direction == "down" { | ||||
| 			section.Lines = append(section.Lines, lineSection) | ||||
| 		} | ||||
| 	} | ||||
| 	ctx.Data["section"] = section | ||||
| 	ctx.Data["fileName"] = filePath | ||||
| 	ctx.Data["highlightClass"] = highlight.FileNameToHighlightClass(filepath.Base(filePath)) | ||||
| 	ctx.Data["AfterCommitID"] = commitID | ||||
| 	ctx.Data["Anchor"] = anchor | ||||
| 	ctx.HTML(200, tplBlobExcerpt) | ||||
| } | ||||
| 
 | ||||
| func getExcerptLines(commit *git.Commit, filePath string, idxLeft int, idxRight int, chunkSize int) ([]*gitdiff.DiffLine, error) { | ||||
| 	blob, err := commit.Tree.GetBlobByPath(filePath) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	reader, err := blob.DataAsync() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer reader.Close() | ||||
| 	scanner := bufio.NewScanner(reader) | ||||
| 	var diffLines []*gitdiff.DiffLine | ||||
| 	for line := 0; line < idxRight+chunkSize; line++ { | ||||
| 		if ok := scanner.Scan(); !ok { | ||||
| 			break | ||||
| 		} | ||||
| 		if line < idxRight { | ||||
| 			continue | ||||
| 		} | ||||
| 		lineText := scanner.Text() | ||||
| 		diffLine := &gitdiff.DiffLine{ | ||||
| 			LeftIdx:  idxLeft + (line - idxRight) + 1, | ||||
| 			RightIdx: line + 1, | ||||
| 			Type:     gitdiff.DiffLinePlain, | ||||
| 			Content:  " " + lineText, | ||||
| 		} | ||||
| 		diffLines = append(diffLines, diffLine) | ||||
| 	} | ||||
| 	return diffLines, nil | ||||
| } | ||||
|  | ||||
| @ -552,6 +552,7 @@ func ViewPullFiles(ctx *context.Context) { | ||||
| 		ctx.Data["Username"] = pull.MustHeadUserName() | ||||
| 		ctx.Data["Reponame"] = pull.HeadRepo.Name | ||||
| 	} | ||||
| 	ctx.Data["AfterCommitID"] = endCommitID | ||||
| 
 | ||||
| 	diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath, | ||||
| 		startCommitID, endCommitID, setting.Git.MaxGitDiffLines, | ||||
|  | ||||
| @ -864,6 +864,10 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||
| 			m.Get("", repo.Branches) | ||||
| 		}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) | ||||
| 
 | ||||
| 		m.Group("/blob_excerpt", func() { | ||||
| 			m.Get("/:sha", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob) | ||||
| 		}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) | ||||
| 
 | ||||
| 		m.Group("/pulls/:index", func() { | ||||
| 			m.Get(".diff", repo.DownloadPullDiff) | ||||
| 			m.Get(".patch", repo.DownloadPullPatch) | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
							
								
								
									
										50
									
								
								templates/repo/diff/blob_excerpt.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								templates/repo/diff/blob_excerpt.tmpl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| {{if $.IsSplitStyle}} | ||||
|   {{range $k, $line := $.section.Lines}} | ||||
|   <tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> | ||||
|     {{if eq .GetType 4}} | ||||
|     <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"> | ||||
|       {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} | ||||
|       <i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="{{$.Anchor}}"></i> | ||||
|       {{end}} | ||||
|       {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} | ||||
|       <i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="{{$.Anchor}}"></i> | ||||
|       {{end}} | ||||
|       {{if or (eq $line.GetExpandDirection 2)}} | ||||
|       <i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="{{$.Anchor}}"></i> | ||||
|       {{end}} | ||||
|     </td> | ||||
|     <td colspan="5" class="lines-code lines-code-old "><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{$.section.GetComputedInlineDiffFor $line}}</span></td> | ||||
|     {{else}} | ||||
|     <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $.fileName}}L{{$line.LeftIdx}}{{end}}"></span></td> | ||||
|     <td class="blob-excerpt lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker=""></span>{{end}}</td> | ||||
|     <td class="blob-excerpt lines-code lines-code-old halfwidth"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$.section.GetComputedInlineDiffFor $line}}{{end}}</span></td> | ||||
|     <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $.fileName}}R{{$line.RightIdx}}{{end}}"></span></td> | ||||
|     <td class="blob-excerpt lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker=""></span>{{end}}</td> | ||||
|     <td class="blob-excerpt lines-code lines-code-new halfwidth"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$.section.GetComputedInlineDiffFor $line}}{{end}}</span></td> | ||||
|     {{end}} | ||||
|   </tr> | ||||
|   {{end}} | ||||
| {{else}} | ||||
|   {{range $k, $line := $.section.Lines}} | ||||
|   <tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> | ||||
|     {{if eq .GetType 4}} | ||||
|     <td colspan="2" class="lines-num"> | ||||
|       {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} | ||||
|       <i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="{{$.Anchor}}"></i> | ||||
|       {{end}} | ||||
|       {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} | ||||
|       <i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="{{$.Anchor}}"></i> | ||||
|       {{end}} | ||||
|       {{if or (eq $line.GetExpandDirection 2)}} | ||||
|       <i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="{{$.Anchor}}"></i> | ||||
|       {{end}} | ||||
|     </td> | ||||
|     {{else}} | ||||
|     <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $.fileName}}L{{$line.LeftIdx}}{{end}}"></span></td> | ||||
|     <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $.fileName}}R{{$line.RightIdx}}{{end}}"></span></td> | ||||
|     {{end}} | ||||
|     <td class="blob-excerpt lines-type-marker"><span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td> | ||||
|     <td class="blob-excerpt lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{$.section.GetComputedInlineDiffFor $line}}</span></td> | ||||
|   </tr> | ||||
|   {{end}} | ||||
| {{end}} | ||||
| @ -81,6 +81,15 @@ | ||||
| 			{{else}} | ||||
| 				<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}"> | ||||
| 					<h4 class="ui top attached normal header"> | ||||
| 						{{$isImage := false}} | ||||
| 						{{if $file.IsDeleted}} | ||||
| 							{{$isImage = (call $.IsImageFileInBase $file.Name)}} | ||||
| 						{{else}} | ||||
| 							{{$isImage = (call $.IsImageFileInHead $file.Name)}} | ||||
| 						{{end}} | ||||
| 						{{if or (not $file.IsBin) $isImage}} | ||||
| 						<i class="ui fold-code grey fa fa-chevron-down"></i> | ||||
| 						{{end}} | ||||
| 						<div class="diff-counter count"> | ||||
| 							{{if $file.IsBin}} | ||||
| 								{{$.i18n.Tr "repo.diff.bin"}} | ||||
| @ -104,12 +113,6 @@ | ||||
| 					</h4> | ||||
| 					<div class="ui attached unstackable table segment"> | ||||
| 						{{if ne $file.Type 4}} | ||||
| 							{{$isImage := false}} | ||||
| 							{{if $file.IsDeleted}} | ||||
| 								{{$isImage = (call $.IsImageFileInBase $file.Name)}} | ||||
| 							{{else}} | ||||
| 								{{$isImage = (call $.IsImageFileInHead $file.Name)}} | ||||
| 							{{end}} | ||||
| 							<div class="file-body file-code code-view code-diff {{if $.IsSplitStyle}}code-diff-split{{else}}code-diff-unified{{end}}"> | ||||
| 								<table> | ||||
| 									<tbody> | ||||
| @ -121,12 +124,27 @@ | ||||
| 												{{range $j, $section := $file.Sections}} | ||||
| 													{{range $k, $line := $section.Lines}} | ||||
| 														<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> | ||||
| 															<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> | ||||
| 															<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> | ||||
| 															<td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> | ||||
| 															<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> | ||||
| 															<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> | ||||
| 															<td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> | ||||
| 															{{if eq .GetType 4}} | ||||
| 																<td class="lines-num lines-num-old"> | ||||
| 																	{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} | ||||
| 																		<i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i> | ||||
| 																	{{end}} | ||||
| 																	{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} | ||||
| 																		<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i> | ||||
| 																	{{end}} | ||||
| 																	{{if or (eq $line.GetExpandDirection 2)}} | ||||
| 																		<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i> | ||||
| 																	{{end}} | ||||
| 																</td> | ||||
| 																<td colspan="5" class="lines-code lines-code-old "><span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{$section.GetComputedInlineDiffFor $line}}</span></td> | ||||
| 															{{else}} | ||||
| 																<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> | ||||
| 																<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> | ||||
| 																<td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> | ||||
| 																<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> | ||||
| 																<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> | ||||
| 																<td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> | ||||
| 															{{end}} | ||||
| 														</tr> | ||||
| 														{{if gt (len $line.Comments) 0}} | ||||
| 															<tr class="add-code-comment"> | ||||
|  | ||||
| @ -4,9 +4,17 @@ | ||||
| 	{{range $k, $line := $section.Lines}} | ||||
| 		<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> | ||||
| 			{{if eq .GetType 4}} | ||||
| 			<td colspan="2" class="lines-num"> | ||||
| 				{{/* {{if gt $j 0}}<span class="fold octicon octicon-fold"></span>{{end}} */}} | ||||
| 			</td> | ||||
| 				<td colspan="2" class="lines-num"> | ||||
| 				{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} | ||||
| 					<i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i> | ||||
| 				{{end}} | ||||
| 				{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }} | ||||
| 					<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i> | ||||
| 				{{end}} | ||||
| 				{{if or (eq $line.GetExpandDirection 2)}} | ||||
| 					<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i> | ||||
| 				{{end}} | ||||
| 				</td> | ||||
| 			{{else}} | ||||
| 			<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> | ||||
| 			<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> | ||||
|  | ||||
| @ -1852,6 +1852,27 @@ function initCodeView() { | ||||
|       } | ||||
|     }).trigger('hashchange'); | ||||
|   } | ||||
|   $('.ui.fold-code').on('click', (e) => { | ||||
|     const $foldButton = $(e.target); | ||||
|     if ($foldButton.hasClass('fa-chevron-down')) { | ||||
|       $(e.target).parent().next().slideUp('fast', () => { | ||||
|         $foldButton.removeClass('fa-chevron-down').addClass('fa-chevron-right'); | ||||
|       }); | ||||
|     } else { | ||||
|       $(e.target).parent().next().slideDown('fast', () => { | ||||
|         $foldButton.removeClass('fa-chevron-right').addClass('fa-chevron-down'); | ||||
|       }); | ||||
|     } | ||||
|   }); | ||||
|   function insertBlobExcerpt(e) { | ||||
|     const $blob = $(e.target); | ||||
|     const $row = $blob.parent().parent(); | ||||
|     $.get(`${$blob.data('url')}?${$blob.data('query')}&anchor=${$blob.data('anchor')}`, (blob) => { | ||||
|       $row.replaceWith(blob); | ||||
|       $(`[data-anchor="${$blob.data('anchor')}"]`).on('click', (e) => { insertBlobExcerpt(e); }); | ||||
|     }); | ||||
|   } | ||||
|   $('.ui.blob-excerpt').on('click', (e) => { insertBlobExcerpt(e); }); | ||||
| } | ||||
| 
 | ||||
| function initU2FAuth() { | ||||
|  | ||||
| @ -2438,6 +2438,10 @@ tbody.commit-list { | ||||
|     padding-bottom: 8px; | ||||
| } | ||||
| 
 | ||||
| td.blob-excerpt { | ||||
|     background-color: #fafafa; | ||||
| } | ||||
| 
 | ||||
| .issue-keyword { | ||||
|     border-bottom: 1px dotted #959da5; | ||||
|     display: inline-block; | ||||
|  | ||||
| @ -108,3 +108,26 @@ | ||||
|     font: 12px @monospaced-fonts, monospace; | ||||
|     color: rgba(0, 0, 0, 0.87); | ||||
| } | ||||
| 
 | ||||
| .ui.fold-code { | ||||
|     margin-right: 1em; | ||||
|     padding-left: 5px; | ||||
|     cursor: pointer; | ||||
|     width: 22px; | ||||
|     font-size: 12px; | ||||
| } | ||||
| 
 | ||||
| .ui.fold-code:hover { | ||||
|     color: #428bca; | ||||
| } | ||||
| 
 | ||||
| .ui.blob-excerpt { | ||||
|     display: block; | ||||
|     line-height: 20px; | ||||
|     font-size: 16px; | ||||
|     cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| .ui.blob-excerpt:hover { | ||||
|     color: #428bca; | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user