[インデックス 14314] ファイルの概要
このコミットは、Go言語の公式ドキュメントツールであるgodoc
のプレイグラウンド機能におけるコードフォーマットの挙動を修正するものです。具体的には、プレイグラウンドでコードをフォーマットする際に、標準のgofmt
ツールと同じプリンタ設定を使用するように変更されています。これにより、godoc
のプレイグラウンドで表示されるコードが、開発者がローカルでgofmt
を実行した際と同じフォーマットになるよう統一されます。
コミット
commit c1c136d0c4c2057f33f2ce66c7f9ed60e3c2548d
Author: Andrew Gerrand <adg@golang.org>
Date: Mon Nov 5 22:46:28 2012 +0100
cmd/godoc: use normal gofmt printer settings for playground fmt
R=gri
CC=golang-dev
https://golang.org/cl/6815081
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c1c136d0c4c2057f33f2ce66c7f9ed60e3c2548d
元コミット内容
cmd/godoc: use normal gofmt printer settings for playground fmt
R=gri
CC=golang-dev
https://golang.org/cl/6815081
変更の背景
Go言語には、コードの自動フォーマットを行うための標準ツールgofmt
が存在します。gofmt
は、Goのコードスタイルガイドラインに沿ってコードを整形し、一貫性のあるコードベースを維持するために広く利用されています。
godoc
は、Goのソースコードからドキュメントを生成し、Webブラウザで閲覧可能にするツールです。このgodoc
には、Goのコードスニペットを実行できる「プレイグラウンド」機能が組み込まれています。ユーザーがプレイグラウンドでコードを入力し、フォーマットボタンを押すと、そのコードが整形されて表示されます。
このコミット以前は、godoc
のプレイグラウンドにおけるコードフォーマットが、標準のgofmt
ツールが使用する設定と完全に一致していませんでした。これにより、ユーザーがgodoc
のプレイグラウンドでコードをフォーマットした結果と、ローカルでgofmt
を実行した結果との間に差異が生じる可能性がありました。このような不一致は、ユーザーエクスペリエンスを損ない、Goコードの標準的なフォーマットに関する混乱を招く恐れがありました。
この変更の背景には、Goエコシステム全体でコードフォーマットの一貫性を保ち、開発者がどの環境でコードを扱っても同じ整形結果が得られるようにするという、Goプロジェクトの強い哲学があります。gofmt
はGo言語の設計思想の一部であり、その挙動は予測可能でなければなりません。godoc
のプレイグラウンドもこの一貫性に従うべきであるという判断から、この修正が導入されました。
前提知識の解説
このコミットを理解するためには、以下のGo言語のツールとパッケージに関する知識が必要です。
godoc
: Go言語のソースコードからドキュメントを生成し、Webサーバーとして提供するツールです。Goの標準ライブラリのドキュメントもgodoc
によって生成されています。また、コードスニペットをブラウザ上で実行できる「プレイグラウンド」機能も提供します。gofmt
: Go言語のソースコードを自動的にフォーマットするツールです。Goのコードスタイルガイドラインに厳密に従い、インデント、スペース、改行などを整形します。Goコミュニティでは、gofmt
によってフォーマットされたコードが標準とされています。go/ast
パッケージ: Goのソースコードを抽象構文木(Abstract Syntax Tree, AST)として表現するためのデータ構造と関数を提供します。gofmt
やコンパイラ、リンターなどのツールは、まずソースコードをASTにパースし、そのASTを操作することで様々な処理を行います。go/token
パッケージ: Goのソースコード内のトークン(キーワード、識別子、演算子など)の位置情報(ファイル、行番号、列番号など)を管理するための型と関数を提供します。token.FileSet
は、複数のファイルのトークン位置情報を効率的に管理するための構造体です。go/printer
パッケージ:go/ast
パッケージで表現されたASTを、Goのソースコードとして整形して出力するための機能を提供します。gofmt
はこのパッケージを利用してコードを整形しています。printer.Config
:go/printer
パッケージでコードを整形する際の詳細な設定を定義するための構造体です。インデントの種類(スペースかタブか)、タブ幅、コメントの扱いなど、様々なフォーマットオプションを指定できます。printer.Mode
:printer.Config
内で使用されるフラグのセットで、フォーマットの挙動を制御します。printer.UseSpaces
: インデントにタブではなくスペースを使用することを示します。printer.TabIndent
: インデントにタブを使用することを示します。printer.Fprint
関数:printer.Config
構造体を受け取り、指定された設定でASTを整形してio.Writer
に書き出す関数です。
bytes.Buffer
:bytes
パッケージに含まれる型で、可変長のバイトシーケンスをメモリ上で効率的に操作するためのバッファを提供します。このコミットでは、フォーマットされたコードの出力先として使用されています。ast.SortImports
:go/ast
パッケージの関数で、Goソースコードのインポート宣言を標準的な順序にソートします。gofmt
もこの機能を利用しています。
技術的詳細
Go言語のコードフォーマットは、gofmt
ツールによって行われますが、その内部ではgo/ast
パッケージとgo/printer
パッケージが重要な役割を担っています。
- パース: まず、入力されたGoのソースコードは
go/parser
パッケージ(直接は示されていませんが、ast.SortImports
やprinter.Fprint
が*ast.File
と*token.FileSet
を引数に取ることから、コードがASTにパースされていることがわかります)によって抽象構文木(AST)にパースされます。このASTは、コードの構造を木構造で表現したものです。 - インポートのソート: パースされたASTに対して、
ast.SortImports(fset, f)
が呼び出されます。これは、Goのソースコード内のインポート宣言(import (...)
ブロック)を、標準的なgofmt
のルールに従ってアルファベット順にソートし、グループ化する処理です。これにより、インポートの順序に関する一貫性が保たれます。 - コードの整形と出力: ソートされたASTは、
go/printer
パッケージを使用して整形され、最終的なGoのソースコードとして出力されます。- コミット前のコードでは、
printer.Fprint(&buf, fset, f)
が直接呼び出されていました。このprinter.Fprint
関数は、printer.Config
を明示的に指定しない場合、デフォルトのプリンタ設定を使用します。当時のデフォルト設定が、gofmt
の標準設定と完全に一致していなかった可能性があります。特に、タブとスペースの扱い、タブ幅などが異なっていたことが推測されます。 - コミット後のコードでは、
printer.Config
構造体が明示的に作成され、Mode
フィールドにprinter.UseSpaces | printer.TabIndent
が設定され、Tabwidth
が8
に設定されています。printer.UseSpaces
: このフラグは、インデントにスペースを使用することを示唆しますが、printer.TabIndent
と組み合わせることで、gofmt
のデフォルトであるタブインデント(タブ幅8)をエミュレートする挙動になります。Goのgofmt
は、デフォルトでタブインデントを使用し、タブ幅は8です。printer.TabIndent
: インデントにタブ文字を使用することを示します。Tabwidth: 8
: タブ文字の幅を8文字として扱います。これはgofmt
の標準的なタブ幅です。
- この明示的な
printer.Config
をconfig.Fprint(&buf, fset, f)
に渡すことで、godoc
のプレイグラウンドでのコードフォーマットが、gofmt
の標準的な挙動と完全に一致するようになります。
- コミット前のコードでは、
この変更は、godoc
のプレイグラウンドが、Go言語の公式ツールとして、gofmt
が提供する一貫したコードフォーマット体験をユーザーに提供することを保証するためのものです。
コアとなるコードの変更箇所
--- a/src/cmd/godoc/play.go
+++ b/src/cmd/godoc/play.go
@@ -59,7 +59,11 @@ func gofmt(body string) (string, error) {
}\n \tast.SortImports(fset, f)\n \tvar buf bytes.Buffer\n-\terr = printer.Fprint(&buf, fset, f)\n+\tconfig := printer.Config{\n+\t\tMode: printer.UseSpaces | printer.TabIndent,\n+\t\tTabwidth: 8,\n+\t}\n+\terr = config.Fprint(&buf, fset, f)\n \tif err != nil {\n \t\treturn \"\", err\n \t}\n```
## コアとなるコードの解説
変更は`src/cmd/godoc/play.go`ファイルの`gofmt`関数内で行われています。この関数は、Goのプレイグラウンドでユーザーが入力したコードをフォーマットする役割を担っています。
* **変更前**:
```go
err = printer.Fprint(&buf, fset, f)
```
この行では、`go/printer`パッケージの`Fprint`関数が直接呼び出されていました。`printer.Fprint`は、`printer.Config`を引数に取らないオーバーロードを使用した場合、デフォルトのフォーマット設定でコードを整形します。このデフォルト設定が、`gofmt`が使用する標準的な設定と異なっていたため、フォーマット結果に差異が生じていました。
* **変更後**:
```go
config := printer.Config{
Mode: printer.UseSpaces | printer.TabIndent,
Tabwidth: 8,
}
err = config.Fprint(&buf, fset, f)
```
変更後では、まず`printer.Config`型の変数`config`が明示的に初期化されています。
* `Mode: printer.UseSpaces | printer.TabIndent`: ここで`printer.Mode`フラグが設定されています。`printer.UseSpaces`はスペースによるインデントを示唆しますが、`printer.TabIndent`と組み合わせることで、`gofmt`のデフォルトであるタブインデント(タブ幅8)をエミュレートする挙動になります。Goの`gofmt`は、デフォルトでタブインデントを使用します。
* `Tabwidth: 8`: タブ文字の幅を8文字として扱います。これも`gofmt`の標準的な設定です。
このように明示的に設定された`config`オブジェクトを、`config.Fprint(&buf, fset, f)`という形で`Fprint`メソッドに渡すことで、`godoc`のプレイグラウンドでのコードフォーマットが、`gofmt`の標準的なフォーマットルールに厳密に従うように修正されました。これにより、`godoc`のプレイグラウンドとローカルの`gofmt`ツールとの間で、コードフォーマットの一貫性が保証されるようになりました。
## 関連リンク
* Go言語公式ドキュメント: [https://go.dev/](https://go.dev/)
* `godoc`コマンドについて: [https://pkg.go.dev/cmd/godoc](https://pkg.go.dev/cmd/godoc)
* `gofmt`コマンドについて: [https://pkg.go.dev/cmd/gofmt](https://pkg.go.dev/cmd/gofmt)
* `go/ast`パッケージ: [https://pkg.go.dev/go/ast](https://pkg.go.dev/go/ast)
* `go/token`パッケージ: [https://pkg.go.dev/go/token](https://pkg.go.dev/go/token)
* `go/printer`パッケージ: [https://pkg.go.dev/go/printer](https://pkg.go.dev/go/printer)
* Go Playground: [https://go.dev/play/](https://go.dev/play/)
## 参考にした情報源リンク
* Go言語の公式ドキュメント(上記「関連リンク」に記載の各パッケージおよびコマンドのドキュメント)
* Go言語のソースコード(特に`src/cmd/gofmt/gofmt.go`や`src/go/printer/printer.go`など、`gofmt`の実装に関するファイル)
* Go言語のコミット履歴とコードレビューシステム(Gerrit): [https://go.dev/cl/6815081](https://go.dev/cl/6815081) (元の変更リスト)
* Go言語のIssueトラッカー(関連するバグ報告や議論がある場合)
* Stack OverflowやGoコミュニティの議論(`gofmt`の挙動や`go/printer`の使用方法に関する一般的な情報)
* Go言語のブログ記事やチュートリアル(`gofmt`や`godoc`の利用方法に関する一般的な情報)# [インデックス 14314] ファイルの概要
このコミットは、Go言語の公式ドキュメントツールである`godoc`のプレイグラウンド機能におけるコードフォーマットの挙動を修正するものです。具体的には、プレイグラウンドでコードをフォーマットする際に、標準の`gofmt`ツールと同じプリンタ設定を使用するように変更されています。これにより、`godoc`のプレイグラウンドで表示されるコードが、開発者がローカルで`gofmt`を実行した際と同じフォーマットになるよう統一されます。
## コミット
commit c1c136d0c4c2057f33f2ce66c7f9ed60e3c2548d Author: Andrew Gerrand adg@golang.org Date: Mon Nov 5 22:46:28 2012 +0100
cmd/godoc: use normal gofmt printer settings for playground fmt
R=gri
CC=golang-dev
https://golang.org/cl/6815081
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/c1c136d0c4c2057f33f2ce66c7f9ed60e3c2548d](https://github.com/golang/go/commit/c1c136d0c4c2057f33f2ce66c7f9ed60e3c2548d)
## 元コミット内容
cmd/godoc: use normal gofmt printer settings for playground fmt
R=gri CC=golang-dev https://golang.org/cl/6815081
## 変更の背景
Go言語には、コードの自動フォーマットを行うための標準ツール`gofmt`が存在します。`gofmt`は、Goのコードスタイルガイドラインに沿ってコードを整形し、一貫性のあるコードベースを維持するために広く利用されています。
`godoc`は、Goのソースコードからドキュメントを生成し、Webブラウザで閲覧可能にするツールです。この`godoc`には、Goのコードスニペットを実行できる「プレイグラウンド」機能が組み込まれています。ユーザーがプレイグラウンドでコードを入力し、フォーマットボタンを押すと、そのコードが整形されて表示されます。
このコミット以前は、`godoc`のプレイグラウンドにおけるコードフォーマットが、標準の`gofmt`ツールが使用する設定と完全に一致していませんでした。これにより、ユーザーが`godoc`のプレイグラウンドでコードをフォーマットした結果と、ローカルで`gofmt`を実行した結果との間に差異が生じる可能性がありました。このような不一致は、ユーザーエクスペリエンスを損ない、Goコードの標準的なフォーマットに関する混乱を招く恐れがありました。
この変更の背景には、Goエコシステム全体でコードフォーマットの一貫性を保ち、開発者がどの環境でコードを扱っても同じ整形結果が得られるようにするという、Goプロジェクトの強い哲学があります。`gofmt`はGo言語の設計思想の一部であり、その挙動は予測可能でなければなりません。`godoc`のプレイグラウンドもこの一貫性に従うべきであるという判断から、この修正が導入されました。
## 前提知識の解説
このコミットを理解するためには、以下のGo言語のツールとパッケージに関する知識が必要です。
* **`godoc`**: Go言語のソースコードからドキュメントを生成し、Webサーバーとして提供するツールです。Goの標準ライブラリのドキュメントも`godoc`によって生成されています。また、コードスニペットをブラウザ上で実行できる「プレイグラウンド」機能も提供します。
* **`gofmt`**: Go言語のソースコードを自動的にフォーマットするツールです。Goのコードスタイルガイドラインに厳密に従い、インデント、スペース、改行などを整形します。Goコミュニティでは、`gofmt`によってフォーマットされたコードが標準とされています。
* **`go/ast`パッケージ**: Goのソースコードを抽象構文木(Abstract Syntax Tree, AST)として表現するためのデータ構造と関数を提供します。`gofmt`やコンパイラ、リンターなどのツールは、まずソースコードをASTにパースし、そのASTを操作することで様々な処理を行います。
* **`go/token`パッケージ**: Goのソースコード内のトークン(キーワード、識別子、演算子など)の位置情報(ファイル、行番号、列番号など)を管理するための型と関数を提供します。`token.FileSet`は、複数のファイルのトークン位置情報を効率的に管理するための構造体です。
* **`go/printer`パッケージ**: `go/ast`パッケージで表現されたASTを、Goのソースコードとして整形して出力するための機能を提供します。`gofmt`はこのパッケージを利用してコードを整形しています。
* **`printer.Config`**: `go/printer`パッケージでコードを整形する際の詳細な設定を定義するための構造体です。インデントの種類(スペースかタブか)、タブ幅、コメントの扱いなど、様々なフォーマットオプションを指定できます。
* **`printer.Mode`**: `printer.Config`内で使用されるフラグのセットで、フォーマットの挙動を制御します。
* `printer.UseSpaces`: インデントにタブではなくスペースを使用することを示します。
* `printer.TabIndent`: インデントにタブを使用することを示します。
* `printer.Fprint`関数: `printer.Config`構造体を受け取り、指定された設定でASTを整形して`io.Writer`に書き出す関数です。
* **`bytes.Buffer`**: `bytes`パッケージに含まれる型で、可変長のバイトシーケンスをメモリ上で効率的に操作するためのバッファを提供します。このコミットでは、フォーマットされたコードの出力先として使用されています。
* **`ast.SortImports`**: `go/ast`パッケージの関数で、Goソースコードのインポート宣言を標準的な順序にソートします。`gofmt`もこの機能を利用しています。
## 技術的詳細
Go言語のコードフォーマットは、`gofmt`ツールによって行われますが、その内部では`go/ast`パッケージと`go/printer`パッケージが重要な役割を担っています。
1. **パース**: まず、入力されたGoのソースコードは`go/parser`パッケージ(直接は示されていませんが、`ast.SortImports`や`printer.Fprint`が`*ast.File`と`*token.FileSet`を引数に取ることから、コードがASTにパースされていることがわかります)によって抽象構文木(AST)にパースされます。このASTは、コードの構造を木構造で表現したものです。
2. **インポートのソート**: パースされたASTに対して、`ast.SortImports(fset, f)`が呼び出されます。これは、Goのソースコード内のインポート宣言(`import (...)`ブロック)を、標準的な`gofmt`のルールに従ってアルファベット順にソートし、グループ化する処理です。これにより、インポートの順序に関する一貫性が保たれます。
3. **コードの整形と出力**: ソートされたASTは、`go/printer`パッケージを使用して整形され、最終的なGoのソースコードとして出力されます。
* コミット前のコードでは、`printer.Fprint(&buf, fset, f)`が直接呼び出されていました。この`printer.Fprint`関数は、`printer.Config`を明示的に指定しない場合、デフォルトのプリンタ設定を使用します。当時のデフォルト設定が、`gofmt`の標準設定と完全に一致していなかった可能性があります。特に、タブとスペースの扱い、タブ幅などが異なっていたことが推測されます。
* コミット後のコードでは、`printer.Config`構造体が明示的に作成され、`Mode`フィールドに`printer.UseSpaces | printer.TabIndent`が設定され、`Tabwidth`が`8`に設定されています。
* `printer.UseSpaces`: このフラグは、インデントにスペースを使用することを示唆しますが、`printer.TabIndent`と組み合わせることで、`gofmt`のデフォルトであるタブインデント(タブ幅8)をエミュレートする挙動になります。Goの`gofmt`は、デフォルトでタブインデントを使用し、タブ幅は8です。
* `printer.TabIndent`: インデントにタブ文字を使用することを示します。
* `Tabwidth: 8`: タブ文字の幅を8文字として扱います。これは`gofmt`の標準的なタブ幅です。
* この明示的な`printer.Config`を`config.Fprint(&buf, fset, f)`に渡すことで、`godoc`のプレイグラウンドでのコードフォーマットが、`gofmt`の標準的な挙動と完全に一致するようになります。
この変更は、`godoc`のプレイグラウンドが、Go言語の公式ツールとして、`gofmt`が提供する一貫したコードフォーマット体験をユーザーに提供することを保証するためのものです。
## コアとなるコードの変更箇所
```diff
--- a/src/cmd/godoc/play.go
+++ b/src/cmd/godoc/play.go
@@ -59,7 +59,11 @@ func gofmt(body string) (string, error) {
}\n \tast.SortImports(fset, f)\n \tvar buf bytes.Buffer\n-\terr = printer.Fprint(&buf, fset, f)\n+\tconfig := printer.Config{\n+\t\tMode: printer.UseSpaces | printer.TabIndent,\n+\t\tTabwidth: 8,\n+\t}\n+\terr = config.Fprint(&buf, fset, f)\n \tif err != nil {\n \t\treturn \"\", err\n \t}\n```
## コアとなるコードの解説
変更は`src/cmd/godoc/play.go`ファイルの`gofmt`関数内で行われています。この関数は、Goのプレイグラウンドでユーザーが入力したコードをフォーマットする役割を担っています。
* **変更前**:
```go
err = printer.Fprint(&buf, fset, f)
```
この行では、`go/printer`パッケージの`Fprint`関数が直接呼び出されていました。`printer.Fprint`は、`printer.Config`を引数に取らないオーバーロードを使用した場合、デフォルトのフォーマット設定でコードを整形します。このデフォルト設定が、`gofmt`が使用する標準的な設定と異なっていたため、フォーマット結果に差異が生じていました。
* **変更後**:
```go
config := printer.Config{
Mode: printer.UseSpaces | printer.TabIndent,
Tabwidth: 8,
}
err = config.Fprint(&buf, fset, f)
```
変更後では、まず`printer.Config`型の変数`config`が明示的に初期化されています。
* `Mode: printer.UseSpaces | printer.TabIndent`: ここで`printer.Mode`フラグが設定されています。`printer.UseSpaces`はスペースによるインデントを示唆しますが、`printer.TabIndent`と組み合わせることで、`gofmt`のデフォルトであるタブインデント(タブ幅8)をエミュレートする挙動になります。Goの`gofmt`は、デフォルトでタブインデントを使用します。
* `Tabwidth: 8`: タブ文字の幅を8文字として扱います。これも`gofmt`の標準的な設定です。
このように明示的に設定された`config`オブジェクトを、`config.Fprint(&buf, fset, f)`という形で`Fprint`メソッドに渡すことで、`godoc`のプレイグラウンドでのコードフォーマットが、`gofmt`の標準的なフォーマットルールに厳密に従うように修正されました。これにより、`godoc`のプレイグラウンドとローカルの`gofmt`ツールとの間で、コードフォーマットの一貫性が保証されるようになりました。
## 関連リンク
* Go言語公式ドキュメント: [https://go.dev/](https://go.dev/)
* `godoc`コマンドについて: [https://pkg.go.dev/cmd/godoc](https://pkg.go.dev/cmd/godoc)
* `gofmt`コマンドについて: [https://pkg.go.dev/cmd/gofmt](https://pkg.go.dev/cmd/gofmt)
* `go/ast`パッケージ: [https://pkg.go.dev/go/ast](https://pkg.go.dev/go/ast)
* `go/token`パッケージ: [https://pkg.go.dev/go/token](https://pkg.go.dev/go/token)
* `go/printer`パッケージ: [https://pkg.go.dev/go/printer](https://pkg.go.dev/go/printer)
* Go Playground: [https://go.dev/play/](https://go.dev/play/)
## 参考にした情報源リンク
* Go言語の公式ドキュメント(上記「関連リンク」に記載の各パッケージおよびコマンドのドキュメント)
* Go言語のソースコード(特に`src/cmd/gofmt/gofmt.go`や`src/go/printer/printer.go`など、`gofmt`の実装に関するファイル)
* Go言語のコミット履歴とコードレビューシステム(Gerrit): [https://go.dev/cl/6815081](https://go.dev/cl/6815081) (元の変更リスト)
* Go言語のIssueトラッカー(関連するバグ報告や議論がある場合)
* Stack OverflowやGoコミュニティの議論(`gofmt`の挙動や`go/printer`の使用方法に関する一般的な情報)
* Go言語のブログ記事やチュートリアル(`gofmt`や`godoc`の利用方法に関する一般的な情報)