Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ SECRET_KEY=secret_key # generate a secret key with `openssl rand -base64 32`
HOME_URL=https://example.com/ # optional; if present, the home page will redirect to this URL
# Comma-separated locale patterns for Gukhanmun readings, e.g. ko,ko-*
GUKHANMUN=
# Optional post Markdown extensions; empty disables all:
# https://docs.hollo.social/markdown/
# footnote,deflist,sub,sup,mark,ruby,ins,abbr,tasklist,math
MARKDOWN_EXTENSIONS=

LOG_LEVEL=info
LOG_QUERY=false
Expand Down
9 changes: 9 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ To be released.
14 adds post-quantum ML-DSA passkey support on runtimes that provide the
algorithms. \[[GHSA-2g3p-m8c9-hhwh], [GHSA-j3h4-m3m2-7p7j]]

- Added opt-in Markdown extensions for local posts. Set
`MARKDOWN_EXTENSIONS` to select footnotes, definition lists, subscripts,
superscripts, highlights, ruby annotations, insertions, abbreviations,
task lists, or math. Existing posts retain their rendered content until
explicitly edited. Remote software may simplify the resulting HTML.
[[#679], [#680]]

- Changed the HTTP server to avoid buffering entire uploads and incoming
activities before handling them behind a reverse proxy. Shutdown now waits
for active HTTP requests alongside background workers within the existing
Expand Down Expand Up @@ -194,6 +201,8 @@ To be released.
[#664]: https://github.com/fedify-dev/hollo/pull/664
[#672]: https://github.com/fedify-dev/hollo/issues/672
[#673]: https://github.com/fedify-dev/hollo/pull/673
[#679]: https://github.com/fedify-dev/hollo/issues/679
[#680]: https://github.com/fedify-dev/hollo/pull/680


Version 0.9.24
Expand Down
12 changes: 12 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,15 @@ public login page — prefer the passkey pattern over an inline blob:
should be hidden behind a button the user has to click).
- Wire to the DOM via stable `id`s on the form / button the page
already renders. The server-rendered markup is the contract.


Markdown extensions
-------------------

Post bodies use native semantic HTML for optional Markdown extensions.
Footnotes include visible numbers in their text; suppress duplicate list
numbering in Hollo. Retain their generated IDs only in the canonical post
body, so repeated cards link back to that document without duplicate IDs.
Task lists use static text markers. Highlight text uses the account theme
palette in both color schemes. Display math may scroll horizontally within
the post body; no client-side typesetting or KaTeX stylesheet is required.
3 changes: 3 additions & 0 deletions bin/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { isIP } from "node:net";

import "../src/logging";
import { checkHandleHostConsistency } from "../src/handle-host-check";
import { getMarkdownExtensions } from "../src/markdown-settings";
import { configureSentry } from "../src/sentry";
import { createServerLifecycle } from "../src/server-lifecycle";

Expand Down Expand Up @@ -39,6 +40,8 @@ if (!["all", "web", "worker"].includes(NODE_TYPE)) {
process.exit(1);
}

getMarkdownExtensions();

const lifecycle = createServerLifecycle([
async () => {
// Warn if HANDLE_HOST disagrees with an existing account.
Expand Down
11 changes: 11 additions & 0 deletions changes.d/markdown-extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
links:
'#679': https://github.com/fedify-dev/hollo/issues/679
'#680': https://github.com/fedify-dev/hollo/pull/680
---
- Added opt-in Markdown extensions for local posts. Set
`MARKDOWN_EXTENSIONS` to select footnotes, definition lists, subscripts,
superscripts, highlights, ruby annotations, insertions, abbreviations,
task lists, or math. Existing posts retain their rendered content until
explicitly edited. Remote software may simplify the resulting HTML.
[[#679], [#680]]
2 changes: 2 additions & 0 deletions compose-fs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ services:
BEHIND_PROXY: "${BEHIND_PROXY}"
# REMOTE_REPLIES_SCRAPE_MAX_REQUESTS: "200"
# GUKHANMUN: "ko,ko-*"
# Optional post Markdown extensions; empty disables all:
# MARKDOWN_EXTENSIONS: "" # e.g. "footnote,ruby,math"
DRIVE_DISK: fs
STORAGE_URL_BASE: http://localhost:3000/assets/
FS_STORAGE_PATH: /var/lib/hollo
Expand Down
2 changes: 2 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ services:
BEHIND_PROXY: "${BEHIND_PROXY}"
# REMOTE_REPLIES_SCRAPE_MAX_REQUESTS: "200"
# GUKHANMUN: "ko,ko-*"
# Optional post Markdown extensions; empty disables all:
# MARKDOWN_EXTENSIONS: "" # e.g. "footnote,ruby,math"
DRIVE_DISK: s3
STORAGE_URL_BASE: http://localhost:9000/hollo/
S3_REGION: us-east-1
Expand Down
10 changes: 10 additions & 0 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@ export default defineConfig({
"zh-TW": "已測試的客戶端",
},
},
{
slug: "markdown",
label: "Markdown",
translations: {
ko: "Markdown",
ja: "Markdown",
"zh-CN": "Markdown",
"zh-TW": "Markdown",
},
},
{
slug: "search",
label: "Search",
Expand Down
20 changes: 20 additions & 0 deletions docs/src/content/docs/install/env.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,26 @@ Additional features
If present, the home page will redirect to this URL. If not set, the home page
will show the list of accounts on the instance.

### `MARKDOWN_EXTENSIONS` <Badge text="Optional" />

A comma-separated list of optional Markdown extensions for local posts:
`footnote`, `deflist`, `sub`, `sup`, `mark`, `ruby`, `ins`, `abbr`, `tasklist`,
and `math`. For example, `MARKDOWN_EXTENSIONS=footnote,ruby,math` enables
footnotes, ruby annotations, and mathematics. Surrounding whitespace is
ignored, duplicate names are accepted, and unknown names prevent startup.
Unset or empty means all optional extensions are disabled. Tables and
strikethrough remain available without this setting.

Extensions apply when local posts are created or explicitly edited, not to
profile biographies or fields. Changing this setting does not change stored
source or HTML, or send updates for existing posts. Editing a post renders it
with the current setting, so disabling an extension can make its syntax appear
literally after an edit.

See the [Markdown guide] for syntax, escaping, and federation limitations.

[Markdown guide]: /markdown/

### `GUKHANMUN` <Badge text="Optional" />

A comma-separated list of locale tag patterns for local posts that should have
Expand Down
19 changes: 19 additions & 0 deletions docs/src/content/docs/ja/install/env.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,25 @@ Holloは起動に失敗します。**最初のアカウントを作成する前
設定された場合、トップページへにアクセスした時にこのURLにリダイレクトされます。
設定されていない場合、トップページにはアカウント一覧が表示されます。

### `MARKDOWN_EXTENSIONS` <Badge text="オプション" />

ローカル投稿で使う任意のMarkdown拡張をカンマで区切って指定します。
指定できる名前は`footnote`、`deflist`、`sub`、`sup`、`mark`、`ruby`、
`ins`、`abbr`、`tasklist`、`math`です。たとえば
`MARKDOWN_EXTENSIONS=footnote,ruby,math`で脚注、ルビ、数式を有効にします。
名前の前後の空白は無視され、重複は許可されます。不明な名前があると起動に
失敗します。未設定または空の場合、任意の拡張はすべて無効です。
表と取り消し線はこの設定なしでも使えます。

ローカル投稿の作成時と明示的な編集時に適用され、プロフィールの自己紹介や
フィールドには適用されません。設定を変えても既存の投稿の保存済みソースや
HTMLは変わらず、更新も送信しません。編集時は現在の設定で描画するため、
拡張を無効にしてから編集すると、その構文が文字として表示される場合があります。

構文、エスケープ、連合時の制限は[Markdownガイド]を参照してください。

[Markdownガイド]: /ja/markdown/

### `GUKHANMUN` <Badge text="オプション" />

[Gukhanmun]で漢字にハングルの読みを付けるローカル投稿のロケールタグ
Expand Down
147 changes: 147 additions & 0 deletions docs/src/content/docs/ja/markdown.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: Markdown
description: 任意のMarkdown拡張を使った投稿方法とその制限を説明します。
---

Holloは表や`~~取り消し線~~`を含むMarkdown投稿に対応しています。
インスタンスの管理者は[`MARKDOWN_EXTENSIONS`][設定]で構文を追加できます。
拡張はローカル投稿の作成時と明示的な編集時に適用されます。
プロフィールの自己紹介やフィールドは従来のMarkdown構文を使います。

[設定]: /ja/install/env/#markdown_extensions-


拡張を有効にする
----------------

*.env*に使いたい拡張を設定し、Holloを再起動してください。

~~~~ bash
MARKDOWN_EXTENSIONS=footnote,ruby,math
~~~~

指定できる名前は`footnote`、`deflist`、`sub`、`sup`、`mark`、`ruby`、
`ins`、`abbr`、`tasklist`、`math`です。未設定または空ならすべて無効です。
名前の前後の空白と重複は無視され、不明な名前があると起動に失敗します。

設定を変えても保存済みのソースやHTMLは変わらず、既存の投稿の更新を送信しません。
明示的に編集すると現在の設定で描画し直します。拡張を無効にしてから古い投稿を
編集すると、元の構文が文字として現れる場合があります。


構文
----

| 拡張 | ソース | 意味 |
| ---------- | ------------------------------------- | ---------------------------- |
| `footnote` | `本文[^1]`と`[^1]: 脚注` | 番号付き脚注 |
| `deflist` | 用語の次の行に`: 定義` | 定義リスト |
| `sub` | `H~2~O` | 下付き文字 |
| `sup` | `x^2^` | 上付き文字 |
| `mark` | `==強調箇所==` | ハイライト |
| `ruby` | `{漢字:かんじ}` | ルビ |
| `ins` | `++追加した内容++` | 挿入した内容 |
| `abbr` | `*[HTML]: Hyper Text Markup Language` | 略語の定義 |
| `tasklist` | `- [x] 完了`と`- [ ] 未完了` | 静的なタスク状態 |
| `math` | `$x^2$`と`$$x^2$$` | インライン数式と別行立て数式 |

対応する拡張を有効にすると、次のように書けます。

~~~~ markdown
ある主張[^1]。HTML は要素を持ちます。

[^1]: 補足説明。

用語
: 定義

*[HTML]: Hyper Text Markup Language

- [x] 執筆
- [ ] 確認
~~~~

脚注には実際の番号と元の投稿への絶対リンクが付きます。
定義リストには用語と説明を区切る句読点が含まれます。
ルビにはタグが除去される場合に備えた括弧が付きます。
Gukhanmunは明示的なルビを保護し、読みを重ねて追加しません。

略語は大文字・小文字と単語の境界を区別します。`HTML5`、`html`、`HTML은`は
`HTML`に一致しません。通常の文章で最初に一致した略語には、
「HTML (Hyper Text Markup Language)」のように展開した説明が表示されます。
リンクのラベル、URL、メンション、ハッシュタグ、コード、数式は対象外です。
重複する定義は最初のものを使い、説明は通常のテキストとして扱います。

タスク状態はクリックできるチェックボックスではなく、実際の`[x]`または`[ ]`の
文字として残ります。`[X]`も完了として認識します。印の後には空白か行末が
必要です。状態は投稿を編集して変えます。
`- [x]: note`のような行は、タスクではなくMarkdownのリンク定義になる場合があります。


エスケープと紛らわしい表記
--------------------------

構文をそのまま書くには、コードスパンを使うか区切り文字の前にバックスラッシュを
付けてください。`sup`や`sub`が有効な場合、顔文字や範囲に含まれる対の
キャレットやチルダが書式になることがあります。`\^_\^`や`1\~2,3\~4`と書くと
表記を保てます。添字内の空白は`x^a\ b^`のようにエスケープしてください。
従来の`~~取り消し線~~`も引き続き使えます。

`footnote`が有効なら`^[note]`はインライン脚注で、`sup`が有効なら
`^[note]^`は上付き文字です。受信側で添字が通常の文字列になる場合があるため、
重要な指数は「xのa+b乗」のように通常の文章でも説明してください。


数式
----

インラインの`$...$`は改行をまたげません。開始の`$`の直後と終了の`$`の直前には
空白を置けず、終了の`$`の直後には数字を置けません。
そのため`$5`や`$20 and $30`は通常の通貨表記として残ります。
ドル記号自体は`\$`でエスケープするか、コードスパン内に書いてください。

別行立て数式は行頭の`$$`で始めます。字下げは可能です。
終了の`$$`の後には、その行では空白だけを置けます。
`$$x^2$$`のように1行にも書けますが、文の途中の別行立て数式には対応していません。

~~~~ markdown
インライン数式は$x^2$です。

$$
\frac{a}{b}
$$
~~~~

数式は[FEP-dc88]で説明される方式に沿って、MathMLとTeX注釈を使います。
不正な式、安全でないコマンド、描画上限に達した式は、エスケープしたソースを
表示します。式ごとに独立したマクロ状態を持ち、展開回数と大きさを制限します。

上限は1式あたり8,192 UTF-16コード単位、1投稿あたり64式、1式の出力256 KiB、
数式出力の合計1 MiBです。投稿のソースが65,536 UTF-16コード単位を超えると、
数式の解析だけが無効になります。通常のMarkdownやメンション、ハッシュタグ、
リンクの処理は続きます。この場合、ドル記号で囲まれたテキストも保護された数式ではなく、
通常のMarkdown規則で解釈されます。

[FEP-dc88]: https://w3id.org/fep/dc88


他のサーバーで読む
------------------

受信側のサーバーやクライアントは書式を除去する場合があります。添字、ハイライト、
挿入の印、略語のツールチップが失われる可能性があります。
重要な訂正や定義は本文にも明記してください。
MastodonやMisskeyのルビ対応は内容や受信側のバージョンによります。

Mastodonは数式の注釈をドル記号付きのTeX文字列として表示できる場合がありますが、
数式の組版を保証するものではありません。Misskeyでは数式の表示テキストと
TeX注釈が連結される場合があります。表示はサーバーやクライアントによって
異なります。数式が重要な意味を持つ場合は、通常の言葉でも説明を添えてください。

実際のサーバー間[受け入れテスト]ではMastodon 4.7.3とMisskey 2026.10.0で
全10種類の例の受信を確認しました。Mastodonは編集を反映しましたが、
Misskey 2026.10.0はNoteの更新を無視し、元の内容を保持しました。
記録には受信したHTML/MFMと失われた情報が含まれます。
ブラウザー、クライアント、アクセシビリティの確認は未完了です。

[受け入れテスト]: https://github.com/fedify-dev/hollo/blob/main/tests/markdown-federation/README.md
19 changes: 19 additions & 0 deletions docs/src/content/docs/ko/install/env.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ Hollo가 L7 로드 밸런서 뒤에 위치할 경우 (일반적으로 그래야
설정될 경우, 첫 페이지 접속 시 이 URL로 리다이렉트됩니다. 설정되지 않을 경우,
첫 페이지에서 인스턴스 내 계정 목록이 보입니다.

### `MARKDOWN_EXTENSIONS` <Badge text="선택" />

로컬 게시물에 적용할 선택적 Markdown 확장의 이름을 쉼표로 구분합니다.
사용 가능한 이름은 `footnote`, `deflist`, `sub`, `sup`, `mark`, `ruby`,
`ins`, `abbr`, `tasklist`, `math`입니다. 예를 들어
`MARKDOWN_EXTENSIONS=footnote,ruby,math`는 각주, 루비, 수식을 켭니다.
이름 앞뒤 공백은 무시하고 중복은 허용하며, 모르는 이름이 있으면 시작에
실패합니다. 미설정 또는 빈 값이면 모든 선택적 확장이 꺼집니다.
표와 취소선은 이 설정 없이도 사용할 수 있습니다.

로컬 게시물을 생성하거나 명시적으로 수정할 때만 적용되며, 프로필 소개나
필드에는 적용되지 않습니다. 설정을 바꿔도 기존 게시물의 저장된 원문과 HTML은
바뀌지 않으며 갱신을 전송하지 않습니다. 수정 시에는 현재 설정으로 렌더링하므로,
확장을 끈 뒤 수정하면 해당 문법이 그대로 보일 수 있습니다.

문법, 이스케이프, 연합 시 제약은 [Markdown 안내]를 참고하세요.

[Markdown 안내]: /ko/markdown/

### `GUKHANMUN` <Badge text="선택" />

[Gukhanmun]으로 한자에 한글 독음을 붙일 로컬 게시물의 로캘 태그 패턴을
Expand Down
Loading
Loading