aboutsummaryrefslogtreecommitdiffstats
path: root/services/markup/renderhelper_codepreview.go
diff options
context:
space:
mode:
Diffstat (limited to 'services/markup/renderhelper_codepreview.go')
-rw-r--r--services/markup/renderhelper_codepreview.go119
1 files changed, 119 insertions, 0 deletions
diff --git a/services/markup/renderhelper_codepreview.go b/services/markup/renderhelper_codepreview.go
new file mode 100644
index 0000000000..170c70c409
--- /dev/null
+++ b/services/markup/renderhelper_codepreview.go
@@ -0,0 +1,119 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package markup
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "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/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"
+ "code.gitea.io/gitea/services/repository/files"
+)
+
+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, ok := ctx.Value(gitea_context.WebContextKey).(*gitea_context.Context)
+ if !ok {
+ return "", fmt.Errorf("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, _ := files.TryGetContentLanguage(gitRepo, opts.CommitID, opts.FilePath)
+ blob, err := commit.GetBlobByPath(opts.FilePath)
+ if err != nil {
+ return "", err
+ }
+
+ if blob.Size() > setting.UI.MaxDisplayFileSize {
+ return "", fmt.Errorf("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,
+ })
+}