プレーンテキスト貼り付け時の改行消失バグを修正

basecamp/lexxy

iA Writer など外部エディタからテキストを貼り付けると、単一の改行が無声で削除されてテキストが一塊になる問題を修正しました。marked()breaks: true を渡す1行の変更で、CommonMark のデフォルト挙動を上書きしています。

背景

CommonMark 仕様 では、単一の \n はソフトブレーク(HTML 上はスペース)として扱われ、段落の区切りには \n\n(空行)が必要です。Lexxy のクリップボードハンドラは、プレーンテキストをいったん Markdown として解釈したうえで HTML に変換するため、この仕様が直接影響していました。

外部エディタから「Line 1\nLine 2\nLine 3」を貼り付けると、marked() はデフォルト設定で3行を連結したひとつの段落として出力します。ユーザーから見ると「壁のようなテキスト」が生成され、元の構造が失われていました。

この問題の影響範囲はプレーンテキストの貼り付けパスに限定されており、HTML 貼り付けや添付ファイルを含む貼り付けなど、他のコードパスは影響を受けていません。

技術的な変更

src/editor/clipboard.js#pasteMarkdown メソッドで、marked() の呼び出しに { breaks: true } オプションを追加しました。

変更前:

#pasteMarkdown(text) {
  const html = marked(text)
  const doc = parseHtml(html)
  // ...
}

変更後:

#pasteMarkdown(text) {
  const html = marked(text, { breaks: true })
  const doc = parseHtml(html)
  // ...
}

breaks: true を有効にすると、marked は単一の \n<br> タグに変換します。二重の \n\n は引き続き別々の <p> 要素を生成するため、段落構造の保持も維持されます。

変更に合わせて test/browser/tests/paste.test.js にブラウザテストが2件追加されました。1件目は「Line 1\nLine 2\nLine 3」が <p>Line 1<br>Line 2<br>Line 3</p> になることを、2件目は「Paragraph 1\n\nParagraph 2」が <p>Paragraph 1</p><p>Paragraph 2</p> になることをそれぞれ検証しています。

設計判断

既存の #pasteMarkdown パスを変更する最小限の修正 が選ばれました。プレーンテキストの貼り付けはクリップボードハンドラ内で独立したコードパスを持っており、marked の設定変更の影響範囲はこのパスに閉じています。

また、.claude/skills/bugs-reproducer.md のアーキテクチャドキュメントにも「markdown パスは breaks: truemarked を使用している。このオプションがないと貼り付けたプレーンテキストの単一改行は CommonMark のデフォルトで飲み込まれる。貼り付けで空白や構造が失われる場合はまず marked の設定を確認すること」という注記が追加されました。バグの根本原因を将来の調査者へ伝える目的で、コード変更と並行してドキュメントも更新されています。

まとめ

marked() への breaks: true 1オプションの追加で、CommonMark のデフォルト動作がもたらすユーザー体験の損失を修正しています。コード変更を最小化しつつ、根本原因をドキュメントに記録するアプローチは、同種のバグに対する将来の診断コストを下げる実践的な判断です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
188ddf4b

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「リード文(総論)→各論(背景、技術的変更、設計判断)→まとめ(結論)」の3部構成が明確に適用されており、非常に分かりやすい構成です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```javascript:src/editor/clipboard.js)およびPR番号のリンク記法([PR #819](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

CommonMark仕様や`marked`ライブラリに関する説明は、専門知識を持つエンジニアを対象としており、過度な初心者向け解説がなく適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論で構成され、各段落がトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が遵守されており、可読性が高いです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

`src/editor/clipboard.js`における`{ breaks: true }`オプションの追加というコード変更が、Diff内容と正確に一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「CommonMark」「ソフトブレーク」「marked()」などの技術用語が、PRの文脈に沿って正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

`breaks: true`オプションの効果や、追加されたテストケースの内容に関する説明が、技術的に正確で論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(`iA Writer`の例、`bugs-reproducer.md`へのドキュメント追記など)がPR DescriptionやDiff内容によって裏付けられており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号「#819」が正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトル「プレーンテキスト貼り付け時の改行消失バグを修正」は、PRの主題「Fix line breaks lost when pasting plain text」を正確に反映しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に含まれない外部知識(バージョンのサポート状況、リリース日程など)の記載はなく、すべての情報が提供された資料に基づいています。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

過去の事象(バグ)と完了したアクション(修正)として記述されており、時間表現に歪曲や誤りはありません。