Skip to content
Open
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
10 changes: 8 additions & 2 deletions CONVERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

| → Target | Markdown | HTML | Word (.docx) | LaTeX | JSON | PDF | SRT |
|----------:|:--------:|:----:|:------------:|:-----:|:----:|:---:|:---:|
| **Markdown** | — | ✅ `md-to-html` | ✅ `md-to-word` | · | · | · | · |
| **Markdown** | — | ✅ `md-to-html` | ✅ `md-to-word` (OMath opt-in) | · | · | · | · |
| **HTML** | ✅ `html-to-md` | — | ✅ `html-to-word` | · | · | · | · |
| **Word (.docx)** | ✅ `word-to-md` | ✅ `word-to-html` | — | · | · | · | · |
| **PDF** | ✅ `pdf-to-md` | · | ✅ `pdf-to-docx` | ✅ `pdf-to-latex` | · | — | · |
Expand All @@ -34,10 +34,16 @@
| PDF → Markdown | `pdf-to-md-swift` | ✅ implemented | direct path via PDFKit, heading/list heuristics |
| Word → HTML | `word-to-html-swift` | ✅ implemented | direct path preserves Word semantics |
| HTML → Word | `html-to-word-swift` | ✅ implemented | SwiftSoup → OOXML writer |
| Markdown → Word | `md-to-word-swift` | ✅ implemented | swift-markdown AST → OOXML writer |
| Markdown → Word | `md-to-word-swift` | ✅ implemented | swift-markdown AST → OOXML writer; native OMath is opt-in with `macdoc convert input.md --to docx --math omath --output output.docx` (`literal` is the default) |
| PDF → DOCX | `pdf-to-docx-swift` | ✅ implemented | PDFKit text extraction → OOXML writer |
| Note → HTML | `note-to-html-swift` | ✅ implemented | Notability .note → interactive HTML player with audio-synced stroke replay |

### Markdown → Word native math boundary

Native Word OMath applies only to the Markdown → Word (`.docx`) route and must be enabled with `--math omath`. Without `--math`, or with `--math literal`, dollar-delimited formulas remain literal Markdown text.

OMath mode supports the [versioned `latex-math-swift` macro subset](https://github.com/PsychQuant/latex-math-swift#supported-macros): fractions and radicals, subscript and superscript, accents, delimiters, n-ary operators, functions, limits, text, Greek symbols, and common operators. Full TeX support and Pandoc texmath parity are outside this capability. Every other conversion route rejects `--math omath`.

## Rules

- Open **one issue per converter** before writing code.
Expand Down
9 changes: 9 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ cp .build/release/macdoc ~/bin/macdoc
macdoc convert --to md file.docx
macdoc convert --to docx file.md

# Markdown → Word:選擇性將行內 $...$ 與獨立段落 $$...$$ 轉為原生 OMath
macdoc convert --to docx file.md --math omath

# Word ↔ HTML
macdoc convert --to html file.docx
macdoc convert --to docx file.html
Expand All @@ -109,6 +112,15 @@ macdoc convert --to html notes.note --full
macdoc convert --to html notes.note --full --css dark
```

Markdown → Word 的數學模式預設為 `literal`,因此未指定 `--math omath` 時,
`$...$` 與 `$$...$$` 會保留為一般 Markdown 文字。原生 OMath 轉換採選擇性啟用,
且只適用於 Markdown → DOCX 路由。

`omath` 模式採用 [`latex-math-swift`](https://github.com/PsychQuant/latex-math-swift)
定義的支援子集:分數與根號、上下標、重音符號、成對分隔符號、求和/積分/乘積、
函數與極限、`\text{}`、希臘字母及常用運算子。這項功能不等同完整 TeX 引擎,
也不追求與 Pandoc texmath 相同的語法涵蓋範圍;子集以連結套件的版本化文件為準。

常用選項:

| 選項 | 說明 |
Expand All @@ -117,6 +129,7 @@ macdoc convert --to html notes.note --full --css dark
| `--stdout` | 輸出到 stdout |
| `--frontmatter` | 含 YAML frontmatter(Word → MD) |
| `--html-extensions` | 保留 `<u>/<sup>/<sub>/<mark>`(→ MD) |
| `--math literal\|omath` | Markdown → DOCX 數學模式(預設 `literal`;`omath` 為原生 Word 數學) |
| `--full` | 輸出完整 HTML 文件 |
| `--css dark\|light` | SRT 主題 |
| `--css minimal\|web` | Bib 樣式 |
Expand Down
22 changes: 21 additions & 1 deletion Sources/MacDocCLI/MacDoc+Convert.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ import NoteToPDF
// MARK: - Convert 子命令(textutil-compatible 統一入口)
extension MacDoc {
struct Convert: AsyncParsableCommand {
private enum MathOption: String, CaseIterable, ExpressibleByArgument {
case literal
case omath

var converterMode: MarkdownMathMode {
switch self {
case .literal: .literal
case .omath: .omath
}
}
}

static let configuration = CommandConfiguration(
commandName: "convert",
abstract: "Convert documents between formats (textutil-compatible)"
Expand Down Expand Up @@ -50,6 +62,9 @@ extension MacDoc {
@Flag(name: .long, help: "Preserve <u>/<sup>/<sub>/<mark> as raw HTML in Markdown")
var htmlExtensions: Bool = false

@Option(name: .long, help: "Markdown math mode: literal|omath (Markdown to DOCX only; default: literal)")
private var math: MathOption?

@Argument(help: "Input file")
var input: String

Expand All @@ -59,6 +74,10 @@ extension MacDoc {
let ext = inputURL.pathExtension.lowercased()
let target = to.lowercased()

if math != nil && !(["md", "markdown"].contains(ext) && target == "docx") {
throw ValidationError("--math 只支援 Markdown 轉 DOCX")
}

switch (ext, target) {
case ("docx", "md"):
try convertWordToMD(inputURL: inputURL)
Expand Down Expand Up @@ -290,7 +309,8 @@ extension MacDoc {
options.hardLineBreaks = hardBreaks

let outputURL = try resolveDocxOutputURL(inputURL: inputURL)
try MarkdownToWordConverter().convertToFile(input: inputURL, output: outputURL, options: options)
let converter = MarkdownToWordConverter(mathMode: (math ?? .literal).converterMode)
try converter.convertToFile(input: inputURL, output: outputURL, options: options)
FileHandle.standardError.write(Data("已寫入: \(outputURL.path)\n".utf8))
}

Expand Down
Loading
Loading