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

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

このコミットは、Go言語のドキュメンテーションツールであるgodocsrc/cmd/godoc/template.goファイルに対する変更です。template.goは、godocが生成するHTMLドキュメント内でコードを整形・表示するためのテンプレート処理ロジックを扱っています。具体的には、GoのソースコードをHTMLページに埋め込む際に、そのコードが適切にフォーマットされ、必要に応じてシンタックスハイライトが適用されるようにする役割を担っています。

コミット

このコミットは、godocがHTMLテンプレート内でコードをフォーマットする際に、既存のtemplate.HTMLEscapeString関数からFormatText関数を使用するように変更しています。これにより、HTML出力におけるコードの整形とシンタックスハイライトの品質が向上し、特にコメントのシンタックスカラーリングが他の部分と一貫するようになります。

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

https://github.com/golang/go/commit/2b3fd37066694374d6ea6c6c6f2df8cad08410eb

元コミット内容

godoc: use FormatText for formating code in html template.

R=golang-dev, rsc, r, adg, gri, r
CC=golang-dev
https://golang.org/cl/5835046

変更の背景

godocはGo言語のソースコードからドキュメントを自動生成するツールであり、その出力は通常HTML形式で提供されます。このHTMLドキュメントには、Goのソースコードスニペットが含まれることが多く、これらのコードは可読性を高めるために適切に整形され、シンタックスハイライトが施される必要があります。

以前の実装では、コードのHTMLエスケープにhtml/templateパッケージのHTMLEscapeString関数が使用されていました。しかし、この関数は単にHTML特殊文字をエスケープするだけであり、Goコードのシンタックスハイライト(特にコメント部分のカラーリング)を適切に行う機能は持っていませんでした。その結果、godocが生成するHTMLドキュメント内のコード表示において、コメントの表示が一貫性を欠いたり、期待通りのシンタックスハイライトが適用されないという問題がありました。

このコミットは、この問題を解決するために、godoc内部で既に利用されていた、より高度なコード整形・シンタックスハイライト機能を持つFormatText関数を、HTMLテンプレート内のコード表示にも適用することを目的としています。これにより、godocの出力するHTMLドキュメント全体で、コードの表示品質と一貫性が向上します。

前提知識の解説

godoc

godocは、Go言語のソースコードからドキュメントを生成するためのツールです。Goのパッケージ、関数、型、変数などの定義に付随するコメントを解析し、それらを整形されたHTMLページとして提供します。開発者はgodocを使って、ローカルでGoの標準ライブラリや自身のプロジェクトのドキュメントを閲覧したり、公開サーバーとしてドキュメントを提供したりできます。godocは、Goのコードベースの可読性と保守性を高める上で非常に重要な役割を果たしています。

HTMLエスケープ

