From 751997ad34fdd52b9f3956b14395560b059c9ac1 Mon Sep 17 00:00:00 2001
From: wxiaoguang <wxiaoguang@gmail.com>
Date: Mon, 1 Apr 2024 21:11:30 +0800
Subject: [PATCH] Refactor file view & render (#30227)

The old code is inconsistent and fragile, and the UI isn't right.
---
 routers/web/repo/blame.go             | 10 +++++++++-
 routers/web/repo/setting/lfs.go       | 17 ++++++++---------
 routers/web/repo/view.go              | 12 +++++++-----
 templates/repo/blame.tmpl             |  4 ++++
 templates/repo/settings/lfs_file.tmpl | 10 ++++------
 templates/repo/view_file.tmpl         | 16 ++++------------
 templates/shared/filetoolarge.tmpl    |  4 ++++
 7 files changed, 40 insertions(+), 33 deletions(-)
 create mode 100644 templates/shared/filetoolarge.tmpl

diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go
index 935e6d78fc..1887e4d95d 100644
--- a/routers/web/repo/blame.go
+++ b/routers/web/repo/blame.go
@@ -16,6 +16,7 @@ import (
 	"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/modules/templates"
 	"code.gitea.io/gitea/modules/timeutil"
 	"code.gitea.io/gitea/modules/util"
@@ -87,9 +88,16 @@ func RefBlame(ctx *context.Context) {
 
 	ctx.Data["IsBlame"] = true
 
-	ctx.Data["FileSize"] = blob.Size()
+	fileSize := blob.Size()
+	ctx.Data["FileSize"] = fileSize
 	ctx.Data["FileName"] = blob.Name()
 
+	if fileSize >= setting.UI.MaxDisplayFileSize {
+		ctx.Data["IsFileTooLarge"] = true
+		ctx.HTML(http.StatusOK, tplRepoHome)
+		return
+	}
+
 	ctx.Data["NumLines"], err = blob.GetBlobLineCount()
 	ctx.Data["NumLinesSet"] = true
 
diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go
index 32049cf0a4..6dddade066 100644
--- a/routers/web/repo/setting/lfs.go
+++ b/routers/web/repo/setting/lfs.go
@@ -287,22 +287,19 @@ func LFSFileGet(ctx *context.Context) {
 
 	st := typesniffer.DetectContentType(buf)
 	ctx.Data["IsTextFile"] = st.IsText()
-	isRepresentableAsText := st.IsRepresentableAsText()
-
-	fileSize := meta.Size
 	ctx.Data["FileSize"] = meta.Size
 	ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s/%s.git/info/lfs/objects/%s/%s", setting.AppURL, url.PathEscape(ctx.Repo.Repository.OwnerName), url.PathEscape(ctx.Repo.Repository.Name), url.PathEscape(meta.Oid), "direct")
 	switch {
-	case isRepresentableAsText:
-		if st.IsSvgImage() {
-			ctx.Data["IsImageFile"] = true
-		}
-
-		if fileSize >= setting.UI.MaxDisplayFileSize {
+	case st.IsRepresentableAsText():
+		if meta.Size >= setting.UI.MaxDisplayFileSize {
 			ctx.Data["IsFileTooLarge"] = true
 			break
 		}
 
+		if st.IsSvgImage() {
+			ctx.Data["IsImageFile"] = true
+		}
+
 		rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{})
 
 		// Building code view blocks with line number on server side.
@@ -338,6 +335,8 @@ func LFSFileGet(ctx *context.Context) {
 		ctx.Data["IsAudioFile"] = true
 	case st.IsImage() && (setting.UI.SVG.Enabled || !st.IsSvgImage()):
 		ctx.Data["IsImageFile"] = true
+	default:
+		// TODO: the logic is not the same as "renderFile" in "view.go"
 	}
 	ctx.HTML(http.StatusOK, tplSettingsLFSFile)
 }
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 93e0f5bcbd..8aa9dbb1be 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -482,17 +482,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
 
 	switch {
 	case isRepresentableAsText:
+		if fInfo.fileSize >= setting.UI.MaxDisplayFileSize {
+			ctx.Data["IsFileTooLarge"] = true
+			break
+		}
+
 		if fInfo.st.IsSvgImage() {
 			ctx.Data["IsImageFile"] = true
 			ctx.Data["CanCopyContent"] = true
 			ctx.Data["HasSourceRenderedToggle"] = true
 		}
 
-		if fInfo.fileSize >= setting.UI.MaxDisplayFileSize {
-			ctx.Data["IsFileTooLarge"] = true
-			break
-		}
-
 		rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{})
 
 		shouldRenderSource := ctx.FormString("display") == "source"
@@ -606,6 +606,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
 			break
 		}
 
+		// TODO: this logic seems strange, it duplicates with "isRepresentableAsText=true", it is not the same as "LFSFileGet" in "lfs.go"
+		// maybe for this case, the file is a binary file, and shouldn't be rendered?
 		if markupType := markup.Type(blob.Name()); markupType != "" {
 			rd := io.MultiReader(bytes.NewReader(buf), dataRc)
 			ctx.Data["IsMarkup"] = true
diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl
index 1a148a2d1c..30d1a3d78d 100644
--- a/templates/repo/blame.tmpl
+++ b/templates/repo/blame.tmpl
@@ -30,6 +30,9 @@
 	</h4>
 	<div class="ui attached table unstackable segment">
 		<div class="file-view code-view unicode-escaped">
+			{{if .IsFileTooLarge}}
+				{{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}}
+			{{else}}
 			<table>
 				<tbody>
 					{{range $row := .BlameRows}}
@@ -75,6 +78,7 @@
 					{{end}}
 				</tbody>
 			</table>
+			{{end}}{{/* end if .IsFileTooLarge */}}
 			<div class="code-line-menu tippy-target">
 				{{if $.Permission.CanRead $.UnitTypeIssues}}
 					<a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a>
diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl
index 43afba96c3..cb65236f23 100644
--- a/templates/repo/settings/lfs_file.tmpl
+++ b/templates/repo/settings/lfs_file.tmpl
@@ -14,7 +14,9 @@
 			<div class="ui attached table unstackable segment">
 				{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
 				<div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextFile}} code-view{{end}}">
-					{{if .IsMarkup}}
+					{{if .IsFileTooLarge}}
+						{{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}}
+					{{else if .IsMarkup}}
 						{{if .FileContent}}{{.FileContent | SafeHTML}}{{end}}
 					{{else if .IsPlainText}}
 						<pre>{{if .FileContent}}{{.FileContent | SafeHTML}}{{end}}</pre>
@@ -33,19 +35,15 @@
 							{{else if .IsPDFFile}}
 								<div class="pdf-content is-loading" data-src="{{$.RawFileLink}}" data-fallback-button-text="{{ctx.Locale.Tr "diff.view_file"}}"></div>
 							{{else}}
-								<a href="{{$.RawFileLink}}" rel="nofollow">{{ctx.Locale.Tr "repo.file_view_raw"}}</a>
+								<a href="{{$.RawFileLink}}" rel="nofollow" class="tw-p-4">{{ctx.Locale.Tr "repo.file_view_raw"}}</a>
 							{{end}}
 						</div>
 					{{else if .FileSize}}
 						<table>
 							<tbody>
 								<tr>
-								{{if .IsFileTooLarge}}
-									<td><strong>{{ctx.Locale.Tr "repo.file_too_large"}}</strong></td>
-								{{else}}
 									<td class="lines-num">{{.LineNums}}</td>
 									<td class="lines-code"><pre><code class="{{.HighlightClass}}"><ol>{{.FileContent}}</ol></code></pre></td>
-								{{end}}
 								</tr>
 							</tbody>
 						</table>
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl
index b7c1b9eeae..9c5bd9094d 100644
--- a/templates/repo/view_file.tmpl
+++ b/templates/repo/view_file.tmpl
@@ -89,7 +89,9 @@
 			{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
 		{{end}}
 		<div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextSource}} code-view{{end}}">
-			{{if .IsMarkup}}
+			{{if .IsFileTooLarge}}
+				{{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}}
+			{{else if .IsMarkup}}
 				{{if .FileContent}}{{.FileContent}}{{end}}
 			{{else if .IsPlainText}}
 				<pre>{{if .FileContent}}{{.FileContent}}{{end}}</pre>
@@ -108,19 +110,10 @@
 					{{else if .IsPDFFile}}
 						<div class="pdf-content is-loading" data-src="{{$.RawFileLink}}" data-fallback-button-text="{{ctx.Locale.Tr "repo.diff.view_file"}}"></div>
 					{{else}}
-						<a href="{{$.RawFileLink}}" rel="nofollow">{{ctx.Locale.Tr "repo.file_view_raw"}}</a>
+						<a href="{{$.RawFileLink}}" rel="nofollow" class="tw-p-4">{{ctx.Locale.Tr "repo.file_view_raw"}}</a>
 					{{end}}
 				</div>
 			{{else if .FileSize}}
-				{{if .IsFileTooLarge}}
-				<table>
-					<tbody>
-						<tr>
-							<td><strong>{{ctx.Locale.Tr "repo.file_too_large"}}</strong></td>
-						</tr>
-					</tbody>
-				</table>
-				{{else}}
 				<table>
 					<tbody>
 						{{range $idx, $code := .FileContent}}
@@ -142,7 +135,6 @@
 					<a class="item view_git_blame" role="menuitem" href="{{.Repository.Link}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{ctx.Locale.Tr "repo.view_git_blame"}}</a>
 					<a class="item copy-line-permalink" role="menuitem" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}">{{ctx.Locale.Tr "repo.file_copy_permalink"}}</a>
 				</div>
-				{{end}}
 			{{end}}
 		</div>
 	</div>
diff --git a/templates/shared/filetoolarge.tmpl b/templates/shared/filetoolarge.tmpl
new file mode 100644
index 0000000000..8842fb1b91
--- /dev/null
+++ b/templates/shared/filetoolarge.tmpl
@@ -0,0 +1,4 @@
+<div class="tw-p-4">
+	{{ctx.Locale.Tr "repo.file_too_large"}}
+	{{if .RawFileLink}}<a href="{{.RawFileLink}}" rel="nofollow">{{ctx.Locale.Tr "repo.file_view_raw"}}</a>{{end}}
+</div>