FossilRepo

Render forum post bodies through content renderer, fix more link routes - Forum thread posts now rendered via _render_fossil_content (markdown links like [check-in hash](/info/hash) now clickable) - /dir -> code browser - /builtin/path -> code file viewer - Doc viewer: directory links fall back to index.html/md/wiki

lmata 2026-04-07 00:00 trunk
Commit c686b549a107c969d434af7deb49a34ac83d4541a79d1a91349db724dc37df7a
+16 -3
--- fossil/views.py
+++ fossil/views.py
@@ -161,13 +161,20 @@
161161
return f'href="{base}/docs/www/help.wiki"'
162162
# Bare .wiki or .md file paths (from relative link resolution)
163163
m = re.match(r"/([^/]+\.(?:wiki|md|html))", url)
164164
if m:
165165
return f'href="{base}/docs/www/{m.group(1)}"'
166
- # /setup_*, /admin_* -> these are Fossil server routes, link to admin
166
+ # /dir -> our code browser
167
+ if url == "/dir" or url.startswith("/dir?"):
168
+ return f'href="{base}/code/"'
169
+ # /builtin/path -> code file (these are embedded skin files)
170
+ m = re.match(r"/builtin/(.+)", url)
171
+ if m:
172
+ return f'href="{base}/code/file/skins/{m.group(1)}"'
173
+ # /setup_*, /admin_* -> Fossil server routes, no mapping
167174
if re.match(r"/(setup_|admin_)", url):
168
- return match.group(0) # Keep as-is, no good mapping
175
+ return match.group(0)
169176
# Keep external and unrecognized links as-is
170177
return match.group(0)
171178
172179
def replace_scheme_link(match):
173180
"""Handle Fossil URI schemes like forum:/forumpost/HASH, wiki:PageName, info:HASH."""
@@ -618,17 +625,23 @@
618625
posts = reader.get_forum_thread(thread_uuid)
619626
620627
if not posts:
621628
raise Http404("Forum thread not found")
622629
630
+ # Render each post's body through the content renderer
631
+ rendered_posts = []
632
+ for post in posts:
633
+ body_html = mark_safe(_render_fossil_content(post.body, project_slug=slug)) if post.body else ""
634
+ rendered_posts.append({"post": post, "body_html": body_html})
635
+
623636
return render(
624637
request,
625638
"fossil/forum_thread.html",
626639
{
627640
"project": project,
628641
"fossil_repo": fossil_repo,
629
- "posts": posts,
642
+ "posts": rendered_posts,
630643
"thread_uuid": thread_uuid,
631644
"active_tab": "forum",
632645
},
633646
)
634647
635648
--- fossil/views.py
+++ fossil/views.py
@@ -161,13 +161,20 @@
161 return f'href="{base}/docs/www/help.wiki"'
162 # Bare .wiki or .md file paths (from relative link resolution)
163 m = re.match(r"/([^/]+\.(?:wiki|md|html))", url)
164 if m:
165 return f'href="{base}/docs/www/{m.group(1)}"'
166 # /setup_*, /admin_* -> these are Fossil server routes, link to admin
 
 
 
 
 
 
 
