package stone type Color uint8 const ( ColorBackground Color = 0x0 ColorSelection Color = 0x1 ColorForeground Color = 0x2 ColorApplication Color = 0x3 ) type Style uint8 const ( StyleNormal Style = iota StyleBold Style = iota >> 1 StyleItalic StyleBoldItalic Style = StyleBold | StyleItalic ) type Cell struct { color Color style Style content rune } func (cell Cell) Color (color Color) { color = cell.color return } func (cell Cell) Style (style Style) { style = cell.style return } func (cell Cell) Rune () (content rune) { content = cell.content return } type Buffer struct { content []Cell width int height int Dot struct { X int Y int } } func (buffer *Buffer) isOutOfBounds (x, y int) (outOfBounds bool) { outOfBounds = x < 0 || y < 0 || x >= buffer.width || y >= buffer.height return } func (buffer *Buffer) Size () (width, height int) { width = buffer.width height = buffer.height return } func (buffer *Buffer) SetSize (width, height int) { if width < 0 || height < 0 { return } buffer.width = width buffer.height = height buffer.content = make([]Cell, width * height) } func (buffer *Buffer) Cell (x, y int) (cell Cell) { if buffer.isOutOfBounds(x, y) { return } cell = buffer.content[x + y * buffer.width] return } func (buffer *Buffer) SetColor (x, y int, color Color) { if buffer.isOutOfBounds(x, y) { return } buffer.content[x + y * buffer.width].color = color } func (buffer *Buffer) SetStyle (x, y int, style Style) { if buffer.isOutOfBounds(x, y) { return } buffer.content[x + y * buffer.width].style = style } func (buffer *Buffer) SetRune (x, y int, content rune) { if buffer.isOutOfBounds(x, y) { return } buffer.content[x + y * buffer.width].content = content } func (buffer *Buffer) Write (bytes []byte) (bytesWritten int, err error) { text := string(bytes) bytesWritten = len(bytes) for _, character := range text { buffer.SetRune(buffer.Dot.X, buffer.Dot.Y, character) buffer.Dot.X ++ if buffer.Dot.X > buffer.width { break } } return } func (buffer *Buffer) ResetDot () { buffer.Dot.X = 0 buffer.Dot.Y = 0 } type DamageBuffer struct { Buffer clean []bool } func (buffer *DamageBuffer) SetSize (width, height int) { if width < 0 || height < 0 { return } buffer.Buffer.SetSize(width, height) buffer.clean = make([]bool, width * height) } func (buffer *DamageBuffer) SetColor (x, y int, color Color) { if buffer.isOutOfBounds(x, y) { return } index := x + y * buffer.width buffer.clean[index] = buffer.content[index].color == color buffer.Buffer.SetColor(x, y, color) } func (buffer *DamageBuffer) SetStyle (x, y int, style Style) { if buffer.isOutOfBounds(x, y) { return } index := x + y * buffer.width buffer.clean[index] = buffer.content[index].style == style buffer.Buffer.SetStyle(x, y, style) } func (buffer *DamageBuffer) SetRune (x, y int, content rune) { if buffer.isOutOfBounds(x, y) { return } index := x + y * buffer.width buffer.clean[index] = buffer.content[index].content == content buffer.Buffer.SetRune(x, y, content) } func (buffer *DamageBuffer) Write (bytes []byte) (bytesWritten int, err error) { text := string(bytes) bytesWritten = len(bytes) for _, character := range text { buffer.SetRune(buffer.Dot.X, buffer.Dot.Y, character) buffer.Dot.X ++ if buffer.Dot.X > buffer.width { break } } return } func (buffer *DamageBuffer) Clean (x, y int) (clean bool) { if buffer.isOutOfBounds(x, y) { return } clean = buffer.clean[x + y * buffer.width] return } func (buffer *DamageBuffer) MarkClean (x, y int) { if buffer.isOutOfBounds(x, y) { return } buffer.clean[x + y * buffer.width] = true }