Skip to content

Commit

Permalink
Merge 3b7ae3e into 2f1d16b
Browse files Browse the repository at this point in the history
  • Loading branch information
mum4k committed Apr 27, 2019
2 parents 2f1d16b + 3b7ae3e commit 311d57b
Show file tree
Hide file tree
Showing 20 changed files with 5,460 additions and 294 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- The `TextInput` widget, an input field allowing interactive text input.

### Changed

- Widgets now get information whether their container is focused when Draw is
Expand All @@ -26,6 +30,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Termdash now requires at least Go version 1.10, which allows us to utilize
`math.Round` instead of our own implementation and `strings.Builder` instead
of `bytes.Buffer`.
- Terminal shortcuts like `Ctrl-A` no longer come as two separate events,
Termdash now mirrors termbox-go and sends these as one event.

## [0.8.0] - 30-Mar-2019

Expand Down
14 changes: 13 additions & 1 deletion README.md
Expand Up @@ -10,7 +10,7 @@

Termdash is a cross-platform customizable terminal based dashboard.

[<img src="./doc/images/termdashdemo_0_8_0.gif" alt="termdashdemo" type="image/gif">](termdashdemo/termdashdemo.go)
[<img src="./doc/images/termdashdemo_0_9_0.gif" alt="termdashdemo" type="image/gif">](termdashdemo/termdashdemo.go)

The feature set is inspired by the
[gizak/termui](http://github.com/gizak/termui) project, which in turn was
Expand Down Expand Up @@ -86,6 +86,18 @@ go run github.com/mum4k/termdash/widgets/button/buttondemo/buttondemo.go

[<img src="./doc/images/buttondemo.gif" alt="buttondemo" type="image/gif" width="50%">](widgets/button/buttondemo/buttondemo.go)

## The TextInput

Allows users to interact with the application by entering, editing and
submitting text data. Run the
[textinputdemo](widgets/textinput/textinputdemo/textinputdemo.go).

```go
go run github.com/mum4k/termdash/widgets/textinput/textinputdemo/textinputdemo.go
```

[<img src="./doc/images/textinputdemo.gif" alt="textinputdemo" type="image/gif" width="50%">](widgets/textinput/textinputdemo/textinputdemo.go)

## The Gauge

Displays the progress of an operation. Run the
Expand Down
Binary file removed doc/images/termdashdemo_0_7_0.gif
Binary file not shown.
Binary file added doc/images/termdashdemo_0_9_0.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/textinputdemo.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions internal/area/area.go
Expand Up @@ -78,6 +78,29 @@ func VSplit(area image.Rectangle, widthPerc int) (left image.Rectangle, right im
return left, right, nil
}

// VSplitCells returns two new areas created by splitting the provided area
// after the specified amount of cells of its width. The number of cells must
// be a zero or a positive integer. Providing a zero returns left=image.ZR,
// right=area. Providing a number equal or larger to area's width returns
// left=area, right=image.ZR.
func VSplitCells(area image.Rectangle, cells int) (left image.Rectangle, right image.Rectangle, err error) {
if min := 0; cells < min {
return image.ZR, image.ZR, fmt.Errorf("invalid cells %d, must be a positive integer", cells)
}
if cells == 0 {
return image.ZR, area, nil
}

width := area.Dx()
if cells >= width {
return area, image.ZR, nil
}

left = image.Rect(area.Min.X, area.Min.Y, area.Min.X+cells, area.Max.Y)
right = image.Rect(area.Min.X+cells, area.Min.Y, area.Max.X, area.Max.Y)
return left, right, nil
}

// ExcludeBorder returns a new area created by subtracting a border around the
// provided area. Return the zero area if there isn't enough space to exclude
// the border.
Expand Down
85 changes: 85 additions & 0 deletions internal/area/area_test.go
Expand Up @@ -282,6 +282,91 @@ func TestVSplit(t *testing.T) {
}
}