167 if re.match(r"/(setup_|admin_)", url):
168 return match.group(0) # Keep as-is, no good mapping
169 # Keep external and unrecognized links as-is
170 return match.group(0)
171
172 def replace_scheme_link(match):
173 """Handle Fossil URI schemes like forum:/forumpost/HASH, wiki:PageName, info:HASH."""
@@ -618,17 +625,23 @@
618 posts = reader.get_forum_thread(thread_uuid)
619
620 if not posts:
621 raise Http404("Forum thread not found")
622
 
 
 
 
 
 
623 return render(
624 request,
625 "fossil/forum_thread.html",
626 {
627 "project": project,
628 "fossil_repo": fossil_repo,
629 "posts": posts,
630 "thread_uuid": thread_uuid,
631 "active_tab": "forum",
632 },
633 )
634
635
--- fossil/views.py
+++ fossil/views.py
@@ -161,13 +161,20 @@
161 return f'href="{base}/docs/www/help.wiki"'
162 # Bare .wiki or .md file paths (from relative link resolution)
163 m = re.match(r"/([^/]+\.(?:wiki|md|html))", url)
164 if m:
165 return f'href="{base}/docs/www/{m.group(1)}"'
166 # /dir -> our code browser
167 if url == "/dir" or url.startswith("/dir?"):
168 return f'href="{base}/code/"'
169 # /builtin/path -> code file (these are embedded skin files)
170 m = re.match(r"/builtin/(.+)", url)
171 if m:
172 return f'href="{base}/code/file/skins/{m.group(1)}"'
173 # /setup_*, /admin_* -> Fossil server routes, no mapping
174 if re.match(r"/(setup_|admin_)", url):
175 return match.group(0)
176 # Keep external and unrecognized links as-is
177 return match.group(0)
178
179 def replace_scheme_link(match):
180 """Handle Fossil URI schemes like forum:/forumpost/HASH, wiki:PageName, info:HASH."""
@@ -618,17 +625,23 @@
625 posts = reader.get_forum_thread(thread_uuid)
626
627 if not posts:
628 raise Http404("Forum thread not found")
629
630 # Render each post's body through the content renderer
631 rendered_posts = []
632 for post in posts:
633 body_html = mark_safe(_render_fossil_content(post.body, project_slug=slug)) if post.body else ""
634 rendered_posts.append({"post": post, "body_html": body_html})
635
636 return render(
637 request,
638 "fossil/forum_thread.html",
639 {
640 "project": project,
641 "fossil_repo": fossil_repo,
642 "posts": rendered_posts,
643 "thread_uuid": thread_uuid,
644 "active_tab": "forum",
645 },
646 )
647
648
--- templates/fossil/forum_thread.html
+++ templates/fossil/forum_thread.html
@@ -8,26 +8,26 @@
88
<div class="mb-4">
99
<a href="{% url 'fossil:forum' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">&larr; Back to forum</a>
1010
</div>
1111
1212
<div class="space-y-3">
13
- {% for post in posts %}
14
- <div class="rounded-lg bg-gray-800 border border-gray-700 {% if post.in_reply_to %}ml-8{% endif %}">
13
+ {% for item in posts %}
14
+ <div class="rounded-lg bg-gray-800 border border-gray-700 {% if item.post.in_reply_to %}ml-8{% endif %}">
1515
<div class="px-5 py-4">
1616
<div class="flex items-center justify-between mb-2">
17
- <a href="{% url 'fossil:user_activity' slug=project.slug username=post.user %}" class="text-sm font-medium text-gray-200 hover:text-brand-light">{{ post.user }}</a>
18
- <span class="text-xs text-gray-500">{{ post.timestamp|timesince }} ago</span>
17
+ <a href="{% url 'fossil:user_activity' slug=project.slug username=item.post.user %}" class="text-sm font-medium text-gray-200 hover:text-brand-light">{{ item.post.user }}</a>
18
+ <span class="text-xs text-gray-500">{{ item.post.timestamp|timesince }} ago</span>
1919
</div>
20
- {% if post.title and forloop.first %}
21
- <h2 class="text-lg font-semibold text-gray-100 mb-3">{{ post.title }}</h2>
20
+ {% if item.post.title and forloop.first %}
21
+ <h2 class="text-lg font-semibold text-gray-100 mb-3">{{ item.post.title }}</h2>
2222
{% endif %}
23
- {% if post.body %}
23
+ {% if item.body_html %}
2424
<div class="prose prose-invert prose-sm prose-gray max-w-none">
25
- {{ post.body|linebreaksbr }}
25
+ {{ item.body_html }}
2626
</div>
2727
{% else %}
28
- <p class="text-sm text-gray-500 italic">{{ post.title|default:"(empty)" }}</p>
28
+ <p class="text-sm text-gray-500 italic">{{ item.post.title|default:"(empty)" }}</p>
2929
{% endif %}
3030
</div>
3131
</div>
3232
{% empty %}
3333
<p class="text-sm text-gray-500 py-8 text-center">No posts in this thread.</p>
3434
--- templates/fossil/forum_thread.html
+++ templates/fossil/forum_thread.html
@@ -8,26 +8,26 @@
8 <div class="mb-4">
9 <a href="{% url 'fossil:forum' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">&larr; Back to forum</a>
10 </div>
11
12 <div class="space-y-3">
13 {% for post in posts %}
14 <div class="rounded-lg bg-gray-800 border border-gray-700 {% if post.in_reply_to %}ml-8{% endif %}">
15 <div class="px-5 py-4">
16 <div class="flex items-center justify-between mb-2">
17 <a href="{% url 'fossil:user_activity' slug=project.slug username=post.user %}" class="text-sm font-medium text-gray-200 hover:text-brand-light">{{ post.user }}</a>
18 <span class="text-xs text-gray-500">{{ post.timestamp|timesince }} ago</span>
19 </div>
20 {% if post.title and forloop.first %}
21 <h2 class="text-lg font-semibold text-gray-100 mb-3">{{ post.title }}</h2>
22 {% endif %}
23 {% if post.body %}
24 <div class="prose prose-invert prose-sm prose-gray max-w-none">
25 {{ post.body|linebreaksbr }}
26 </div>
27 {% else %}
28 <p class="text-sm text-gray-500 italic">{{ post.title|default:"(empty)" }}</p>
29 {% endif %}
30 </div>
31 </div>
32 {% empty %}
33 <p class="text-sm text-gray-500 py-8 text-center">No posts in this thread.</p>
34
--- templates/fossil/forum_thread.html
+++ templates/fossil/forum_thread.html
@@ -8,26 +8,26 @@
8 <div class="mb-4">
9 <a href="{% url 'fossil:forum' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">&larr; Back to forum</a>
10 </div>
11
12 <div class="space-y-3">
13 {% for item in posts %}
14 <div class="rounded-lg bg-gray-800 border border-gray-700 {% if item.post.in_reply_to %}ml-8{% endif %}">
15 <div class="px-5 py-4">
16 <div class="flex items-center justify-between mb-2">
17 <a href="{% url 'fossil:user_activity' slug=project.slug username=item.post.user %}" class="text-sm font-medium text-gray-200 hover:text-brand-light">{{ item.post.user }}</a>
18 <span class="text-xs text-gray-500">{{ item.post.timestamp|timesince }} ago</span>
19 </div>
20 {% if item.post.title and forloop.first %}
21 <h2 class="text-lg font-semibold text-gray-100 mb-3">{{ item.post.title }}</h2>
22 {% endif %}
23 {% if item.body_html %}
24 <div class="prose prose-invert prose-sm prose-gray max-w-none">
25 {{ item.body_html }}
26 </div>
27 {% else %}
28 <p class="text-sm text-gray-500 italic">{{ item.post.title|default:"(empty)" }}</p>
29 {% endif %}
30 </div>
31 </div>
32 {% empty %}
33 <p class="text-sm text-gray-500 py-8 text-center">No posts in this thread.</p>
34

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button