Skip to content

Fix Mermaid code blocks broken on dashboard feed (#36582)#36604

Closed
silverwind wants to merge 4 commits intogo-gitea:mainfrom
silverwind:feedcut
Closed

Fix Mermaid code blocks broken on dashboard feed (#36582)#36604
silverwind wants to merge 4 commits intogo-gitea:mainfrom
silverwind:feedcut

Conversation

@silverwind
Copy link
Copy Markdown
Member

@silverwind silverwind commented Feb 12, 2026

Fixes: #36582

Fixes two bugs causing broken rendering of fenced code blocks in dashboard feed comments:

  1. Truncation at 200 chars could cut mid-code-block, leaving an unclosed fence that produces a parse error.

  2. The action content format index|body was parsed with SplitN(..., 3), but mermaid source can contain |, workaround by splitting only on the first |.

Before:

Screenshot 2026-02-12 at 20 41 13 Screenshot 2026-02-12 at 20 41 37

After:

Screenshot 2026-02-12 at 20 41 22 Screenshot 2026-02-12 at 20 41 44

Fix two bugs causing broken rendering of fenced code blocks (e.g. Mermaid
diagrams) in dashboard feed comments:

1. Truncation at 200 chars could cut mid-code-block, leaving an unclosed
   fence that produces a parse error. Add trimUnclosedCodeBlock() to strip
   the partial block after truncation.

2. The action content format "index|body" was parsed with SplitN(..., 3),
   splitting the comment body at its first "|" character. Mermaid syntax
   commonly uses "|" (e.g. "A -->|text| B"). Add GetIssueContentBody()
   which splits only on the first "|" and use it in the feed template.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 12, 2026
@github-actions github-actions bot added modifies/go Pull requests that update Go code modifies/templates This PR modifies the template files labels Feb 12, 2026
@silverwind silverwind requested a review from Copilot February 12, 2026 20:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes broken Mermaid/Markdown rendering in the signed-in user dashboard activity feed by ensuring truncated comment previews don’t leave invalid/unclosed fenced blocks, and by correctly extracting comment bodies from Action.Content even when the body contains | (e.g. Mermaid edge labels).

Changes:

  • Update dashboard feed template to use a new Action.GetIssueContentBody() accessor instead of GetIssueInfos()[1] so | inside comment bodies is preserved.
  • Add trimUnclosedCodeBlock to strip trailing unclosed fenced code blocks from truncated comment previews before rendering.
  • Add unit tests for trimUnclosedCodeBlock.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
templates/user/dashboard/feeds.tmpl Switches dashboard feed comment rendering to a body accessor that doesn’t break on `
services/feed/notifier.go Trims truncated comment previews to avoid unclosed fenced code blocks breaking Markdown/Mermaid rendering.
services/feed/notifier_test.go Adds unit tests covering unclosed/closed fenced code block trimming behavior.
models/activities/action.go Adds GetIssueContentBody() to split action content on the first `

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…dy test

Only call trimUnclosedCodeBlock when truncation actually occurred, and
add unit tests for GetIssueContentBody covering pipe-delimited content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@wxiaoguang wxiaoguang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is right.

I think mermaid shouldn't be rendered in the timeline event. In my mind, timeline is only used for showing the summary of the changed contents, but not a full diagram.

Actually the problem is also same to:

  • truncated math blocks (inline) ` `
  • truncated attachments
  • truncated HTML tags and links

And more. The timeline shouldn't render these uncontrollable code blocks

Instead of silently removing the content, a placeholder should be there, otherwise it would read very strange to end users.

Maybe either:

  1. Don't render the content as markdown, only show the raw content as-is (strip HTML tags)
  2. Only do simple rendering based on 1 (just like commit messages, only simple back-quotes and links)
  3. Still render the content as markdown, and do more processing for the rendered content, replace uncontrollable blocks with placeholders

@GiteaBot GiteaBot added lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Feb 13, 2026
@silverwind
Copy link
Copy Markdown
Member Author

silverwind commented Feb 13, 2026

I think mermaid shouldn't be rendered in the timeline event. In my mind, timeline is only used for showing the summary of the changed contents, but not a full diagram.

I guess it makes sense, but we currently also currently render images in the timeline which can expand to huge rendered blocks. If we omit mermaid, we ought to emit any other non-text content as well and only render text. I think that makes sense and should be easier to implement too.

@tyroneyeh
Copy link
Copy Markdown
Contributor

tyroneyeh commented Feb 13, 2026

Hi @silverwind

I'd like to improve the trimUnclosedCodeBlock functionality as follows. Can I push this directly to your branch?

Thanks,

Details
diff --git a/services/feed/notifier.go b/services/feed/notifier.go
index 0acc0c59e1..3ac2587af6 100644
--- a/services/feed/notifier.go
+++ b/services/feed/notifier.go
@@ -31,31 +31,41 @@ type actionNotifier struct {
 // the renderer tries (and fails) to process. This function detects the
 // situation and strips the partial block.
 func trimUnclosedCodeBlock(s string) string {
+       lines := strings.Split(s, "\n")
        inBlock := false
-       lastOpenIdx := -1
-       i := 0
-       for i < len(s) {
-               lineStart := i
-               lineEnd := strings.Index(s[i:], "\n")
-               var line string
-               if lineEnd == -1 {
-                       line = s[i:]
-                       i = len(s)
-               } else {
-                       line = s[i : i+lineEnd]
-                       i = i + lineEnd + 1
+       fenceChar := byte(0)
+       fenceLen := 0
+
+       for _, line := range lines {
+               trimmed := strings.TrimLeft(line, " ")
+               if len(trimmed) < 3 {
+                       continue
                }
-               if strings.HasPrefix(strings.TrimLeft(line, " "), "```") {
+
+               if strings.HasPrefix(trimmed, "```") || strings.HasPrefix(trimmed, "~~~") {
+                       char := trimmed[0]
+                       count := 1
+                       for count < len(trimmed) && trimmed[count] == char {
+                               count++
+                       }
+
                        if !inBlock {
-                               lastOpenIdx = lineStart
                                inBlock = true
-                       } else {
+                               fenceChar = char
+                               fenceLen = count
+                       } else if char == fenceChar && count >= fenceLen {
                                inBlock = false
                        }
                }
        }
-       if inBlock && lastOpenIdx >= 0 {
-               return strings.TrimRight(s[:lastOpenIdx], " \t\n")
+
+       if inBlock && fenceLen > 0 {
+               s = strings.TrimRight(s, " \t\n")
+               if strings.HasSuffix(s, "…") {
+                       s = strings.TrimRight(s, "…") + "\n" + strings.Repeat(string(fenceChar), fenceLen) + "\n…"
+               } else {
+                       s += "\n" + strings.Repeat(string(fenceChar), fenceLen) + "\n"
+               }
        }
        return s
 }

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Feb 13, 2026

I'd like to improve the trimUnclosedCodeBlock functionality as follows. Can I push this directly to your branch?

I think you should read and understand this first. #36604 (review)

By the way, your "trim" is not right. You are just trying to write a new incorrect parser&render.

Sample:

Details
```
```
````
```
```
````
image

@tyroneyeh
Copy link
Copy Markdown
Contributor

tyroneyeh commented Feb 13, 2026

I updated the patch, is that okay?

Details image image

@silverwind
Copy link
Copy Markdown
Member Author

silverwind commented Feb 13, 2026

My current plan is eliminate code blocks if their line count exceeds like 5-10 lines or if the total character count is above 200 and it would cut off the block. Mermaid blocks will always be eliminated, Math blocks likely also. Images as well. Goal is to keep the frontpage feed compact.

@tyroneyeh I think it's better that you not try. I will exercise Claude on it which should produce something useable given these clear success criteria.

@wxiaoguang
Copy link
Copy Markdown
Contributor

wxiaoguang commented Feb 13, 2026

I updated the patch, is that okay?

Certainly you haven't read or understood #36604 (review)

Why such a large diagram in timeline makes sense?

"You are just trying to write a new incorrect parser&render."

What if the truncation occurs in the diagram syntax?

@tyroneyeh
Copy link
Copy Markdown
Contributor

The timeline is mainly intended to show a summary of changes, not the full content.
If truncation occurs within code blocks or Mermaid diagrams, rendering them fully may fail.
Therefore, my approach is to replace truncated code or Mermaid blocks with placeholders (e.g., [code omitted], [Mermaid diagram omitted]), while preserving the trailing ….
This way, users know that content has been truncated, timeline rendering remains safe, and the interface stays clean.

@silverwind
Copy link
Copy Markdown
Member Author

silverwind commented Feb 13, 2026

Hmm @wxiaoguang had suggested placeholders as well, but I'm not sold on the idea. The whole point of the feed is to give a very concise preview, I see no point in littering the feed with placeholders.

@wxiaoguang
Copy link
Copy Markdown
Contributor

I mean "either" with these suggestions. Placeholders can be used for some special cases for example a <video> tag is not suitable to be rendered directly, just in case, just an idea.

@wxiaoguang wxiaoguang mentioned this pull request Apr 2, 2026
@silverwind
Copy link
Copy Markdown
Member Author

silverwind commented Apr 2, 2026

I think the current approach here of "don't cut off code blocks in the middle" may be good enough. It's better than not rendering markup at all. Placeholders are not the right approach imho, placeholders are ugly.

@wxiaoguang could you accept the current approach?

@wxiaoguang
Copy link
Copy Markdown
Contributor

I think the current approach here of "don't cut off code blocks in the middle" may be good enough.

  1. It's hard to make it right. Fix Mermaid code blocks broken on dashboard feed (#36582) #36604 (review)
  2. Why such a large diagram in timeline makes sense?

It's better than not rendering markup at all

The backend-rendered content is still there. I don't think they are "Placeholders", they are the source code of katex math or mermaid diagram.

* origin/main: (192 commits)
  Fix NuGet package upload error handling (go-gitea#37074)
  Desaturate dark theme background colors (go-gitea#37056)
  Update JS dependencies and misc tweaks (go-gitea#37064)
  Redirect to the only OAuth2 provider when no other login methods and fix various problems (go-gitea#36901)
  Show workflow link (go-gitea#37070)
  Remove leftover `webpackChunkName` comments from codeeditor (go-gitea#37062)
  Update Go dependencies (go-gitea#36781)
  Add webhook name field to improve webhook identification (go-gitea#37025) (go-gitea#37040)
  Upgrade `go-git` to v5.17.2 (go-gitea#37060)
  Replace Monaco with CodeMirror (go-gitea#36764)
  Update Combine method to treat warnings as failures and adjust tests (go-gitea#37048)
  Raise minimum Node.js version to 22.18.0 (go-gitea#37058)
  Update golangci-lint to v2.11.4 (go-gitea#37059)
  Upgrade `golang.org/x/image` to v0.38.0 (go-gitea#37054)
  Increase e2e test timeouts on CI to fix flaky tests (go-gitea#37053)
  Refactor "org teams" page and help new users to "add member" to an org (go-gitea#37051)
  Refactor issue sidebar and fix various problems (go-gitea#37045)
  Add tests for pull request's content_version in API (go-gitea#37044)
  Enable concurrent vitest execution (go-gitea#36998)
  Fix theme discovery and Vite dev server in dev mode (go-gitea#37033)
  ...

# Conflicts:
#	templates/user/dashboard/feeds.tmpl
@silverwind silverwind marked this pull request as ready for review April 2, 2026 11:05
@silverwind
Copy link
Copy Markdown
Member Author

Hmm yeah I guess we should just strip all multi-line code blocks then, keep the markup rendering, but strip blocks.

@silverwind silverwind marked this pull request as draft April 2, 2026 11:06
@silverwind
Copy link
Copy Markdown
Member Author

#37077 merged a worse solution (dont't render markup) which I don't agree with but it made this obsolete.

@silverwind silverwind closed this Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged modifies/go Pull requests that update Go code modifies/templates This PR modifies the template files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mermaid code block truncated on homepage causes parse error

5 participants