diff --git a/modules/context/context.go b/modules/context/context.go
index 5876e23cc4..1eff1459a1 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -628,7 +628,9 @@ func (ctx *Context) Value(key interface{}) interface{} {
 	if key == git.RepositoryContextKey && ctx.Repo != nil {
 		return ctx.Repo.GitRepo
 	}
-
+	if key == translation.ContextKey && ctx.Locale != nil {
+		return ctx.Locale
+	}
 	return ctx.Req.Context().Value(key)
 }
 
diff --git a/modules/markup/html.go b/modules/markup/html.go
index 76fc54cf46..11888b8536 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -22,6 +22,7 @@ import (
 	"code.gitea.io/gitea/modules/regexplru"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/templates/vars"
+	"code.gitea.io/gitea/modules/translation"
 	"code.gitea.io/gitea/modules/util"
 
 	"golang.org/x/net/html"
@@ -97,14 +98,30 @@ var issueFullPattern *regexp.Regexp
 // Once for to prevent races
 var issueFullPatternOnce sync.Once
 
+// regexp for full links to hash comment in pull request files changed tab
+var filesChangedFullPattern *regexp.Regexp
+
+// Once for to prevent races
+var filesChangedFullPatternOnce sync.Once
+
 func getIssueFullPattern() *regexp.Regexp {
 	issueFullPatternOnce.Do(func() {
+		// example: https://domain/org/repo/pulls/27#hash
 		issueFullPattern = regexp.MustCompile(regexp.QuoteMeta(setting.AppURL) +
 			`[\w_.-]+/[\w_.-]+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#](\S+)?)?\b`)
 	})
 	return issueFullPattern
 }
 
+func getFilesChangedFullPattern() *regexp.Regexp {
+	filesChangedFullPatternOnce.Do(func() {
+		// example: https://domain/org/repo/pulls/27/files#hash
+		filesChangedFullPattern = regexp.MustCompile(regexp.QuoteMeta(setting.AppURL) +
+			`[\w_.-]+/[\w_.-]+/pulls/((?:\w{1,10}-)?[1-9][0-9]*)/files([\?|#](\S+)?)?\b`)
+	})
+	return filesChangedFullPattern
+}
+
 // CustomLinkURLSchemes allows for additional schemes to be detected when parsing links within text
 func CustomLinkURLSchemes(schemes []string) {
 	schemes = append(schemes, "http", "https")
@@ -793,15 +810,30 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
 	if ctx.Metas == nil {
 		return
 	}
-
 	next := node.NextSibling
 	for node != nil && node != next {
 		m := getIssueFullPattern().FindStringSubmatchIndex(node.Data)
 		if m == nil {
 			return
 		}
+
+		mDiffView := getFilesChangedFullPattern().FindStringSubmatchIndex(node.Data)
+		// leave it as it is if the link is from "Files Changed" tab in PR Diff View https://domain/org/repo/pulls/27/files
+		if mDiffView != nil {
+			return
+		}
+
 		link := node.Data[m[0]:m[1]]
-		id := "#" + node.Data[m[2]:m[3]]
+		text := "#" + node.Data[m[2]:m[3]]
+		// if m[4] and m[5] is not -1, then link is to a comment
+		// indicate that in the text by appending (comment)
+		if m[4] != -1 && m[5] != -1 {
+			if locale, ok := ctx.Ctx.Value(translation.ContextKey).(translation.Locale); ok {
+				text += " " + locale.Tr("repo.from_comment")
+			} else {
+				text += " (comment)"
+			}
+		}
 
 		// extract repo and org name from matched link like
 		// http://localhost:3000/gituser/myrepo/issues/1
@@ -810,12 +842,10 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
 		matchRepo := linkParts[len(linkParts)-3]
 
 		if matchOrg == ctx.Metas["user"] && matchRepo == ctx.Metas["repo"] {
-			// TODO if m[4]:m[5] is not nil, then link is to a comment,
-			// and we should indicate that in the text somehow
-			replaceContent(node, m[0], m[1], createLink(link, id, "ref-issue"))
+			replaceContent(node, m[0], m[1], createLink(link, text, "ref-issue"))
 		} else {
-			orgRepoID := matchOrg + "/" + matchRepo + id
-			replaceContent(node, m[0], m[1], createLink(link, orgRepoID, "ref-issue"))
+			text = matchOrg + "/" + matchRepo + text
+			replaceContent(node, m[0], m[1], createLink(link, text, "ref-issue"))
 		}
 		node = node.NextSibling.NextSibling
 	}
diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go
index a048f1f527..7e04b03531 100644
--- a/modules/markup/html_internal_test.go
+++ b/modules/markup/html_internal_test.go
@@ -330,13 +330,17 @@ func TestRender_FullIssueURLs(t *testing.T) {
 	test("Look here http://localhost:3000/person/repo/issues/4",
 		`Look here <a href="http://localhost:3000/person/repo/issues/4" class="ref-issue">person/repo#4</a>`)
 	test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
-		`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4</a>`)
+		`<a href="http://localhost:3000/person/repo/issues/4#issuecomment-1234" class="ref-issue">person/repo#4 (comment)</a>`)
 	test("http://localhost:3000/gogits/gogs/issues/4",
 		`<a href="http://localhost:3000/gogits/gogs/issues/4" class="ref-issue">#4</a>`)
 	test("http://localhost:3000/gogits/gogs/issues/4 test",
 		`<a href="http://localhost:3000/gogits/gogs/issues/4" class="ref-issue">#4</a> test`)
 	test("http://localhost:3000/gogits/gogs/issues/4?a=1&b=2#comment-123 test",
-		`<a href="http://localhost:3000/gogits/gogs/issues/4?a=1&amp;b=2#comment-123" class="ref-issue">#4</a> test`)
+		`<a href="http://localhost:3000/gogits/gogs/issues/4?a=1&amp;b=2#comment-123" class="ref-issue">#4 (comment)</a> test`)
+	test("http://localhost:3000/testOrg/testOrgRepo/pulls/2/files#issuecomment-24",
+		"http://localhost:3000/testOrg/testOrgRepo/pulls/2/files#issuecomment-24")
+	test("http://localhost:3000/testOrg/testOrgRepo/pulls/2/files",
+		"http://localhost:3000/testOrg/testOrgRepo/pulls/2/files")
 }
 
 func TestRegExp_sha1CurrentPattern(t *testing.T) {
diff --git a/modules/translation/translation.go b/modules/translation/translation.go
index 5a1009bfa3..3165390c32 100644
--- a/modules/translation/translation.go
+++ b/modules/translation/translation.go
@@ -18,6 +18,10 @@ import (
 	"golang.org/x/text/language"
 )
 
+type contextKey struct{}
+
+var ContextKey interface{} = &contextKey{}
+
 // Locale represents an interface to translation
 type Locale interface {
 	Language() string
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index b7180d7967..5834703556 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1104,6 +1104,7 @@ download_file = Download file
 normal_view = Normal View
 line = line
 lines = lines
+from_comment = (comment)
 
 editor.add_file = Add File
 editor.new_file = New File
diff --git a/web_src/js/features/comp/MarkupContentPreview.js b/web_src/js/features/comp/MarkupContentPreview.js
index 61fd699b29..a32bf30184 100644
--- a/web_src/js/features/comp/MarkupContentPreview.js
+++ b/web_src/js/features/comp/MarkupContentPreview.js
@@ -1,5 +1,6 @@
 import $ from 'jquery';
 import {initMarkupContent} from '../../markup/content.js';
+import {attachRefIssueContextPopup} from '../contextpopup.js';
 
 const {csrfToken} = window.config;
 
@@ -16,6 +17,8 @@ export function initCompMarkupContentPreviewTab($form) {
     }, (data) => {
       const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`);
       $previewPanel.html(data);
+      const refIssues = $previewPanel.find('p .ref-issue');
+      attachRefIssueContextPopup(refIssues);
       initMarkupContent();
     });
   });
diff --git a/web_src/js/features/contextpopup.js b/web_src/js/features/contextpopup.js
index c685d93db0..7b37035547 100644
--- a/web_src/js/features/contextpopup.js
+++ b/web_src/js/features/contextpopup.js
@@ -6,8 +6,11 @@ import {createTippy} from '../modules/tippy.js';
 
 export function initContextPopups() {
   const refIssues = $('.ref-issue');
-  if (!refIssues.length) return;
+  attachRefIssueContextPopup(refIssues);
+}
 
+export function attachRefIssueContextPopup(refIssues) {
+  if (!refIssues.length) return;
   refIssues.each(function () {
     if ($(this).hasClass('ref-external-issue')) {
       return;
diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js
index f7fc1aa4eb..3689c34272 100644
--- a/web_src/js/features/repo-legacy.js
+++ b/web_src/js/features/repo-legacy.js
@@ -26,6 +26,7 @@ import {initCompReactionSelector} from './comp/ReactionSelector.js';
 import {initRepoSettingBranches} from './repo-settings.js';
 import {initRepoPullRequestMergeForm} from './repo-issue-pr-form.js';
 import {hideElem, showElem} from '../utils/dom.js';
+import {attachRefIssueContextPopup} from './contextpopup.js';
 
 const {csrfToken} = window.config;
 
@@ -439,6 +440,8 @@ async function onEditContent(event) {
         } else {
           $renderContent.html(data.content);
           $rawContent.text($textarea.val());
+          const refIssues = $renderContent.find('p .ref-issue');
+          attachRefIssueContextPopup(refIssues);
         }
         const $content = $segment;
         if (!$content.find('.dropzone-attachments').length) {