Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11171] ファイルの概要

このコミットは、Go言語のドキュメンテーション生成ツールであるgo/docパッケージにおけるテキスト整形ロジックの修正に関するものです。具体的には、ドキュメンテーションコメントをプレーンテキスト形式で出力する際に、段落間に不要な改行が複数挿入されてしまう問題を解決しています。これにより、生成されるドキュメントの可読性が向上し、より自然な段落区切りが実現されます。

コミット

commit 2374edc6401401fcaa0d328bab38c9e3cffc9274
Author: Rob Pike <r@golang.org>
Date:   Sat Jan 14 11:57:32 2012 -0800

    go/doc: print only one newline between paragraphs
    Fixes #2595.
    
    R=golang-dev, gri
    CC=golang-dev
    https://golang.org/cl/5544068

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/2374edc6401401fcaa0d32c8bab38c9e3cffc9274

元コミット内容

go/doc: print only one newline between paragraphs Fixes #2595.

変更の背景

この変更は、Go言語のドキュメンテーションツールが生成するテキスト出力において、段落間の改行が過剰になるという問題(Issue #2595)を解決するために行われました。

Go言語のドキュメンテーションコメントは、コードの可読性を高め、APIの利用方法を説明するために非常に重要です。go/docパッケージは、これらのコメントを解析し、go docコマンドなどで表示される整形されたドキュメントを生成します。

しかし、以前の実装では、ドキュメンテーションコメント内の複数の段落をプレーンテキストとして出力する際に、各段落の間に複数の改行(例えば、段落の終わりと次の段落の始まりでそれぞれ改行が追加されるなど)が挿入されてしまうことがありました。これにより、生成されるドキュメントが不必要に縦長になり、視覚的に読みにくくなるという問題が発生していました。

このコミットは、段落間の改行を単一の改行に制限することで、この整形上の問題を修正し、よりクリーンで読みやすいドキュメント出力を実現することを目的としています。

前提知識の解説

  • Go言語のドキュメンテーションコメント: Go言語では、パッケージ、関数、型、変数などの宣言の直前に記述されたコメントがドキュメンテーションコメントとして扱われます。これらはgo docコマンドやgodocツールによって解析され、APIドキュメントとして利用されます。
    • 単一行コメント (//) または複数行コメント (/* ... */) のいずれも使用できますが、慣習的には//が推奨されます。
    • コメントの最初の段落は、その要素の概要として扱われます。
    • 段落は空行で区切られます。
  • go/docパッケージ: Go標準ライブラリの一部であり、Goのソースコードからドキュメンテーションを抽出・整形するための機能を提供します。go docコマンドの基盤となっています。
  • io.Writerインターフェース: Go言語における基本的なI/Oインターフェースの一つです。Write([]byte) (n int, err error)メソッドを持ち、バイトスライスを書き込むための抽象化を提供します。ファイル、ネットワーク接続、標準出力など、様々な出力先にデータを書き込む際に利用されます。
  • テキスト整形: プログラムによってテキストを読みやすく、特定のフォーマットに沿って出力するプロセスです。このコミットでは、特に段落間のスペース(改行)の制御が焦点となっています。
  • Gerrit (golang.org/cl): Goプロジェクトでは、コードレビューシステムとしてGerritが使用されています。https://golang.org/cl/5544068のようなリンクは、特定の変更リスト(Change List, CL)を指し、その変更に関する詳細な議論やレビュー履歴を確認できます。

技術的詳細

このコミットで変更されたsrc/pkg/go/doc/comment.goファイルは、Goのドキュメンテーションコメントを解析し、整形されたテキストとして出力するロジックを担っています。

  • ToText関数: この関数は、Goのドキュメンテーションコメントのテキストをプレーンテキスト形式に変換し、指定されたio.Writerに書き出す役割を担っています。引数には、出力先となるio.Writer、元のコメントテキスト、インデント文字列、プリインデント文字列、そして行の最大幅が渡されます。
  • blocks関数: ToText関数内で利用されるblocks関数(またはそれに相当する内部ロジック)は、入力されたドキュメンテーションコメントのテキストを、意味的なブロック(例: 段落、コードブロック、リストなど)に分割します。各ブロックは、その種類を示すopフィールドと、その内容を表すlinesフィールドを持つ構造体として表現されます。
  • opPara: blocks関数によって識別されるブロックタイプの一つで、通常のテキスト段落を示します。
  • l.writeメソッド: ToText関数内で使用される内部的なヘルパーメソッド(lineWriter構造体のメソッドと推測される)で、整形された行をio.Writerに書き込む責任を持ちます。このメソッドは、行の書き込みに加えて、必要に応じて先行する改行(leading newline)を自動的に追加するロジックを持っていることが、今回の修正の鍵となります。

以前の実装では、ToText関数がblocksから取得した各ブロックをループ処理する際に、opParaタイプのブロック(段落)に対して、最初の段落でない場合に無条件で改行を書き込むロジックが含まれていました。これは、if i > 0 { w.Write(nl) }というコードで表現されていました。このロジックと、l.writeが持つ「必要に応じて先行改行を追加する」機能が重複し、結果として段落間に余分な改行が挿入される原因となっていました。

今回の修正は、この重複する改行挿入ロジックを削除することで、l.writeに段落間の改行制御を一任し、単一の適切な改行のみが挿入されるようにしています。

コアとなるコードの変更箇所

--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -353,12 +353,10 @@ func ToText(w io.Writer, text string, indent, preIndent string, width int) {
 		width:  width,
 		indent: indent,
 	}
-	for i, b := range blocks(text) {
+	for _, b := range blocks(text) {
 		switch b.op {
 		case opPara:
-\t\t\tif i > 0 {\n-\t\t\t\tw.Write(nl)\n-\t\t\t}\n+		// l.write will add leading newline if required
 			for _, line := range b.lines {
 				l.write(line)
 			}

コアとなるコードの解説

変更はsrc/pkg/go/doc/comment.goファイルのToText関数内にあります。

  1. 変更前:

    for i, b := range blocks(text) {
        switch b.op {
        case opPara:
            if i > 0 {
                w.Write(nl)
            }
            for _, line := range b.lines {
                l.write(line)
            }
    

    このコードでは、blocks(text)から取得した各ブロックをi(インデックス)と共にループしています。opPara(段落)タイプのブロックに遭遇し、かつそれが最初のブロック(i > 0)でない場合、w.Write(nl)によって明示的に改行(nlはnewlineバイトスライス)を書き込んでいました。その後、各行をl.write(line)で書き出しています。

  2. 変更後:

    for _, b := range blocks(text) {
        switch b.op {
        case opPara:
            // l.write will add leading newline if required
            for _, line := range b.lines {
                l.write(line)
            }
    

    変更点としては、以下の2つが挙げられます。

    • ループ変数のi(インデックス)が削除され、_(ブランク識別子)に変更されました。これは、ループ内でインデックスが不要になったことを示します。
    • if i > 0 { w.Write(nl) }という行が完全に削除されました。
    • 削除された行の代わりに、// l.write will add leading newline if requiredというコメントが追加されました。

この変更の核心は、l.writeメソッドが既に「必要に応じて先行する改行を追加する」というロジックを持っているという事実に基づいています。以前のコードは、このl.writeの機能に加えて、ToText関数自身が段落の開始時に明示的に改行を追加していました。この二重の改行挿入が、段落間に余分な改行を生み出す原因となっていました。

if i > 0の条件付き改行挿入を削除することで、段落間の改行制御は完全にl.writeに委ねられることになります。l.writeは、その内部ロジックに基づいて、段落の間に適切な単一の改行のみを挿入するようになります。これにより、go/docが生成するテキストドキュメントの段落間のスペースが修正され、より自然で読みやすい出力が実現されます。

関連リンク

参考にした情報源リンク

  • コミット情報 (./commit_data/11171.txt)
  • GitHub上のコミットページ
  • Go Issue #2595
  • Gerrit Change-ID 5544068
  • Go言語のドキュメンテーションに関する一般的な知識
  • Go言語のioパッケージに関する一般的な知識