HTMLエスケープとは、HTMLドキュメント内で特殊な意味を持つ文字(例: <, >, &, ", ')を、その文字自体として表示するために、対応するHTMLエンティティ(例: &lt;, &gt;, &amp;, &quot;, &#39;)に変換する処理です。これにより、例えばGoのコードスニペットに含まれる<>がHTMLタグとして解釈されることを防ぎ、コードがそのままの形でブラウザに表示されるようになります。セキュリティの観点からも、ユーザー入力などをHTMLに表示する際にはXSS(クロスサイトスクリプティング)攻撃を防ぐために必須の処理です。

シンタックスハイライト

シンタックスハイライトとは、プログラミング言語のソースコードを、その構文要素(キーワード、変数名、文字列、コメントなど)に応じて異なる色やスタイルで表示する機能です。これにより、コードの構造が視覚的に明確になり、可読性が大幅に向上します。godocのようなドキュメンテーションツールでは、コードスニペットをユーザーに提示する際に、シンタックスハイライトを適用することで、コードの理解を助けます。

bytes.Buffer

Go言語のbytes.Buffer型は、可変長のバイトシーケンスを扱うためのバッファです。io.Writerインターフェースを実装しており、バイトデータを効率的に書き込むことができます。文字列の連結や、データを一時的に保持して後でまとめて処理するような場合に便利です。このコミットでは、FormatText関数の出力先としてbytes.Bufferが使用され、整形されたコードが一時的にバッファに格納された後、最終的なHTML文字列に組み込まれます。

技術的詳細

このコミットの核心は、godoccode関数内で、コードのHTML整形とシンタックスハイライトの方法をtemplate.HTMLEscapeStringからFormatTextへ変更した点にあります。

template.HTMLEscapeStringの問題点

template.HTMLEscapeStringは、Goの標準ライブラリhtml/templateパッケージに含まれる関数で、文字列内のHTML特殊文字をエスケープする機能を提供します。これは、HTMLに任意のテキストを安全に埋め込むための基本的なセキュリティ対策としては十分ですが、プログラミングコードのシンタックスハイライト、特にコメントのカラーリングのような高度な整形機能は持ち合わせていませんでした。そのため、godocが生成するHTMLドキュメントでは、コードブロック内のコメントが他のコード要素と異なる、あるいは期待しないスタイルで表示される可能性がありました。

FormatTextの導入

FormatTextは、godoc内部で既にGoのソースコードを整形し、シンタックスハイライトを適用するために使用されていた関数です。この関数は、Goの構文を解析し、キーワード、文字列、コメントなどを識別して、それぞれに適切なHTMLタグやCSSクラスを付与することで、視覚的に整形されたコードを生成します。特に、コメントのシンタックスカラーリングも適切に処理する能力を持っています。

このコミットでは、code関数内でFormatTextを使用するために、以下の変更が行われました。

  1. bytes.Bufferの導入: FormatTextio.Writerインターフェースを引数に取るため、その出力先としてbytes.Bufferが導入されました。これにより、FormatTextが生成した整形済みHTMLコードを一時的にメモリ上に保持し、後で文字列として取得できるようになります。
  2. FormatTextの呼び出し: 以前のtemplate.HTMLEscapeString(text)の代わりに、FormatText(&buf, []byte(text), -1, true, "", nil)が呼び出されます。
    • &buf: bytes.Bufferのポインタを渡し、整形されたコードがこのバッファに書き込まれるようにします。
    • []byte(text): フォーマット対象のコードテキストをバイトスライスとして渡します。
    • -1: 行番号の表示に関する引数で、この場合は行番号を表示しないことを意味します。
    • true: HTMLエスケープを適用するかどうかを示すブール値で、trueに設定されています。これにより、FormatText自体がHTMLエスケープ処理も行います。
    • "", nil: その他のオプション引数で、このコンテキストでは使用されません。
  3. 出力の取得: FormatTextの実行後、buf.Bytes()を呼び出すことで、バッファに書き込まれた整形済みHTMLコードをバイトスライスとして取得し、最終的な<pre>タグ内に埋め込みます。

この変更により、godocはHTMLテンプレート内でコードを表示する際に、より高度な整形とシンタックスハイライト(特にコメントのカラーリング)を適用できるようになり、ドキュメントの視覚的な一貫性と品質が向上しました。

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

--- a/src/cmd/godoc/template.go
+++ b/src/cmd/godoc/template.go
@@ -32,6 +32,7 @@
 package main
 
 import (
+\t"bytes"
 \t"fmt"
 \t"log"
 \t"regexp"
@@ -98,10 +99,11 @@ func code(file string, arg ...interface{}) (s string, err error) {
 	text = strings.Trim(text, "\n")
 	// Replace tabs by spaces, which work better in HTML.
 	text = strings.Replace(text, "\t", "    ", -1)
-	// Escape the program text for HTML.
-	text = template.HTMLEscapeString(text)
+\tvar buf bytes.Buffer
+\t// HTML-escape text and syntax-color comments like elsewhere.
+\tFormatText(&buf, []byte(text), -1, true, "", nil)
 	// Include the command as a comment.
-	text = fmt.Sprintf("<pre><!--{{%s}}\\n-->%s</pre>", command, text)
+\ttext = fmt.Sprintf("<pre><!--{{%s}}\\n-->%s</pre>", command, buf.Bytes())
 	return text, nil
 }
 

コアとなるコードの解説

このコミットにおける主要な変更は、src/cmd/godoc/template.goファイルのcode関数内にあります。

  1. import "bytes"の追加: bytes.Bufferを使用するために、bytesパッケージがインポートリストに追加されました。

    import (
    	"bytes" // 追加
    	"fmt"
    	"log"
    	"regexp"
    	"strings"
    	"text/template"
    )
    
  2. template.HTMLEscapeStringの削除とbytes.Bufferの導入: 元のコードでは、Goのソースコードテキスト(text変数)をHTMLエスケープするためにtemplate.HTMLEscapeString(text)が直接呼び出されていました。

    // Escape the program text for HTML.
    text = template.HTMLEscapeString(text)
    

    この行が削除され、代わりにbytes.Bufferのインスタンスが作成されました。

    var buf bytes.Buffer
    
  3. FormatText関数の呼び出し: 新しく導入されたbytes.Bufferbuf)を書き込み先として、FormatText関数が呼び出されます。

    // HTML-escape text and syntax-color comments like elsewhere.
    FormatText(&buf, []byte(text), -1, true, "", nil)
    
    • &buf: FormatTextの最初の引数はio.Writer型を期待するため、bytes.Bufferのアドレスを渡します。FormatTextはこのバッファに整形されたHTMLコードを書き込みます。
    • []byte(text): フォーマット対象のGoソースコードをバイトスライスに変換して渡します。
    • -1: 行番号を表示しないことを示します。
    • true: FormatTextが内部でHTMLエスケープ処理も行うことを指示します。これにより、以前のtemplate.HTMLEscapeStringの役割もFormatTextが担うことになります。
    • "", nil: その他のオプション引数で、このコンテキストではデフォルト値が使用されます。

    この変更により、コードは単にHTMLエスケープされるだけでなく、godocの他の部分と同様に、シンタックスハイライト(特にコメントのカラーリング)が適用された状態で整形されます。

  4. fmt.Sprintfの変更: 最終的な<pre>タグで囲まれたHTML文字列を生成する部分も変更されました。

    元のコード:

    text = fmt.Sprintf("<pre><!--{{%s}}\\n-->%s</pre>", command, text)
    

    変更後:

    text = fmt.Sprintf("<pre><!--{{%s}}\\n-->%s</pre>", command, buf.Bytes())
    

    以前はtext変数(template.HTMLEscapeStringによって処理された文字列)が直接埋め込まれていましたが、変更後はbuf.Bytes()FormatTextによって整形されたバイトスライス)が埋め込まれるようになりました。buf.Bytes()はバイトスライスですが、fmt.Sprintf%sフォーマット指定子によって自動的に文字列に変換されます。

これらの変更により、godocが生成するHTMLドキュメント内のコードブロックは、より一貫性のある、高品質なシンタックスハイライト(コメントのカラーリングを含む)が適用されるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメントおよびパッケージドキュメント
  • GitHub上のGo言語リポジトリのソースコード
  • Go言語のgodocツールの動作に関する一般的な知識