パッケージ textbox

タイピングゲームを作成するために,textboxというパッケージを利用します.このパッケージは田中が作成したものです(Go言語組み込みのパッケージではありません).

仕様

パッケージtextboxの仕様は次の通りです.

PACKAGE

package textbox

import "./textbox"

textboxパッケージは,VT100互換のキャラクタ端末上の矩形領域にテキストを表示するライブラリです.TextBoxは,キャラクタ端末上の矩形領域にテキストを表示する抽象データ型です.生成,領域の移 動,領域のクリア,領域への文字の挿入,領域への文字列の挿入の機能を持ちます.パッケージには,型TextBoxのほかに,ディスプレー画面全体をクリアする関数,ディスプレー上の位置を指定してカ ーソルを移動する関数が定義されています.ディスプレー中の位置や,矩形領域中の位置は左上を原点(0,0)とする座標で指定します.1行1カラ ム目が(0,0),n行mカラム目が(m-1,n-1)です.

注意:WindowsのコマンドプロンプトはVT100互換ではないので(エスケープシーケンスが使えないので),このパッケージは利用できません.

FUNCTIONS

func Clear()

画面全体をクリアする.

func Move(x int, y int)

ディスプレー上の指定された位置にカーソルを移動する.

y+1行 x+1カラムにカーソルを移動.

x,yはディスプレーの大きさ(W,H)未満でなければならない.(0 <= x < W, 0<= y < H)

TYPES

type TextBox struct {

// contains filtered or unexported fields

}

func New(x, y, w, h int) (tb *TextBox)

ディスプレー上の位置が(x,y)で,大きさがw列h行のTextBoxを生成する.カーソル位置を(0,0)とす る.

位置はディスプレーの大きさ未満でなければならない.(0 <= x < W, 0<= y < H)

ディスプレーの大きさ(H,W)内に収まる位置と大きさでなければならない.(0 < w+x <=W, 0< h+y <= H)

func (tb *TextBox) Clear()

テキストボックスをクリアする(空白文字で埋める).

func (tb *TextBox) Move(x int, y int)

カーソルをテキストボックス内のx列y行へ移動する.

x,yはtbの大きさ(w,h)未満でなければならない.(0 <= x < w, 0<= y < h)

func (tb *TextBox) PutRune(c rune)

カーソル位置に文字c(UTF-8エンコードされたUnicode文字,日本語可)を表示する.

文字の表示に2カラム占める場合は,1カラムだけtbの領域からはみ出ることがある.

カーソルは次のカラムへ移動する.

(行末なら自動的に改行し先頭カラムへ,最終行の行末なら先頭行先頭カラムへ移動する)

func (tb *TextBox) Putc(c byte)

カーソル位置に文字c(ASCII文字)を表示する.

カーソルは次のカラムへ移動する.

(行末なら自動的に改行し先頭カラムへ,最終行の行末なら先頭行先頭カラムへ移動する)

func (tb *TextBox) Puts(s string)

カーソル位置に文字列を表示する(日本語可).

カーソルは文字列を表示した次のカラムへ移動する.

文字列内では改行されない.(手抜き ^^;)

ソースコード

