mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
Implementing canvas functionality.
Done here: - adding helper library which determines area from size and vice versa. - fixing an off-by-one bug related to area sizes. - allowing overwrite of cell options by passing an existing cell.Options instance. - implementing canvas and its tests.
This commit is contained in:
parent
59e1bd6472
commit
dc1f2c5a29
23
area/area.go
Normal file
23
area/area.go
Normal file
@ -0,0 +1,23 @@
|
||||
// Package area provides functions working with image areas.
|
||||
package area
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
)
|
||||
|
||||
// Size returns the size of the provided area.
|
||||
func Size(area image.Rectangle) image.Point {
|
||||
return image.Point{
|
||||
area.Dx(),
|
||||
area.Dy(),
|
||||
}
|
||||
}
|
||||
|
||||
// FromSize returns the corresponding area for the provided size.
|
||||
func FromSize(size image.Point) (image.Rectangle, error) {
|
||||
if size.X < 0 || size.Y < 0 {
|
||||
return image.Rectangle{}, fmt.Errorf("cannot convert zero or negative size to an area, got: %+v", size)
|
||||
}
|
||||
return image.Rect(0, 0, size.X, size.Y), nil
|
||||
}
|
104
area/area_test.go
Normal file
104
area/area_test.go
Normal file
@ -0,0 +1,104 @@
|
||||
package area
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
)
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
area image.Rectangle
|
||||
want image.Point
|
||||
}{
|
||||
{
|
||||
desc: "zero area",
|
||||
area: image.Rect(0, 0, 0, 0),
|
||||
want: image.Point{0, 0},
|
||||
},
|
||||
{
|
||||
desc: "1-D on X axis",
|
||||
area: image.Rect(0, 0, 1, 0),
|
||||
want: image.Point{1, 0},
|
||||
},
|
||||
{
|
||||
desc: "1-D on Y axis",
|
||||
area: image.Rect(0, 0, 0, 1),
|
||||
want: image.Point{0, 1},
|
||||
},
|
||||
{
|
||||
desc: "area with a single cell",
|
||||
area: image.Rect(0, 0, 1, 1),
|
||||
want: image.Point{1, 1},
|
||||
},
|
||||
{
|
||||
desc: "a rectangle",
|
||||
area: image.Rect(0, 0, 2, 3),
|
||||
want: image.Point{2, 3},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got := Size(tc.area)
|
||||
if diff := pretty.Compare(tc.want, got); diff != "" {
|
||||
t.Errorf("Size => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromSize(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
size image.Point
|
||||
want image.Rectangle
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
desc: "negative size on X axis",
|
||||
size: image.Point{-1, 0},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "negative size on Y axis",
|
||||
size: image.Point{0, -1},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "zero size",
|
||||
},
|
||||
{
|
||||
desc: "1-D on X axis",
|
||||
size: image.Point{1, 0},
|
||||
want: image.Rect(0, 0, 1, 0),
|
||||
},
|
||||
{
|
||||
desc: "1-D on Y axis",
|
||||
size: image.Point{0, 1},
|
||||
want: image.Rect(0, 0, 0, 1),
|
||||
},
|
||||
{
|
||||
desc: "a rectangle",
|
||||
size: image.Point{2, 3},
|
||||
want: image.Rect(0, 0, 2, 3),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got, err := FromSize(tc.size)
|
||||
if (err != nil) != tc.wantErr {
|
||||
t.Fatalf("FromSize => unexpected error: %v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if diff := pretty.Compare(tc.want, got); diff != "" {
|
||||
t.Errorf("FromSize => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -2,10 +2,10 @@
|
||||
package canvas
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
|
||||
"github.com/mum4k/termdash/area"
|
||||
"github.com/mum4k/termdash/cell"
|
||||
"github.com/mum4k/termdash/terminalapi"
|
||||
)
|
||||
@ -13,6 +13,8 @@ import (
|
||||
// Canvas is where a widget draws its output for display on the terminal.
|
||||
type Canvas struct {
|
||||
// area is the area the buffer was created for.
|
||||
// Contains absolute coordinates on the target terminal, while the buffer
|
||||
// contains relative zero-based coordinates for this canvas.
|
||||
area image.Rectangle
|
||||
|
||||
// buffer is where the drawing happens.
|
||||
@ -20,20 +22,17 @@ type Canvas struct {
|
||||
}
|
||||
|
||||
// New returns a new Canvas with a buffer for the provided area.
|
||||
func New(area image.Rectangle) (*Canvas, error) {
|
||||
if area.Min.X < 0 || area.Min.Y < 0 || area.Max.X < 0 || area.Max.Y < 0 {
|
||||
return nil, fmt.Errorf("area cannot start or end on the negative axis, got: %+v", area)
|
||||
func New(ar image.Rectangle) (*Canvas, error) {
|
||||
if ar.Min.X < 0 || ar.Min.Y < 0 || ar.Max.X < 0 || ar.Max.Y < 0 {
|
||||
return nil, fmt.Errorf("area cannot start or end on the negative axis, got: %+v", ar)
|
||||
}
|
||||
size := image.Point{
|
||||
area.Dx() + 1,
|
||||
area.Dy() + 1,
|
||||
}
|
||||
b, err := cell.NewBuffer(size)
|
||||
|
||||
b, err := cell.NewBuffer(area.Size(ar))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Canvas{
|
||||
area: area,
|
||||
area: ar,
|
||||
buffer: b,
|
||||
}, nil
|
||||
}
|
||||
@ -57,8 +56,12 @@ func (c *Canvas) Clear() error {
|
||||
// Use the options to specify which attributes to modify, if an attribute
|
||||
// option isn't specified, the attribute retains its previous value.
|
||||
func (c *Canvas) SetCell(p image.Point, r rune, opts ...cell.Option) error {
|
||||
if area := c.buffer.Area(); !p.In(area) {
|
||||
return fmt.Errorf("cell at point %+v falls out of the canvas area %+v", p, area)
|
||||
ar, err := area.FromSize(c.buffer.Size())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.In(ar) {
|
||||
return fmt.Errorf("cell at point %+v falls out of the canvas area %+v", p, ar)
|
||||
}
|
||||
|
||||
cell := c.buffer[p.X][p.Y]
|
||||
@ -67,8 +70,35 @@ func (c *Canvas) SetCell(p image.Point, r rune, opts ...cell.Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyTo copies the content of the canvas onto the provided terminal.
|
||||
// Apply applies the canvas to the corresponding area of the terminal.
|
||||
// Guarantees to stay within limits of the area the canvas was created with.
|
||||
func (c *Canvas) Apply(t terminalapi.Terminal) error {
|
||||
return errors.New("unimplemented")
|
||||
termArea, err := area.FromSize(t.Size())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bufArea, err := area.FromSize(c.buffer.Size())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !bufArea.In(termArea) {
|
||||
return fmt.Errorf("the canvas area %+v doesn't fit onto the terminal %+v", bufArea, termArea)
|
||||
}
|
||||
|
||||
for col := range c.buffer {
|
||||
for row := range c.buffer[col] {
|
||||
cell := c.buffer[col][row]
|
||||
// The image.Point{0, 0} of this canvas isn't always exactly at
|
||||
// image.Point{0, 0} on the terminal.
|
||||
// Depends on area assigned by the container.
|
||||
offset := c.area.Min
|
||||
p := image.Point{col, row}.Add(offset)
|
||||
if err := t.SetCell(p, cell.Rune, cell.Opts); err != nil {
|
||||
return fmt.Errorf("terminal.SetCell(%+v) => error: %v", p, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
"github.com/mum4k/termdash/cell"
|
||||
"github.com/mum4k/termdash/terminal/faketerm"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
@ -34,20 +36,25 @@ func TestNew(t *testing.T) {
|
||||
area: image.Rect(0, 0, 0, -1),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "zero area is invalid",
|
||||
area: image.Rect(0, 0, 0, 0),
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
desc: "smallest valid size",
|
||||
area: image.Rect(0, 0, 0, 0),
|
||||
area: image.Rect(0, 0, 1, 1),
|
||||
wantSize: image.Point{1, 1},
|
||||
},
|
||||
{
|
||||
desc: "rectangular canvas 3 by 4",
|
||||
area: image.Rect(0, 0, 2, 3),
|
||||
area: image.Rect(0, 0, 3, 4),
|
||||
wantSize: image.Point{3, 4},
|
||||
},
|
||||
{
|
||||
desc: "non-zero based area",
|
||||
area: image.Rect(1, 1, 2, 3),
|
||||
wantSize: image.Point{2, 3},
|
||||
wantSize: image.Point{1, 2},
|
||||
},
|
||||
}
|
||||
|
||||
@ -68,3 +75,280 @@ func TestNew(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCellAndApply(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
termSize image.Point
|
||||
canvasArea image.Rectangle
|
||||
point image.Point
|
||||
r rune
|
||||
opts []cell.Option
|
||||
want cell.Buffer // Expected back buffer in the fake terminal.
|
||||
wantSetCellErr bool
|
||||
wantApplyErr bool
|
||||
}{
|
||||
{
|
||||
desc: "setting cell outside the designated area",
|
||||
termSize: image.Point{2, 2},
|
||||
canvasArea: image.Rect(0, 0, 1, 1),
|
||||
point: image.Point{0, 2},
|
||||
wantSetCellErr: true,
|
||||
},
|
||||
{
|
||||
desc: "sets a top-left corner cell",
|
||||
termSize: image.Point{3, 3},
|
||||
canvasArea: image.Rect(1, 1, 3, 3),
|
||||
point: image.Point{0, 0},
|
||||
r: 'X',
|
||||
want: cell.Buffer{
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New('X'),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "sets a top-right corner cell",
|
||||
termSize: image.Point{3, 3},
|
||||
canvasArea: image.Rect(1, 1, 3, 3),
|
||||
point: image.Point{1, 0},
|
||||
r: 'X',
|
||||
want: cell.Buffer{
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New('X'),
|
||||
cell.New(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "sets a bottom-left corner cell",
|
||||
termSize: image.Point{3, 3},
|
||||
canvasArea: image.Rect(1, 1, 3, 3),
|
||||
point: image.Point{0, 1},
|
||||
r: 'X',
|
||||
want: cell.Buffer{
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New('X'),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "sets a bottom-right corner cell",
|
||||
termSize: image.Point{3, 3},
|
||||
canvasArea: image.Rect(1, 1, 3, 3),
|
||||
point: image.Point{1, 1},
|
||||
r: 'Z',
|
||||
want: cell.Buffer{
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New('Z'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "sets cell options",
|
||||
termSize: image.Point{3, 3},
|
||||
canvasArea: image.Rect(1, 1, 3, 3),
|
||||
point: image.Point{1, 1},
|
||||
r: 'A',
|
||||
opts: []cell.Option{
|
||||
cell.BgColor(cell.ColorRed),
|
||||
},
|
||||
want: cell.Buffer{
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New('A', cell.BgColor(cell.ColorRed)),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "canvas size equals terminal size",
|
||||
termSize: image.Point{1, 1},
|
||||
canvasArea: image.Rect(0, 0, 1, 1),
|
||||
point: image.Point{0, 0},
|
||||
r: 'A',
|
||||
want: cell.Buffer{
|
||||
{
|
||||
cell.New('A'),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "terminal too small for the area",
|
||||
termSize: image.Point{1, 1},
|
||||
canvasArea: image.Rect(0, 0, 2, 2),
|
||||
point: image.Point{0, 0},
|
||||
r: 'A',
|
||||
wantApplyErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
c, err := New(tc.canvasArea)
|
||||
if err != nil {
|
||||
t.Fatalf("New => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
err = c.SetCell(tc.point, tc.r, tc.opts...)
|
||||
if (err != nil) != tc.wantSetCellErr {
|
||||
t.Errorf("SetCell => unexpected error: %v, wantSetCellErr: %v", err, tc.wantSetCellErr)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ft, err := faketerm.New(tc.termSize)
|
||||
if err != nil {
|
||||
t.Fatalf("faketerm.New => unexpected error: %v", err)
|
||||
}
|
||||
err = c.Apply(ft)
|
||||
if (err != nil) != tc.wantApplyErr {
|
||||
t.Errorf("Apply => unexpected error: %v, wantApplyErr: %v", err, tc.wantApplyErr)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
got := ft.BackBuffer()
|
||||
if diff := pretty.Compare(tc.want, got); diff != "" {
|
||||
t.Errorf("faketerm.BackBuffer => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClear(t *testing.T) {
|
||||
c, err := New(image.Rect(1, 1, 3, 3))
|
||||
if err != nil {
|
||||
t.Fatalf("New => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if err := c.SetCell(image.Point{0, 0}, 'X'); err != nil {
|
||||
t.Fatalf("SetCell => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
ft, err := faketerm.New(image.Point{3, 3})
|
||||
if err != nil {
|
||||
t.Fatalf("faketerm.New => unexpected error: %v", err)
|
||||
}
|
||||
// Set one cell outside of the canvas on the terminal.
|
||||
if err := ft.SetCell(image.Point{0, 0}, 'A'); err != nil {
|
||||
t.Fatalf("faketerm.SetCell => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if err := c.Apply(ft); err != nil {
|
||||
t.Fatalf("Apply => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
want := cell.Buffer{
|
||||
{
|
||||
cell.New('A'),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New('X'),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
}
|
||||
got := ft.BackBuffer()
|
||||
if diff := pretty.Compare(want, got); diff != "" {
|
||||
t.Errorf("faketerm.BackBuffer before Clear => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
|
||||
// Call Clear(), Apply() and verify that only the area belonging to the
|
||||
// canvas was cleared.
|
||||
if err := c.Clear(); err != nil {
|
||||
t.Fatalf("Clear => unexpected error: %v", err)
|
||||
}
|
||||
if err := c.Apply(ft); err != nil {
|
||||
t.Fatalf("Apply => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
want = cell.Buffer{
|
||||
{
|
||||
cell.New('A'),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
{
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
cell.New(0),
|
||||
},
|
||||
}
|
||||
|
||||
got = ft.BackBuffer()
|
||||
if diff := pretty.Compare(want, got); diff != "" {
|
||||
t.Errorf("faketerm.BackBuffer after Clear => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
11
cell/cell.go
11
cell/cell.go
@ -22,6 +22,11 @@ type Options struct {
|
||||
BgColor Color
|
||||
}
|
||||
|
||||
// set allows existing options to be passed as an option.
|
||||
func (o *Options) set(other *Options) {
|
||||
*other = *o
|
||||
}
|
||||
|
||||
// NewOptions returns a new Options instance after applying the provided options.
|
||||
func NewOptions(opts ...Option) *Options {
|
||||
o := &Options{}
|
||||
@ -86,12 +91,6 @@ func (b Buffer) Size() image.Point {
|
||||
}
|
||||
}
|
||||
|
||||
// Area returns the area that is covered by this buffer.
|
||||
func (b Buffer) Area() image.Rectangle {
|
||||
s := b.Size()
|
||||
return image.Rect(0, 0, s.X-1, s.Y-1)
|
||||
}
|
||||
|
||||
// option implements Option.
|
||||
type option func(*Options)
|
||||
|
||||
|
@ -94,6 +94,23 @@ func TestNew(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "passing full Options overwrites existing",
|
||||
r: 'X',
|
||||
opts: []Option{
|
||||
&Options{
|
||||
FgColor: ColorBlack,
|
||||
BgColor: ColorBlue,
|
||||
},
|
||||
},
|
||||
want: Cell{
|
||||
Rune: 'X',
|
||||
Opts: &Options{
|
||||
FgColor: ColorBlack,
|
||||
BgColor: ColorBlue,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
@ -236,42 +253,3 @@ func TestBufferSize(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferArea(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
size image.Point
|
||||
want image.Rectangle
|
||||
}{
|
||||
{
|
||||
desc: "single cell buffer",
|
||||
size: image.Point{1, 1},
|
||||
want: image.Rectangle{
|
||||
Min: image.Point{0, 0},
|
||||
Max: image.Point{0, 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "rectangular buffer",
|
||||
size: image.Point{3, 4},
|
||||
want: image.Rectangle{
|
||||
Min: image.Point{0, 0},
|
||||
Max: image.Point{2, 3},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
b, err := NewBuffer(tc.size)
|
||||
if err != nil {
|
||||
t.Fatalf("NewBuffer => unexpected error: %v", err)
|
||||
}
|
||||
|
||||
got := b.Area()
|
||||
if diff := pretty.Compare(tc.want, got); diff != "" {
|
||||
t.Errorf("Area => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"image"
|
||||
"log"
|
||||
|
||||
"github.com/mum4k/termdash/area"
|
||||
"github.com/mum4k/termdash/cell"
|
||||
"github.com/mum4k/termdash/terminalapi"
|
||||
)
|
||||
@ -49,6 +50,11 @@ func New(size image.Point, opts ...Option) (*Terminal, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// BackBuffer returns the back buffer of the fake terminal.
|
||||
func (t *Terminal) BackBuffer() cell.Buffer {
|
||||
return t.buffer
|
||||
}
|
||||
|
||||
// Implements terminalapi.Terminal.Size.
|
||||
func (t *Terminal) Size() image.Point {
|
||||
return t.buffer.Size()
|
||||
@ -81,8 +87,12 @@ func (t *Terminal) HideCursor() {
|
||||
|
||||
// Implements terminalapi.Terminal.SetCell.
|
||||
func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
|
||||
if area := t.buffer.Area(); !p.In(area) {
|
||||
return fmt.Errorf("cell at point %+v falls out of the terminal area %+v", p, area)
|
||||
ar, err := area.FromSize(t.buffer.Size())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !p.In(ar) {
|
||||
return fmt.Errorf("cell at point %+v falls out of the terminal area %+v", p, ar)
|
||||
}
|
||||
|
||||
cell := t.buffer[p.X][p.Y]
|
||||
|
Loading…
x
Reference in New Issue
Block a user