func TestVSplitCells(t *testing.T) {
tests := []struct {
desc string
area image.Rectangle
cells int
wantLeft image.Rectangle
wantRight image.Rectangle
wantErr bool
}{
{
desc: "fails on negative cells",
area: image.Rect(1, 1, 2, 2),
cells: -1,
wantErr: true,
},
{
desc: "returns area as left on cells too large",
area: image.Rect(1, 1, 2, 2),
cells: 2,
wantLeft: image.Rect(1, 1, 2, 2),
wantRight: image.ZR,
},
{
desc: "returns area as left on cells equal area width",
area: image.Rect(1, 1, 2, 2),
cells: 1,
wantLeft: image.Rect(1, 1, 2, 2),
wantRight: image.ZR,
},
{
desc: "returns area as right on zero cells",
area: image.Rect(1, 1, 2, 2),
cells: 0,
wantRight: image.Rect(1, 1, 2, 2),
wantLeft: image.ZR,
},
{
desc: "zero area to begin with",
area: image.ZR,
cells: 0,
wantLeft: image.ZR,
wantRight: image.ZR,
},
{
desc: "splits area with even width",
area: image.Rect(1, 1, 3, 3),
cells: 1,
wantLeft: image.Rect(1, 1, 2, 3),
wantRight: image.Rect(2, 1, 3, 3),
},
{
desc: "splits area with odd width",
area: image.Rect(1, 1, 4, 4),
cells: 1,
wantLeft: image.Rect(1, 1, 2, 4),
wantRight: image.Rect(2, 1, 4, 4),
},
{
desc: "splits to unequal areas",
area: image.Rect(0, 0, 4, 4),
cells: 3,
wantLeft: image.Rect(0, 0, 3, 4),
wantRight: image.Rect(3, 0, 4, 4),
},
}

for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
gotLeft, gotRight, err := VSplitCells(tc.area, tc.cells)
if (err != nil) != tc.wantErr {
t.Errorf("VSplitCells => unexpected error:%v, wantErr:%v", err, tc.wantErr)
}
if err != nil {
return
}
if diff := pretty.Compare(tc.wantLeft, gotLeft); diff != "" {
t.Errorf("VSplitCells => left value unexpected diff (-want, +got):\n%s", diff)
}
if diff := pretty.Compare(tc.wantRight, gotRight); diff != "" {
t.Errorf("VSplitCells => right value unexpected diff (-want, +got):\n%s", diff)
}
})
}
}

