[インデックス 19026] ファイルの概要
このコミットは、Go言語のgo/doc
パッケージ内のToText
関数におけるバグを修正します。具体的には、事前フォーマット済みテキストブロック(preformatted text blocks)内の空白行が正しく処理されず、生成されるドキュメントのレイアウトが崩れる問題に対処しています。
コミット
commit b8851ad701e0ca73469706c35fb802a81e645225
Author: Robert Griesemer <gri@golang.org>
Date: Thu Apr 3 15:52:04 2014 -0700
go/doc: fix ToText
Fixes #6769.
LGTM=bradfitz
R=bgarcia, rsc, bradfitz
CC=golang-codereviews
https://golang.org/cl/84220044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b8851ad701e0ca73469706c35fb802a81e645225
元コミット内容
go/doc: fix ToText
Fixes #6769.
LGTM=bradfitz
R=bgarcia, rsc, bradfitz
CC=golang-codereviews
https://golang.org/cl/84220044
変更の背景
go/doc
パッケージのToText
関数は、Goのソースコードコメントからプレーンテキスト形式のドキュメントを生成する際に使用されます。この関数には、事前フォーマット済みテキストブロック(例えば、コード例やアスキーアートなど、空白や改行がそのまま表示されるべき内容)内の空白行を正しく処理できないバグが存在していました。
以前の実装では、ToText
関数が事前フォーマット済みブロック内の空白行を検出すると、その行を完全にスキップしていました。この結果、生成されるドキュメントにおいて、事前フォーマット済みテキストの意図されたレイアウト(特に空白行による整形)が失われ、可読性が損なわれる問題が発生していました。このコミットは、このレイアウトの崩れを引き起こすバグを修正することを目的としています。
前提知識の解説
go/doc
パッケージ: Go言語の標準ライブラリの一部であり、Goのソースコードからドキュメンテーションコメントを解析し、構造化されたドキュメントを生成するための機能を提供します。go doc
コマンドなどで利用されています。ToText
関数:go/doc
パッケージ内で定義されている関数の一つで、解析されたドキュメンテーションコメントのブロック(パラグラフ、見出し、事前フォーマット済みブロックなど)を、整形されたプレーンテキスト形式の出力に変換する役割を担います。- Goのドキュメンテーションコメントの構造: Goのドキュメンテーションコメントは、特定の書式規則に従って記述されます。
- パラグラフ: 通常のテキストブロック。
- 見出し: 行頭にタブまたは複数のスペースでインデントされたテキスト。
- 事前フォーマット済みブロック (Preformatted Blocks): 行頭にタブまたは複数のスペースでインデントされた連続する行で構成されます。これらのブロック内のテキストは、空白や改行を含め、記述された通りのフォーマットで表示されることが期待されます。コード例やアスキーアートなどに利用されます。
ToText
関数は、これらのブロックを適切に整形して出力する必要があります。
技術的詳細
このコミットの技術的な核心は、ToText
関数が事前フォーマット済みブロック(opPre
)を処理するロジックの変更にあります。
ToText
関数は、コメントを解析して得られた操作(op
)のリストを順に処理します。opPre
タイプの場合、関数はブロック内の各行を反復処理し、preIndent
(事前フォーマット済みブロックのインデント)と行の内容を書き込みます。
修正前のコードでは、opPre
ブロック内の行がisBlank(line)
関数によって空白行と判定された場合、その行はif !isBlank(line)
という条件によってスキップされていました。これは、通常のパラグラフでは空白行を無視して整形する挙動としては正しいのですが、事前フォーマット済みブロックにおいては、空白行もレイアウトの一部として保持されるべきでした。
このコミットでは、このロジックを修正し、opPre
ブロック内でisBlank(line)
がtrue
を返した場合(つまり空白行の場合)には、単に改行文字(\n
)を出力するように変更しました。これにより、事前フォーマット済みブロック内の空白行が正しく改行として扱われ、意図されたレイアウトが維持されるようになりました。空白行でない場合は、これまで通りpreIndent
と行の内容が出力されます。
この変更により、go/doc
によって生成されるドキュメントにおいて、事前フォーマット済みテキストブロックの視覚的な整合性が保たれるようになります。
コアとなるコードの変更箇所
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index 5c8c43e0c1..274a625cf0 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -392,7 +392,9 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) {
case opPre:
w.Write(nl)
for _, line := range b.lines {
- if !isBlank(line) {
+ if isBlank(line) {
+ w.Write([]byte("\n"))
+ } else {
w.Write([]byte(preIndent))
w.Write([]byte(line))
}
diff --git a/src/pkg/go/doc/comment_test.go b/src/pkg/go/doc/comment_test.go
index aa21b8d1b3..9f29a61153 100644
--- a/src/pkg/go/doc/comment_test.go
+++ b/src/pkg/go/doc/comment_test.go
@@ -42,8 +42,9 @@ func TestIsHeading(t *testing.T) {
}
var blocksTests = []struct {
- in string
- out []block
+ in string
+ out []block
+ text string
}{
{\n \tin: `Para 1.\n@@ -59,6 +60,22 @@ Para 3.\n pre1\n \n Para 4.\n+\n+\tpre\n+\tpre1\n+\n+\tpre2\n+\n+Para 5.\n+\n+\n+\tpre\n+\n+\n+\tpre1\n+\tpre2\n+\n+Para 6.\n pre\n pre2\n `,\n@@ -69,8 +86,44 @@ Para 4.\n {opPara, []string{"Para 3.\\n"}},\n {opPre, []string{"pre\\n", "pre1\\n"}},\n {opPara, []string{"Para 4.\\n"}},\n+\t\t\t{opPre, []string{"pre\\n", "pre1\\n", "\\n", "pre2\\n"}},\n+\t\t\t{opPara, []string{"Para 5.\\n"}},\n+\t\t\t{opPre, []string{"pre\\n", "\\n", "\\n", "pre1\\n", "pre2\\n"}},\n+\t\t\t{opPara, []string{"Para 6.\\n"}},\n {opPre, []string{"pre\\n", "pre2\\n"}},\n },\n+\t\ttext: `. Para 1. Para 1 line 2.\n+\n+. Para 2.\n+\n+\n+. Section\n+\n+. Para 3.\n+\n+$\tpre\n+$\tpre1\n+\n+. Para 4.\n+\n+$\tpre\n+$\tpre1\n+\n+$\tpre2\n+\n+. Para 5.\n+\n+$\tpre\n+\n+\n+$\tpre1\n+$\tpre2\n+\n+. Para 6.\n+\n+$\tpre\n+$\tpre2\n+`,\n },\n }\n \n@@ -83,6 +136,17 @@ func TestBlocks(t *testing.T) {\n }\n }\n \n+func TestToText(t *testing.T) {\n+\tvar buf bytes.Buffer\n+\tfor i, tt := range blocksTests {\n+\t\tToText(&buf, tt.in, \". \", \"$\\t\", 40)\n+\t\tif have := buf.String(); have != tt.text {\n+\t\t\tt.Errorf(\"#%d: mismatch\\nhave: %s\\nwant: %s\\nhave vs want:\\n%q\\n%q\", i, have, tt.text, have, tt.text)\n+\t\t}\n+\t\tbuf.Reset()\n+\t}\n+}\n+\n var emphasizeTests = []struct {\n \tin string\n \tout string\n```
## コアとなるコードの解説
### `src/pkg/go/doc/comment.go` の変更
* **`ToText`関数の`opPre`ケースの修正**:
* 変更前: `if !isBlank(line)`という条件で、空白行でない場合にのみ`preIndent`と`line`を書き込んでいました。
* 変更後: `if isBlank(line)`という条件に変更され、空白行である場合に`w.Write([]byte("\n"))`を実行して改行を出力するようになりました。
* `else`ブロックが追加され、空白行でない場合はこれまで通り`preIndent`と`line`を書き込むようになりました。
* この変更により、事前フォーマット済みブロック内の空白行が、単にスキップされるのではなく、明示的な改行として出力されるようになり、意図されたレイアウトが保持されるようになりました。
### `src/pkg/go/doc/comment_test.go` の変更
* **`blocksTests`構造体の拡張**:
* `blocksTests`というテストデータ構造に、`text string`フィールドが追加されました。これは、`ToText`関数によって生成される期待される最終的なテキスト出力を保持するために使用されます。
* **新しいテストケースの追加**:
* `blocksTests`に、事前フォーマット済みブロック内に空白行が含まれる場合の新しい入力(`in`フィールド)と、それに対応する期待されるブロック構造(`out`フィールド)、そして最終的なテキスト出力(`text`フィールド)が追加されました。
* 特に、`pre\n`, `pre1\n`, `\n`, `pre2\n` のように、事前フォーマット済みブロック内に明示的に空白行が挿入された場合のテストが追加され、修正が正しく機能することを確認しています。
* **`TestToText`関数の追加**:
* `TestToText`という新しいテスト関数が追加されました。この関数は、`blocksTests`の各テストケースを反復処理し、`ToText`関数を呼び出して実際の出力を生成します。
* 生成された出力(`have`)と期待される出力(`tt.text`)を比較し、不一致があればエラーを報告します。これにより、`ToText`関数の修正が、さまざまなコメント構造、特に空白行を含む事前フォーマット済みブロックに対して正しく機能することを検証しています。
これらの変更により、`ToText`関数のバグが修正され、その修正が新しいテストケースによって検証されるようになりました。
## 関連リンク
* Go CL (Code Review): [https://golang.org/cl/84220044](https://golang.org/cl/84220044)
## 参考にした情報源リンク
* Go言語の公式ドキュメント (`go/doc`パッケージに関する情報)
* Go言語のソースコード (`src/pkg/go/doc/comment.go` および `src/pkg/go/doc/comment_test.go`)
* Go言語のドキュメンテーションコメントの書式に関する情報 (例: `go help doc`)