patx/gitman

improve markdown rendering in readmes and comments

Commit 87c5a7f · patx · 2026-05-10T21:39:28Z

Changeset
87c5a7f79b6d43e234baf3a40326381a89c28438
Parents
003ab593f6c0909a00913da287e0d054fd474c38

View source at this commit

Comments

No comments yet.

Log in to comment

Diff

diff --git a/app.py b/app.py
index 01bcaa2..dd4a240 100644
--- a/app.py
+++ b/app.py
@@ -900,6 +900,7 @@ def render(template_name, **context):
     context.setdefault("error", None)
     context.setdefault("notice", None)
     context.setdefault("csrf_field", csrf_field)
+    context.setdefault("render_markdown", render_markdown)
     context.setdefault("render_markdown_links", render_markdown_links)
     context.setdefault("render_repo_description", render_repo_description)
     context.setdefault("format_ref_label", format_ref_label)
diff --git a/static/styles.css b/static/styles.css
index ab2bb01..4e35874 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -314,6 +314,18 @@ button, .button {
 .repo-card strong, .repo-card span, .repo-card small, .clone-box code { display: block; }
 .markdown-body { overflow-x: auto; }
 .markdown-body img { max-width: 100%; }
+.markdown-body code {
+  padding: .12rem .28rem;
+  border-radius: .25rem;
+  background: var(--soft-surface);
+  font: .9em/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
+}
+.markdown-body pre code {
+  display: block;
+  padding: 0;
+  background: transparent;
+  font: inherit;
+}
 .grid.two { display: grid; grid-template-columns: 1fr 18rem; gap: 2rem; }
 .meta-list { display: grid; grid-template-columns: 8rem 1fr; gap: .35rem 1rem; }
 .meta-list dt { color: var(--muted); }
@@ -323,8 +335,19 @@ button, .button {
 .activity-title, .activity-detail { margin-bottom: .25rem; }
 .activity-detail { color: var(--detail); }
 .comment-list { display: grid; gap: 1rem; }
-.comment { border-bottom: 1px solid var(--soft-border); }
+.comment { padding-bottom: 1rem; border-bottom: 1px solid var(--soft-border); }
 .comment, .activity-feed li { min-width: 0; }
+.comment-meta {
+  display: flex;
+  gap: .5rem;
+  align-items: baseline;
+  margin-bottom: .35rem;
+}
+.comment-body {
+  line-height: 1.6;
+  overflow-wrap: anywhere;
+}
+.comment-body > :last-child { margin-bottom: 0; }
 .comment p, .activity-title, .activity-detail {
   font-size: 1rem;
   line-height: 1.6;
diff --git a/templates/comment.tpl b/templates/comment.tpl
new file mode 100644
index 0000000..1e886a6
--- /dev/null
+++ b/templates/comment.tpl
@@ -0,0 +1,7 @@
+<article class="comment">
+  <header class="comment-meta">
+    <strong><a href="/{{comment["author_username"]}}">@{{comment["author_username"]}}</a></strong>
+    <small class="muted">{{comment["created_at"]}}</small>
+  </header>
+  <div class="comment-body markdown-body">{{!render_markdown(comment["body"])}}</div>
+</article>
diff --git a/templates/commit_detail.tpl b/templates/commit_detail.tpl
index 7686f1c..456cfc5 100644
--- a/templates/commit_detail.tpl
+++ b/templates/commit_detail.tpl
@@ -34,9 +34,7 @@
   % if comments:
     <div class="comment-list">
       % for comment in comments:
-        <article class="comment">
-            <p><strong><a href="/{{comment["author_username"]}}">@{{comment["author_username"]}}</a>:</strong> {{!render_markdown_links(comment["body"])}} <small class="muted">{{comment["created_at"]}}</small></p>
-        </article>
+        % include("comment.tpl", comment=comment)
       % end
     </div>
   % else:
diff --git a/templates/issue_detail.tpl b/templates/issue_detail.tpl
index 3e452b6..c374059 100644
--- a/templates/issue_detail.tpl
+++ b/templates/issue_detail.tpl
@@ -41,9 +41,7 @@
   % if comments:
     <div class="comment-list">
       % for comment in comments:
-        <article class="comment">
-            <p><strong><a href="/{{comment["author_username"]}}">@{{comment["author_username"]}}</a>:</strong> {{!render_markdown_links(comment["body"])}} <small class="muted">{{comment["created_at"]}}</small></p>
-        </article>
+        % include("comment.tpl", comment=comment)
       % end
     </div>
   % else:
diff --git a/templates/pull_request_detail.tpl b/templates/pull_request_detail.tpl
index 8fddd93..8c0fd47 100644
--- a/templates/pull_request_detail.tpl
+++ b/templates/pull_request_detail.tpl
@@ -48,9 +48,7 @@
   % if comments:
     <div class="comment-list">
       % for comment in comments:
-        <article class="comment">
-            <p><strong><a href="/{{comment["author_username"]}}">@{{comment["author_username"]}}</a>:</strong> {{!render_markdown_links(comment["body"])}} <small class="muted">{{comment["created_at"]}}</small></p>
-        </article>
+        % include("comment.tpl", comment=comment)
       % end
     </div>
   % else:
diff --git a/tests/test_app.py b/tests/test_app.py
index 982fbfa..2a8ab64 100644
--- a/tests/test_app.py
+++ b/tests/test_app.py
@@ -449,6 +449,12 @@ def test_render_markdown_strips_scripts_and_unsafe_links():
 | A |
 | - |
 | B |
+
+Inline `print('code')`.
+
+```
+print('block')
+```
 """
     )
 
@@ -457,6 +463,8 @@ def test_render_markdown_strips_scripts_and_unsafe_links():
     assert "javascript:" not in rendered.lower()
     assert 'href="https://example.com"' in rendered
     assert "<table>" in rendered
+    assert "<code>print('code')</code>" in rendered
+    assert "<pre><code>print('block')" in rendered
 
 
 def test_render_markdown_links_allows_only_links():
@@ -2255,9 +2263,14 @@ def test_bottle_issue_routes_create_comment_close_and_reopen(isolated_app):
     assert response.status_code == 200
     assert "Comment body is required." in response.text
 
-    response = client.post("/alice/demo/issues/1", {"action": "comment", "body": "I can reproduce this"})
+    comment_body = "I can reproduce this\n\n`print('code')`\n\n```\nprint('block')\n```"
+    response = client.post("/alice/demo/issues/1", {"action": "comment", "body": comment_body})
     assert response.status_code == 303
-    assert "I can reproduce this" in client.get("/alice/demo/issues/1").text
+    issue_response = client.get("/alice/demo/issues/1")
+    assert "I can reproduce this" in issue_response.text
+    assert 'class="comment-body markdown-body"' in issue_response.text
+    assert "<code>print('code')</code>" in issue_response.text
+    assert "<pre><code>print('block')" in issue_response.text
 
     response = client.post("/alice/demo/issues/1", {"action": "close"})
     assert response.status_code == 303