func TestExcludeBorder(t *testing.T) {
tests := []struct {
desc string
Expand Down
5 changes: 5 additions & 0 deletions internal/canvas/buffer/buffer.go
Expand Up @@ -115,6 +115,11 @@ func (b Buffer) SetCell(p image.Point, r rune, opts ...cell.Option) (int, error)
return -1, err
}
rw := runewidth.RuneWidth(r)
if rw == 0 {
// Even if the rune is invisible, like the zero-value rune, it still
// occupies at least the target cell.
rw = 1
}
if rw > remW {
return -1, fmt.Errorf("cannot set rune %q of width %d at point %v, only have %d remaining cells at this line", r, rw, p, remW)
}
Expand Down
12 changes: 12 additions & 0 deletions internal/canvas/buffer/buffer_test.go
Expand Up @@ -411,6 +411,18 @@ func TestSetCell(t *testing.T) {
return b
}(),
},
{
desc: "sets zero-value rune in a cell",
buffer: mustNew(image.Point{3, 3}),
point: image.Point{1, 2},
r: 0,
wantCells: 1,
want: func() Buffer {
b := mustNew(size)
b[1][2].Rune = 0
return b
}(),
},
{
desc: "sets cell options",
buffer: mustNew(image.Point{3, 3}),
Expand Down
4 changes: 2 additions & 2 deletions internal/runewidth/runewidth_test.go
Expand Up @@ -66,12 +66,12 @@ func TestRuneWidth(t *testing.T) {
},
{
desc: "termdash special runes",
runes: []rune{'⇄', '…', '⇧', '⇩'},
runes: []rune{'⇄', '…', '⇧', '⇩', '⇦', '⇨'},
want: 1,
},
{
desc: "termdash special runes in eastAsian",
runes: []rune{'⇄', '…', '⇧', '⇩'},
runes: []rune{'⇄', '…', '⇧', '⇩', '⇦', '⇨'},
eastAsian: true,
want: 1,
},
Expand Down
77 changes: 75 additions & 2 deletions keyboard/keyboard.go
Expand Up @@ -55,11 +55,40 @@ var buttonNames = map[Key]string{
KeyArrowDown: "KeyArrowDown",
KeyArrowLeft: "KeyArrowLeft",
KeyArrowRight: "KeyArrowRight",
KeyCtrlTilde: "KeyCtrlTilde",
KeyCtrlA: "KeyCtrlA",
KeyCtrlB: "KeyCtrlB",
KeyCtrlC: "KeyCtrlC",
KeyCtrlD: "KeyCtrlD",
KeyCtrlE: "KeyCtrlE",
KeyCtrlF: "KeyCtrlF",
KeyCtrlG: "KeyCtrlG",
KeyBackspace: "KeyBackspace",
KeyTab: "KeyTab",
KeyCtrlJ: "KeyCtrlJ",
KeyCtrlK: "KeyCtrlK",
KeyCtrlL: "KeyCtrlL",
KeyEnter: "KeyEnter",
KeyCtrlN: "KeyCtrlN",
KeyCtrlO: "KeyCtrlO",
KeyCtrlP: "KeyCtrlP",
KeyCtrlQ: "KeyCtrlQ",
KeyCtrlR: "KeyCtrlR",
KeyCtrlS: "KeyCtrlS",
KeyCtrlT: "KeyCtrlT",
KeyCtrlU: "KeyCtrlU",
KeyCtrlV: "KeyCtrlV",
KeyCtrlW: "KeyCtrlW",
KeyCtrlX: "KeyCtrlX",
KeyCtrlY: "KeyCtrlY",
KeyCtrlZ: "KeyCtrlZ",
KeyEsc: "KeyEsc",
KeyCtrl: "KeyCtrl",
KeyCtrl4: "KeyCtrl4",
KeyCtrl5: "KeyCtrl5",
KeyCtrl6: "KeyCtrl6",
KeyCtrl7: "KeyCtrl7",
KeySpace: "KeySpace",
KeyBackspace2: "KeyBackspace2",
}

// Printable characters, but worth having constants for them.
Expand Down Expand Up @@ -91,9 +120,53 @@ const (
KeyArrowDown
KeyArrowLeft
KeyArrowRight
KeyCtrlTilde
KeyCtrlA
KeyCtrlB
KeyCtrlC
KeyCtrlD
KeyCtrlE
KeyCtrlF
KeyCtrlG
KeyBackspace
KeyTab
KeyCtrlJ
KeyCtrlK
KeyCtrlL
KeyEnter
KeyCtrlN
KeyCtrlO
KeyCtrlP
KeyCtrlQ
KeyCtrlR
KeyCtrlS
KeyCtrlT
KeyCtrlU
KeyCtrlV
KeyCtrlW
KeyCtrlX
KeyCtrlY
KeyCtrlZ
KeyEsc
KeyCtrl
KeyCtrl4
KeyCtrl5
KeyCtrl6
KeyCtrl7
KeyBackspace2
)

// Keys declared as duplicates by termbox.
const (
KeyCtrl2 Key = KeyCtrlTilde
KeyCtrlSpace Key = KeyCtrlTilde
KeyCtrlH Key = KeyBackspace
KeyCtrlI Key = KeyTab
KeyCtrlM Key = KeyEnter
KeyCtrlLsqBracket Key = KeyEsc
KeyCtrl3 Key = KeyEsc
KeyCtrlBackslash Key = KeyCtrl4
KeyCtrlRsqBracket Key = KeyCtrl5
KeyCtrlSlash Key = KeyCtrl7
KeyCtrlUnderscore Key = KeyCtrl7
KeyCtrl8 Key = KeyBackspace2
)

0 comments on commit 311d57b

Please sign in to comment.