github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/text/tabwriter/tabwriter.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // tabwriterパッケージは、入力のタブ区切りの列を適切に整列したテキストに変換する
     6  // 書き込みフィルタ(tabwriter.Writer)を実装します。
     7  //
     8  // このパッケージは、http://nickgravgaard.com/elastictabstops/index.html で
     9  // 説明されているElastic Tabstopsアルゴリズムを使用しています。
    10  //
    11  // text/tabwriterパッケージは凍結されており、新しい機能は受け入れていません。
    12  package tabwriter
    13  
    14  import (
    15  	"github.com/shogo82148/std/io"
    16  )
    17  
    18  // Writerは、入力のタブ区切りの列の周囲にパディングを挿入して、
    19  // 出力でそれらを整列させるフィルタです。
    20  //
    21  // Writerは、入力バイトを水平('\t')または垂直('\v')のタブ、
    22  // 改行('\n')またはフォームフィード('\f')文字で終了するセルとして
    23  // 扱います。改行とフォームフィードの両方が行の区切りとして機能します。
    24  //
    25  // 連続する行のタブで終了するセルは列を構成します。Writerは、
    26  // 列内のすべてのセルが同じ幅になるように必要に応じてパディングを挿入し、
    27  // 事実上、列を整列させます。すべての文字が同じ幅を持つと仮定していますが、
    28  // タブについてはタブ幅を指定する必要があります。列のセルはタブで終了する必要があり、
    29  // タブで区切られるべきではありません:行の終わりの非タブで終了する末尾のテキストは
    30  // セルを形成しますが、そのセルは整列した列の一部ではありません。
    31  // 例えば、この例では(ここで | は水平タブを表します):
    32  //
    33  //	aaaa|bbb|d
    34  //	aa  |b  |dd
    35  //	a   |
    36  //	aa  |cccc|eee
    37  //
    38  // bとcは別々の列にあります(b列は連続していません)。
    39  // dとeは全く列にありません(終端のタブがなく、列も連続していません)。
    40  //
    41  // Writerは、すべてのUnicodeコードポイントが同じ幅を持つと仮定しています。
    42  // これは、一部のフォントでは真ではないかもしれません、または文字列が結合文字を含んでいる場合。
    43  //
    44  // [DiscardEmptyColumns] が設定されている場合、垂直(または「ソフト」)タブによって
    45  // 完全に終了する空の列は破棄されます。水平(または「ハード」)タブで終了する列は
    46  // このフラグの影響を受けません。
    47  //
    48  // WriterがHTMLをフィルタリングするように設定されている場合、HTMLタグとエンティティは
    49  // そのまま通過します。タグとエンティティの幅は、フォーマットの目的でゼロ(タグ)と
    50  // 一(エンティティ)とみなされます。
    51  //
    52  // テキストのセグメントは、[Escape] 文字でそれを括ることでエスケープできます。
    53  // tabwriterはエスケープされたテキストセグメントをそのまま通過させます。
    54  // 特に、セグメント内のタブや改行は解釈しません。[StripEscape] フラグが設定されている場合、
    55  // Escape文字は出力から削除されます。それ以外の場合、それらもそのまま通過します。
    56  // フォーマットの目的で、エスケープされたテキストの幅は常にEscape文字を除いて計算されます。
    57  //
    58  // フォームフィード文字は改行のように機能しますが、現在の行のすべての列も終了します
    59  // (事実上 [Writer.Flush] を呼び出します)。次の行のタブで終了するセルは新しい列を開始します。
    60  // HTMLタグ内やエスケープされたテキストセグメント内で見つからない限り、
    61  // フォームフィード文字は出力で改行として表示されます。
    62  //
    63  // Writerは、適切な行の間隔が将来の行のセルに依存する可能性があるため、
    64  // 入力を内部的にバッファリングする必要があります。クライアントは、
    65  // [Writer.Write] の呼び出しが終了したらFlushを呼び出す必要があります。
    66  type Writer struct {
    67  	// configuration
    68  	output   io.Writer
    69  	minwidth int
    70  	tabwidth int
    71  	padding  int
    72  	padbytes [8]byte
    73  	flags    uint
    74  
    75  	// current state
    76  	buf     []byte
    77  	pos     int
    78  	cell    cell
    79  	endChar byte
    80  	lines   [][]cell
    81  	widths  []int
    82  }
    83  
    84  // これらのフラグを使用して、フォーマットを制御できます。
    85  const (
    86  	// HTMLタグを無視し、エンティティ('&'で始まり';'で終わる)を単一の文字(幅=1)として扱います。
    87  	FilterHTML uint = 1 << iota
    88  
    89  	// エスケープされたテキストセグメントを括るエスケープ文字を削除します。
    90  	// テキストと一緒に変更せずにそれらを通過させる代わりに。
    91  	StripEscape
    92  
    93  	// セルの内容を右揃えに強制します。
    94  	// デフォルトは左揃えです。
    95  	AlignRight
    96  
    97  	// 空の列を、最初から入力に存在しなかったかのように扱います。
    98  	DiscardEmptyColumns
    99  
   100  	// 常にタブをインデント列(つまり、左側の先頭の空セルのパディング)に使用します。
   101  	// padcharに関係なく。
   102  	TabIndent
   103  
   104  	// 列の間に垂直バー ('|') を印刷します(フォーマット後)。
   105  	// 破棄された列はゼロ幅の列として表示されます ("||")。
   106  	Debug
   107  )
   108  
   109  // [Writer] は、Initへの呼び出しで初期化する必要があります。最初のパラメータ(output)は
   110  // フィルタ出力を指定します。残りのパラメータはフォーマットを制御します:
   111  //
   112  //	minwidth	パディングを含む最小セル幅
   113  //	tabwidth	タブ文字の幅(相当するスペースの数)
   114  //	padding		セルの幅を計算する前にセルに追加されるパディング
   115  //	padchar		パディングに使用されるASCII文字
   116  //			もし padchar == '\t' なら、Writerはフォーマットされた出力の
   117  //			'\t'の幅がtabwidthであると仮定し、align_leftに関係なく
   118  //			セルは左揃えになります
   119  //			(正確に見える結果のために、tabwidthは結果を表示するビューアの
   120  //			タブ幅に対応している必要があります)
   121  //	flags		フォーマット制御
   122  func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer
   123  
   124  // テキストセグメントをエスケープするには、Escape文字でそれを括ります。
   125  // 例えば、この文字列 "Ignore this tab: \xff\t\xff" のタブはセルを終了せず、
   126  // フォーマットの目的で幅一の単一文字を構成します。
   127  //
   128  // 値0xffは、有効なUTF-8シーケンスには現れないため選ばれました。
   129  const Escape = '\xff'
   130  
   131  // [Writer.Write] の最後の呼び出し後にFlushを呼び出す必要があります。これにより、
   132  // [Writer] にバッファリングされたデータがすべて出力に書き込まれます。終了時に不完全な
   133  // エスケープシーケンスは、フォーマットの目的で完全と見なされます。
   134  func (b *Writer) Flush() error
   135  
   136  // Writeは、bufをライターbに書き込みます。
   137  // 返されるエラーは、基礎となる出力ストリームへの書き込み中に遭遇したものだけです。
   138  func (b *Writer) Write(buf []byte) (n int, err error)
   139  
   140  // NewWriterは新しい [Writer] を割り当てて初期化します。
   141  // パラメータはInit関数と同じです。
   142  func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer