mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	This PR moved git attributes related code to `modules/git/attribute` sub package and moved language stats related code to `modules/git/languagestats` sub package to make it easier to maintain. And it also introduced a performance improvement which use the `git check-attr --source` which can be run in a bare git repository so that we don't need to create a git index file. The new parameter need a git version >= 2.40 . If git version less than 2.40, it will fall back to previous implementation. --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: yp05327 <576951401@qq.com>
		
			
				
	
	
		
			120 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2024 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package markup
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"html/template"
 | |
| 	"strings"
 | |
| 
 | |
| 	"code.gitea.io/gitea/models/perm/access"
 | |
| 	"code.gitea.io/gitea/models/repo"
 | |
| 	"code.gitea.io/gitea/models/unit"
 | |
| 	"code.gitea.io/gitea/modules/charset"
 | |
| 	"code.gitea.io/gitea/modules/git/languagestats"
 | |
| 	"code.gitea.io/gitea/modules/gitrepo"
 | |
| 	"code.gitea.io/gitea/modules/indexer/code"
 | |
| 	"code.gitea.io/gitea/modules/markup"
 | |
| 	"code.gitea.io/gitea/modules/setting"
 | |
| 	"code.gitea.io/gitea/modules/util"
 | |
| 	gitea_context "code.gitea.io/gitea/services/context"
 | |
| )
 | |
| 
 | |
| func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePreviewOptions) (template.HTML, error) {
 | |
| 	opts.LineStop = max(opts.LineStop, opts.LineStart)
 | |
| 	lineCount := opts.LineStop - opts.LineStart + 1
 | |
| 	if lineCount <= 0 || lineCount > 140 /* GitHub at most show 140 lines */ {
 | |
| 		lineCount = 10
 | |
| 		opts.LineStop = opts.LineStart + lineCount
 | |
| 	}
 | |
| 
 | |
| 	dbRepo, err := repo.GetRepositoryByOwnerAndName(ctx, opts.OwnerName, opts.RepoName)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	webCtx := gitea_context.GetWebContext(ctx)
 | |
| 	if webCtx == nil {
 | |
| 		return "", errors.New("context is not a web context")
 | |
| 	}
 | |
| 	doer := webCtx.Doer
 | |
| 
 | |
| 	perms, err := access.GetUserRepoPermission(ctx, dbRepo, doer)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	if !perms.CanRead(unit.TypeCode) {
 | |
| 		return "", util.ErrPermissionDenied
 | |
| 	}
 | |
| 
 | |
| 	gitRepo, err := gitrepo.OpenRepository(ctx, dbRepo)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	defer gitRepo.Close()
 | |
| 
 | |
| 	commit, err := gitRepo.GetCommit(opts.CommitID)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	language, _ := languagestats.GetFileLanguage(ctx, gitRepo, opts.CommitID, opts.FilePath)
 | |
| 	blob, err := commit.GetBlobByPath(opts.FilePath)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 
 | |
| 	if blob.Size() > setting.UI.MaxDisplayFileSize {
 | |
| 		return "", errors.New("file is too large")
 | |
| 	}
 | |
| 
 | |
| 	dataRc, err := blob.DataAsync()
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	defer dataRc.Close()
 | |
| 
 | |
| 	reader := bufio.NewReader(dataRc)
 | |
| 	for i := 1; i < opts.LineStart; i++ {
 | |
| 		if _, err = reader.ReadBytes('\n'); err != nil {
 | |
| 			return "", err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	lineNums := make([]int, 0, lineCount)
 | |
| 	lineCodes := make([]string, 0, lineCount)
 | |
| 	for i := opts.LineStart; i <= opts.LineStop; i++ {
 | |
| 		line, err := reader.ReadString('\n')
 | |
| 		if err != nil && line == "" {
 | |
| 			break
 | |
| 		}
 | |
| 
 | |
| 		lineNums = append(lineNums, i)
 | |
| 		lineCodes = append(lineCodes, line)
 | |
| 	}
 | |
| 	realLineStop := max(opts.LineStart, opts.LineStart+len(lineNums)-1)
 | |
| 	highlightLines := code.HighlightSearchResultCode(opts.FilePath, language, lineNums, strings.Join(lineCodes, ""))
 | |
| 
 | |
| 	escapeStatus := &charset.EscapeStatus{}
 | |
| 	lineEscapeStatus := make([]*charset.EscapeStatus, len(highlightLines))
 | |
| 	for i, hl := range highlightLines {
 | |
| 		lineEscapeStatus[i], hl.FormattedContent = charset.EscapeControlHTML(hl.FormattedContent, webCtx.Base.Locale, charset.RuneNBSP)
 | |
| 		escapeStatus = escapeStatus.Or(lineEscapeStatus[i])
 | |
| 	}
 | |
| 
 | |
| 	return webCtx.RenderToHTML("base/markup_codepreview", map[string]any{
 | |
| 		"FullURL":          opts.FullURL,
 | |
| 		"FilePath":         opts.FilePath,
 | |
| 		"LineStart":        opts.LineStart,
 | |
| 		"LineStop":         realLineStop,
 | |
| 		"RepoLink":         dbRepo.Link(),
 | |
| 		"CommitID":         opts.CommitID,
 | |
| 		"HighlightLines":   highlightLines,
 | |
| 		"EscapeStatus":     escapeStatus,
 | |
| 		"LineEscapeStatus": lineEscapeStatus,
 | |
| 	})
 | |
| }
 |