mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Add buttons to allow loading of incomplete diffs (#16829)
This PR adds two buttons to the stats and the end of the diffs list to load the (some of) the remaining incomplete diff sections. Contains #16775 Signed-off-by: Andrew Thornton <art27@cantab.net> ## Screenshots ### Show more button at the end of the diff  ### Show more button at the end of the diff stats box 
This commit is contained in:
		@@ -46,7 +46,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetCompareInfo generates and returns compare information between base and head branches of repositories.
 | 
					// GetCompareInfo generates and returns compare information between base and head branches of repositories.
 | 
				
			||||||
func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison bool) (_ *CompareInfo, err error) {
 | 
					func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string, directComparison, fileOnly bool) (_ *CompareInfo, err error) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		remoteBranch string
 | 
							remoteBranch string
 | 
				
			||||||
		tmpRemote    string
 | 
							tmpRemote    string
 | 
				
			||||||
@@ -87,13 +87,17 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string,
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// We have a common base - therefore we know that ... should work
 | 
							// We have a common base - therefore we know that ... should work
 | 
				
			||||||
		logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
 | 
							if !fileOnly {
 | 
				
			||||||
		if err != nil {
 | 
								logs, err := NewCommand("log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
 | 
				
			||||||
			return nil, err
 | 
								if err != nil {
 | 
				
			||||||
		}
 | 
									return nil, err
 | 
				
			||||||
		compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
 | 
								}
 | 
				
			||||||
		if err != nil {
 | 
								compareInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
 | 
				
			||||||
			return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								compareInfo.Commits = []*Commit{}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		compareInfo.Commits = []*Commit{}
 | 
							compareInfo.Commits = []*Commit{}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2027,7 +2027,8 @@ diff.file_image_height = Height
 | 
				
			|||||||
diff.file_byte_size = Size
 | 
					diff.file_byte_size = Size
 | 
				
			||||||
diff.file_suppressed = File diff suppressed because it is too large
 | 
					diff.file_suppressed = File diff suppressed because it is too large
 | 
				
			||||||
diff.file_suppressed_line_too_long = File diff suppressed because one or more lines are too long
 | 
					diff.file_suppressed_line_too_long = File diff suppressed because one or more lines are too long
 | 
				
			||||||
diff.too_many_files = Some files were not shown because too many files changed in this diff
 | 
					diff.too_many_files = Some files were not shown because too many files have changed in this diff
 | 
				
			||||||
 | 
					diff.show_more = Show More
 | 
				
			||||||
diff.generated = generated
 | 
					diff.generated = generated
 | 
				
			||||||
diff.vendored = vendored
 | 
					diff.vendored = vendored
 | 
				
			||||||
diff.comment.placeholder = Leave a comment
 | 
					diff.comment.placeholder = Leave a comment
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1016,7 +1016,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
 | 
				
			|||||||
		return nil, nil, nil, nil, "", ""
 | 
							return nil, nil, nil, nil, "", ""
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true)
 | 
						compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch, true, false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		headGitRepo.Close()
 | 
							headGitRepo.Close()
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
 | 
							ctx.Error(http.StatusInternalServerError, "GetCompareInfo", err)
 | 
				
			||||||
@@ -1193,9 +1193,9 @@ func GetPullRequestCommits(ctx *context.APIContext) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	defer baseGitRepo.Close()
 | 
						defer baseGitRepo.Close()
 | 
				
			||||||
	if pr.HasMerged {
 | 
						if pr.HasMerged {
 | 
				
			||||||
		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true)
 | 
							prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName(), true, false)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true)
 | 
							prInfo, err = baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName(), true, false)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.ServerError("GetCompareInfo", err)
 | 
							ctx.ServerError("GetCompareInfo", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -264,6 +264,8 @@ func Diff(ctx *context.Context) {
 | 
				
			|||||||
		err     error
 | 
							err     error
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fileOnly := ctx.FormBool("file-only")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ctx.Data["PageIsWiki"] != nil {
 | 
						if ctx.Data["PageIsWiki"] != nil {
 | 
				
			||||||
		gitRepo, err = git.OpenRepository(ctx.Repo.Repository.WikiPath())
 | 
							gitRepo, err = git.OpenRepository(ctx.Repo.Repository.WikiPath())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -288,16 +290,8 @@ func Diff(ctx *context.Context) {
 | 
				
			|||||||
		commitID = commit.ID.String()
 | 
							commitID = commit.ID.String()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Error("GetLatestCommitStatus: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses)
 | 
					 | 
				
			||||||
	ctx.Data["CommitStatuses"] = statuses
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	diff, err := gitdiff.GetDiffCommitWithWhitespaceBehavior(gitRepo,
 | 
						diff, err := gitdiff.GetDiffCommitWithWhitespaceBehavior(gitRepo,
 | 
				
			||||||
		commitID, setting.Git.MaxGitDiffLines,
 | 
							commitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines,
 | 
				
			||||||
		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles,
 | 
							setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles,
 | 
				
			||||||
		gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
 | 
							gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)),
 | 
				
			||||||
		false)
 | 
							false)
 | 
				
			||||||
@@ -333,10 +327,23 @@ func Diff(ctx *context.Context) {
 | 
				
			|||||||
	setCompareContext(ctx, parentCommit, commit, headTarget)
 | 
						setCompareContext(ctx, parentCommit, commit, headTarget)
 | 
				
			||||||
	ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
 | 
						ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
 | 
				
			||||||
	ctx.Data["Commit"] = commit
 | 
						ctx.Data["Commit"] = commit
 | 
				
			||||||
 | 
						ctx.Data["Diff"] = diff
 | 
				
			||||||
 | 
						if fileOnly {
 | 
				
			||||||
 | 
							ctx.HTML(http.StatusOK, tplDiffBox)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						statuses, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetLatestCommitStatus: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses)
 | 
				
			||||||
 | 
						ctx.Data["CommitStatuses"] = statuses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	verification := models.ParseCommitWithSignature(commit)
 | 
						verification := models.ParseCommitWithSignature(commit)
 | 
				
			||||||
	ctx.Data["Verification"] = verification
 | 
						ctx.Data["Verification"] = verification
 | 
				
			||||||
	ctx.Data["Author"] = models.ValidateCommitWithEmail(commit)
 | 
						ctx.Data["Author"] = models.ValidateCommitWithEmail(commit)
 | 
				
			||||||
	ctx.Data["Diff"] = diff
 | 
					 | 
				
			||||||
	ctx.Data["Parents"] = parents
 | 
						ctx.Data["Parents"] = parents
 | 
				
			||||||
	ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
 | 
						ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,7 @@ import (
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	tplCompare     base.TplName = "repo/diff/compare"
 | 
						tplCompare     base.TplName = "repo/diff/compare"
 | 
				
			||||||
	tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt"
 | 
						tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt"
 | 
				
			||||||
 | 
						tplDiffBox     base.TplName = "repo/diff/box"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// setCompareContext sets context data.
 | 
					// setCompareContext sets context data.
 | 
				
			||||||
@@ -161,6 +162,8 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 | 
				
			|||||||
	baseRepo := ctx.Repo.Repository
 | 
						baseRepo := ctx.Repo.Repository
 | 
				
			||||||
	ci := &CompareInfo{}
 | 
						ci := &CompareInfo{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fileOnly := ctx.FormBool("file-only")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get compared branches information
 | 
						// Get compared branches information
 | 
				
			||||||
	// A full compare url is of the form:
 | 
						// A full compare url is of the form:
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
@@ -411,15 +414,19 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 | 
				
			|||||||
	if rootRepo != nil &&
 | 
						if rootRepo != nil &&
 | 
				
			||||||
		rootRepo.ID != ci.HeadRepo.ID &&
 | 
							rootRepo.ID != ci.HeadRepo.ID &&
 | 
				
			||||||
		rootRepo.ID != baseRepo.ID {
 | 
							rootRepo.ID != baseRepo.ID {
 | 
				
			||||||
		perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo)
 | 
							canRead := rootRepo.CheckUnitUser(ctx.User, models.UnitTypeCode)
 | 
				
			||||||
		if err != nil {
 | 
							if canRead {
 | 
				
			||||||
			ctx.ServerError("GetBranchesForRepo", err)
 | 
					 | 
				
			||||||
			return nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if perm {
 | 
					 | 
				
			||||||
			ctx.Data["RootRepo"] = rootRepo
 | 
								ctx.Data["RootRepo"] = rootRepo
 | 
				
			||||||
			ctx.Data["RootRepoBranches"] = branches
 | 
								if !fileOnly {
 | 
				
			||||||
			ctx.Data["RootRepoTags"] = tags
 | 
									branches, tags, err := getBranchesAndTagsForRepo(ctx.User, rootRepo)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										ctx.ServerError("GetBranchesForRepo", err)
 | 
				
			||||||
 | 
										return nil
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									ctx.Data["RootRepoBranches"] = branches
 | 
				
			||||||
 | 
									ctx.Data["RootRepoTags"] = tags
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -432,15 +439,18 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 | 
				
			|||||||
		ownForkRepo.ID != ci.HeadRepo.ID &&
 | 
							ownForkRepo.ID != ci.HeadRepo.ID &&
 | 
				
			||||||
		ownForkRepo.ID != baseRepo.ID &&
 | 
							ownForkRepo.ID != baseRepo.ID &&
 | 
				
			||||||
		(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) {
 | 
							(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) {
 | 
				
			||||||
		perm, branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo)
 | 
							canRead := ownForkRepo.CheckUnitUser(ctx.User, models.UnitTypeCode)
 | 
				
			||||||
		if err != nil {
 | 
							if canRead {
 | 
				
			||||||
			ctx.ServerError("GetBranchesForRepo", err)
 | 
					 | 
				
			||||||
			return nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if perm {
 | 
					 | 
				
			||||||
			ctx.Data["OwnForkRepo"] = ownForkRepo
 | 
								ctx.Data["OwnForkRepo"] = ownForkRepo
 | 
				
			||||||
			ctx.Data["OwnForkRepoBranches"] = branches
 | 
								if !fileOnly {
 | 
				
			||||||
			ctx.Data["OwnForkRepoTags"] = tags
 | 
									branches, tags, err := getBranchesAndTagsForRepo(ctx.User, ownForkRepo)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										ctx.ServerError("GetBranchesForRepo", err)
 | 
				
			||||||
 | 
										return nil
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									ctx.Data["OwnForkRepoBranches"] = branches
 | 
				
			||||||
 | 
									ctx.Data["OwnForkRepoTags"] = tags
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -492,7 +502,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 | 
				
			|||||||
		headBranchRef = git.TagPrefix + ci.HeadBranch
 | 
							headBranchRef = git.TagPrefix + ci.HeadBranch
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison)
 | 
						ci.CompareInfo, err = ci.HeadGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranchRef, headBranchRef, ci.DirectComparison, fileOnly)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.ServerError("GetCompareInfo", err)
 | 
							ctx.ServerError("GetCompareInfo", err)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
@@ -545,7 +555,7 @@ func PrepareCompareDiff(
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(ci.HeadGitRepo,
 | 
						diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(ci.HeadGitRepo,
 | 
				
			||||||
		beforeCommitID, headCommitID, setting.Git.MaxGitDiffLines,
 | 
							beforeCommitID, headCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines,
 | 
				
			||||||
		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, whitespaceBehavior, ci.DirectComparison)
 | 
							setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, whitespaceBehavior, ci.DirectComparison)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err)
 | 
							ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err)
 | 
				
			||||||
@@ -606,29 +616,22 @@ func PrepareCompareDiff(
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (bool, []string, []string, error) {
 | 
					func getBranchesAndTagsForRepo(user *models.User, repo *models.Repository) (branches, tags []string, err error) {
 | 
				
			||||||
	perm, err := models.GetUserRepoPermission(repo, user)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return false, nil, nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !perm.CanRead(models.UnitTypeCode) {
 | 
					 | 
				
			||||||
		return false, nil, nil, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	gitRepo, err := git.OpenRepository(repo.RepoPath())
 | 
						gitRepo, err := git.OpenRepository(repo.RepoPath())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return false, nil, nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer gitRepo.Close()
 | 
						defer gitRepo.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	branches, _, err := gitRepo.GetBranches(0, 0)
 | 
						branches, _, err = gitRepo.GetBranches(0, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return false, nil, nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tags, err := gitRepo.GetTags(0, 0)
 | 
						tags, err = gitRepo.GetTags(0, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return false, nil, nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return true, branches, tags, nil
 | 
						return branches, tags, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CompareDiff show different from one commit to another commit
 | 
					// CompareDiff show different from one commit to another commit
 | 
				
			||||||
@@ -665,6 +668,12 @@ func CompareDiff(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["Tags"] = baseTags
 | 
						ctx.Data["Tags"] = baseTags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fileOnly := ctx.FormBool("file-only")
 | 
				
			||||||
 | 
						if fileOnly {
 | 
				
			||||||
 | 
							ctx.HTML(http.StatusOK, tplDiffBox)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	headBranches, _, err := ci.HeadGitRepo.GetBranches(0, 0)
 | 
						headBranches, _, err := ci.HeadGitRepo.GetBranches(0, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.ServerError("GetBranches", err)
 | 
							ctx.ServerError("GetBranches", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -318,7 +318,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C
 | 
				
			|||||||
	ctx.Data["HasMerged"] = true
 | 
						ctx.Data["HasMerged"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(),
 | 
						compareInfo, err := ctx.Repo.GitRepo.GetCompareInfo(ctx.Repo.Repository.RepoPath(),
 | 
				
			||||||
		pull.MergeBase, pull.GetGitRefName(), true)
 | 
							pull.MergeBase, pull.GetGitRefName(), true, false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") {
 | 
							if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "unknown revision or path not in the working tree") {
 | 
				
			||||||
			ctx.Data["IsPullRequestBroken"] = true
 | 
								ctx.Data["IsPullRequestBroken"] = true
 | 
				
			||||||
@@ -401,7 +401,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
 | 
							compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
 | 
				
			||||||
			pull.MergeBase, pull.GetGitRefName(), true)
 | 
								pull.MergeBase, pull.GetGitRefName(), true, false)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			if strings.Contains(err.Error(), "fatal: Not a valid object name") {
 | 
								if strings.Contains(err.Error(), "fatal: Not a valid object name") {
 | 
				
			||||||
				ctx.Data["IsPullRequestBroken"] = true
 | 
									ctx.Data["IsPullRequestBroken"] = true
 | 
				
			||||||
@@ -517,7 +517,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
 | 
						compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
 | 
				
			||||||
		git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true)
 | 
							git.BranchPrefix+pull.BaseBranch, pull.GetGitRefName(), true, false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if strings.Contains(err.Error(), "fatal: Not a valid object name") {
 | 
							if strings.Contains(err.Error(), "fatal: Not a valid object name") {
 | 
				
			||||||
			ctx.Data["IsPullRequestBroken"] = true
 | 
								ctx.Data["IsPullRequestBroken"] = true
 | 
				
			||||||
@@ -633,7 +633,7 @@ func ViewPullFiles(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["AfterCommitID"] = endCommitID
 | 
						ctx.Data["AfterCommitID"] = endCommitID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(gitRepo,
 | 
						diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(gitRepo,
 | 
				
			||||||
		startCommitID, endCommitID, setting.Git.MaxGitDiffLines,
 | 
							startCommitID, endCommitID, ctx.FormString("skip-to"), setting.Git.MaxGitDiffLines,
 | 
				
			||||||
		setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles,
 | 
							setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles,
 | 
				
			||||||
		gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), false)
 | 
							gitdiff.GetWhitespaceFlag(ctx.Data["WhitespaceBehavior"].(string)), false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -653,6 +653,7 @@ func getCommitFileLineCount(commit *git.Commit, filePath string) int {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Diff represents a difference between two git trees.
 | 
					// Diff represents a difference between two git trees.
 | 
				
			||||||
type Diff struct {
 | 
					type Diff struct {
 | 
				
			||||||
 | 
						Start, End                             string
 | 
				
			||||||
	NumFiles, TotalAddition, TotalDeletion int
 | 
						NumFiles, TotalAddition, TotalDeletion int
 | 
				
			||||||
	Files                                  []*DiffFile
 | 
						Files                                  []*DiffFile
 | 
				
			||||||
	IsIncomplete                           bool
 | 
						IsIncomplete                           bool
 | 
				
			||||||
@@ -719,6 +720,9 @@ parsingLoop:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// TODO: Handle skipping first n files
 | 
							// TODO: Handle skipping first n files
 | 
				
			||||||
		if len(diff.Files) >= maxFiles {
 | 
							if len(diff.Files) >= maxFiles {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								lastFile := createDiffFile(diff, line)
 | 
				
			||||||
 | 
								diff.End = lastFile.Name
 | 
				
			||||||
			diff.IsIncomplete = true
 | 
								diff.IsIncomplete = true
 | 
				
			||||||
			_, err := io.Copy(io.Discard, reader)
 | 
								_, err := io.Copy(io.Discard, reader)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
@@ -1217,7 +1221,7 @@ func readFileName(rd *strings.Reader) (string, bool) {
 | 
				
			|||||||
// GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository.
 | 
					// GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository.
 | 
				
			||||||
// Passing the empty string as beforeCommitID returns a diff from the parent commit.
 | 
					// Passing the empty string as beforeCommitID returns a diff from the parent commit.
 | 
				
			||||||
// The whitespaceBehavior is either an empty string or a git flag
 | 
					// The whitespaceBehavior is either an empty string or a git flag
 | 
				
			||||||
func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
 | 
					func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, afterCommitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
 | 
				
			||||||
	repoPath := gitRepo.Path
 | 
						repoPath := gitRepo.Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	commit, err := gitRepo.GetCommit(afterCommitID)
 | 
						commit, err := gitRepo.GetCommit(afterCommitID)
 | 
				
			||||||
@@ -1228,31 +1232,42 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
 | 
				
			|||||||
	ctx, cancel := context.WithTimeout(git.DefaultContext, time.Duration(setting.Git.Timeout.Default)*time.Second)
 | 
						ctx, cancel := context.WithTimeout(git.DefaultContext, time.Duration(setting.Git.Timeout.Default)*time.Second)
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var cmd *exec.Cmd
 | 
						argsLength := 6
 | 
				
			||||||
 | 
						if len(whitespaceBehavior) > 0 {
 | 
				
			||||||
 | 
							argsLength++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(skipTo) > 0 {
 | 
				
			||||||
 | 
							argsLength++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						diffArgs := make([]string, 0, argsLength)
 | 
				
			||||||
	if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
 | 
						if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
 | 
				
			||||||
		diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"}
 | 
							diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M")
 | 
				
			||||||
		if len(whitespaceBehavior) != 0 {
 | 
							if len(whitespaceBehavior) != 0 {
 | 
				
			||||||
			diffArgs = append(diffArgs, whitespaceBehavior)
 | 
								diffArgs = append(diffArgs, whitespaceBehavior)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// append empty tree ref
 | 
							// append empty tree ref
 | 
				
			||||||
		diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904")
 | 
							diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904")
 | 
				
			||||||
		diffArgs = append(diffArgs, afterCommitID)
 | 
							diffArgs = append(diffArgs, afterCommitID)
 | 
				
			||||||
		cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		actualBeforeCommitID := beforeCommitID
 | 
							actualBeforeCommitID := beforeCommitID
 | 
				
			||||||
		if len(actualBeforeCommitID) == 0 {
 | 
							if len(actualBeforeCommitID) == 0 {
 | 
				
			||||||
			parentCommit, _ := commit.Parent(0)
 | 
								parentCommit, _ := commit.Parent(0)
 | 
				
			||||||
			actualBeforeCommitID = parentCommit.ID.String()
 | 
								actualBeforeCommitID = parentCommit.ID.String()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"}
 | 
							diffArgs = append(diffArgs, "diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M")
 | 
				
			||||||
		if len(whitespaceBehavior) != 0 {
 | 
							if len(whitespaceBehavior) != 0 {
 | 
				
			||||||
			diffArgs = append(diffArgs, whitespaceBehavior)
 | 
								diffArgs = append(diffArgs, whitespaceBehavior)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		diffArgs = append(diffArgs, actualBeforeCommitID)
 | 
							diffArgs = append(diffArgs, actualBeforeCommitID)
 | 
				
			||||||
		diffArgs = append(diffArgs, afterCommitID)
 | 
							diffArgs = append(diffArgs, afterCommitID)
 | 
				
			||||||
		cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
 | 
					 | 
				
			||||||
		beforeCommitID = actualBeforeCommitID
 | 
							beforeCommitID = actualBeforeCommitID
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if skipTo != "" {
 | 
				
			||||||
 | 
							diffArgs = append(diffArgs, "--skip-to="+skipTo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						cmd := exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd.Dir = repoPath
 | 
						cmd.Dir = repoPath
 | 
				
			||||||
	cmd.Stderr = os.Stderr
 | 
						cmd.Stderr = os.Stderr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1272,6 +1287,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("ParsePatch: %v", err)
 | 
							return nil, fmt.Errorf("ParsePatch: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						diff.Start = skipTo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var checker *git.CheckAttributeReader
 | 
						var checker *git.CheckAttributeReader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1299,7 +1315,7 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
 | 
				
			|||||||
				log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
 | 
									log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				go func() {
 | 
									go func() {
 | 
				
			||||||
					err = checker.Run()
 | 
										err := checker.Run()
 | 
				
			||||||
					if err != nil && err != ctx.Err() {
 | 
										if err != nil && err != ctx.Err() {
 | 
				
			||||||
						log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
 | 
											log.Error("Unable to open checker for %s. Error: %v", afterCommitID, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
@@ -1382,8 +1398,8 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID.
 | 
					// GetDiffCommitWithWhitespaceBehavior builds a Diff representing the given commitID.
 | 
				
			||||||
// The whitespaceBehavior is either an empty string or a git flag
 | 
					// The whitespaceBehavior is either an empty string or a git flag
 | 
				
			||||||
func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
 | 
					func GetDiffCommitWithWhitespaceBehavior(gitRepo *git.Repository, commitID, skipTo string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string, directComparison bool) (*Diff, error) {
 | 
				
			||||||
	return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison)
 | 
						return GetDiffRangeWithWhitespaceBehavior(gitRepo, "", commitID, skipTo, maxLines, maxLineCharacters, maxFiles, whitespaceBehavior, directComparison)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CommentAsDiff returns c.Patch as *Diff
 | 
					// CommentAsDiff returns c.Patch as *Diff
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -522,7 +522,7 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	defer gitRepo.Close()
 | 
						defer gitRepo.Close()
 | 
				
			||||||
	for _, behavior := range []string{"-w", "--ignore-space-at-eol", "-b", ""} {
 | 
						for _, behavior := range []string{"-w", "--ignore-space-at-eol", "-b", ""} {
 | 
				
			||||||
		diffs, err := GetDiffRangeWithWhitespaceBehavior(gitRepo, "559c156f8e0178b71cb44355428f24001b08fc68", "bd7063cc7c04689c4d082183d32a604ed27a24f9",
 | 
							diffs, err := GetDiffRangeWithWhitespaceBehavior(gitRepo, "559c156f8e0178b71cb44355428f24001b08fc68", "bd7063cc7c04689c4d082183d32a604ed27a24f9", "",
 | 
				
			||||||
			setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles, behavior, false)
 | 
								setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffFiles, behavior, false)
 | 
				
			||||||
		assert.NoError(t, err, fmt.Sprintf("Error when diff with %s", behavior))
 | 
							assert.NoError(t, err, fmt.Sprintf("Error when diff with %s", behavior))
 | 
				
			||||||
		for _, f := range diffs.Files {
 | 
							for _, f := range diffs.Files {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,7 +80,7 @@ func NewPullRequest(repo *models.Repository, pull *models.Issue, labelIDs []int6
 | 
				
			|||||||
	defer baseGitRepo.Close()
 | 
						defer baseGitRepo.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(),
 | 
						compareInfo, err := baseGitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(),
 | 
				
			||||||
		git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), true)
 | 
							git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName(), true, false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,105 +42,115 @@
 | 
				
			|||||||
					<a class="file mono" href="#diff-{{.Index}}">{{.Name}}</a>
 | 
										<a class="file mono" href="#diff-{{.Index}}">{{.Name}}</a>
 | 
				
			||||||
				</li>
 | 
									</li>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
 | 
								{{if .Diff.IsIncomplete}}
 | 
				
			||||||
 | 
									<li id="diff-too-many-files-stats" class="pt-2">
 | 
				
			||||||
 | 
										<span class="file df ac sb">{{$.i18n.Tr "repo.diff.too_many_files"}}
 | 
				
			||||||
 | 
											<a class="ui basic tiny button" id="diff-show-more-files-stats" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{.i18n.Tr "repo.diff.show_more"}}</a>
 | 
				
			||||||
 | 
										</span>
 | 
				
			||||||
 | 
									</li>
 | 
				
			||||||
 | 
								{{end}}
 | 
				
			||||||
		</ol>
 | 
							</ol>
 | 
				
			||||||
		{{range $i, $file := .Diff.Files}}
 | 
							<div id="diff-file-boxes">
 | 
				
			||||||
			{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}}
 | 
								{{range $i, $file := .Diff.Files}}
 | 
				
			||||||
			{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}}
 | 
									{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}}
 | 
				
			||||||
			{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}}
 | 
									{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}}
 | 
				
			||||||
			{{$isCsv := (call $.IsCsvFile $file)}}
 | 
									{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}}
 | 
				
			||||||
			{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}}
 | 
									{{$isCsv := (call $.IsCsvFile $file)}}
 | 
				
			||||||
			<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{.Index}}" {{if $file.IsGenerated}}data-folded="true"{{end}}>
 | 
									{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}}
 | 
				
			||||||
				<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb">
 | 
									<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{.Index}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if $file.IsGenerated}}data-folded="true"{{end}}>
 | 
				
			||||||
					<div class="fold-file df ac">
 | 
										<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb">
 | 
				
			||||||
						<a role="button" class="chevron muted mr-2">
 | 
											<div class="fold-file df ac">
 | 
				
			||||||
 | 
												<a role="button" class="fold-file muted mr-2">
 | 
				
			||||||
 | 
													{{if $file.IsGenerated}}
 | 
				
			||||||
 | 
														{{svg "octicon-chevron-right" 18}}
 | 
				
			||||||
 | 
													{{else}}
 | 
				
			||||||
 | 
														{{svg "octicon-chevron-down" 18}}
 | 
				
			||||||
 | 
													{{end}}
 | 
				
			||||||
 | 
												</a>
 | 
				
			||||||
 | 
												<div class="bold df ac">
 | 
				
			||||||
 | 
													{{if $file.IsBin}}
 | 
				
			||||||
 | 
														<span class="ml-1 mr-3">
 | 
				
			||||||
 | 
															{{$.i18n.Tr "repo.diff.bin"}}
 | 
				
			||||||
 | 
														</span>
 | 
				
			||||||
 | 
													{{else}}
 | 
				
			||||||
 | 
														{{template "repo/diff/stats" dict "file" . "root" $}}
 | 
				
			||||||
 | 
													{{end}}
 | 
				
			||||||
 | 
												</div>
 | 
				
			||||||
 | 
												<span class="file mono">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}{{if .IsLFSFile}} ({{$.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
 | 
				
			||||||
							{{if $file.IsGenerated}}
 | 
												{{if $file.IsGenerated}}
 | 
				
			||||||
								{{svg "octicon-chevron-right" 18}}
 | 
													<span class="ui label ml-3">{{$.i18n.Tr "repo.diff.generated"}}</span>
 | 
				
			||||||
							{{else}}
 | 
					 | 
				
			||||||
								{{svg "octicon-chevron-down" 18}}
 | 
					 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</a>
 | 
												{{if $file.IsVendored}}
 | 
				
			||||||
						<div class="bold df ac">
 | 
													<span class="ui label ml-3">{{$.i18n.Tr "repo.diff.vendored"}}</span>
 | 
				
			||||||
							{{if $file.IsBin}}
 | 
					 | 
				
			||||||
								<span class="ml-1 mr-3">
 | 
					 | 
				
			||||||
									{{$.i18n.Tr "repo.diff.bin"}}
 | 
					 | 
				
			||||||
								</span>
 | 
					 | 
				
			||||||
							{{else}}
 | 
					 | 
				
			||||||
								{{template "repo/diff/stats" dict "file" . "root" $}}
 | 
					 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
						<span class="file mono">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}{{if .IsLFSFile}} ({{$.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
 | 
											<div class="diff-file-header-actions df ac">
 | 
				
			||||||
						{{if $file.IsGenerated}}
 | 
												{{if $showFileViewToggle}}
 | 
				
			||||||
							<span class="ui label ml-3">{{$.i18n.Tr "repo.diff.generated"}}</span>
 | 
													<div class="ui compact icon buttons">
 | 
				
			||||||
						{{end}}
 | 
														<span class="ui tiny basic button poping up file-view-toggle" data-toggle-selector="#diff-source-{{$i}}" data-content="{{$.i18n.Tr "repo.file_view_source"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-code"}}</span>
 | 
				
			||||||
						{{if $file.IsVendored}}
 | 
														<span class="ui tiny basic button poping up file-view-toggle active" data-toggle-selector="#diff-rendered-{{$i}}" data-content="{{$.i18n.Tr "repo.file_view_rendered"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-file"}}</span>
 | 
				
			||||||
							<span class="ui label ml-3">{{$.i18n.Tr "repo.diff.vendored"}}</span>
 | 
													</div>
 | 
				
			||||||
						{{end}}
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
					<div class="diff-file-header-actions df ac">
 | 
					 | 
				
			||||||
						{{if $showFileViewToggle}}
 | 
					 | 
				
			||||||
							<div class="ui compact icon buttons">
 | 
					 | 
				
			||||||
								<span class="ui tiny basic button poping up file-view-toggle" data-toggle-selector="#diff-source-{{$i}}" data-content="{{$.i18n.Tr "repo.file_view_source"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-code"}}</span>
 | 
					 | 
				
			||||||
								<span class="ui tiny basic button poping up file-view-toggle active" data-toggle-selector="#diff-rendered-{{$i}}" data-content="{{$.i18n.Tr "repo.file_view_rendered"}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-file"}}</span>
 | 
					 | 
				
			||||||
							</div>
 | 
					 | 
				
			||||||
						{{end}}
 | 
					 | 
				
			||||||
						{{if $file.IsProtected}}
 | 
					 | 
				
			||||||
							<span class="ui basic label">{{$.i18n.Tr "repo.diff.protected"}}</span>
 | 
					 | 
				
			||||||
						{{end}}
 | 
					 | 
				
			||||||
						{{if and (not $file.IsSubmodule) (not $.PageIsWiki)}}
 | 
					 | 
				
			||||||
							{{if $file.IsDeleted}}
 | 
					 | 
				
			||||||
								<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
 | 
					 | 
				
			||||||
							{{else}}
 | 
					 | 
				
			||||||
								<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
 | 
					 | 
				
			||||||
							{{end}}
 | 
												{{end}}
 | 
				
			||||||
						{{end}}
 | 
												{{if $file.IsProtected}}
 | 
				
			||||||
					</div>
 | 
													<span class="ui basic label">{{$.i18n.Tr "repo.diff.protected"}}</span>
 | 
				
			||||||
				</h4>
 | 
												{{end}}
 | 
				
			||||||
				<div class="diff-file-body ui attached unstackable table segment">
 | 
												{{if and (not $file.IsSubmodule) (not $.PageIsWiki)}}
 | 
				
			||||||
					<div id="diff-source-{{$i}}" class="file-body file-code code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}">
 | 
													{{if $file.IsDeleted}}
 | 
				
			||||||
						{{if or $file.IsIncomplete $file.IsBin}}
 | 
														<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.BeforeSourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
 | 
				
			||||||
							<div class="diff-file-body binary" style="padding: 5px 10px;">
 | 
													{{else}}
 | 
				
			||||||
								{{if $file.IsIncomplete}}
 | 
														<a class="ui basic tiny button" rel="nofollow" href="{{EscapePound $.SourcePath}}/{{EscapePound .Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
 | 
				
			||||||
									{{if $file.IsIncompleteLineTooLong}}
 | 
													{{end}}
 | 
				
			||||||
										{{$.i18n.Tr "repo.diff.file_suppressed_line_too_long"}}
 | 
												{{end}}
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
										</h4>
 | 
				
			||||||
 | 
										<div class="diff-file-body ui attached unstackable table segment">
 | 
				
			||||||
 | 
											<div id="diff-source-{{$i}}" class="file-body file-code code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}">
 | 
				
			||||||
 | 
												{{if or $file.IsIncomplete $file.IsBin}}
 | 
				
			||||||
 | 
													<div class="diff-file-body binary" style="padding: 5px 10px;">
 | 
				
			||||||
 | 
														{{if $file.IsIncomplete}}
 | 
				
			||||||
 | 
															{{if $file.IsIncompleteLineTooLong}}
 | 
				
			||||||
 | 
																{{$.i18n.Tr "repo.diff.file_suppressed_line_too_long"}}
 | 
				
			||||||
 | 
															{{else}}
 | 
				
			||||||
 | 
																{{$.i18n.Tr "repo.diff.file_suppressed"}}
 | 
				
			||||||
 | 
															{{end}}
 | 
				
			||||||
									{{else}}
 | 
														{{else}}
 | 
				
			||||||
										{{$.i18n.Tr "repo.diff.file_suppressed"}}
 | 
															{{$.i18n.Tr "repo.diff.bin_not_shown"}}
 | 
				
			||||||
									{{end}}
 | 
														{{end}}
 | 
				
			||||||
								{{else}}
 | 
													</div>
 | 
				
			||||||
									{{$.i18n.Tr "repo.diff.bin_not_shown"}}
 | 
												{{else}}
 | 
				
			||||||
								{{end}}
 | 
													<table class="chroma">
 | 
				
			||||||
 | 
														{{if $.IsSplitStyle}}
 | 
				
			||||||
 | 
															{{template "repo/diff/section_split" dict "file" . "root" $}}
 | 
				
			||||||
 | 
														{{else}}
 | 
				
			||||||
 | 
															{{template "repo/diff/section_unified" dict "file" . "root" $}}
 | 
				
			||||||
 | 
														{{end}}
 | 
				
			||||||
 | 
													</table>
 | 
				
			||||||
 | 
												{{end}}
 | 
				
			||||||
 | 
											</div>
 | 
				
			||||||
 | 
											{{if $showFileViewToggle}}
 | 
				
			||||||
 | 
												<div id="diff-rendered-{{$i}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}">
 | 
				
			||||||
 | 
													<table class="chroma w-100">
 | 
				
			||||||
 | 
														{{if $isImage}}
 | 
				
			||||||
 | 
															{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
 | 
				
			||||||
 | 
														{{else}}
 | 
				
			||||||
 | 
															{{template "repo/diff/csv_diff" dict "file" . "root" $}}
 | 
				
			||||||
 | 
														{{end}}
 | 
				
			||||||
 | 
													</table>
 | 
				
			||||||
							</div>
 | 
												</div>
 | 
				
			||||||
						{{else}}
 | 
					 | 
				
			||||||
							<table class="chroma">
 | 
					 | 
				
			||||||
								{{if $.IsSplitStyle}}
 | 
					 | 
				
			||||||
									{{template "repo/diff/section_split" dict "file" . "root" $}}
 | 
					 | 
				
			||||||
								{{else}}
 | 
					 | 
				
			||||||
									{{template "repo/diff/section_unified" dict "file" . "root" $}}
 | 
					 | 
				
			||||||
								{{end}}
 | 
					 | 
				
			||||||
							</table>
 | 
					 | 
				
			||||||
						{{end}}
 | 
											{{end}}
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					{{if $showFileViewToggle}}
 | 
					 | 
				
			||||||
						<div id="diff-rendered-{{$i}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}">
 | 
					 | 
				
			||||||
							<table class="chroma w-100">
 | 
					 | 
				
			||||||
								{{if $isImage}}
 | 
					 | 
				
			||||||
									{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
 | 
					 | 
				
			||||||
								{{else}}
 | 
					 | 
				
			||||||
									{{template "repo/diff/csv_diff" dict "file" . "root" $}}
 | 
					 | 
				
			||||||
								{{end}}
 | 
					 | 
				
			||||||
							</table>
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
					{{end}}
 | 
					 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			</div>
 | 
								{{end}}
 | 
				
			||||||
		{{end}}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{{if .Diff.IsIncomplete}}
 | 
								{{if .Diff.IsIncomplete}}
 | 
				
			||||||
			<div class="diff-file-box diff-box file-content mt-3">
 | 
									<div class="diff-file-box diff-box file-content mt-3" id="diff-incomplete">
 | 
				
			||||||
				<h4 class="ui top attached normal header">
 | 
										<h4 class="ui top attached normal header df ac sb">
 | 
				
			||||||
					{{$.i18n.Tr "repo.diff.too_many_files"}}
 | 
											{{$.i18n.Tr "repo.diff.too_many_files"}}
 | 
				
			||||||
				</h4>
 | 
											<a class="ui basic tiny button" id="diff-show-more-files" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{.i18n.Tr "repo.diff.show_more"}}</a>
 | 
				
			||||||
			</div>
 | 
										</h4>
 | 
				
			||||||
		{{end}}
 | 
									</div>
 | 
				
			||||||
 | 
								{{end}}
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{{if not $.Repository.IsArchived}}
 | 
							{{if not $.Repository.IsArchived}}
 | 
				
			||||||
			<div class="hide" id="edit-content-form">
 | 
								<div class="hide" id="edit-content-form">
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								web_src/js/features/diff.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web_src/js/features/diff.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					export function initDiffShowMore() {
 | 
				
			||||||
 | 
					  $('#diff-files, #diff-file-boxes').on('click', '#diff-show-more-files, #diff-show-more-files-stats', (e) => {
 | 
				
			||||||
 | 
					    e.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ($(e.target).hasClass('disabled')) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    $('#diff-show-more-files, #diff-show-more-files-stats').addClass('disabled');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const url = $('#diff-show-more-files, #diff-show-more-files-stats').data('href');
 | 
				
			||||||
 | 
					    $.ajax({
 | 
				
			||||||
 | 
					      type: 'GET',
 | 
				
			||||||
 | 
					      url,
 | 
				
			||||||
 | 
					    }).done((resp) => {
 | 
				
			||||||
 | 
					      if (!resp || resp.html === '' || resp.empty) {
 | 
				
			||||||
 | 
					        $('#diff-show-more-files, #diff-show-more-files-stats').removeClass('disabled');
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      $('#diff-too-many-files-stats').remove();
 | 
				
			||||||
 | 
					      $('#diff-files').append($(resp).find('#diff-files li'));
 | 
				
			||||||
 | 
					      $('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children());
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -27,6 +27,7 @@ import {initNotificationsTable, initNotificationCount} from './features/notifica
 | 
				
			|||||||
import {initLastCommitLoader} from './features/lastcommitloader.js';
 | 
					import {initLastCommitLoader} from './features/lastcommitloader.js';
 | 
				
			||||||
import {initIssueContentHistory} from './features/issue-content-history.js';
 | 
					import {initIssueContentHistory} from './features/issue-content-history.js';
 | 
				
			||||||
import {initStopwatch} from './features/stopwatch.js';
 | 
					import {initStopwatch} from './features/stopwatch.js';
 | 
				
			||||||
 | 
					import {initDiffShowMore} from './features/diff.js';
 | 
				
			||||||
import {showLineButton} from './code/linebutton.js';
 | 
					import {showLineButton} from './code/linebutton.js';
 | 
				
			||||||
import {initMarkupContent, initCommentContent} from './markup/content.js';
 | 
					import {initMarkupContent, initCommentContent} from './markup/content.js';
 | 
				
			||||||
import {stripTags, mqBinarySearch} from './utils.js';
 | 
					import {stripTags, mqBinarySearch} from './utils.js';
 | 
				
			||||||
@@ -2881,6 +2882,7 @@ $(document).ready(async () => {
 | 
				
			|||||||
  initFileViewToggle();
 | 
					  initFileViewToggle();
 | 
				
			||||||
  initReleaseEditor();
 | 
					  initReleaseEditor();
 | 
				
			||||||
  initRelease();
 | 
					  initRelease();
 | 
				
			||||||
 | 
					  initDiffShowMore();
 | 
				
			||||||
  initIssueContentHistory();
 | 
					  initIssueContentHistory();
 | 
				
			||||||
  initAdminUserListSearchForm();
 | 
					  initAdminUserListSearchForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user