演習を進めるのに,ソースコードの中身を理解する必要はありません.仕様だけを理解すれば,textboxをインポートして利用できます.パッケージtextboxのソースコードは参考として以下に示します.

  1. /*
  2. textboxパッケージは,VT100互換のキャラクタ端末上の矩形領域にテキストを表示するライブラリです.TextBoxは,キャラクタ端末上の矩形領域にテキストを表示する抽象データ型です.生成,領域の移 動,領域のクリア,領域への文字の挿入,領域への文字列の挿入の機能を持ちます.パッケージには,型TextBoxのほかに,ディスプレー画面全体をクリアする関数,ディスプレー上の位置を指定してカ ーソルを移動する関数が定義されています.ディスプレー中の位置や,矩形領域中の位置は左上を原点(0,0)とする座標で指定します.1行1カラ ム目が(0,0),n行mカラム目が(m-1,n-1)です.
  3. */
  4. package textbox
  5. import "fmt"
  6. const esc = 0x1B
  7. type TextBox struct {
  8. x,y,w,h int // 位置と大きさ
  9. cx,cy int // TextBox中のカーソルの位置
  10. }
  11. // ディスプレー上の位置が(x,y)で,大きさがw列h行のTextBoxを生成する.カーソル位置を(0,0)とする.
  12. // 位置はディスプレーの大きさ未満でなければならない. (0 <= x < W, 0<= y < H)
  13. // ディスプレーの大きさ(H,W)内に収まる位置と大きさでなければならない. (0 < w+x <=W, 0< h+y <= H)
  14. func New(x, y, w, h int) (tb* TextBox) {
  15. tb = &TextBox{x,y,w,h,0,0}
  16. return
  17. }
  18. // カーソルをテキストボックス内のx列y行へ移動する.
  19. // x,yはtbの大きさ(w,h)未満でなければならない. (0 <= x < W, 0<= y < H)
  20. func (tb *TextBox) Move(x int, y int) {
  21. tb.cx = x
  22. tb.cy = y
  23. fmt.Printf("%c[%d;%dH", esc, tb.y+tb.cy+1, tb.x+tb.cx+1)
  24. }
  25. // テキストボックスをクリアする(空白文字で埋める).
  26. // カーソルは(0,0)に移動する.
  27. func (tb *TextBox) Clear() {
  28. s := make([]byte,tb.w)
  29. for i:=0; i< tb.w; i++ {
  30. s[i] = ' '
  31. }
  32. for i:=0; i < tb.h; i++ {
  33. fmt.Printf("%c[%d;%df%s", esc, tb.y+i+1, tb.x+1, string(s))
  34. }
  35. tb.Move(0,0)
  36. }
  37. // カーソル位置に文字c(ASCII文字)を表示する.
  38. // カーソルは次のカラムへ移動する
  39. // 行末なら自動的に改行し先頭カラムへ移動する.
  40. // 最終行の行末なら先頭行先頭カラムへ移動する.
  41. func (tb *TextBox) Putc(c byte) {
  42. fmt.Printf("%c[%d;%df%c", esc, tb.y+tb.cy+1, tb.x+tb.cx+1, c)
  43. tb.Move((tb.cx+1)%tb.w,(tb.cy+(tb.cx+1)/tb.w)%tb.h)
  44. Move(0,999) // カーソルを目立たない位置へ
  45. }
  46. // カーソル位置に文字c(UTF-8エンコードされたUnicode文字,日本語可)を表示する.
  47. // 文字が2カラム占める場合は,1カラムだけtbの領域からはみ出る.
  48. // カーソルは次のカラムへ移動する.
  49. func (tb *TextBox) PutRune(c rune) {
  50. fmt.Printf("%c[%d;%df%c", esc, tb.y+tb.cy+1, tb.x+tb.cx+1, c)
  51. col := 1
  52. if c > 0x7F {col = 2} // ASCIIコードより大きなコードは2カラム占めるとしている(手抜きです^^;)
  53. tb.Move((tb.cx+col)%tb.w,(tb.cy+(tb.cx+col)/tb.w)%tb.h)
  54. Move(0,999) // カーソルを目立たない位置へ
  55. }
  56. // カーソル位置に文字列を表示する(日本語可).
  57. // カーソルは文字列を表示した次のカラムへ移動する.
  58. // 文字列内では改行されない.(手抜き ^^;)
  59. func (tb *TextBox) Puts(s string) {
  60. fmt.Printf("%c[%d;%df%s", esc, tb.y+tb.cy+1, tb.x+tb.cx+1, s)
  61. col := 0
  62. for _,e := range []rune(s) {
  63. if e > 0x7F {col += 2} else {col++}
  64. }
  65. tb.Move((tb.cx+col)%tb.w,(tb.cy+(tb.cx+col)/tb.w)%tb.h)
  66. Move(0,999) // カーソルを目立たない位置へ
  67. }
  68. // ディスプレー上の指定された位置にカーソルを移動する.
  69. // y+1行 x+1カラムにカーソルを移動.
  70. // x,yはディスプレーの大きさ(W,H)未満でなければならない. (0 <= x < W, 0<= y < H)
  71. func Move(x int, y int) {
  72. fmt.Printf("%c[%d;%dH", esc, y+1, x+1)
  73. }
  74. // 画面全体をクリアする.
  75. func Clear() {
  76. fmt.Printf("%c[2J", esc)
  77. }

解説

VT100エスケープシーケンスの利用

  • textboxパッケージはVT100互換の端末エミュレータ上で実行されることを想定しています.カーソル移動と画面のクリアにVT100のエスケープシーケンスを利用しています.x行yカラムにカーソルを移動するエスケープシーケンスは ESC[x;yH] (81行目など), 画面をクリアするエスケープシーケンスは ESC[2J (86行目)です.

スライス

  • スライスは配列をラップした参照型です.配列を扱うGo言語のプログラムでは,配列そのままではなくスライスが多用されます.
  • スライスは参照型なので,別のスライスに代入したときは,双方が同じ配列を参照します.たとえば関数がスライスを引数として取るとき,関数内でスライスの要素に変更を加えると,ポインタ渡しのように関数の呼び元からも変更内容が参照できます.
  • スライスは,組込み関数makeで,型と大きさ(と容量)を指定して生成します.33行目では,s:=make([]byte,tb.w)によって,byte型の要素をもつ長さがtb.wのスライスを生成してsに代入しています.要素へのアクセスは配列と同様にs[i]とすることで i 番目の要素のアクセスすることができます.
  • スライスに関する詳細は言語仕様のスライス型スライスを参照してください.
  • 文字列は,byteのスライスまたはruneのスライスに変換できます.文字列の値を []byte型へ変換することで,文字列のバイトデータを要素として持つスライスが得られます.また,文字列の値を[]rune型へ変換することで,文字列の各Unicodeコードポイントを持つスライスが得られます.70行目では, []rune(s) によって文字列 s をruneのスライスに変換しています.
  • 変換に関する詳細は言語仕様を参照してください.

コメント

  • Go言語では,C++と同様に/* */ブロックコメント,および//行コメントが使用できます.
  • 基本は行コメントです.
  • ブロックコメントはパッケージコメント(1行目~3行目)として使われたり,コードをブロック単位で無効化するのに役立ちます.

godoc

  • go言語には,godocというツール(Webサーバ機能ももつ)があります.
  • godocは,Go言語のソースファイルから,そのパッケージに関するドキュメントを抽出します.
  • 宣言の前に空行を挟まずに記述されているコメントが,その宣言の説明となります.また,パッケージ文の前に置かれたコメント(パッケージコメント)がパッケージの説明となります.
  • 上記の仕様は,上記のソースコードからgodocで抽出したドキュメントです.