summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2022-03-06 17:40:35 +0100
committerToni Uhlig <matzeton@googlemail.com>2022-03-06 17:40:35 +0100
commit29c72fb30bb7d5614c0a8ebb73bee2ac7eca6608 (patch)
tree8a58c288c11d6e3be5c4de1651d635776c8efb68 /examples
parent46f68501d575431656b5254a4bda8acb2982ab77 (diff)
Removed go-dashboard example.
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/go-dashboard/main.go218
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/.travis.yml16
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/LICENSE21
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/README.md27
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/go.mod3
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/go.test.sh12
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth.go257
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_appengine.go8
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_js.go9
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_posix.go82
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_table.go437
-rw-r--r--examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_windows.go28
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/.gitignore2
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/.travis.yml17
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/CHANGELOG.md361
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/CONTRIBUTING.md38
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/LICENSE201
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/README.md215
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/align/align.go70
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/cell/cell.go64
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/cell/color.go106
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/container/container.go471
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/container/draw.go175
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/container/focus.go116
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/container/options.go817
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/container/traversal.go86
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/go.mod10
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/keyboard/keyboard.go172
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/linestyle/linestyle.go51
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/mouse/mouse.go48
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/alignfor/alignfor.go128
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/area/area.go258
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/button/button.go135
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/braille/braille.go284
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/buffer/buffer.go188
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/canvas.go247
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/border.go182
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_circle.go263
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_fill.go160
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_line.go204
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/draw.go17
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line.go207
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line_graph.go206
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/line_style.go129
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/rectangle.go93
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/text.go195
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/vertical_text.go120
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/event/event.go260
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/event/eventqueue/eventqueue.go231
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/numbers.go222
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/trig/trig.go224
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/runewidth/runewidth.go98
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/private/wrap/wrap.go409
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/termdash.go362
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/cell_options.go37
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/color_mode.go38
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/event.go179
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/termbox.go164
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/color_mode.go60
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/event.go106
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/terminalapi.go56
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/widgetapi/widgetapi.go185
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/line_trim.go117
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/options.go156
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/scroll.go165
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/text.go286
-rw-r--r--examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/write_options.go67
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/AUTHORS4
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/LICENSE19
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/README.md51
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/api.go500
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/api_common.go187
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/api_windows.go257
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/collect_terminfo.py110
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/escwait.go11
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/escwait_darwin.go9
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin.go41
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go40
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_dragonfly.go39
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_freebsd.go39
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_linux.go33
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_netbsd.go39
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_openbsd.go39
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_windows.go61
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/termbox.go529
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_common.go59
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_windows.go952
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo.go232
-rw-r--r--examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo_builtin.go64
-rw-r--r--examples/go-dashboard/src/ui/go.mod8
-rw-r--r--examples/go-dashboard/src/ui/ui.go104
-rw-r--r--examples/go-dashboard/src/ui/ui/go.mod8
-rw-r--r--examples/go-dashboard/src/ui/ui/ui.go104
93 files changed, 0 insertions, 14115 deletions
diff --git a/examples/go-dashboard/main.go b/examples/go-dashboard/main.go
deleted file mode 100644
index c4cad3fb1..000000000
--- a/examples/go-dashboard/main.go
+++ /dev/null
@@ -1,218 +0,0 @@
-package main
-
-import (
- "bufio"
- "encoding/json"
- "fmt"
- "io"
- "log"
- "net"
- "os"
- "strconv"
- "strings"
-
- "ui"
-)
-
-var (
- WarningLogger *log.Logger
- InfoLogger *log.Logger
- ErrorLogger *log.Logger
-
- NETWORK_BUFFER_MAX_SIZE uint16 = 13312
- NETWORK_BUFFER_LENGTH_DIGITS uint16 = 5
-)
-
-type packet_event struct {
- ThreadID uint8 `json:"thread_id"`
- PacketID uint64 `json:"packet_id"`
-
- FlowID uint32 `json:"flow_id"`
- FlowPacketID uint64 `json:"flow_packet_id"`
-
- Timestamp uint64 `json:"ts_msec"`
-
- PacketEventID uint8 `json:"packet_event_id"`
- PacketEventName string `json:"packet_event_name"`
- PacketOversize bool `json:"pkt_oversize"`
- PacketLength uint32 `json:"pkt_len"`
- PacketL4Length uint32 `json:"pkt_l4_len"`
- Packet string `json:"pkt"`
- PacketCaptureLength uint32 `json:"pkt_caplen"`
- PacketType uint32 `json:"pkt_type"`
- PacketL3Offset uint32 `json:"pkt_l3_offset"`
- PacketL4Offset uint32 `json:"pkt_l4_offset"`
-}
-
-type flow_event struct {
- ThreadID uint8 `json:"thread_id"`
- PacketID uint64 `json:"packet_id"`
-
- FlowID uint32 `json:"flow_id"`
- FlowPacketID uint64 `json:"flow_packets_processed"`
- FlowFirstSeen uint64 `json:"flow_first_seen"`
- FlowLastSeen uint64 `json:"flow_last_seen"`
- FlowTotalLayer4DataLength uint64 `json:"flow_tot_l4_data_len"`
- FlowMinLayer4DataLength uint64 `json:"flow_min_l4_data_len"`
- FlowMaxLayer4DataLength uint64 `json:"flow_max_l4_data_len"`
- FlowAvgLayer4DataLength uint64 `json:"flow_avg_l4_data_len"`
- FlowDatalinkLayer uint8 `json:"flow_datalink"`
- MaxPackets uint8 `json:"flow_max_packets"`
- IsMidstreamFlow uint32 `json:"midstream"`
-}
-
-type basic_event struct {
- ThreadID uint8 `json:"thread_id"`
- PacketID uint64 `json:"packet_id"`
-
- BasicEventID uint8 `json:"basic_event_id"`
- BasicEventName string `json:"basic_event_name"`
-}
-
-func processJson(jsonStr string) {
- jsonMap := make(map[string]interface{})
- err := json.Unmarshal([]byte(jsonStr), &jsonMap)
- if err != nil {
- ErrorLogger.Printf("BUG: JSON error: %v\n", err)
- os.Exit(1)
- }
- if jsonMap["packet_event_id"] != nil {
- pe := packet_event{}
- if err := json.Unmarshal([]byte(jsonStr), &pe); err != nil {
- ErrorLogger.Printf("BUG: JSON Unmarshal error: %v\n", err)
- os.Exit(1)
- }
- InfoLogger.Printf("PACKET EVENT %v\n", pe)
- } else if jsonMap["flow_event_id"] != nil {
- fe := flow_event{}
- if err := json.Unmarshal([]byte(jsonStr), &fe); err != nil {
- ErrorLogger.Printf("BUG: JSON Unmarshal error: %v\n", err)
- os.Exit(1)
- }
- InfoLogger.Printf("FLOW EVENT %v\n", fe)
- } else if jsonMap["basic_event_id"] != nil {
- be := basic_event{}
- if err := json.Unmarshal([]byte(jsonStr), &be); err != nil {
- ErrorLogger.Printf("BUG: JSON Unmarshal error: %v\n", err)
- os.Exit(1)
- }
- InfoLogger.Printf("BASIC EVENT %v\n", be)
- } else {
- ErrorLogger.Printf("BUG: Unknown JSON: %v\n", jsonStr)
- os.Exit(1)
- }
- //InfoLogger.Printf("JSON map: %v\n-------------------------------------------------------\n", jsonMap)
-}
-
-func eventHandler(ui *ui.Tui, wdgts *ui.Widgets, reader chan string) {
- for {
- select {
- case <-ui.MainTicker.C:
- if err := wdgts.RawJson.Write(fmt.Sprintf("%s\n", "--- HEARTBEAT ---")); err != nil {
- panic(err)
- }
-
- case <-ui.Context.Done():
- return
-
- case jsonStr := <-reader:
- if err := wdgts.RawJson.Write(fmt.Sprintf("%s\n", jsonStr)); err != nil {
- panic(err)
- }
- }
- }
-}
-
-func main() {
- InfoLogger = log.New(os.Stderr, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
- WarningLogger = log.New(os.Stderr, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile)
- ErrorLogger = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile)
-
- writer := make(chan string, 256)
-
- go func(writer chan string) {
- con, err := net.Dial("tcp", "127.0.0.1:7000")
- if err != nil {
- ErrorLogger.Printf("Connection failed: %v\n", err)
- os.Exit(1)
- }
-
- buf := make([]byte, NETWORK_BUFFER_MAX_SIZE)
- jsonStr := string("")
- jsonStrLen := uint16(0)
- jsonLen := uint16(0)
- brd := bufio.NewReaderSize(con, int(NETWORK_BUFFER_MAX_SIZE))
-
- for {
- nread, err := brd.Read(buf)
-
- if err != nil {
- if err != io.EOF {
- ErrorLogger.Printf("Read Error: %v\n", err)
- break
- }
- }
-
- if nread == 0 || err == io.EOF {
- WarningLogger.Printf("Disconnect from Server\n")
- break
- }
-
- jsonStr += string(buf[:nread])
- jsonStrLen += uint16(nread)
-
- for {
- if jsonStrLen < NETWORK_BUFFER_LENGTH_DIGITS+1 {
- break
- }
-
- if jsonStr[NETWORK_BUFFER_LENGTH_DIGITS] != '{' {
- ErrorLogger.Printf("BUG: JSON invalid opening character at position %d: '%s' (%x)\n",
- NETWORK_BUFFER_LENGTH_DIGITS,
- string(jsonStr[:NETWORK_BUFFER_LENGTH_DIGITS]), jsonStr[NETWORK_BUFFER_LENGTH_DIGITS])
- os.Exit(1)
- }
-
- if jsonLen == 0 {
- var tmp uint64
- if tmp, err = strconv.ParseUint(strings.TrimLeft(jsonStr[:NETWORK_BUFFER_LENGTH_DIGITS], "0"), 10, 16); err != nil {
- ErrorLogger.Printf("BUG: Could not parse length of a JSON string: %v\n", err)
- os.Exit(1)
- } else {
- jsonLen = uint16(tmp)
- }
- }
-
- if jsonStrLen < jsonLen+NETWORK_BUFFER_LENGTH_DIGITS {
- break
- }
-
- if jsonStr[jsonLen+NETWORK_BUFFER_LENGTH_DIGITS-2] != '}' || jsonStr[jsonLen+NETWORK_BUFFER_LENGTH_DIGITS-1] != '\n' {
- ErrorLogger.Printf("BUG: JSON invalid closing character at position %d: '%s'\n",
- jsonLen+NETWORK_BUFFER_LENGTH_DIGITS,
- string(jsonStr[jsonLen+NETWORK_BUFFER_LENGTH_DIGITS-1]))
- os.Exit(1)
- }
-
- writer <- jsonStr[NETWORK_BUFFER_LENGTH_DIGITS : NETWORK_BUFFER_LENGTH_DIGITS+jsonLen]
-
- jsonStr = jsonStr[jsonLen+NETWORK_BUFFER_LENGTH_DIGITS:]
- jsonStrLen -= (jsonLen + NETWORK_BUFFER_LENGTH_DIGITS)
- jsonLen = 0
- }
- }
- }(writer)
-
- tui, wdgts := ui.Init()
- go eventHandler(tui, wdgts, writer)
- ui.Run(tui)
-
-/*
- for {
- select {
- case _ = <-writer:
- break
- }
- }
-*/
-}
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/.travis.yml b/examples/go-dashboard/src/github.com/mattn/go-runewidth/.travis.yml
deleted file mode 100644
index 6a21813a3..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/.travis.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-language: go
-sudo: false
-go:
- - 1.13.x
- - tip
-
-before_install:
- - go get -t -v ./...
-
-script:
- - go generate
- - git diff --cached --exit-code
- - ./go.test.sh
-
-after_success:
- - bash <(curl -s https://codecov.io/bash)
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/LICENSE b/examples/go-dashboard/src/github.com/mattn/go-runewidth/LICENSE
deleted file mode 100644
index 91b5cef30..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Yasuhiro Matsumoto
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/README.md b/examples/go-dashboard/src/github.com/mattn/go-runewidth/README.md
deleted file mode 100644
index aa56ab96c..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/README.md
+++ /dev/null
@@ -1,27 +0,0 @@
-go-runewidth
-============
-
-[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth)
-[![Codecov](https://codecov.io/gh/mattn/go-runewidth/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-runewidth)
-[![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth)
-[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-runewidth)](https://goreportcard.com/report/github.com/mattn/go-runewidth)
-
-Provides functions to get fixed width of the character or string.
-
-Usage
------
-
-```go
-runewidth.StringWidth("つのだ☆HIRO") == 12
-```
-
-
-Author
-------
-
-Yasuhiro Matsumoto
-
-License
--------
-
-under the MIT License: http://mattn.mit-license.org/2013
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/go.mod b/examples/go-dashboard/src/github.com/mattn/go-runewidth/go.mod
deleted file mode 100644
index fa7f4d864..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/mattn/go-runewidth
-
-go 1.9
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/go.test.sh b/examples/go-dashboard/src/github.com/mattn/go-runewidth/go.test.sh
deleted file mode 100644
index 012162b07..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/go.test.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-echo "" > coverage.txt
-
-for d in $(go list ./... | grep -v vendor); do
- go test -race -coverprofile=profile.out -covermode=atomic "$d"
- if [ -f profile.out ]; then
- cat profile.out >> coverage.txt
- rm profile.out
- fi
-done
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth.go b/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth.go
deleted file mode 100644
index 19f8e0449..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth.go
+++ /dev/null
@@ -1,257 +0,0 @@
-package runewidth
-
-import (
- "os"
-)
-
-//go:generate go run script/generate.go
-
-var (
- // EastAsianWidth will be set true if the current locale is CJK
- EastAsianWidth bool
-
- // ZeroWidthJoiner is flag to set to use UTR#51 ZWJ
- ZeroWidthJoiner bool
-
- // DefaultCondition is a condition in current locale
- DefaultCondition = &Condition{}
-)
-
-func init() {
- handleEnv()
-}
-
-func handleEnv() {
- env := os.Getenv("RUNEWIDTH_EASTASIAN")
- if env == "" {
- EastAsianWidth = IsEastAsian()
- } else {
- EastAsianWidth = env == "1"
- }
- // update DefaultCondition
- DefaultCondition.EastAsianWidth = EastAsianWidth
- DefaultCondition.ZeroWidthJoiner = ZeroWidthJoiner
-}
-
-type interval struct {
- first rune
- last rune
-}
-
-type table []interval
-
-func inTables(r rune, ts ...table) bool {
- for _, t := range ts {
- if inTable(r, t) {
- return true
- }
- }
- return false
-}
-
-func inTable(r rune, t table) bool {
- if r < t[0].first {
- return false
- }
-
- bot := 0
- top := len(t) - 1
- for top >= bot {
- mid := (bot + top) >> 1
-
- switch {
- case t[mid].last < r:
- bot = mid + 1
- case t[mid].first > r:
- top = mid - 1
- default:
- return true
- }
- }
-
- return false
-}
-
-var private = table{
- {0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD},
-}
-
-var nonprint = table{
- {0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD},
- {0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F},
- {0x2028, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
- {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
-}
-
-// Condition have flag EastAsianWidth whether the current locale is CJK or not.
-type Condition struct {
- EastAsianWidth bool
- ZeroWidthJoiner bool
-}
-
-// NewCondition return new instance of Condition which is current locale.
-func NewCondition() *Condition {
- return &Condition{
- EastAsianWidth: EastAsianWidth,
- ZeroWidthJoiner: ZeroWidthJoiner,
- }
-}
-
-// RuneWidth returns the number of cells in r.
-// See http://www.unicode.org/reports/tr11/
-func (c *Condition) RuneWidth(r rune) int {
- switch {
- case r < 0 || r > 0x10FFFF || inTables(r, nonprint, combining, notassigned):
- return 0
- case (c.EastAsianWidth && IsAmbiguousWidth(r)) || inTables(r, doublewidth):
- return 2
- default:
- return 1
- }
-}
-
-func (c *Condition) stringWidth(s string) (width int) {
- for _, r := range []rune(s) {
- width += c.RuneWidth(r)
- }
- return width
-}
-
-func (c *Condition) stringWidthZeroJoiner(s string) (width int) {
- r1, r2 := rune(0), rune(0)
- for _, r := range []rune(s) {
- if r == 0xFE0E || r == 0xFE0F {
- continue
- }
- w := c.RuneWidth(r)
- if r2 == 0x200D && inTables(r, emoji) && inTables(r1, emoji) {
- if width < w {
- width = w
- }
- } else {
- width += w
- }
- r1, r2 = r2, r
- }
- return width
-}
-
-// StringWidth return width as you can see
-func (c *Condition) StringWidth(s string) (width int) {
- if c.ZeroWidthJoiner {
- return c.stringWidthZeroJoiner(s)
- }
- return c.stringWidth(s)
-}
-
-// Truncate return string truncated with w cells
-func (c *Condition) Truncate(s string, w int, tail string) string {
- if c.StringWidth(s) <= w {
- return s
- }
- r := []rune(s)
- tw := c.StringWidth(tail)
- w -= tw
- width := 0
- i := 0
- for ; i < len(r); i++ {
- cw := c.RuneWidth(r[i])
- if width+cw > w {
- break
- }
- width += cw
- }
- return string(r[0:i]) + tail
-}
-
-// Wrap return string wrapped with w cells
-func (c *Condition) Wrap(s string, w int) string {
- width := 0
- out := ""
- for _, r := range []rune(s) {
- cw := RuneWidth(r)
- if r == '\n' {
- out += string(r)
- width = 0
- continue
- } else if width+cw > w {
- out += "\n"
- width = 0
- out += string(r)
- width += cw
- continue
- }
- out += string(r)
- width += cw
- }
- return out
-}
-
-// FillLeft return string filled in left by spaces in w cells
-func (c *Condition) FillLeft(s string, w int) string {
- width := c.StringWidth(s)
- count := w - width
- if count > 0 {
- b := make([]byte, count)
- for i := range b {
- b[i] = ' '
- }
- return string(b) + s
- }
- return s
-}
-
-// FillRight return string filled in left by spaces in w cells
-func (c *Condition) FillRight(s string, w int) string {
- width := c.StringWidth(s)
- count := w - width
- if count > 0 {
- b := make([]byte, count)
- for i := range b {
- b[i] = ' '
- }
- return s + string(b)
- }
- return s
-}
-
-// RuneWidth returns the number of cells in r.
-// See http://www.unicode.org/reports/tr11/
-func RuneWidth(r rune) int {
- return DefaultCondition.RuneWidth(r)
-}
-
-// IsAmbiguousWidth returns whether is ambiguous width or not.
-func IsAmbiguousWidth(r rune) bool {
- return inTables(r, private, ambiguous)
-}
-
-// IsNeutralWidth returns whether is neutral width or not.
-func IsNeutralWidth(r rune) bool {
- return inTable(r, neutral)
-}
-
-// StringWidth return width as you can see
-func StringWidth(s string) (width int) {
- return DefaultCondition.StringWidth(s)
-}
-
-// Truncate return string truncated with w cells
-func Truncate(s string, w int, tail string) string {
- return DefaultCondition.Truncate(s, w, tail)
-}
-
-// Wrap return string wrapped with w cells
-func Wrap(s string, w int) string {
- return DefaultCondition.Wrap(s, w)
-}
-
-// FillLeft return string filled in left by spaces in w cells
-func FillLeft(s string, w int) string {
- return DefaultCondition.FillLeft(s, w)
-}
-
-// FillRight return string filled in left by spaces in w cells
-func FillRight(s string, w int) string {
- return DefaultCondition.FillRight(s, w)
-}
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_appengine.go b/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_appengine.go
deleted file mode 100644
index 7d99f6e52..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_appengine.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// +build appengine
-
-package runewidth
-
-// IsEastAsian return true if the current locale is CJK
-func IsEastAsian() bool {
- return false
-}
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_js.go b/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_js.go
deleted file mode 100644
index c5fdf40ba..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_js.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// +build js
-// +build !appengine
-
-package runewidth
-
-func IsEastAsian() bool {
- // TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
- return false
-}
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_posix.go b/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_posix.go
deleted file mode 100644
index 480ad7485..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_posix.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// +build !windows
-// +build !js
-// +build !appengine
-
-package runewidth
-
-import (
- "os"
- "regexp"
- "strings"
-)
-
-var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
-
-var mblenTable = map[string]int{
- "utf-8": 6,
- "utf8": 6,
- "jis": 8,
- "eucjp": 3,
- "euckr": 2,
- "euccn": 2,
- "sjis": 2,
- "cp932": 2,
- "cp51932": 2,
- "cp936": 2,
- "cp949": 2,
- "cp950": 2,
- "big5": 2,
- "gbk": 2,
- "gb2312": 2,
-}
-
-func isEastAsian(locale string) bool {
- charset := strings.ToLower(locale)
- r := reLoc.FindStringSubmatch(locale)
- if len(r) == 2 {
- charset = strings.ToLower(r[1])
- }
-
- if strings.HasSuffix(charset, "@cjk_narrow") {
- return false
- }
-
- for pos, b := range []byte(charset) {
- if b == '@' {
- charset = charset[:pos]
- break
- }
- }
- max := 1
- if m, ok := mblenTable[charset]; ok {
- max = m
- }
- if max > 1 && (charset[0] != 'u' ||
- strings.HasPrefix(locale, "ja") ||
- strings.HasPrefix(locale, "ko") ||
- strings.HasPrefix(locale, "zh")) {
- return true
- }
- return false
-}
-
-// IsEastAsian return true if the current locale is CJK
-func IsEastAsian() bool {
- locale := os.Getenv("LC_ALL")
- if locale == "" {
- locale = os.Getenv("LC_CTYPE")
- }
- if locale == "" {
- locale = os.Getenv("LANG")
- }
-
- // ignore C locale
- if locale == "POSIX" || locale == "C" {
- return false
- }
- if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') {
- return false
- }
-
- return isEastAsian(locale)
-}
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_table.go b/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_table.go
deleted file mode 100644
index b27d77d89..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_table.go
+++ /dev/null
@@ -1,437 +0,0 @@
-// Code generated by script/generate.go. DO NOT EDIT.
-
-package runewidth
-
-var combining = table{
- {0x0300, 0x036F}, {0x0483, 0x0489}, {0x07EB, 0x07F3},
- {0x0C00, 0x0C00}, {0x0C04, 0x0C04}, {0x0D00, 0x0D01},
- {0x135D, 0x135F}, {0x1A7F, 0x1A7F}, {0x1AB0, 0x1AC0},
- {0x1B6B, 0x1B73}, {0x1DC0, 0x1DF9}, {0x1DFB, 0x1DFF},
- {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2DE0, 0x2DFF},
- {0x3099, 0x309A}, {0xA66F, 0xA672}, {0xA674, 0xA67D},
- {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA8E0, 0xA8F1},
- {0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, {0x10376, 0x1037A},
- {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x11300, 0x11301},
- {0x1133B, 0x1133C}, {0x11366, 0x1136C}, {0x11370, 0x11374},
- {0x16AF0, 0x16AF4}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172},
- {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
- {0x1D242, 0x1D244}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018},
- {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A},
- {0x1E8D0, 0x1E8D6},
-}
-
-var doublewidth = table{
- {0x1100, 0x115F}, {0x231A, 0x231B}, {0x2329, 0x232A},
- {0x23E9, 0x23EC}, {0x23F0, 0x23F0}, {0x23F3, 0x23F3},
- {0x25FD, 0x25FE}, {0x2614, 0x2615}, {0x2648, 0x2653},
- {0x267F, 0x267F}, {0x2693, 0x2693}, {0x26A1, 0x26A1},
- {0x26AA, 0x26AB}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5},
- {0x26CE, 0x26CE}, {0x26D4, 0x26D4}, {0x26EA, 0x26EA},
- {0x26F2, 0x26F3}, {0x26F5, 0x26F5}, {0x26FA, 0x26FA},
- {0x26FD, 0x26FD}, {0x2705, 0x2705}, {0x270A, 0x270B},
- {0x2728, 0x2728}, {0x274C, 0x274C}, {0x274E, 0x274E},
- {0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797},
- {0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C},
- {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99},
- {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB},
- {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF},
- {0x3105, 0x312F}, {0x3131, 0x318E}, {0x3190, 0x31E3},
- {0x31F0, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x4DBF},
- {0x4E00, 0xA48C}, {0xA490, 0xA4C6}, {0xA960, 0xA97C},
- {0xAC00, 0xD7A3}, {0xF900, 0xFAFF}, {0xFE10, 0xFE19},
- {0xFE30, 0xFE52}, {0xFE54, 0xFE66}, {0xFE68, 0xFE6B},
- {0xFF01, 0xFF60}, {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE4},
- {0x16FF0, 0x16FF1}, {0x17000, 0x187F7}, {0x18800, 0x18CD5},
- {0x18D00, 0x18D08}, {0x1B000, 0x1B11E}, {0x1B150, 0x1B152},
- {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1F004, 0x1F004},
- {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A},
- {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248},
- {0x1F250, 0x1F251}, {0x1F260, 0x1F265}, {0x1F300, 0x1F320},
- {0x1F32D, 0x1F335}, {0x1F337, 0x1F37C}, {0x1F37E, 0x1F393},
- {0x1F3A0, 0x1F3CA}, {0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0},
- {0x1F3F4, 0x1F3F4}, {0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440},
- {0x1F442, 0x1F4FC}, {0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E},
- {0x1F550, 0x1F567}, {0x1F57A, 0x1F57A}, {0x1F595, 0x1F596},
- {0x1F5A4, 0x1F5A4}, {0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5},
- {0x1F6CC, 0x1F6CC}, {0x1F6D0, 0x1F6D2}, {0x1F6D5, 0x1F6D7},
- {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6FC}, {0x1F7E0, 0x1F7EB},
- {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1F978},
- {0x1F97A, 0x1F9CB}, {0x1F9CD, 0x1F9FF}, {0x1FA70, 0x1FA74},
- {0x1FA78, 0x1FA7A}, {0x1FA80, 0x1FA86}, {0x1FA90, 0x1FAA8},
- {0x1FAB0, 0x1FAB6}, {0x1FAC0, 0x1FAC2}, {0x1FAD0, 0x1FAD6},
- {0x20000, 0x2FFFD}, {0x30000, 0x3FFFD},
-}
-
-var ambiguous = table{
- {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8},
- {0x00AA, 0x00AA}, {0x00AD, 0x00AE}, {0x00B0, 0x00B4},
- {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6},
- {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1},
- {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED},
- {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA},
- {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101},
- {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B},
- {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133},
- {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144},
- {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153},
- {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE},
- {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4},
- {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA},
- {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261},
- {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB},
- {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB},
- {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0300, 0x036F},
- {0x0391, 0x03A1}, {0x03A3, 0x03A9}, {0x03B1, 0x03C1},
- {0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F},
- {0x0451, 0x0451}, {0x2010, 0x2010}, {0x2013, 0x2016},
- {0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022},
- {0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033},
- {0x2035, 0x2035}, {0x203B, 0x203B}, {0x203E, 0x203E},
- {0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084},
- {0x20AC, 0x20AC}, {0x2103, 0x2103}, {0x2105, 0x2105},
- {0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116},
- {0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B},
- {0x2153, 0x2154}, {0x215B, 0x215E}, {0x2160, 0x216B},
- {0x2170, 0x2179}, {0x2189, 0x2189}, {0x2190, 0x2199},
- {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, {0x21D4, 0x21D4},
- {0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203},
- {0x2207, 0x2208}, {0x220B, 0x220B}, {0x220F, 0x220F},
- {0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A},
- {0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225},
- {0x2227, 0x222C}, {0x222E, 0x222E}, {0x2234, 0x2237},
- {0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C},
- {0x2252, 0x2252}, {0x2260, 0x2261}, {0x2264, 0x2267},
- {0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283},
- {0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299},
- {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, {0x2312, 0x2312},
- {0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573},
- {0x2580, 0x258F}, {0x2592, 0x2595}, {0x25A0, 0x25A1},
- {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7},
- {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8},
- {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, {0x25E2, 0x25E5},
- {0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609},
- {0x260E, 0x260F}, {0x261C, 0x261C}, {0x261E, 0x261E},
- {0x2640, 0x2640}, {0x2642, 0x2642}, {0x2660, 0x2661},
- {0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D},
- {0x266F, 0x266F}, {0x269E, 0x269F}, {0x26BF, 0x26BF},
- {0x26C6, 0x26CD}, {0x26CF, 0x26D3}, {0x26D5, 0x26E1},
- {0x26E3, 0x26E3}, {0x26E8, 0x26E9}, {0x26EB, 0x26F1},
- {0x26F4, 0x26F4}, {0x26F6, 0x26F9}, {0x26FB, 0x26FC},
- {0x26FE, 0x26FF}, {0x273D, 0x273D}, {0x2776, 0x277F},
- {0x2B56, 0x2B59}, {0x3248, 0x324F}, {0xE000, 0xF8FF},
- {0xFE00, 0xFE0F}, {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A},
- {0x1F110, 0x1F12D}, {0x1F130, 0x1F169}, {0x1F170, 0x1F18D},
- {0x1F18F, 0x1F190}, {0x1F19B, 0x1F1AC}, {0xE0100, 0xE01EF},
- {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD},
-}
-var notassigned = table{
- {0x27E6, 0x27ED}, {0x2985, 0x2986},
-}
-
-var neutral = table{
- {0x0000, 0x001F}, {0x007F, 0x00A0}, {0x00A9, 0x00A9},
- {0x00AB, 0x00AB}, {0x00B5, 0x00B5}, {0x00BB, 0x00BB},
- {0x00C0, 0x00C5}, {0x00C7, 0x00CF}, {0x00D1, 0x00D6},
- {0x00D9, 0x00DD}, {0x00E2, 0x00E5}, {0x00E7, 0x00E7},
- {0x00EB, 0x00EB}, {0x00EE, 0x00EF}, {0x00F1, 0x00F1},
- {0x00F4, 0x00F6}, {0x00FB, 0x00FB}, {0x00FD, 0x00FD},
- {0x00FF, 0x0100}, {0x0102, 0x0110}, {0x0112, 0x0112},
- {0x0114, 0x011A}, {0x011C, 0x0125}, {0x0128, 0x012A},
- {0x012C, 0x0130}, {0x0134, 0x0137}, {0x0139, 0x013E},
- {0x0143, 0x0143}, {0x0145, 0x0147}, {0x014C, 0x014C},
- {0x014E, 0x0151}, {0x0154, 0x0165}, {0x0168, 0x016A},
- {0x016C, 0x01CD}, {0x01CF, 0x01CF}, {0x01D1, 0x01D1},
- {0x01D3, 0x01D3}, {0x01D5, 0x01D5}, {0x01D7, 0x01D7},
- {0x01D9, 0x01D9}, {0x01DB, 0x01DB}, {0x01DD, 0x0250},
- {0x0252, 0x0260}, {0x0262, 0x02C3}, {0x02C5, 0x02C6},
- {0x02C8, 0x02C8}, {0x02CC, 0x02CC}, {0x02CE, 0x02CF},
- {0x02D1, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE},
- {0x02E0, 0x02FF}, {0x0370, 0x0377}, {0x037A, 0x037F},
- {0x0384, 0x038A}, {0x038C, 0x038C}, {0x038E, 0x0390},
- {0x03AA, 0x03B0}, {0x03C2, 0x03C2}, {0x03CA, 0x0400},
- {0x0402, 0x040F}, {0x0450, 0x0450}, {0x0452, 0x052F},
- {0x0531, 0x0556}, {0x0559, 0x058A}, {0x058D, 0x058F},
- {0x0591, 0x05C7}, {0x05D0, 0x05EA}, {0x05EF, 0x05F4},
- {0x0600, 0x061C}, {0x061E, 0x070D}, {0x070F, 0x074A},
- {0x074D, 0x07B1}, {0x07C0, 0x07FA}, {0x07FD, 0x082D},
- {0x0830, 0x083E}, {0x0840, 0x085B}, {0x085E, 0x085E},
- {0x0860, 0x086A}, {0x08A0, 0x08B4}, {0x08B6, 0x08C7},
- {0x08D3, 0x0983}, {0x0985, 0x098C}, {0x098F, 0x0990},
- {0x0993, 0x09A8}, {0x09AA, 0x09B0}, {0x09B2, 0x09B2},
- {0x09B6, 0x09B9}, {0x09BC, 0x09C4}, {0x09C7, 0x09C8},
- {0x09CB, 0x09CE}, {0x09D7, 0x09D7}, {0x09DC, 0x09DD},
- {0x09DF, 0x09E3}, {0x09E6, 0x09FE}, {0x0A01, 0x0A03},
- {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28},
- {0x0A2A, 0x0A30}, {0x0A32, 0x0A33}, {0x0A35, 0x0A36},
- {0x0A38, 0x0A39}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42},
- {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
- {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A76},
- {0x0A81, 0x0A83}, {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91},
- {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3},
- {0x0AB5, 0x0AB9}, {0x0ABC, 0x0AC5}, {0x0AC7, 0x0AC9},
- {0x0ACB, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE3},
- {0x0AE6, 0x0AF1}, {0x0AF9, 0x0AFF}, {0x0B01, 0x0B03},
- {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, {0x0B13, 0x0B28},
- {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, {0x0B35, 0x0B39},
- {0x0B3C, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D},
- {0x0B55, 0x0B57}, {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B63},
- {0x0B66, 0x0B77}, {0x0B82, 0x0B83}, {0x0B85, 0x0B8A},
- {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A},
- {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4},
- {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9}, {0x0BBE, 0x0BC2},
- {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, {0x0BD0, 0x0BD0},
- {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BFA}, {0x0C00, 0x0C0C},
- {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C39},
- {0x0C3D, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
- {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C63},
- {0x0C66, 0x0C6F}, {0x0C77, 0x0C8C}, {0x0C8E, 0x0C90},
- {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
- {0x0CBC, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD},
- {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE3},
- {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, {0x0D00, 0x0D0C},
- {0x0D0E, 0x0D10}, {0x0D12, 0x0D44}, {0x0D46, 0x0D48},
- {0x0D4A, 0x0D4F}, {0x0D54, 0x0D63}, {0x0D66, 0x0D7F},
- {0x0D81, 0x0D83}, {0x0D85, 0x0D96}, {0x0D9A, 0x0DB1},
- {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD}, {0x0DC0, 0x0DC6},
- {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, {0x0DD6, 0x0DD6},
- {0x0DD8, 0x0DDF}, {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF4},
- {0x0E01, 0x0E3A}, {0x0E3F, 0x0E5B}, {0x0E81, 0x0E82},
- {0x0E84, 0x0E84}, {0x0E86, 0x0E8A}, {0x0E8C, 0x0EA3},
- {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EBD}, {0x0EC0, 0x0EC4},
- {0x0EC6, 0x0EC6}, {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9},
- {0x0EDC, 0x0EDF}, {0x0F00, 0x0F47}, {0x0F49, 0x0F6C},
- {0x0F71, 0x0F97}, {0x0F99, 0x0FBC}, {0x0FBE, 0x0FCC},
- {0x0FCE, 0x0FDA}, {0x1000, 0x10C5}, {0x10C7, 0x10C7},
- {0x10CD, 0x10CD}, {0x10D0, 0x10FF}, {0x1160, 0x1248},
- {0x124A, 0x124D}, {0x1250, 0x1256}, {0x1258, 0x1258},
- {0x125A, 0x125D}, {0x1260, 0x1288}, {0x128A, 0x128D},
- {0x1290, 0x12B0}, {0x12B2, 0x12B5}, {0x12B8, 0x12BE},
- {0x12C0, 0x12C0}, {0x12C2, 0x12C5}, {0x12C8, 0x12D6},
- {0x12D8, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x135A},
- {0x135D, 0x137C}, {0x1380, 0x1399}, {0x13A0, 0x13F5},
- {0x13F8, 0x13FD}, {0x1400, 0x169C}, {0x16A0, 0x16F8},
- {0x1700, 0x170C}, {0x170E, 0x1714}, {0x1720, 0x1736},
- {0x1740, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770},
- {0x1772, 0x1773}, {0x1780, 0x17DD}, {0x17E0, 0x17E9},
- {0x17F0, 0x17F9}, {0x1800, 0x180E}, {0x1810, 0x1819},
- {0x1820, 0x1878}, {0x1880, 0x18AA}, {0x18B0, 0x18F5},
- {0x1900, 0x191E}, {0x1920, 0x192B}, {0x1930, 0x193B},
- {0x1940, 0x1940}, {0x1944, 0x196D}, {0x1970, 0x1974},
- {0x1980, 0x19AB}, {0x19B0, 0x19C9}, {0x19D0, 0x19DA},
- {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C},
- {0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, {0x1AA0, 0x1AAD},
- {0x1AB0, 0x1AC0}, {0x1B00, 0x1B4B}, {0x1B50, 0x1B7C},
- {0x1B80, 0x1BF3}, {0x1BFC, 0x1C37}, {0x1C3B, 0x1C49},
- {0x1C4D, 0x1C88}, {0x1C90, 0x1CBA}, {0x1CBD, 0x1CC7},
- {0x1CD0, 0x1CFA}, {0x1D00, 0x1DF9}, {0x1DFB, 0x1F15},
- {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
- {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B},
- {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4},
- {0x1FB6, 0x1FC4}, {0x1FC6, 0x1FD3}, {0x1FD6, 0x1FDB},
- {0x1FDD, 0x1FEF}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFE},
- {0x2000, 0x200F}, {0x2011, 0x2012}, {0x2017, 0x2017},
- {0x201A, 0x201B}, {0x201E, 0x201F}, {0x2023, 0x2023},
- {0x2028, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034},
- {0x2036, 0x203A}, {0x203C, 0x203D}, {0x203F, 0x2064},
- {0x2066, 0x2071}, {0x2075, 0x207E}, {0x2080, 0x2080},
- {0x2085, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8},
- {0x20AA, 0x20AB}, {0x20AD, 0x20BF}, {0x20D0, 0x20F0},
- {0x2100, 0x2102}, {0x2104, 0x2104}, {0x2106, 0x2108},
- {0x210A, 0x2112}, {0x2114, 0x2115}, {0x2117, 0x2120},
- {0x2123, 0x2125}, {0x2127, 0x212A}, {0x212C, 0x2152},
- {0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F},
- {0x217A, 0x2188}, {0x218A, 0x218B}, {0x219A, 0x21B7},
- {0x21BA, 0x21D1}, {0x21D3, 0x21D3}, {0x21D5, 0x21E6},
- {0x21E8, 0x21FF}, {0x2201, 0x2201}, {0x2204, 0x2206},
- {0x2209, 0x220A}, {0x220C, 0x220E}, {0x2210, 0x2210},
- {0x2212, 0x2214}, {0x2216, 0x2219}, {0x221B, 0x221C},
- {0x2221, 0x2222}, {0x2224, 0x2224}, {0x2226, 0x2226},
- {0x222D, 0x222D}, {0x222F, 0x2233}, {0x2238, 0x223B},
- {0x223E, 0x2247}, {0x2249, 0x224B}, {0x224D, 0x2251},
- {0x2253, 0x225F}, {0x2262, 0x2263}, {0x2268, 0x2269},
- {0x226C, 0x226D}, {0x2270, 0x2281}, {0x2284, 0x2285},
- {0x2288, 0x2294}, {0x2296, 0x2298}, {0x229A, 0x22A4},
- {0x22A6, 0x22BE}, {0x22C0, 0x2311}, {0x2313, 0x2319},
- {0x231C, 0x2328}, {0x232B, 0x23E8}, {0x23ED, 0x23EF},
- {0x23F1, 0x23F2}, {0x23F4, 0x2426}, {0x2440, 0x244A},
- {0x24EA, 0x24EA}, {0x254C, 0x254F}, {0x2574, 0x257F},
- {0x2590, 0x2591}, {0x2596, 0x259F}, {0x25A2, 0x25A2},
- {0x25AA, 0x25B1}, {0x25B4, 0x25B5}, {0x25B8, 0x25BB},
- {0x25BE, 0x25BF}, {0x25C2, 0x25C5}, {0x25C9, 0x25CA},
- {0x25CC, 0x25CD}, {0x25D2, 0x25E1}, {0x25E6, 0x25EE},
- {0x25F0, 0x25FC}, {0x25FF, 0x2604}, {0x2607, 0x2608},
- {0x260A, 0x260D}, {0x2610, 0x2613}, {0x2616, 0x261B},
- {0x261D, 0x261D}, {0x261F, 0x263F}, {0x2641, 0x2641},
- {0x2643, 0x2647}, {0x2654, 0x265F}, {0x2662, 0x2662},
- {0x2666, 0x2666}, {0x266B, 0x266B}, {0x266E, 0x266E},
- {0x2670, 0x267E}, {0x2680, 0x2692}, {0x2694, 0x269D},
- {0x26A0, 0x26A0}, {0x26A2, 0x26A9}, {0x26AC, 0x26BC},
- {0x26C0, 0x26C3}, {0x26E2, 0x26E2}, {0x26E4, 0x26E7},
- {0x2700, 0x2704}, {0x2706, 0x2709}, {0x270C, 0x2727},
- {0x2729, 0x273C}, {0x273E, 0x274B}, {0x274D, 0x274D},
- {0x274F, 0x2752}, {0x2756, 0x2756}, {0x2758, 0x2775},
- {0x2780, 0x2794}, {0x2798, 0x27AF}, {0x27B1, 0x27BE},
- {0x27C0, 0x27E5}, {0x27EE, 0x2984}, {0x2987, 0x2B1A},
- {0x2B1D, 0x2B4F}, {0x2B51, 0x2B54}, {0x2B5A, 0x2B73},
- {0x2B76, 0x2B95}, {0x2B97, 0x2C2E}, {0x2C30, 0x2C5E},
- {0x2C60, 0x2CF3}, {0x2CF9, 0x2D25}, {0x2D27, 0x2D27},
- {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D70},
- {0x2D7F, 0x2D96}, {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE},
- {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6},
- {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE},
- {0x2DE0, 0x2E52}, {0x303F, 0x303F}, {0x4DC0, 0x4DFF},
- {0xA4D0, 0xA62B}, {0xA640, 0xA6F7}, {0xA700, 0xA7BF},
- {0xA7C2, 0xA7CA}, {0xA7F5, 0xA82C}, {0xA830, 0xA839},
- {0xA840, 0xA877}, {0xA880, 0xA8C5}, {0xA8CE, 0xA8D9},
- {0xA8E0, 0xA953}, {0xA95F, 0xA95F}, {0xA980, 0xA9CD},
- {0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, {0xAA00, 0xAA36},
- {0xAA40, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA5C, 0xAAC2},
- {0xAADB, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E},
- {0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E},
- {0xAB30, 0xAB6B}, {0xAB70, 0xABED}, {0xABF0, 0xABF9},
- {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDFFF},
- {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB36},
- {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41},
- {0xFB43, 0xFB44}, {0xFB46, 0xFBC1}, {0xFBD3, 0xFD3F},
- {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, {0xFDF0, 0xFDFD},
- {0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC},
- {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFC}, {0x10000, 0x1000B},
- {0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003C, 0x1003D},
- {0x1003F, 0x1004D}, {0x10050, 0x1005D}, {0x10080, 0x100FA},
- {0x10100, 0x10102}, {0x10107, 0x10133}, {0x10137, 0x1018E},
- {0x10190, 0x1019C}, {0x101A0, 0x101A0}, {0x101D0, 0x101FD},
- {0x10280, 0x1029C}, {0x102A0, 0x102D0}, {0x102E0, 0x102FB},
- {0x10300, 0x10323}, {0x1032D, 0x1034A}, {0x10350, 0x1037A},
- {0x10380, 0x1039D}, {0x1039F, 0x103C3}, {0x103C8, 0x103D5},
- {0x10400, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3},
- {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563},
- {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755},
- {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808},
- {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C},
- {0x1083F, 0x10855}, {0x10857, 0x1089E}, {0x108A7, 0x108AF},
- {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x1091B},
- {0x1091F, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x109B7},
- {0x109BC, 0x109CF}, {0x109D2, 0x10A03}, {0x10A05, 0x10A06},
- {0x10A0C, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A35},
- {0x10A38, 0x10A3A}, {0x10A3F, 0x10A48}, {0x10A50, 0x10A58},
- {0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6}, {0x10AEB, 0x10AF6},
- {0x10B00, 0x10B35}, {0x10B39, 0x10B55}, {0x10B58, 0x10B72},
- {0x10B78, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF},
- {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2},
- {0x10CFA, 0x10D27}, {0x10D30, 0x10D39}, {0x10E60, 0x10E7E},
- {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD}, {0x10EB0, 0x10EB1},
- {0x10F00, 0x10F27}, {0x10F30, 0x10F59}, {0x10FB0, 0x10FCB},
- {0x10FE0, 0x10FF6}, {0x11000, 0x1104D}, {0x11052, 0x1106F},
- {0x1107F, 0x110C1}, {0x110CD, 0x110CD}, {0x110D0, 0x110E8},
- {0x110F0, 0x110F9}, {0x11100, 0x11134}, {0x11136, 0x11147},
- {0x11150, 0x11176}, {0x11180, 0x111DF}, {0x111E1, 0x111F4},
- {0x11200, 0x11211}, {0x11213, 0x1123E}, {0x11280, 0x11286},
- {0x11288, 0x11288}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D},
- {0x1129F, 0x112A9}, {0x112B0, 0x112EA}, {0x112F0, 0x112F9},
- {0x11300, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310},
- {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333},
- {0x11335, 0x11339}, {0x1133B, 0x11344}, {0x11347, 0x11348},
- {0x1134B, 0x1134D}, {0x11350, 0x11350}, {0x11357, 0x11357},
- {0x1135D, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
- {0x11400, 0x1145B}, {0x1145D, 0x11461}, {0x11480, 0x114C7},
- {0x114D0, 0x114D9}, {0x11580, 0x115B5}, {0x115B8, 0x115DD},
- {0x11600, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C},
- {0x11680, 0x116B8}, {0x116C0, 0x116C9}, {0x11700, 0x1171A},
- {0x1171D, 0x1172B}, {0x11730, 0x1173F}, {0x11800, 0x1183B},
- {0x118A0, 0x118F2}, {0x118FF, 0x11906}, {0x11909, 0x11909},
- {0x1190C, 0x11913}, {0x11915, 0x11916}, {0x11918, 0x11935},
- {0x11937, 0x11938}, {0x1193B, 0x11946}, {0x11950, 0x11959},
- {0x119A0, 0x119A7}, {0x119AA, 0x119D7}, {0x119DA, 0x119E4},
- {0x11A00, 0x11A47}, {0x11A50, 0x11AA2}, {0x11AC0, 0x11AF8},
- {0x11C00, 0x11C08}, {0x11C0A, 0x11C36}, {0x11C38, 0x11C45},
- {0x11C50, 0x11C6C}, {0x11C70, 0x11C8F}, {0x11C92, 0x11CA7},
- {0x11CA9, 0x11CB6}, {0x11D00, 0x11D06}, {0x11D08, 0x11D09},
- {0x11D0B, 0x11D36}, {0x11D3A, 0x11D3A}, {0x11D3C, 0x11D3D},
- {0x11D3F, 0x11D47}, {0x11D50, 0x11D59}, {0x11D60, 0x11D65},
- {0x11D67, 0x11D68}, {0x11D6A, 0x11D8E}, {0x11D90, 0x11D91},
- {0x11D93, 0x11D98}, {0x11DA0, 0x11DA9}, {0x11EE0, 0x11EF8},
- {0x11FB0, 0x11FB0}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399},
- {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543},
- {0x13000, 0x1342E}, {0x13430, 0x13438}, {0x14400, 0x14646},
- {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69},
- {0x16A6E, 0x16A6F}, {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF5},
- {0x16B00, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61},
- {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16E40, 0x16E9A},
- {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87}, {0x16F8F, 0x16F9F},
- {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88},
- {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BCA3}, {0x1D000, 0x1D0F5},
- {0x1D100, 0x1D126}, {0x1D129, 0x1D1E8}, {0x1D200, 0x1D245},
- {0x1D2E0, 0x1D2F3}, {0x1D300, 0x1D356}, {0x1D360, 0x1D378},
- {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F},
- {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC},
- {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3},
- {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514},
- {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E},
- {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, {0x1D54A, 0x1D550},
- {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B},
- {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
- {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
- {0x1E026, 0x1E02A}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D},
- {0x1E140, 0x1E149}, {0x1E14E, 0x1E14F}, {0x1E2C0, 0x1E2F9},
- {0x1E2FF, 0x1E2FF}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6},
- {0x1E900, 0x1E94B}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F},
- {0x1EC71, 0x1ECB4}, {0x1ED01, 0x1ED3D}, {0x1EE00, 0x1EE03},
- {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, {0x1EE24, 0x1EE24},
- {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37},
- {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B}, {0x1EE42, 0x1EE42},
- {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49}, {0x1EE4B, 0x1EE4B},
- {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52}, {0x1EE54, 0x1EE54},
- {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59}, {0x1EE5B, 0x1EE5B},
- {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F}, {0x1EE61, 0x1EE62},
- {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72},
- {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, {0x1EE7E, 0x1EE7E},
- {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3},
- {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, {0x1EEF0, 0x1EEF1},
- {0x1F000, 0x1F003}, {0x1F005, 0x1F02B}, {0x1F030, 0x1F093},
- {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF}, {0x1F0C1, 0x1F0CE},
- {0x1F0D1, 0x1F0F5}, {0x1F10B, 0x1F10F}, {0x1F12E, 0x1F12F},
- {0x1F16A, 0x1F16F}, {0x1F1AD, 0x1F1AD}, {0x1F1E6, 0x1F1FF},
- {0x1F321, 0x1F32C}, {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D},
- {0x1F394, 0x1F39F}, {0x1F3CB, 0x1F3CE}, {0x1F3D4, 0x1F3DF},
- {0x1F3F1, 0x1F3F3}, {0x1F3F5, 0x1F3F7}, {0x1F43F, 0x1F43F},
- {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FE}, {0x1F53E, 0x1F54A},
- {0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594},
- {0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F},
- {0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6D3, 0x1F6D4},
- {0x1F6E0, 0x1F6EA}, {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773},
- {0x1F780, 0x1F7D8}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847},
- {0x1F850, 0x1F859}, {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD},
- {0x1F8B0, 0x1F8B1}, {0x1F900, 0x1F90B}, {0x1F93B, 0x1F93B},
- {0x1F946, 0x1F946}, {0x1FA00, 0x1FA53}, {0x1FA60, 0x1FA6D},
- {0x1FB00, 0x1FB92}, {0x1FB94, 0x1FBCA}, {0x1FBF0, 0x1FBF9},
- {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
-}
-
-var emoji = table{
- {0x203C, 0x203C}, {0x2049, 0x2049}, {0x2122, 0x2122},
- {0x2139, 0x2139}, {0x2194, 0x2199}, {0x21A9, 0x21AA},
- {0x231A, 0x231B}, {0x2328, 0x2328}, {0x2388, 0x2388},
- {0x23CF, 0x23CF}, {0x23E9, 0x23F3}, {0x23F8, 0x23FA},
- {0x24C2, 0x24C2}, {0x25AA, 0x25AB}, {0x25B6, 0x25B6},
- {0x25C0, 0x25C0}, {0x25FB, 0x25FE}, {0x2600, 0x2605},
- {0x2607, 0x2612}, {0x2614, 0x2685}, {0x2690, 0x2705},
- {0x2708, 0x2712}, {0x2714, 0x2714}, {0x2716, 0x2716},
- {0x271D, 0x271D}, {0x2721, 0x2721}, {0x2728, 0x2728},
- {0x2733, 0x2734}, {0x2744, 0x2744}, {0x2747, 0x2747},
- {0x274C, 0x274C}, {0x274E, 0x274E}, {0x2753, 0x2755},
- {0x2757, 0x2757}, {0x2763, 0x2767}, {0x2795, 0x2797},
- {0x27A1, 0x27A1}, {0x27B0, 0x27B0}, {0x27BF, 0x27BF},
- {0x2934, 0x2935}, {0x2B05, 0x2B07}, {0x2B1B, 0x2B1C},
- {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x3030, 0x3030},
- {0x303D, 0x303D}, {0x3297, 0x3297}, {0x3299, 0x3299},
- {0x1F000, 0x1F0FF}, {0x1F10D, 0x1F10F}, {0x1F12F, 0x1F12F},
- {0x1F16C, 0x1F171}, {0x1F17E, 0x1F17F}, {0x1F18E, 0x1F18E},
- {0x1F191, 0x1F19A}, {0x1F1AD, 0x1F1E5}, {0x1F201, 0x1F20F},
- {0x1F21A, 0x1F21A}, {0x1F22F, 0x1F22F}, {0x1F232, 0x1F23A},
- {0x1F23C, 0x1F23F}, {0x1F249, 0x1F3FA}, {0x1F400, 0x1F53D},
- {0x1F546, 0x1F64F}, {0x1F680, 0x1F6FF}, {0x1F774, 0x1F77F},
- {0x1F7D5, 0x1F7FF}, {0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F},
- {0x1F85A, 0x1F85F}, {0x1F888, 0x1F88F}, {0x1F8AE, 0x1F8FF},
- {0x1F90C, 0x1F93A}, {0x1F93C, 0x1F945}, {0x1F947, 0x1FAFF},
- {0x1FC00, 0x1FFFD},
-}
diff --git a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_windows.go b/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_windows.go
deleted file mode 100644
index d6a61777d..000000000
--- a/examples/go-dashboard/src/github.com/mattn/go-runewidth/runewidth_windows.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// +build windows
-// +build !appengine
-
-package runewidth
-
-import (
- "syscall"
-)
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32")
- procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
-)
-
-// IsEastAsian return true if the current locale is CJK
-func IsEastAsian() bool {
- r1, _, _ := procGetConsoleOutputCP.Call()
- if r1 == 0 {
- return false
- }
-
- switch int(r1) {
- case 932, 51932, 936, 949, 950:
- return true
- }
-
- return false
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/.gitignore b/examples/go-dashboard/src/github.com/mum4k/termdash/.gitignore
deleted file mode 100644
index 97e9bcbaa..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# Exclude MacOS attribute files.
-.DS_Store
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/.travis.yml b/examples/go-dashboard/src/github.com/mum4k/termdash/.travis.yml
deleted file mode 100644
index 7c8b739a0..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: go
-go:
- - 1.14.x
- - 1.15.x
- - stable
-script:
- - go get -t ./...
- - go get -u golang.org/x/lint/golint
- - go test ./...
- - CGO_ENABLED=1 go test -race ./...
- - go vet ./...
- - diff -u <(echo -n) <(gofmt -d -s .)
- - diff -u <(echo -n) <(./internal/scripts/autogen_licences.sh .)
- - diff -u <(echo -n) <(golint ./...)
-env:
- global:
- - CGO_ENABLED=0
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/CHANGELOG.md b/examples/go-dashboard/src/github.com/mum4k/termdash/CHANGELOG.md
deleted file mode 100644
index 6889100b4..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/CHANGELOG.md
+++ /dev/null
@@ -1,361 +0,0 @@
-# Changelog
-
-All notable changes to this project are documented here.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [Unreleased]
-
-## [0.12.2] - 31-Aug-2020
-
-### Fixed
-
-- advanced the CI Go versions up to Go 1.15.
-- fixed the build status badge to correctly point to travis-ci.com instead of
- travis-ci.org.
-
-## [0.12.1] - 20-Jun-2020
-
-### Fixed
-
-- the `tcell` unit test can now pass in headless mode (when TERM="") which
- happens under bazel.
-- switching coveralls integration to Github application.
-
-## [0.12.0] - 10-Apr-2020
-
-### Added
-
-- Migrating to [Go modules](https://blog.golang.org/using-go-modules).
-- Renamed directory `internal` to `private` so that external widget development
- is possible. Noted in
- [README.md](https://github.com/mum4k/termdash/blob/master/README.md) that packages in the
- `private` directory don't have any API stability guarantee.
-
-## [0.11.0] - 7-Mar-2020
-
-#### Breaking API changes
-
-- Termdash now requires at least Go version 1.11.
-
-### Added
-
-- New [`tcell`](https://github.com/gdamore/tcell) based terminal implementation
- which implements the `terminalapi.Terminal` interface.
-- tcell implementation supports two initialization `Option`s:
- - `ColorMode` the terminal color output mode (defaults to 256 color mode)
- - `ClearStyle` the foreground and background color style to use when clearing
- the screen (defaults to the global ColorDefault for both foreground and
- background)
-
-### Fixed
-
-- Improved test coverage of the `Gauge` widget.
-
-## [0.10.0] - 5-Jun-2019
-
-### Added
-
-- Added `time.Duration` based `ValueFormatter` for the `LineChart` Y-axis labels.
-- Added round and suffix `ValueFormatter` for the `LineChart` Y-axis labels.
-- Added decimal and suffix `ValueFormatter` for the `LineChart` Y-axis labels.
-- Added a `container.SplitOption` that allows fixed size container splits.
-- Added `grid` functions that allow fixed size rows and columns.
-
-### Changed
-
-- The `LineChart` can format the labels on the Y-axis with a `ValueFormatter`.
-- The `SegmentDisplay` can now display dots and colons ('.' and ':').
-- The `Donut` widget now guarantees spacing between the donut and its label.
-- The continuous build on Travis CI now builds with cgo explicitly disabled to
- ensure both Termdash and its dependencies use pure Go.
-
-### Fixed
-
-- Lint issues found on the Go report card.
-- An internal library belonging to the `Text` widget was incorrectly passing
- `math.MaxUint32` as an int argument.
-
-## [0.9.1] - 15-May-2019
-
-### Fixed
-
-- Termdash could deadlock when a `Button` or a `TextInput` was configured to
- call the `Container.Update` method.
-
-## [0.9.0] - 28-Apr-2019
-
-### Added
-
-- The `TextInput` widget, an input field allowing interactive text input.
-- The `Donut` widget can now display an optional text label under the donut.
-
-### Changed
-
-- Widgets now get information whether their container is focused when Draw is
- executed.
-- The SegmentDisplay widget now has a method that returns the observed character
- capacity the last time Draw was called.
-- The grid.Builder API now allows users to specify options for intermediate
- containers, i.e. containers that don't have widgets, but represent rows and
- columns.
-- Line chart widget now allows `math.NaN` values to represent "no value" (values
- that will not be rendered) in the values slice.
-
-#### Breaking API changes
-
-- The widgetapi.Widget.Draw method now accepts a second argument which provides
- widgets with additional metadata. This affects all implemented widgets.
-- 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
-
-### Added
-
-- New API for building layouts, a grid.Builder. Allows defining the layout
- iteratively as repetitive Elements, Rows and Columns.
-- Containers now support margin around them and padding of their content.
-- Container now supports dynamic layout changes via the new Update method.
-
-### Changed
-
-- The Text widget now supports content wrapping on word boundaries.
-- The BarChart and SparkLine widgets now have a method that returns the
- observed value capacity the last time Draw was called.
-- Moving widgetapi out of the internal directory to allow external users to
- develop their own widgets.
-- Event delivery to widgets now has a stable defined order and happens when the
- container is unlocked so that widgets can trigger dynamic layout changes.
-
-### Fixed
-
-- The termdash_test now correctly waits until all subscribers processed events,
- not just received them.
-- Container focus tracker now correctly tracks focus changes in enlarged areas,
- i.e. when the terminal size increased.
-- The BarChart, LineChart and SegmentDisplay widgets now protect against
- external mutation of the values passed into them by copying the data they
- receive.
-
-## [0.7.2] - 25-Feb-2019
-
-### Added
-
-- Test coverage for data only packages.
-
-### Changed
-
-- Refactoring packages that contained a mix of public and internal identifiers.
-
-#### Breaking API changes
-
-The following packages were refactored, no impact is expected as the removed
-identifiers shouldn't be used externally.
-
-- Functions align.Text and align.Rectangle were moved to a new
- internal/alignfor package.
-- Types cell.Cell and cell.Buffer were moved into a new internal/canvas/buffer
- package.
-
-## [0.7.1] - 24-Feb-2019
-
-### Fixed
-
-- Some of the packages that were moved into internal are required externally.
- This release makes them available again.
-
-### Changed
-
-#### Breaking API changes
-
-- The draw.LineStyle enum was refactored into its own package
- linestyle.LineStyle. Users will have to replace:
-
- - draw.LineStyleNone -> linestyle.None
- - draw.LineStyleLight -> linestyle.Light
- - draw.LineStyleDouble -> linestyle.Double
- - draw.LineStyleRound -> linestyle.Round
-
-## [0.7.0] - 24-Feb-2019
-
-### Added
-
-#### New widgets
-
-- The Button widget.
-
-#### Improvements to documentation
-
-- Clearly marked the public API surface by moving private packages into
- internal directory.
-- Started a GitHub wiki for Termdash.
-
-#### Improvements to the LineChart widget
-
-- The LineChart widget can display X axis labels in vertical orientation.
-- The LineChart widget allows the user to specify a custom scale for the Y
- axis.
-- The LineChart widget now has an option that disables scaling of the X axis.
- Useful for applications that want to continuously feed data and make them
- "roll" through the linechart.
-- The LineChart widget now has a method that returns the observed capacity of
- the LineChart the last time Draw was called.
-- The LineChart widget now supports zoom of the content triggered by mouse
- events.
-
-#### Improvements to the Text widget
-
-- The Text widget now has a Write option that atomically replaces the entire
- text content.
-
-#### Improvements to the infrastructure
-
-- A function that draws text vertically.
-- A non-blocking event distribution system that can throttle repetitive events.
-- Generalized mouse button FSM for use in widgets that need to track mouse
- button clicks.
-
-### Changed
-
-- Termbox is now initialized in 256 color mode by default.
-- The infrastructure now uses the non-blocking event distribution system to
- distribute events to subscribers. Each widget is now an individual
- subscriber.
-- The infrastructure now throttles event driven screen redraw rather than
- redrawing for each input event.
-- Widgets can now specify the scope at which they want to receive keyboard and
- mouse events.
-
-#### Breaking API changes
-
-##### High impact
-
-- The constructors of all the widgets now also return an error so that they
- can validate the options. This is a breaking change for the following
- widgets: BarChart, Gauge, LineChart, SparkLine, Text. The callers will have
- to handle the returned error.
-
-##### Low impact
-
-- The container package no longer exports separate methods to receive Keyboard
- and Mouse events which were replaced by a Subscribe method for the event
- distribution system. This shouldn't affect users as the removed methods
- aren't needed by container users.
-- The widgetapi.Options struct now uses an enum instead of a boolean when
- widget specifies if it wants keyboard or mouse events. This only impacts
- development of new widgets.
-
-### Fixed
-
-- The LineChart widget now correctly determines the Y axis scale when multiple
- series are provided.
-- Lint issues in the codebase, and updated Travis configuration so that golint
- is executed on every run.
-- Termdash now correctly starts in locales like zh_CN.UTF-8 where some of the
- characters it uses internally can have ambiguous width.
-
-## [0.6.1] - 12-Feb-2019
-
-### Fixed
-
-- The LineChart widget now correctly places custom labels.
-
-## [0.6.0] - 07-Feb-2019
-
-### Added
-
-- The SegmentDisplay widget.
-- A CHANGELOG.
-- New line styles for borders.
-
-### Changed
-
-- Better recordings of the individual demos.
-
-### Fixed
-
-- The LineChart now has an option to change the behavior of the Y axis from
- zero anchored to adaptive.
-- Lint errors reported on the Go report card.
-- Widgets now correctly handle a race when new user data are supplied between
- calls to their Options() and Draw() methods.
-
-## [0.5.0] - 21-Jan-2019
-
-### Added
-
-- Draw primitives for drawing circles.
-- The Donut widget.
-
-### Fixed
-
-- Bugfixes in the braille canvas.
-- Lint errors reported on the Go report card.
-- Flaky behavior in termdash_test.
-
-## [0.4.0] - 15-Jan-2019
-
-### Added
-
-- 256 color support.
-- Variable size container splits.
-- A more complete demo of the functionality.
-
-### Changed
-
-- Updated documentation and README.
-
-## [0.3.0] - 13-Jan-2019
-
-### Added
-
-- Primitives for drawing lines.
-- Implementation of a Braille canvas.
-- The LineChart widget.
-
-## [0.2.0] - 02-Jul-2018
-
-### Added
-
-- The SparkLine widget.
-- The BarChart widget.
-- Manually triggered redraw.
-- Travis now checks for presence of licence headers.
-
-### Fixed
-
-- Fixing races in termdash_test.
-
-## 0.1.0 - 13-Jun-2018
-
-### Added
-
-- Documentation of the project and its goals.
-- Drawing infrastructure.
-- Testing infrastructure.
-- The Gauge widget.
-- The Text widget.
-
-[unreleased]: https://github.com/mum4k/termdash/compare/v0.12.2...devel
-[0.12.2]: https://github.com/mum4k/termdash/compare/v0.12.1...v0.12.2
-[0.12.1]: https://github.com/mum4k/termdash/compare/v0.12.0...v0.12.1
-[0.12.0]: https://github.com/mum4k/termdash/compare/v0.11.0...v0.12.0
-[0.11.0]: https://github.com/mum4k/termdash/compare/v0.10.0...v0.11.0
-[0.10.0]: https://github.com/mum4k/termdash/compare/v0.9.1...v0.10.0
-[0.9.1]: https://github.com/mum4k/termdash/compare/v0.9.0...v0.9.1
-[0.9.0]: https://github.com/mum4k/termdash/compare/v0.8.0...v0.9.0
-[0.8.0]: https://github.com/mum4k/termdash/compare/v0.7.2...v0.8.0
-[0.7.2]: https://github.com/mum4k/termdash/compare/v0.7.1...v0.7.2
-[0.7.1]: https://github.com/mum4k/termdash/compare/v0.7.0...v0.7.1
-[0.7.0]: https://github.com/mum4k/termdash/compare/v0.6.1...v0.7.0
-[0.6.1]: https://github.com/mum4k/termdash/compare/v0.6.0...v0.6.1
-[0.6.0]: https://github.com/mum4k/termdash/compare/v0.5.0...v0.6.0
-[0.5.0]: https://github.com/mum4k/termdash/compare/v0.4.0...v0.5.0
-[0.4.0]: https://github.com/mum4k/termdash/compare/v0.3.0...v0.4.0
-[0.3.0]: https://github.com/mum4k/termdash/compare/v0.2.0...v0.3.0
-[0.2.0]: https://github.com/mum4k/termdash/compare/v0.1.0...v0.2.0
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/CONTRIBUTING.md b/examples/go-dashboard/src/github.com/mum4k/termdash/CONTRIBUTING.md
deleted file mode 100644
index 9f2027288..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/CONTRIBUTING.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# How to Contribute
-
-We'd love to accept your patches and contributions to this project. There are
-just a few small guidelines you need to follow.
-
-## Fork and merge into the "devel" branch
-
-All development in termdash repository must happen in the [devel
-branch](https://github.com/mum4k/termdash/tree/devel). The devel branch is
-merged into the master branch during release of each new version.
-
-When you fork the termdash repository, be sure to checkout the devel branch.
-When you are creating a pull request, be sure to pull back into the devel
-branch.
-
-## Contributor License Agreement
-
-Contributions to this project must be accompanied by a Contributor License
-Agreement. You (or your employer) retain the copyright to your contribution;
-this simply gives us permission to use and redistribute your contributions as
-part of the project. Head over to <https://cla.developers.google.com/> to see
-your current agreements on file or to sign a new one.
-
-You generally only need to submit a CLA once, so if you've already submitted one
-(even if it was for a different project), you probably don't need to do it
-again.
-
-## Code reviews
-
-All submissions, including submissions by project members, require review. We
-use GitHub pull requests for this purpose. Consult
-[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
-information on using pull requests.
-
-## Community Guidelines
-
-This project follows [Google's Open Source Community
-Guidelines](https://opensource.google.com/conduct/).
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/LICENSE b/examples/go-dashboard/src/github.com/mum4k/termdash/LICENSE
deleted file mode 100644
index 261eeb9e9..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/README.md b/examples/go-dashboard/src/github.com/mum4k/termdash/README.md
deleted file mode 100644
index 8ecd1fd53..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/README.md
+++ /dev/null
@@ -1,215 +0,0 @@
-[![Doc Status](https://godoc.org/github.com/mum4k/termdash?status.png)](https://godoc.org/github.com/mum4k/termdash)
-[![Build Status](https://travis-ci.com/mum4k/termdash.svg?branch=master)](https://travis-ci.com/mum4k/termdash)
-[![Sourcegraph](https://sourcegraph.com/github.com/mum4k/termdash/-/badge.svg)](https://sourcegraph.com/github.com/mum4k/termdash?badge)
-[![Coverage Status](https://coveralls.io/repos/github/mum4k/termdash/badge.svg?branch=master)](https://coveralls.io/github/mum4k/termdash?branch=master)
-[![Go Report Card](https://goreportcard.com/badge/github.com/mum4k/termdash)](https://goreportcard.com/report/github.com/mum4k/termdash)
-[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/mum4k/termdash/blob/master/LICENSE)
-[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)
-
-# [<img src="./doc/images/termdash.png" alt="termdashlogo" type="image/png" width="30%">](http://github.com/mum4k/termdash/wiki)
-
-Termdash is a cross-platform customizable terminal based dashboard.
-
-[<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
-inspired by
-[yaronn/blessed-contrib](http://github.com/yaronn/blessed-contrib).
-
-This rewrite focuses on code readability, maintainability and testability, see
-the [design goals](doc/design_goals.md). It aims to achieve the following
-[requirements](doc/requirements.md). See the [high-level design](doc/hld.md)
-for more details.
-
-# Public API and status
-
-The public API surface is documented in the
-[wiki](http://github.com/mum4k/termdash/wiki).
-
-Private packages can be identified by the presence of the **/private/**
-directory in their import path. Stability of the private packages isn't
-guaranteed and changes won't be backward compatible.
-
-There might still be breaking changes to the public API, at least until the
-project reaches version 1.0.0. Any breaking changes will be published in the
-[changelog](CHANGELOG.md).
-
-# Current feature set
-
-- Full support for terminal window resizing throughout the infrastructure.
-- Customizable layout, widget placement, borders, margins, padding, colors, etc.
-- Dynamic layout changes at runtime.
-- Binary tree and Grid forms of setting up the layout.
-- Focusable containers and widgets.
-- Processing of keyboard and mouse events.
-- Periodic and event driven screen redraw.
-- A library of widgets, see below.
-- UTF-8 for all text elements.
-- Drawing primitives (Go functions) for widget development with character and
- sub-character resolution.
-
-# Installation
-
-To install this library, run the following:
-
-```go
-go get -u github.com/mum4k/termdash
-```
-
-# Usage
-
-The usage of most of these elements is demonstrated in
-[termdashdemo.go](termdashdemo/termdashdemo.go). To execute the demo:
-
-```go
-go run github.com/mum4k/termdash/termdashdemo/termdashdemo.go
-```
-
-# Documentation
-
-Please refer to the [Termdash wiki](http://github.com/mum4k/termdash/wiki) for
-all documentation and resources.
-
-# Implemented Widgets
-
-## The Button
-
-Allows users to interact with the application, each button press runs a callback function.
-Run the
-[buttondemo](widgets/button/buttondemo/buttondemo.go).
-
-```go
-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="80%">](widgets/textinput/textinputdemo/textinputdemo.go)
-
-## The Gauge
-
-Displays the progress of an operation. Run the
-[gaugedemo](widgets/gauge/gaugedemo/gaugedemo.go).
-
-```go
-go run github.com/mum4k/termdash/widgets/gauge/gaugedemo/gaugedemo.go
-```
-
-[<img src="./doc/images/gaugedemo.gif" alt="gaugedemo" type="image/gif">](widgets/gauge/gaugedemo/gaugedemo.go)
-
-## The Donut
-
-Visualizes progress of an operation as a partial or a complete donut. Run the
-[donutdemo](widgets/donut/donutdemo/donutdemo.go).
-
-```go
-go run github.com/mum4k/termdash/widgets/donut/donutdemo/donutdemo.go
-```
-
-[<img src="./doc/images/donutdemo.gif" alt="donutdemo" type="image/gif">](widgets/donut/donutdemo/donutdemo.go)
-
-## The Text
-
-Displays text content, supports trimming and scrolling of content. Run the
-[textdemo](widgets/text/textdemo/textdemo.go).
-
-```go
-go run github.com/mum4k/termdash/widgets/text/textdemo/textdemo.go
-```
-
-[<img src="./doc/images/textdemo.gif" alt="textdemo" type="image/gif">](widgets/text/textdemo/textdemo.go)
-
-## The SparkLine
-
-Draws a graph showing a series of values as vertical bars. The bars can have
-sub-cell height. Run the
-[sparklinedemo](widgets/sparkline/sparklinedemo/sparklinedemo.go).
-
-```go
-go run github.com/mum4k/termdash/widgets/sparkline/sparklinedemo/sparklinedemo.go
-```
-
-[<img src="./doc/images/sparklinedemo.gif" alt="sparklinedemo" type="image/gif" width="50%">](widgets/sparkline/sparklinedemo/sparklinedemo.go)
-
-## The BarChart
-
-Displays multiple bars showing relative ratios of values. Run the
-[barchartdemo](widgets/barchart/barchartdemo/barchartdemo.go).
-
-```go
-go run github.com/mum4k/termdash/widgets/barchart/barchartdemo/barchartdemo.go
-```
-
-[<img src="./doc/images/barchartdemo.gif" alt="barchartdemo" type="image/gif" width="50%">](widgets/barchart/barchartdemo/barchartdemo.go)
-
-## The LineChart
-
-Displays series of values on a line chart, supports zoom triggered by mouse
-events. Run the
-[linechartdemo](widgets/linechart/linechartdemo/linechartdemo.go).
-
-```go
-go run github.com/mum4k/termdash/widgets/linechart/linechartdemo/linechartdemo.go
-```
-
-[<img src="./doc/images/linechartdemo.gif" alt="linechartdemo" type="image/gif" width="70%">](widgets/linechart/linechartdemo/linechartdemo.go)
-
-## The SegmentDisplay
-
-Displays text by simulating a 16-segment display. Run the
-[segmentdisplaydemo](widgets/segmentdisplay/segmentdisplaydemo/segmentdisplaydemo.go).
-
-```go
-go run github.com/mum4k/termdash/widgets/segmentdisplay/segmentdisplaydemo/segmentdisplaydemo.go
-```
-
-[<img src="./doc/images/segmentdisplaydemo.gif" alt="segmentdisplaydemo" type="image/gif">](widgets/segmentdisplay/segmentdisplaydemo/segmentdisplaydemo.go)
-
-# Contributing
-
-If you are willing to contribute, improve the infrastructure or develop a
-widget, first of all Thank You! Your help is appreciated.
-
-Please see the [CONTRIBUTING.md](CONTRIBUTING.md) file for guidelines related
-to the Google's CLA, and code review requirements.
-
-As stated above the primary goal of this project is to develop readable, well
-designed code, the functionality and efficiency come second. This is achieved
-through detailed code reviews, design discussions and following of the [design
-guidelines](doc/design_guidelines.md). Please familiarize yourself with these
-before contributing.
-
-If you're developing a new widget, please see the [widget
-development](doc/widget_development.md) section.
-
-Termdash uses [this branching model](https://nvie.com/posts/a-successful-git-branching-model/). When you fork the repository, base your changes off the [devel](https://github.com/mum4k/termdash/tree/devel) branch and the pull request should merge it back to the devel branch. Commits to the master branch are limited to releases, major bug fixes and documentation updates.
-
-# Similar projects in Go
-
-- [clui](https://github.com/VladimirMarkelov/clui)
-- [gocui](https://github.com/jroimartin/gocui)
-- [gowid](https://github.com/gcla/gowid)
-- [termui](https://github.com/gizak/termui)
-- [tui-go](https://github.com/marcusolsson/tui-go)
-- [tview](https://github.com/rivo/tview)
-
-# Projects using Termdash
-
-- [datadash](https://github.com/keithknott26/datadash): Visualize streaming or tabular data inside the terminal.
-- [grafterm](https://github.com/slok/grafterm): Metrics dashboards visualization on the terminal.
-- [perfstat](https://github.com/flaviostutz/perfstat): Analyze and show tips about possible bottlenecks in Linux systems.
-
-# Disclaimer
-
-This is not an official Google product.
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/align/align.go b/examples/go-dashboard/src/github.com/mum4k/termdash/align/align.go
deleted file mode 100644
index da4087f57..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/align/align.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package align defines constants representing types of alignment.
-package align
-
-// Horizontal indicates the type of horizontal alignment.
-type Horizontal int
-
-// String implements fmt.Stringer()
-func (h Horizontal) String() string {
- if n, ok := horizontalNames[h]; ok {
- return n
- }
- return "HorizontalUnknown"
-}
-
-// horizontalNames maps Horizontal values to human readable names.
-var horizontalNames = map[Horizontal]string{
- HorizontalLeft: "HorizontalLeft",
- HorizontalCenter: "HorizontalCenter",
- HorizontalRight: "HorizontalRight",
-}
-
-const (
- // HorizontalLeft is left alignment along the horizontal axis.
- HorizontalLeft Horizontal = iota
- // HorizontalCenter is center alignment along the horizontal axis.
- HorizontalCenter
- // HorizontalRight is right alignment along the horizontal axis.
- HorizontalRight
-)
-
-// Vertical indicates the type of vertical alignment.
-type Vertical int
-
-// String implements fmt.Stringer()
-func (v Vertical) String() string {
- if n, ok := verticalNames[v]; ok {
- return n
- }
- return "VerticalUnknown"
-}
-
-// verticalNames maps Vertical values to human readable names.
-var verticalNames = map[Vertical]string{
- VerticalTop: "VerticalTop",
- VerticalMiddle: "VerticalMiddle",
- VerticalBottom: "VerticalBottom",
-}
-
-const (
- // VerticalTop is top alignment along the vertical axis.
- VerticalTop Vertical = iota
- // VerticalMiddle is middle alignment along the vertical axis.
- VerticalMiddle
- // VerticalBottom is bottom alignment along the vertical axis.
- VerticalBottom
-)
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/cell/cell.go b/examples/go-dashboard/src/github.com/mum4k/termdash/cell/cell.go
deleted file mode 100644
index c3eb6df24..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/cell/cell.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package cell implements cell options and attributes.
-package cell
-
-// Option is used to provide options for cells on a 2-D terminal.
-type Option interface {
- // Set sets the provided option.
- Set(*Options)
-}
-
-// Options stores the provided options.
-type Options struct {
- FgColor Color
- 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{}
- for _, opt := range opts {
- opt.Set(o)
- }
- return o
-}
-
-// option implements Option.
-type option func(*Options)
-
-// Set implements Option.set.
-func (co option) Set(opts *Options) {
- co(opts)
-}
-
-// FgColor sets the foreground color of the cell.
-func FgColor(color Color) Option {
- return option(func(co *Options) {
- co.FgColor = color
- })
-}
-
-// BgColor sets the background color of the cell.
-func BgColor(color Color) Option {
- return option(func(co *Options) {
- co.BgColor = color
- })
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/cell/color.go b/examples/go-dashboard/src/github.com/mum4k/termdash/cell/color.go
deleted file mode 100644
index 94560b74c..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/cell/color.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cell
-
-import (
- "fmt"
-)
-
-// color.go defines constants for cell colors.
-
-// Color is the color of a cell.
-type Color int
-
-// String implements fmt.Stringer()
-func (cc Color) String() string {
- if n, ok := colorNames[cc]; ok {
- return n
- }
- return fmt.Sprintf("Color:%d", cc)
-}
-
-// colorNames maps Color values to human readable names.
-var colorNames = map[Color]string{
- ColorDefault: "ColorDefault",
- ColorBlack: "ColorBlack",
- ColorRed: "ColorRed",
- ColorGreen: "ColorGreen",
- ColorYellow: "ColorYellow",
- ColorBlue: "ColorBlue",
- ColorMagenta: "ColorMagenta",
- ColorCyan: "ColorCyan",
- ColorWhite: "ColorWhite",
-}
-
-// The supported terminal colors.
-const (
- ColorDefault Color = iota
-
- // 8 "system" colors.
- ColorBlack
- ColorRed
- ColorGreen
- ColorYellow
- ColorBlue
- ColorMagenta
- ColorCyan
- ColorWhite
-)
-
-// ColorNumber sets a color using its number.
-// Make sure your terminal is set to a terminalapi.ColorMode that supports the
-// target color. The provided value must be in the range 0-255.
-// Larger or smaller values will be reset to the default color.
-//
-// For reference on these colors see the Xterm number in:
-// https://jonasjacek.github.io/colors/
-func ColorNumber(n int) Color {
- if n < 0 || n > 255 {
- return ColorDefault
- }
- return Color(n + 1) // Colors are off-by-one due to ColorDefault being zero.
-}
-
-// ColorRGB6 sets a color using the 6x6x6 terminal color.
-// Make sure your terminal is set to the terminalapi.ColorMode256 mode.
-// The provided values (r, g, b) must be in the range 0-5.
-// Larger or smaller values will be reset to the default color.
-//
-// For reference on these colors see:
-// https://superuser.com/questions/783656/whats-the-deal-with-terminal-colors
-func ColorRGB6(r, g, b int) Color {
- for _, c := range []int{r, g, b} {
- if c < 0 || c > 5 {
- return ColorDefault
- }
- }
- return Color(0x10 + 36*r + 6*g + b + 1) // Colors are off-by-one due to ColorDefault being zero.
-}
-
-// ColorRGB24 sets a color using the 24 bit web color scheme.
-// Make sure your terminal is set to the terminalapi.ColorMode256 mode.
-// The provided values (r, g, b) must be in the range 0-255.
-// Larger or smaller values will be reset to the default color.
-//
-// For reference on these colors see the RGB column in:
-// https://jonasjacek.github.io/colors/
-func ColorRGB24(r, g, b int) Color {
- for _, c := range []int{r, g, b} {
- if c < 0 || c > 255 {
- return ColorDefault
- }
- }
- return ColorRGB6(r/51, g/51, b/51)
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/container/container.go b/examples/go-dashboard/src/github.com/mum4k/termdash/container/container.go
deleted file mode 100644
index 54cef7856..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/container/container.go
+++ /dev/null
@@ -1,471 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/*
-Package container defines a type that wraps other containers or widgets.
-
-The container supports splitting container into sub containers, defining
-container styles and placing widgets. The container also creates and manages
-canvases assigned to the placed widgets.
-*/
-package container
-
-import (
- "errors"
- "fmt"
- "image"
- "sync"
-
- "github.com/mum4k/termdash/linestyle"
- "github.com/mum4k/termdash/private/alignfor"
- "github.com/mum4k/termdash/private/area"
- "github.com/mum4k/termdash/private/event"
- "github.com/mum4k/termdash/terminal/terminalapi"
- "github.com/mum4k/termdash/widgetapi"
-)
-
-// Container wraps either sub containers or widgets and positions them on the
-// terminal.
-// This is thread-safe.
-type Container struct {
- // parent is the parent container, nil if this is the root container.
- parent *Container
- // The sub containers, if these aren't nil, the widget must be.
- first *Container
- second *Container
-
- // term is the terminal this container is placed on.
- // All containers in the tree share the same terminal.
- term terminalapi.Terminal
-
- // focusTracker tracks the active (focused) container.
- // All containers in the tree share the same tracker.
- focusTracker *focusTracker
-
- // area is the area of the terminal this container has access to.
- // Initialized the first time Draw is called.
- area image.Rectangle
-
- // opts are the options provided to the container.
- opts *options
-
- // clearNeeded indicates if the terminal needs to be cleared next time we
- // are clearNeeded the container.
- // This is required if the container was updated and thus the layout might
- // have changed.
- clearNeeded bool
-
- // mu protects the container tree.
- // All containers in the tree share the same lock.
- mu *sync.Mutex
-}
-
-// String represents the container metadata in a human readable format.
-// Implements fmt.Stringer.
-func (c *Container) String() string {
- return fmt.Sprintf("Container@%p{parent:%p, first:%p, second:%p, area:%+v}", c, c.parent, c.first, c.second, c.area)
-}
-
-// New returns a new root container that will use the provided terminal and
-// applies the provided options.
-func New(t terminalapi.Terminal, opts ...Option) (*Container, error) {
- root := &Container{
- term: t,
- opts: newOptions( /* parent = */ nil),
- mu: &sync.Mutex{},
- }
-
- // Initially the root is focused.
- root.focusTracker = newFocusTracker(root)
- if err := applyOptions(root, opts...); err != nil {
- return nil, err
- }
- if err := validateOptions(root); err != nil {
- return nil, err
- }
- return root, nil
-}
-
-// newChild creates a new child container of the given parent.
-func newChild(parent *Container, opts []Option) (*Container, error) {
- child := &Container{
- parent: parent,
- term: parent.term,
- focusTracker: parent.focusTracker,
- opts: newOptions(parent.opts),
- mu: parent.mu,
- }
- if err := applyOptions(child, opts...); err != nil {
- return nil, err
- }
- return child, nil
-}
-
-// hasBorder determines if this container has a border.
-func (c *Container) hasBorder() bool {
- return c.opts.border != linestyle.None
-}
-
-// hasWidget determines if this container has a widget.
-func (c *Container) hasWidget() bool {
- return c.opts.widget != nil
-}
-
-// usable returns the usable area in this container.
-// This depends on whether the container has a border, etc.
-func (c *Container) usable() image.Rectangle {
- if c.hasBorder() {
- return area.ExcludeBorder(c.area)
- }
- return c.area
-}
-
-// widgetArea returns the area in the container that is available for the
-// widget's canvas. Takes the container border, widget's requested maximum size
-// and ratio and container's alignment into account.
-// Returns a zero area if the container has no widget.
-func (c *Container) widgetArea() (image.Rectangle, error) {
- if !c.hasWidget() {
- return image.ZR, nil
- }
-
- padded, err := c.opts.padding.apply(c.usable())
- if err != nil {
- return image.ZR, err
- }
- wOpts := c.opts.widget.Options()
-
- adjusted := padded
- if maxX := wOpts.MaximumSize.X; maxX > 0 && adjusted.Dx() > maxX {
- adjusted.Max.X -= adjusted.Dx() - maxX
- }
- if maxY := wOpts.MaximumSize.Y; maxY > 0 && adjusted.Dy() > maxY {
- adjusted.Max.Y -= adjusted.Dy() - maxY
- }
-
- if wOpts.Ratio.X > 0 && wOpts.Ratio.Y > 0 {
- adjusted = area.WithRatio(adjusted, wOpts.Ratio)
- }
- aligned, err := alignfor.Rectangle(padded, adjusted, c.opts.hAlign, c.opts.vAlign)
- if err != nil {
- return image.ZR, err
- }
- return aligned, nil
-}
-
-// split splits the container's usable area into child areas.
-// Panics if the container isn't configured for a split.
-func (c *Container) split() (image.Rectangle, image.Rectangle, error) {
- ar, err := c.opts.padding.apply(c.usable())
- if err != nil {
- return image.ZR, image.ZR, err
- }
- if c.opts.splitFixed > DefaultSplitFixed {
- if c.opts.split == splitTypeVertical {
- return area.VSplitCells(ar, c.opts.splitFixed)
- }
- return area.HSplitCells(ar, c.opts.splitFixed)
- }
-
- if c.opts.split == splitTypeVertical {
- return area.VSplit(ar, c.opts.splitPercent)
- }
- return area.HSplit(ar, c.opts.splitPercent)
-}
-
-// createFirst creates and returns the first sub container of this container.
-func (c *Container) createFirst(opts []Option) error {
- first, err := newChild(c, opts)
- if err != nil {
- return err
- }
- c.first = first
- return nil
-}
-
-// createSecond creates and returns the second sub container of this container.
-func (c *Container) createSecond(opts []Option) error {
- second, err := newChild(c, opts)
- if err != nil {
- return err
- }
- c.second = second
- return nil
-}
-
-// Draw draws this container and all of its sub containers.
-func (c *Container) Draw() error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if c.clearNeeded {
- if err := c.term.Clear(); err != nil {
- return fmt.Errorf("term.Clear => error: %v", err)
- }
- c.clearNeeded = false
- }
-
- // Update the area we are tracking for focus in case the terminal size
- // changed.
- ar, err := area.FromSize(c.term.Size())
- if err != nil {
- return err
- }
- c.focusTracker.updateArea(ar)
- return drawTree(c)
-}
-
-// Update updates container with the specified id by setting the provided
-// options. This can be used to perform dynamic layout changes, i.e. anything
-// between replacing the widget in the container and completely changing the
-// layout and splits.
-// The argument id must match exactly one container with that was created with
-// matching ID() option. The argument id must not be an empty string.
-func (c *Container) Update(id string, opts ...Option) error {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- target, err := findID(c, id)
- if err != nil {
- return err
- }
- c.clearNeeded = true
-
- if err := applyOptions(target, opts...); err != nil {
- return err
- }
- if err := validateOptions(c); err != nil {
- return err
- }
-
- // The currently focused container might not be reachable anymore, because
- // it was under the target. If that is so, move the focus up to the target.
- if !c.focusTracker.reachableFrom(c) {
- c.focusTracker.setActive(target)
- }
- return nil
-}
-
-// updateFocus processes the mouse event and determines if it changes the
-// focused container.
-// Caller must hold c.mu.
-func (c *Container) updateFocus(m *terminalapi.Mouse) {
- target := pointCont(c, m.Position)
- if target == nil { // Ignore mouse clicks where no containers are.
- return
- }
- c.focusTracker.mouse(target, m)
-}
-
-// processEvent processes events delivered to the container.
-func (c *Container) processEvent(ev terminalapi.Event) error {
- // This is done in two stages.
- // 1) under lock we traverse the container and identify all targets
- // (widgets) that should receive the event.
- // 2) lock is released and events are delivered to the widgets. Widgets
- // themselves are thread-safe. Lock must be releases when delivering,
- // because some widgets might try to mutate the container when they
- // receive the event, like dynamically change the layout.
- c.mu.Lock()
- sendFn, err := c.prepareEvTargets(ev)
- c.mu.Unlock()
- if err != nil {
- return err
- }
- return sendFn()
-}
-
-// prepareEvTargets returns a closure, that when called delivers the event to
-// widgets that registered for it.
-// Also processes the event on behalf of the container (tracks keyboard focus).
-// Caller must hold c.mu.
-func (c *Container) prepareEvTargets(ev terminalapi.Event) (func() error, error) {
- switch e := ev.(type) {
- case *terminalapi.Mouse:
- c.updateFocus(ev.(*terminalapi.Mouse))
-
- targets, err := c.mouseEvTargets(e)
- if err != nil {
- return nil, err
- }
- return func() error {
- for _, mt := range targets {
- if err := mt.widget.Mouse(mt.ev); err != nil {
- return err
- }
- }
- return nil
- }, nil
-
- case *terminalapi.Keyboard:
- targets := c.keyEvTargets()
- return func() error {
- for _, w := range targets {
- if err := w.Keyboard(e); err != nil {
- return err
- }
- }
- return nil
- }, nil
-
- default:
- return nil, fmt.Errorf("container received an unsupported event type %T", ev)
- }
-}
-
-// keyEvTargets returns those widgets found in the container that should
-// receive this keyboard event.
-// Caller must hold c.mu.
-func (c *Container) keyEvTargets() []widgetapi.Widget {
- var (
- errStr string
- widgets []widgetapi.Widget
- )
-
- // All the widgets that should receive this event.
- // For now stable ordering (preOrder).
- preOrder(c, &errStr, visitFunc(func(cur *Container) error {
- if !cur.hasWidget() {
- return nil
- }
-
- wOpt := cur.opts.widget.Options()
- switch wOpt.WantKeyboard {
- case widgetapi.KeyScopeNone:
- // Widget doesn't want any keyboard events.
- return nil
-
- case widgetapi.KeyScopeFocused:
- if cur.focusTracker.isActive(cur) {
- widgets = append(widgets, cur.opts.widget)
- }
-
- case widgetapi.KeyScopeGlobal:
- widgets = append(widgets, cur.opts.widget)
- }
- return nil
- }))
- return widgets
-}
-
-// mouseEvTarget contains a mouse event adjusted relative to the widget's area
-// and the widget that should receive it.
-type mouseEvTarget struct {
- // widget is the widget that should receive the mouse event.
- widget widgetapi.Widget
- // ev is the adjusted mouse event.
- ev *terminalapi.Mouse
-}
-
-// newMouseEvTarget returns a new newMouseEvTarget.
-func newMouseEvTarget(w widgetapi.Widget, wArea image.Rectangle, ev *terminalapi.Mouse) *mouseEvTarget {
- return &mouseEvTarget{
- widget: w,
- ev: adjustMouseEv(ev, wArea),
- }
-}
-
-// mouseEvTargets returns those widgets found in the container that should
-// receive this mouse event.
-// Caller must hold c.mu.
-func (c *Container) mouseEvTargets(m *terminalapi.Mouse) ([]*mouseEvTarget, error) {
- var (
- errStr string
- widgets []*mouseEvTarget
- )
-
- // All the widgets that should receive this event.
- // For now stable ordering (preOrder).
- preOrder(c, &errStr, visitFunc(func(cur *Container) error {
- if !cur.hasWidget() {
- return nil
- }
-
- wOpts := cur.opts.widget.Options()
- wa, err := cur.widgetArea()
- if err != nil {
- return err
- }
-
- switch wOpts.WantMouse {
- case widgetapi.MouseScopeNone:
- // Widget doesn't want any mouse events.
- return nil
-
- case widgetapi.MouseScopeWidget:
- // Only if the event falls inside of the widget's canvas.
- if m.Position.In(wa) {
- widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m))
- }
-
- case widgetapi.MouseScopeContainer:
- // Only if the event falls inside the widget's parent container.
- if m.Position.In(cur.area) {
- widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m))
- }
-
- case widgetapi.MouseScopeGlobal:
- // Widget wants all mouse events.
- widgets = append(widgets, newMouseEvTarget(cur.opts.widget, wa, m))
- }
- return nil
- }))
-
- if errStr != "" {
- return nil, errors.New(errStr)
- }
- return widgets, nil
-}
-
-// Subscribe tells the container to subscribe itself and widgets to the
-// provided event distribution system.
-// This method is private to termdash, stability isn't guaranteed and changes
-// won't be backward compatible.
-func (c *Container) Subscribe(eds *event.DistributionSystem) {
- c.mu.Lock()
- defer c.mu.Unlock()
-
- // maxReps is the maximum number of repetitive events towards widgets
- // before we throttle them.
- const maxReps = 10
-
- // Subscriber the container itself in order to track keyboard focus.
- want := []terminalapi.Event{
- &terminalapi.Keyboard{},
- &terminalapi.Mouse{},
- }
- eds.Subscribe(want, func(ev terminalapi.Event) {
- if err := c.processEvent(ev); err != nil {
- eds.Event(terminalapi.NewErrorf("failed to process event %v: %v", ev, err))
- }
- }, event.MaxRepetitive(maxReps))
-}
-
-// adjustMouseEv adjusts the mouse event relative to the widget area.
-func adjustMouseEv(m *terminalapi.Mouse, wArea image.Rectangle) *terminalapi.Mouse {
- // The sent mouse coordinate is relative to the widget canvas, i.e. zero
- // based, even though the widget might not be in the top left corner on the
- // terminal.
- offset := wArea.Min
- if m.Position.In(wArea) {
- return &terminalapi.Mouse{
- Position: m.Position.Sub(offset),
- Button: m.Button,
- }
- }
- return &terminalapi.Mouse{
- Position: image.Point{-1, -1},
- Button: m.Button,
- }
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/container/draw.go b/examples/go-dashboard/src/github.com/mum4k/termdash/container/draw.go
deleted file mode 100644
index d186b1272..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/container/draw.go
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package container
-
-// draw.go contains logic to draw containers and the contained widgets.
-
-import (
- "errors"
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/area"
- "github.com/mum4k/termdash/private/canvas"
- "github.com/mum4k/termdash/private/draw"
- "github.com/mum4k/termdash/widgetapi"
-)
-
-// drawTree draws this container and all of its sub containers.
-func drawTree(c *Container) error {
- var errStr string
-
- root := rootCont(c)
- size := root.term.Size()
- ar, err := root.opts.margin.apply(image.Rect(0, 0, size.X, size.Y))
- if err != nil {
- return err
- }
- root.area = ar
-
- preOrder(root, &errStr, visitFunc(func(c *Container) error {
- first, second, err := c.split()
- if err != nil {
- return err
- }
- if c.first != nil {
- ar, err := c.first.opts.margin.apply(first)
- if err != nil {
- return err
- }
- c.first.area = ar
- }
-
- if c.second != nil {
- ar, err := c.second.opts.margin.apply(second)
- if err != nil {
- return err
- }
- c.second.area = ar
- }
- return drawCont(c)
- }))
- if errStr != "" {
- return errors.New(errStr)
- }
- return nil
-}
-
-// drawBorder draws the border around the container if requested.
-func drawBorder(c *Container) error {
- if !c.hasBorder() {
- return nil
- }
-
- cvs, err := canvas.New(c.area)
- if err != nil {
- return err
- }
-
- ar, err := area.FromSize(cvs.Size())
- if err != nil {
- return err
- }
-
- var cOpts []cell.Option
- if c.focusTracker.isActive(c) {
- cOpts = append(cOpts, cell.FgColor(c.opts.inherited.focusedColor))
- } else {
- cOpts = append(cOpts, cell.FgColor(c.opts.inherited.borderColor))
- }
-
- if err := draw.Border(cvs, ar,
- draw.BorderLineStyle(c.opts.border),
- draw.BorderTitle(c.opts.borderTitle, draw.OverrunModeThreeDot, cOpts...),
- draw.BorderTitleAlign(c.opts.borderTitleHAlign),
- draw.BorderCellOpts(cOpts...),
- ); err != nil {
- return err
- }
- return cvs.Apply(c.term)
-}
-
-// drawWidget requests the widget to draw on the canvas.
-func drawWidget(c *Container) error {
- widgetArea, err := c.widgetArea()
- if err != nil {
- return err
- }
- if widgetArea == image.ZR {
- return nil
- }
-
- if !c.hasWidget() {
- return nil
- }
-
- needSize := image.Point{1, 1}
- wOpts := c.opts.widget.Options()
- if wOpts.MinimumSize.X > 0 && wOpts.MinimumSize.Y > 0 {
- needSize = wOpts.MinimumSize
- }
-
- if widgetArea.Dx() < needSize.X || widgetArea.Dy() < needSize.Y {
- return drawResize(c, c.usable())
- }
-
- cvs, err := canvas.New(widgetArea)
- if err != nil {
- return err
- }
-
- meta := &widgetapi.Meta{
- Focused: c.focusTracker.isActive(c),
- }
-
- if err := c.opts.widget.Draw(cvs, meta); err != nil {
- return err
- }
- return cvs.Apply(c.term)
-}
-
-// drawResize draws an unicode character indicating that the size is too small to draw this container.
-// Does nothing if the size is smaller than one cell, leaving no space for the character.
-func drawResize(c *Container, area image.Rectangle) error {
- if area.Dx() < 1 || area.Dy() < 1 {
- return nil
- }
-
- cvs, err := canvas.New(area)
- if err != nil {
- return err
- }
- if err := draw.ResizeNeeded(cvs); err != nil {
- return err
- }
- return cvs.Apply(c.term)
-}
-
-// drawCont draws the container and its widget.
-func drawCont(c *Container) error {
- if us := c.usable(); us.Dx() <= 0 || us.Dy() <= 0 {
- return drawResize(c, c.area)
- }
-
- if err := drawBorder(c); err != nil {
- return fmt.Errorf("unable to draw container border: %v", err)
- }
-
- if err := drawWidget(c); err != nil {
- return fmt.Errorf("unable to draw widget %T: %v", c.opts.widget, err)
- }
- return nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/container/focus.go b/examples/go-dashboard/src/github.com/mum4k/termdash/container/focus.go
deleted file mode 100644
index 4320eea73..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/container/focus.go
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package container
-
-// focus.go contains code that tracks the focused container.
-
-import (
- "image"
-
- "github.com/mum4k/termdash/mouse"
- "github.com/mum4k/termdash/private/button"
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-// pointCont finds the top-most (on the screen) container whose area contains
-// the given point. Returns nil if none of the containers in the tree contain
-// this point.
-func pointCont(c *Container, p image.Point) *Container {
- var (
- errStr string
- cont *Container
- )
- postOrder(rootCont(c), &errStr, visitFunc(func(c *Container) error {
- if p.In(c.area) && cont == nil {
- cont = c
- }
- return nil
- }))
- return cont
-}
-
-// focusTracker tracks the active (focused) container.
-// This is not thread-safe, the implementation assumes that the owner of
-// focusTracker performs locking.
-type focusTracker struct {
- // container is the currently focused container.
- container *Container
-
- // candidate is the container that might become focused next. I.e. we got
- // a mouse click and now waiting for a release or a timeout.
- candidate *Container
-
- // buttonFSM is a state machine tracking mouse clicks in containers and
- // moving focus from one container to the next.
- buttonFSM *button.FSM
-}
-
-// newFocusTracker returns a new focus tracker with focus set at the provided
-// container.
-func newFocusTracker(c *Container) *focusTracker {
- return &focusTracker{
- container: c,
- // Mouse FSM tracking clicks inside the entire area for the root
- // container.
- buttonFSM: button.NewFSM(mouse.ButtonLeft, c.area),
- }
-}
-
-// isActive determines if the provided container is the currently active container.
-func (ft *focusTracker) isActive(c *Container) bool {
- return ft.container == c
-}
-
-// setActive sets the currently active container to the one provided.
-func (ft *focusTracker) setActive(c *Container) {
- ft.container = c
-}
-
-// mouse identifies mouse events that change the focused container and track
-// the focused container in the tree.
-// The argument c is the container onto which the mouse event landed.
-func (ft *focusTracker) mouse(target *Container, m *terminalapi.Mouse) {
- clicked, bs := ft.buttonFSM.Event(m)
- switch {
- case bs == button.Down:
- ft.candidate = target
- case bs == button.Up && clicked:
- if target == ft.candidate {
- ft.container = target
- }
- }
-}
-
-// updateArea updates the area that the focus tracker considers active for
-// mouse clicks.
-func (ft *focusTracker) updateArea(ar image.Rectangle) {
- ft.buttonFSM.UpdateArea(ar)
-}
-
-// reachableFrom asserts whether the currently focused container is reachable
-// from the provided node in the tree.
-func (ft *focusTracker) reachableFrom(node *Container) bool {
- var (
- errStr string
- reachable bool
- )
- preOrder(node, &errStr, visitFunc(func(c *Container) error {
- if c == ft.container {
- reachable = true
- }
- return nil
- }))
- return reachable
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/container/options.go b/examples/go-dashboard/src/github.com/mum4k/termdash/container/options.go
deleted file mode 100644
index 2d34af4db..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/container/options.go
+++ /dev/null
@@ -1,817 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package container
-
-// options.go defines container options.
-
-import (
- "errors"
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/align"
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/linestyle"
- "github.com/mum4k/termdash/private/area"
- "github.com/mum4k/termdash/widgetapi"
-)
-
-// applyOptions applies the options to the container and validates them.
-func applyOptions(c *Container, opts ...Option) error {
- for _, opt := range opts {
- if err := opt.set(c); err != nil {
- return err
- }
- }
- return nil
-}
-
-// ensure all the container identifiers are either empty or unique.
-func validateIds(c *Container, seen map[string]bool) error {
- if c.opts.id == "" {
- return nil
- } else if seen[c.opts.id] {
- return fmt.Errorf("duplicate container ID %q", c.opts.id)
- }
- seen[c.opts.id] = true
-
- return nil
-}
-
-// ensure all the container only have one split modifier.
-func validateSplits(c *Container) error {
- if c.opts.splitFixed > DefaultSplitFixed && c.opts.splitPercent != DefaultSplitPercent {
- return fmt.Errorf(
- "only one of splitFixed `%v` and splitPercent `%v` is allowed to be set per container",
- c.opts.splitFixed,
- c.opts.splitPercent,
- )
- }
-
- return nil
-}
-
-// validateOptions validates options set in the container tree.
-func validateOptions(c *Container) error {
- var errStr string
- seenID := map[string]bool{}
- preOrder(c, &errStr, func(c *Container) error {
- if err := validateIds(c, seenID); err != nil {
- return err
- }
- if err := validateSplits(c); err != nil {
- return err
- }
-
- return nil
- })
- if errStr != "" {
- return errors.New(errStr)
- }
-
- return nil
-}
-
-// Option is used to provide options to a container.
-type Option interface {
- // set sets the provided option.
- set(*Container) error
-}
-
-// options stores the options provided to the container.
-type options struct {
- // id is the identifier provided by the user.
- id string
-
- // inherited are options that are inherited by child containers.
- inherited inherited
-
- // split identifies how is this container split.
- split splitType
- splitPercent int
- splitFixed int
-
- // widget is the widget in the container.
- // A container can have either two sub containers (left and right) or a
- // widget. But not both.
- widget widgetapi.Widget
-
- // Alignment of the widget if present.
- hAlign align.Horizontal
- vAlign align.Vertical
-
- // border is the border around the container.
- border linestyle.LineStyle
- borderTitle string
- borderTitleHAlign align.Horizontal
-
- // padding is a space reserved between the outer edge of the container and
- // its content (the widget or other sub-containers).
- padding padding
-
- // margin is a space reserved on the outside of the container.
- margin margin
-}
-
-// margin stores the configured margin for the container.
-// For each margin direction, only one of the percentage or cells is set.
-type margin struct {
- topCells int
- topPerc int
- rightCells int
- rightPerc int
- bottomCells int
- bottomPerc int
- leftCells int
- leftPerc int
-}
-
-// apply applies the configured margin to the area.
-func (p *margin) apply(ar image.Rectangle) (image.Rectangle, error) {
- switch {
- case p.topCells != 0 || p.rightCells != 0 || p.bottomCells != 0 || p.leftCells != 0:
- return area.Shrink(ar, p.topCells, p.rightCells, p.bottomCells, p.leftCells)
- case p.topPerc != 0 || p.rightPerc != 0 || p.bottomPerc != 0 || p.leftPerc != 0:
- return area.ShrinkPercent(ar, p.topPerc, p.rightPerc, p.bottomPerc, p.leftPerc)
- }
- return ar, nil
-}
-
-// padding stores the configured padding for the container.
-// For each padding direction, only one of the percentage or cells is set.
-type padding struct {
- topCells int
- topPerc int
- rightCells int
- rightPerc int
- bottomCells int
- bottomPerc int
- leftCells int
- leftPerc int
-}
-
-// apply applies the configured padding to the area.
-func (p *padding) apply(ar image.Rectangle) (image.Rectangle, error) {
- switch {
- case p.topCells != 0 || p.rightCells != 0 || p.bottomCells != 0 || p.leftCells != 0:
- return area.Shrink(ar, p.topCells, p.rightCells, p.bottomCells, p.leftCells)
- case p.topPerc != 0 || p.rightPerc != 0 || p.bottomPerc != 0 || p.leftPerc != 0:
- return area.ShrinkPercent(ar, p.topPerc, p.rightPerc, p.bottomPerc, p.leftPerc)
- }
- return ar, nil
-}
-
-// inherited contains options that are inherited by child containers.
-type inherited struct {
- // borderColor is the color used for the border.
- borderColor cell.Color
- // focusedColor is the color used for the border when focused.
- focusedColor cell.Color
-}
-
-// newOptions returns a new options instance with the default values.
-// Parent are the inherited options from the parent container or nil if these
-// options are for a container with no parent (the root).
-func newOptions(parent *options) *options {
- opts := &options{
- inherited: inherited{
- focusedColor: cell.ColorYellow,
- },
- hAlign: align.HorizontalCenter,
- vAlign: align.VerticalMiddle,
- splitPercent: DefaultSplitPercent,
- splitFixed: DefaultSplitFixed,
- }
- if parent != nil {
- opts.inherited = parent.inherited
- }
- return opts
-}
-
-// option implements Option.
-type option func(*Container) error
-
-// set implements Option.set.
-func (o option) set(c *Container) error {
- return o(c)
-}
-
-// SplitOption is used when splitting containers.
-type SplitOption interface {
- // setSplit sets the provided split option.
- setSplit(*options) error
-}
-
-// splitOption implements SplitOption.
-type splitOption func(*options) error
-
-// setSplit implements SplitOption.setSplit.
-func (so splitOption) setSplit(opts *options) error {
- return so(opts)
-}
-
-// DefaultSplitPercent is the default value for the SplitPercent option.
-const DefaultSplitPercent = 50
-
-// DefaultSplitFixed is the default value for the SplitFixed option.
-const DefaultSplitFixed = -1
-
-// SplitPercent sets the relative size of the split as percentage of the available space.
-// When using SplitVertical, the provided size is applied to the new left
-// container, the new right container gets the reminder of the size.
-// When using SplitHorizontal, the provided size is applied to the new top
-// container, the new bottom container gets the reminder of the size.
-// The provided value must be a positive number in the range 0 < p < 100.
-// If not provided, defaults to DefaultSplitPercent.
-func SplitPercent(p int) SplitOption {
- return splitOption(func(opts *options) error {
- if min, max := 0, 100; p <= min || p >= max {
- return fmt.Errorf("invalid split percentage %d, must be in range %d < p < %d", p, min, max)
- }
- opts.splitPercent = p
- return nil
- })
-}
-
-// SplitFixed sets the size of the first container to be a fixed value
-// and makes the second container take up the remaining space.
-// When using SplitVertical, the provided size is applied to the new left
-// container, the new right container gets the reminder of the size.
-// When using SplitHorizontal, the provided size is applied to the new top
-// container, the new bottom container gets the reminder of the size.
-// The provided value must be a positive number in the range 0 <= cells.
-// If SplitFixed() is not specified, it defaults to SplitPercent() and its given value.
-// Only one of SplitFixed() and SplitPercent() can be specified per container.
-func SplitFixed(cells int) SplitOption {
- return splitOption(func(opts *options) error {
- if cells < 0 {
- return fmt.Errorf("invalid fixed value %d, must be in range %d <= cells", cells, 0)
- }
- opts.splitFixed = cells
- return nil
- })
-}
-
-// SplitVertical splits the container along the vertical axis into two sub
-// containers. The use of this option removes any widget placed at this
-// container, containers with sub containers cannot contain widgets.
-func SplitVertical(l LeftOption, r RightOption, opts ...SplitOption) Option {
- return option(func(c *Container) error {
- c.opts.split = splitTypeVertical
- c.opts.widget = nil
- for _, opt := range opts {
- if err := opt.setSplit(c.opts); err != nil {
- return err
- }
- }
-
- if err := c.createFirst(l.lOpts()); err != nil {
- return err
- }
- return c.createSecond(r.rOpts())
- })
-}
-
-// SplitHorizontal splits the container along the horizontal axis into two sub
-// containers. The use of this option removes any widget placed at this
-// container, containers with sub containers cannot contain widgets.
-func SplitHorizontal(t TopOption, b BottomOption, opts ...SplitOption) Option {
- return option(func(c *Container) error {
- c.opts.split = splitTypeHorizontal
- c.opts.widget = nil
- for _, opt := range opts {
- if err := opt.setSplit(c.opts); err != nil {
- return err
- }
- }
-
- if err := c.createFirst(t.tOpts()); err != nil {
- return err
- }
-
- return c.createSecond(b.bOpts())
- })
-}
-
-// ID sets an identifier for this container.
-// This ID can be later used to perform dynamic layout changes by passing new
-// options to this container. When provided, it must be a non-empty string that
-// is unique among all the containers.
-func ID(id string) Option {
- return option(func(c *Container) error {
- if id == "" {
- return errors.New("the ID cannot be an empty string")
- }
- c.opts.id = id
- return nil
- })
-}
-
-// Clear clears this container.
-// If the container contains a widget, the widget is removed.
-// If the container had any sub containers or splits, they are removed.
-func Clear() Option {
- return option(func(c *Container) error {
- c.opts.widget = nil
- c.first = nil
- c.second = nil
- return nil
- })
-}
-
-// PlaceWidget places the provided widget into the container.
-// The use of this option removes any sub containers. Containers with sub
-// containers cannot have widgets.
-func PlaceWidget(w widgetapi.Widget) Option {
- return option(func(c *Container) error {
- c.opts.widget = w
- c.first = nil
- c.second = nil
- return nil
- })
-}
-
-// MarginTop sets reserved space outside of the container at its top.
-// The provided number is the absolute margin in cells and must be zero or a
-// positive integer. Only one of MarginTop or MarginTopPercent can be specified.
-func MarginTop(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid MarginTop(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.margin.topPerc > 0 {
- return fmt.Errorf("cannot specify both MarginTop(%d) and MarginTopPercent(%d)", cells, c.opts.margin.topPerc)
- }
- c.opts.margin.topCells = cells
- return nil
- })
-}
-
-// MarginRight sets reserved space outside of the container at its right.
-// The provided number is the absolute margin in cells and must be zero or a
-// positive integer. Only one of MarginRight or MarginRightPercent can be specified.
-func MarginRight(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid MarginRight(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.margin.rightPerc > 0 {
- return fmt.Errorf("cannot specify both MarginRight(%d) and MarginRightPercent(%d)", cells, c.opts.margin.rightPerc)
- }
- c.opts.margin.rightCells = cells
- return nil
- })
-}
-
-// MarginBottom sets reserved space outside of the container at its bottom.
-// The provided number is the absolute margin in cells and must be zero or a
-// positive integer. Only one of MarginBottom or MarginBottomPercent can be specified.
-func MarginBottom(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid MarginBottom(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.margin.bottomPerc > 0 {
- return fmt.Errorf("cannot specify both MarginBottom(%d) and MarginBottomPercent(%d)", cells, c.opts.margin.bottomPerc)
- }
- c.opts.margin.bottomCells = cells
- return nil
- })
-}
-
-// MarginLeft sets reserved space outside of the container at its left.
-// The provided number is the absolute margin in cells and must be zero or a
-// positive integer. Only one of MarginLeft or MarginLeftPercent can be specified.
-func MarginLeft(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid MarginLeft(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.margin.leftPerc > 0 {
- return fmt.Errorf("cannot specify both MarginLeft(%d) and MarginLeftPercent(%d)", cells, c.opts.margin.leftPerc)
- }
- c.opts.margin.leftCells = cells
- return nil
- })
-}
-
-// MarginTopPercent sets reserved space outside of the container at its top.
-// The provided number is a relative margin defined as percentage of the container's height.
-// Only one of MarginTop or MarginTopPercent can be specified.
-// The value must be in range 0 <= value <= 100.
-func MarginTopPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid MarginTopPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.margin.topCells > 0 {
- return fmt.Errorf("cannot specify both MarginTopPercent(%d) and MarginTop(%d)", perc, c.opts.margin.topCells)
- }
- c.opts.margin.topPerc = perc
- return nil
- })
-}
-
-// MarginRightPercent sets reserved space outside of the container at its right.
-// The provided number is a relative margin defined as percentage of the container's height.
-// Only one of MarginRight or MarginRightPercent can be specified.
-// The value must be in range 0 <= value <= 100.
-func MarginRightPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid MarginRightPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.margin.rightCells > 0 {
- return fmt.Errorf("cannot specify both MarginRightPercent(%d) and MarginRight(%d)", perc, c.opts.margin.rightCells)
- }
- c.opts.margin.rightPerc = perc
- return nil
- })
-}
-
-// MarginBottomPercent sets reserved space outside of the container at its bottom.
-// The provided number is a relative margin defined as percentage of the container's height.
-// Only one of MarginBottom or MarginBottomPercent can be specified.
-// The value must be in range 0 <= value <= 100.
-func MarginBottomPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid MarginBottomPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.margin.bottomCells > 0 {
- return fmt.Errorf("cannot specify both MarginBottomPercent(%d) and MarginBottom(%d)", perc, c.opts.margin.bottomCells)
- }
- c.opts.margin.bottomPerc = perc
- return nil
- })
-}
-
-// MarginLeftPercent sets reserved space outside of the container at its left.
-// The provided number is a relative margin defined as percentage of the container's height.
-// Only one of MarginLeft or MarginLeftPercent can be specified.
-// The value must be in range 0 <= value <= 100.
-func MarginLeftPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid MarginLeftPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.margin.leftCells > 0 {
- return fmt.Errorf("cannot specify both MarginLeftPercent(%d) and MarginLeft(%d)", perc, c.opts.margin.leftCells)
- }
- c.opts.margin.leftPerc = perc
- return nil
- })
-}
-
-// PaddingTop sets reserved space between container and the top side of its widget.
-// The widget's area size is decreased to accommodate the padding.
-// The provided number is the absolute padding in cells and must be zero or a
-// positive integer. Only one of PaddingTop or PaddingTopPercent can be specified.
-func PaddingTop(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid PaddingTop(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.padding.topPerc > 0 {
- return fmt.Errorf("cannot specify both PaddingTop(%d) and PaddingTopPercent(%d)", cells, c.opts.padding.topPerc)
- }
- c.opts.padding.topCells = cells
- return nil
- })
-}
-
-// PaddingRight sets reserved space between container and the right side of its widget.
-// The widget's area size is decreased to accommodate the padding.
-// The provided number is the absolute padding in cells and must be zero or a
-// positive integer. Only one of PaddingRight or PaddingRightPercent can be specified.
-func PaddingRight(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid PaddingRight(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.padding.rightPerc > 0 {
- return fmt.Errorf("cannot specify both PaddingRight(%d) and PaddingRightPercent(%d)", cells, c.opts.padding.rightPerc)
- }
- c.opts.padding.rightCells = cells
- return nil
- })
-}
-
-// PaddingBottom sets reserved space between container and the bottom side of its widget.
-// The widget's area size is decreased to accommodate the padding.
-// The provided number is the absolute padding in cells and must be zero or a
-// positive integer. Only one of PaddingBottom or PaddingBottomPercent can be specified.
-func PaddingBottom(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid PaddingBottom(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.padding.bottomPerc > 0 {
- return fmt.Errorf("cannot specify both PaddingBottom(%d) and PaddingBottomPercent(%d)", cells, c.opts.padding.bottomPerc)
- }
- c.opts.padding.bottomCells = cells
- return nil
- })
-}
-
-// PaddingLeft sets reserved space between container and the left side of its widget.
-// The widget's area size is decreased to accommodate the padding.
-// The provided number is the absolute padding in cells and must be zero or a
-// positive integer. Only one of PaddingLeft or PaddingLeftPercent can be specified.
-func PaddingLeft(cells int) Option {
- return option(func(c *Container) error {
- if min := 0; cells < min {
- return fmt.Errorf("invalid PaddingLeft(%d), must be in range %d <= value", cells, min)
- }
- if c.opts.padding.leftPerc > 0 {
- return fmt.Errorf("cannot specify both PaddingLeft(%d) and PaddingLeftPercent(%d)", cells, c.opts.padding.leftPerc)
- }
- c.opts.padding.leftCells = cells
- return nil
- })
-}
-
-// PaddingTopPercent sets reserved space between container and the top side of
-// its widget. The widget's area size is decreased to accommodate the padding.
-// The provided number is a relative padding defined as percentage of the
-// container's height. The value must be in range 0 <= value <= 100.
-// Only one of PaddingTop or PaddingTopPercent can be specified.
-func PaddingTopPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid PaddingTopPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.padding.topCells > 0 {
- return fmt.Errorf("cannot specify both PaddingTopPercent(%d) and PaddingTop(%d)", perc, c.opts.padding.topCells)
- }
- c.opts.padding.topPerc = perc
- return nil
- })
-}
-
-// PaddingRightPercent sets reserved space between container and the right side of
-// its widget. The widget's area size is decreased to accommodate the padding.
-// The provided number is a relative padding defined as percentage of the
-// container's width. The value must be in range 0 <= value <= 100.
-// Only one of PaddingRight or PaddingRightPercent can be specified.
-func PaddingRightPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid PaddingRightPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.padding.rightCells > 0 {
- return fmt.Errorf("cannot specify both PaddingRightPercent(%d) and PaddingRight(%d)", perc, c.opts.padding.rightCells)
- }
- c.opts.padding.rightPerc = perc
- return nil
- })
-}
-
-// PaddingBottomPercent sets reserved space between container and the bottom side of
-// its widget. The widget's area size is decreased to accommodate the padding.
-// The provided number is a relative padding defined as percentage of the
-// container's height. The value must be in range 0 <= value <= 100.
-// Only one of PaddingBottom or PaddingBottomPercent can be specified.
-func PaddingBottomPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid PaddingBottomPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.padding.bottomCells > 0 {
- return fmt.Errorf("cannot specify both PaddingBottomPercent(%d) and PaddingBottom(%d)", perc, c.opts.padding.bottomCells)
- }
- c.opts.padding.bottomPerc = perc
- return nil
- })
-}
-
-// PaddingLeftPercent sets reserved space between container and the left side of
-// its widget. The widget's area size is decreased to accommodate the padding.
-// The provided number is a relative padding defined as percentage of the
-// container's width. The value must be in range 0 <= value <= 100.
-// Only one of PaddingLeft or PaddingLeftPercent can be specified.
-func PaddingLeftPercent(perc int) Option {
- return option(func(c *Container) error {
- if min, max := 0, 100; perc < min || perc > max {
- return fmt.Errorf("invalid PaddingLeftPercent(%d), must be in range %d <= value <= %d", perc, min, max)
- }
- if c.opts.padding.leftCells > 0 {
- return fmt.Errorf("cannot specify both PaddingLeftPercent(%d) and PaddingLeft(%d)", perc, c.opts.padding.leftCells)
- }
- c.opts.padding.leftPerc = perc
- return nil
- })
-}
-
-// AlignHorizontal sets the horizontal alignment for the widget placed in the
-// container. Has no effect if the container contains no widget.
-// Defaults to alignment in the center.
-func AlignHorizontal(h align.Horizontal) Option {
- return option(func(c *Container) error {
- c.opts.hAlign = h
- return nil
- })
-}
-
-// AlignVertical sets the vertical alignment for the widget placed in the container.
-// Has no effect if the container contains no widget.
-// Defaults to alignment in the middle.
-func AlignVertical(v align.Vertical) Option {
- return option(func(c *Container) error {
- c.opts.vAlign = v
- return nil
- })
-}
-
-// Border configures the container to have a border of the specified style.
-func Border(ls linestyle.LineStyle) Option {
- return option(func(c *Container) error {
- c.opts.border = ls
- return nil
- })
-}
-
-// BorderTitle sets a text title within the border.
-func BorderTitle(title string) Option {
- return option(func(c *Container) error {
- c.opts.borderTitle = title
- return nil
- })
-}
-
-// BorderTitleAlignLeft aligns the border title on the left.
-func BorderTitleAlignLeft() Option {
- return option(func(c *Container) error {
- c.opts.borderTitleHAlign = align.HorizontalLeft
- return nil
- })
-}
-
-// BorderTitleAlignCenter aligns the border title in the center.
-func BorderTitleAlignCenter() Option {
- return option(func(c *Container) error {
- c.opts.borderTitleHAlign = align.HorizontalCenter
- return nil
- })
-}
-
-// BorderTitleAlignRight aligns the border title on the right.
-func BorderTitleAlignRight() Option {
- return option(func(c *Container) error {
- c.opts.borderTitleHAlign = align.HorizontalRight
- return nil
- })
-}
-
-// BorderColor sets the color of the border around the container.
-// This option is inherited to sub containers created by container splits.
-func BorderColor(color cell.Color) Option {
- return option(func(c *Container) error {
- c.opts.inherited.borderColor = color
- return nil
- })
-}
-
-// FocusedColor sets the color of the border around the container when it has
-// keyboard focus.
-// This option is inherited to sub containers created by container splits.
-func FocusedColor(color cell.Color) Option {
- return option(func(c *Container) error {
- c.opts.inherited.focusedColor = color
- return nil
- })
-}
-
-// splitType identifies how a container is split.
-type splitType int
-
-// String implements fmt.Stringer()
-func (st splitType) String() string {
- if n, ok := splitTypeNames[st]; ok {
- return n
- }
- return "splitTypeUnknown"
-}
-
-// splitTypeNames maps splitType values to human readable names.
-var splitTypeNames = map[splitType]string{
- splitTypeVertical: "splitTypeVertical",
- splitTypeHorizontal: "splitTypeHorizontal",
-}
-
-const (
- splitTypeVertical splitType = iota
- splitTypeHorizontal
-)
-
-// LeftOption is used to provide options to the left sub container after a
-// vertical split of the parent.
-type LeftOption interface {
- // lOpts returns the options.
- lOpts() []Option
-}
-
-// leftOption implements LeftOption.
-type leftOption func() []Option
-
-// lOpts implements LeftOption.lOpts.
-func (lo leftOption) lOpts() []Option {
- if lo == nil {
- return nil
- }
- return lo()
-}
-
-// Left applies options to the left sub container after a vertical split of the parent.
-func Left(opts ...Option) LeftOption {
- return leftOption(func() []Option {
- return opts
- })
-}
-
-// RightOption is used to provide options to the right sub container after a
-// vertical split of the parent.
-type RightOption interface {
- // rOpts returns the options.
- rOpts() []Option
-}
-
-// rightOption implements RightOption.
-type rightOption func() []Option
-
-// rOpts implements RightOption.rOpts.
-func (lo rightOption) rOpts() []Option {
- if lo == nil {
- return nil
- }
- return lo()
-}
-
-// Right applies options to the right sub container after a vertical split of the parent.
-func Right(opts ...Option) RightOption {
- return rightOption(func() []Option {
- return opts
- })
-}
-
-// TopOption is used to provide options to the top sub container after a
-// horizontal split of the parent.
-type TopOption interface {
- // tOpts returns the options.
- tOpts() []Option
-}
-
-// topOption implements TopOption.
-type topOption func() []Option
-
-// tOpts implements TopOption.tOpts.
-func (lo topOption) tOpts() []Option {
- if lo == nil {
- return nil
- }
- return lo()
-}
-
-// Top applies options to the top sub container after a horizontal split of the parent.
-func Top(opts ...Option) TopOption {
- return topOption(func() []Option {
- return opts
- })
-}
-
-// BottomOption is used to provide options to the bottom sub container after a
-// horizontal split of the parent.
-type BottomOption interface {
- // bOpts returns the options.
- bOpts() []Option
-}
-
-// bottomOption implements BottomOption.
-type bottomOption func() []Option
-
-// bOpts implements BottomOption.bOpts.
-func (lo bottomOption) bOpts() []Option {
- if lo == nil {
- return nil
- }
- return lo()
-}
-
-// Bottom applies options to the bottom sub container after a horizontal split of the parent.
-func Bottom(opts ...Option) BottomOption {
- return bottomOption(func() []Option {
- return opts
- })
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/container/traversal.go b/examples/go-dashboard/src/github.com/mum4k/termdash/container/traversal.go
deleted file mode 100644
index f728b50ba..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/container/traversal.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package container
-
-import (
- "errors"
- "fmt"
-)
-
-// traversal.go provides functions that navigate the container tree.
-
-// rootCont returns the root container.
-func rootCont(c *Container) *Container {
- for p := c.parent; p != nil; p = c.parent {
- c = p
- }
- return c
-}
-
-// visitFunc is executed during traversals when node is visited.
-// If the visit function returns an error, the traversal terminates and the
-// errStr is set to the text of the returned error.
-type visitFunc func(*Container) error
-
-// preOrder performs pre-order DFS traversal on the container tree.
-func preOrder(c *Container, errStr *string, visit visitFunc) {
- if c == nil || *errStr != "" {
- return
- }
-
- if err := visit(c); err != nil {
- *errStr = err.Error()
- return
- }
- preOrder(c.first, errStr, visit)
- preOrder(c.second, errStr, visit)
-}
-
-// postOrder performs post-order DFS traversal on the container tree.
-func postOrder(c *Container, errStr *string, visit visitFunc) {
- if c == nil || *errStr != "" {
- return
- }
-
- postOrder(c.first, errStr, visit)
- postOrder(c.second, errStr, visit)
- if err := visit(c); err != nil {
- *errStr = err.Error()
- return
- }
-}
-
-// findID finds container with the provided ID.
-// Returns an error of there is no container with the specified ID.
-func findID(root *Container, id string) (*Container, error) {
- if id == "" {
- return nil, errors.New("the container ID must not be empty")
- }
-
- var (
- errStr string
- cont *Container
- )
- preOrder(root, &errStr, visitFunc(func(c *Container) error {
- if c.opts.id == id {
- cont = c
- }
- return nil
- }))
- if cont == nil {
- return nil, fmt.Errorf("cannot find container with ID %q", id)
- }
- return cont, nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/go.mod b/examples/go-dashboard/src/github.com/mum4k/termdash/go.mod
deleted file mode 100644
index 3a81b3235..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/go.mod
+++ /dev/null
@@ -1,10 +0,0 @@
-module github.com/mum4k/termdash
-
-go 1.14
-
-require (
- github.com/gdamore/tcell v1.3.0
- github.com/kylelemons/godebug v1.1.0
- github.com/mattn/go-runewidth v0.0.9
- github.com/nsf/termbox-go v0.0.0-20200204031403-4d2b513ad8be
-)
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/keyboard/keyboard.go b/examples/go-dashboard/src/github.com/mum4k/termdash/keyboard/keyboard.go
deleted file mode 100644
index 3a852b326..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/keyboard/keyboard.go
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package keyboard defines well known keyboard keys and shortcuts.
-package keyboard
-
-// Key represents a single button on the keyboard.
-// Printable characters are set to their ASCII/Unicode rune value.
-// Non-printable (control) characters are equal to one of the constants defined
-// below.
-type Key rune
-
-// String implements fmt.Stringer()
-func (b Key) String() string {
- if n, ok := buttonNames[b]; ok {
- return n
- } else if b >= 0 {
- return string(b)
- }
- return "KeyUnknown"
-}
-
-// buttonNames maps Key values to human readable names.
-var buttonNames = map[Key]string{
- KeyF1: "KeyF1",
- KeyF2: "KeyF2",
- KeyF3: "KeyF3",
- KeyF4: "KeyF4",
- KeyF5: "KeyF5",
- KeyF6: "KeyF6",
- KeyF7: "KeyF7",
- KeyF8: "KeyF8",
- KeyF9: "KeyF9",
- KeyF10: "KeyF10",
- KeyF11: "KeyF11",
- KeyF12: "KeyF12",
- KeyInsert: "KeyInsert",
- KeyDelete: "KeyDelete",
- KeyHome: "KeyHome",
- KeyEnd: "KeyEnd",
- KeyPgUp: "KeyPgUp",
- KeyPgDn: "KeyPgDn",
- KeyArrowUp: "KeyArrowUp",
- 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",
- KeyCtrl4: "KeyCtrl4",
- KeyCtrl5: "KeyCtrl5",
- KeyCtrl6: "KeyCtrl6",
- KeyCtrl7: "KeyCtrl7",
- KeySpace: "KeySpace",
- KeyBackspace2: "KeyBackspace2",
-}
-
-// Printable characters, but worth having constants for them.
-const (
- KeySpace = ' '
-)
-
-// Negative values for non-printable characters.
-const (
- KeyF1 Key = -(iota + 1)
- KeyF2
- KeyF3
- KeyF4
- KeyF5
- KeyF6
- KeyF7
- KeyF8
- KeyF9
- KeyF10
- KeyF11
- KeyF12
- KeyInsert
- KeyDelete
- KeyHome
- KeyEnd
- KeyPgUp
- KeyPgDn
- KeyArrowUp
- 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
- 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
-)
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/linestyle/linestyle.go b/examples/go-dashboard/src/github.com/mum4k/termdash/linestyle/linestyle.go
deleted file mode 100644
index c34fc3959..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/linestyle/linestyle.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package linestyle defines various line styles.
-package linestyle
-
-// LineStyle defines the supported line styles.
-type LineStyle int
-
-// String implements fmt.Stringer()
-func (ls LineStyle) String() string {
- if n, ok := lineStyleNames[ls]; ok {
- return n
- }
- return "LineStyleUnknown"
-}
-
-// lineStyleNames maps LineStyle values to human readable names.
-var lineStyleNames = map[LineStyle]string{
- None: "LineStyleNone",
- Light: "LineStyleLight",
- Double: "LineStyleDouble",
- Round: "LineStyleRound",
-}
-
-// Supported line styles.
-// See https://en.wikipedia.org/wiki/Box-drawing_character.
-const (
- // None indicates that no line should be present.
- None LineStyle = iota
-
- // Light is line style using the '─' characters.
- Light
-
- // Double is line style using the '═' characters.
- Double
-
- // Round is line style using the rounded corners '╭' characters.
- Round
-)
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/mouse/mouse.go b/examples/go-dashboard/src/github.com/mum4k/termdash/mouse/mouse.go
deleted file mode 100644
index d21e1d310..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/mouse/mouse.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package mouse defines known mouse buttons.
-package mouse
-
-// Button represents a mouse button.
-type Button int
-
-// String implements fmt.Stringer()
-func (b Button) String() string {
- if n, ok := buttonNames[b]; ok {
- return n
- }
- return "ButtonUnknown"
-}
-
-// buttonNames maps Button values to human readable names.
-var buttonNames = map[Button]string{
- ButtonLeft: "ButtonLeft",
- ButtonRight: "ButtonRight",
- ButtonMiddle: "ButtonMiddle",
- ButtonRelease: "ButtonRelease",
- ButtonWheelUp: "ButtonWheelUp",
- ButtonWheelDown: "ButtonWheelDown",
-}
-
-// Buttons recognized on the mouse.
-const (
- buttonUnknown Button = iota
- ButtonLeft
- ButtonRight
- ButtonMiddle
- ButtonRelease
- ButtonWheelUp
- ButtonWheelDown
-)
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/alignfor/alignfor.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/alignfor/alignfor.go
deleted file mode 100644
index 93cbac844..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/alignfor/alignfor.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package alignfor provides functions that align elements.
-package alignfor
-
-import (
- "fmt"
- "image"
- "strings"
-
- "github.com/mum4k/termdash/align"
- "github.com/mum4k/termdash/private/runewidth"
- "github.com/mum4k/termdash/private/wrap"
-)
-
-// hAlign aligns the given area in the rectangle horizontally.
-func hAlign(rect image.Rectangle, ar image.Rectangle, h align.Horizontal) (image.Rectangle, error) {
- gap := rect.Dx() - ar.Dx()
- switch h {
- case align.HorizontalRight:
- // Use gap from above.
- case align.HorizontalCenter:
- gap /= 2
- case align.HorizontalLeft:
- gap = 0
- default:
- return image.ZR, fmt.Errorf("unsupported horizontal alignment %v", h)
- }
-
- return image.Rect(
- rect.Min.X+gap,
- ar.Min.Y,
- rect.Min.X+gap+ar.Dx(),
- ar.Max.Y,
- ), nil
-}
-
-// vAlign aligns the given area in the rectangle vertically.
-func vAlign(rect image.Rectangle, ar image.Rectangle, v align.Vertical) (image.Rectangle, error) {
- gap := rect.Dy() - ar.Dy()
- switch v {
- case align.VerticalBottom:
- // Use gap from above.
- case align.VerticalMiddle:
- gap /= 2
- case align.VerticalTop:
- gap = 0
- default:
- return image.ZR, fmt.Errorf("unsupported vertical alignment %v", v)
- }
-
- return image.Rect(
- ar.Min.X,
- rect.Min.Y+gap,
- ar.Max.X,
- rect.Min.Y+gap+ar.Dy(),
- ), nil
-}
-
-// Rectangle aligns the area within the rectangle returning the
-// aligned area. The area must fall within the rectangle.
-func Rectangle(rect image.Rectangle, ar image.Rectangle, h align.Horizontal, v align.Vertical) (image.Rectangle, error) {
- if !ar.In(rect) {
- return image.ZR, fmt.Errorf("cannot align area %v inside rectangle %v, the area falls outside of the rectangle", ar, rect)
- }
-
- aligned, err := hAlign(rect, ar, h)
- if err != nil {
- return image.ZR, err
- }
- aligned, err = vAlign(rect, aligned, v)
- if err != nil {
- return image.ZR, err
- }
- return aligned, nil
-}
-
-// Text aligns the text within the given rectangle, returns the start point for the text.
-// For the purposes of the alignment this assumes that text will be trimmed if
-// it overruns the rectangle.
-// This only supports a single line of text, the text must not contain non-printable characters,
-// allows empty text.
-func Text(rect image.Rectangle, text string, h align.Horizontal, v align.Vertical) (image.Point, error) {
- if strings.ContainsRune(text, '\n') {
- return image.ZP, fmt.Errorf("the provided text contains a newline character: %q", text)
- }
-
- if text != "" {
- if err := wrap.ValidText(text); err != nil {
- return image.ZP, fmt.Errorf("the provided text contains non printable character(s): %s", err)
- }
- }
-
- cells := runewidth.StringWidth(text)
- var textLen int
- if cells < rect.Dx() {
- textLen = cells
- } else {
- textLen = rect.Dx()
- }
-
- textRect := image.Rect(
- rect.Min.X,
- rect.Min.Y,
- // For the purposes of aligning the text, assume that it will be
- // trimmed to the available space.
- rect.Min.X+textLen,
- rect.Min.Y+1,
- )
-
- aligned, err := Rectangle(rect, textRect, h, v)
- if err != nil {
- return image.ZP, err
- }
- return image.Point{aligned.Min.X, aligned.Min.Y}, nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/area/area.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/area/area.go
deleted file mode 100644
index 34b21a1b5..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/area/area.go
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package area provides functions working with image areas.
-package area
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/private/numbers"
-)
-
-// 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
-}
-
-// HSplit returns two new areas created by splitting the provided area at the
-// specified percentage of its width. The percentage must be in the range
-// 0 <= heightPerc <= 100.
-// Can return zero size areas.
-func HSplit(area image.Rectangle, heightPerc int) (top image.Rectangle, bottom image.Rectangle, err error) {
- if min, max := 0, 100; heightPerc < min || heightPerc > max {
- return image.ZR, image.ZR, fmt.Errorf("invalid heightPerc %d, must be in range %d <= heightPerc <= %d", heightPerc, min, max)
- }
- height := area.Dy() * heightPerc / 100
- top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, area.Min.Y+height)
- if top.Dy() == 0 {
- top = image.ZR
- }
- bottom = image.Rect(area.Min.X, area.Min.Y+height, area.Max.X, area.Max.Y)
- if bottom.Dy() == 0 {
- bottom = image.ZR
- }
- return top, bottom, nil
-}
-
-// VSplit returns two new areas created by splitting the provided area at the
-// specified percentage of its width. The percentage must be in the range
-// 0 <= widthPerc <= 100.
-// Can return zero size areas.
-func VSplit(area image.Rectangle, widthPerc int) (left image.Rectangle, right image.Rectangle, err error) {
- if min, max := 0, 100; widthPerc < min || widthPerc > max {
- return image.ZR, image.ZR, fmt.Errorf("invalid widthPerc %d, must be in range %d <= widthPerc <= %d", widthPerc, min, max)
- }
- width := area.Dx() * widthPerc / 100
- left = image.Rect(area.Min.X, area.Min.Y, area.Min.X+width, area.Max.Y)
- if left.Dx() == 0 {
- left = image.ZR
- }
- right = image.Rect(area.Min.X+width, area.Min.Y, area.Max.X, area.Max.Y)
- if right.Dx() == 0 {
- right = image.ZR
- }
- 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
-}
-
-// HSplitCells returns two new areas created by splitting the provided area
-// after the specified amount of cells of its height. The number of cells must
-// be a zero or a positive integer. Providing a zero returns top=image.ZR,
-// bottom=area. Providing a number equal or larger to area's height returns
-// top=area, bottom=image.ZR.
-func HSplitCells(area image.Rectangle, cells int) (top image.Rectangle, bottom 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
- }
-
- height := area.Dy()
- if cells >= height {
- return area, image.ZR, nil
- }
-
- top = image.Rect(area.Min.X, area.Min.Y, area.Max.X, area.Min.Y+cells)
- bottom = image.Rect(area.Min.X, area.Min.Y+cells, area.Max.X, area.Max.Y)
- return top, bottom, 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.
-func ExcludeBorder(area image.Rectangle) image.Rectangle {
- // If the area dimensions are smaller than this, subtracting a point for the
- // border on each of its sides results in a zero area.
- const minDim = 2
- if area.Dx() < minDim || area.Dy() < minDim {
- return image.ZR
- }
- return image.Rect(
- numbers.Abs(area.Min.X+1),
- numbers.Abs(area.Min.Y+1),
- numbers.Abs(area.Max.X-1),
- numbers.Abs(area.Max.Y-1),
- )
-}
-
-// WithRatio returns the largest area that has the requested ratio but is
-// either equal or smaller than the provided area. Returns zero area if the
-// area or the ratio are zero, or if there is no such area.
-func WithRatio(area image.Rectangle, ratio image.Point) image.Rectangle {
- ratio = numbers.SimplifyRatio(ratio)
- if area == image.ZR || ratio == image.ZP {
- return image.ZR
- }
-
- wFact := area.Dx() / ratio.X
- hFact := area.Dy() / ratio.Y
-
- var fact int
- if wFact < hFact {
- fact = wFact
- } else {
- fact = hFact
- }
- return image.Rect(
- area.Min.X,
- area.Min.Y,
- ratio.X*fact+area.Min.X,
- ratio.Y*fact+area.Min.Y,
- )
-}
-
-// Shrink returns a new area whose size is reduced by the specified amount of
-// cells. Can return a zero area if there is no space left in the area.
-// The values must be zero or positive integers.
-func Shrink(area image.Rectangle, topCells, rightCells, bottomCells, leftCells int) (image.Rectangle, error) {
- for _, v := range []struct {
- name string
- value int
- }{
- {"topCells", topCells},
- {"rightCells", rightCells},
- {"bottomCells", bottomCells},
- {"leftCells", leftCells},
- } {
- if min := 0; v.value < min {
- return image.ZR, fmt.Errorf("invalid %s(%d), must be in range %d <= value", v.name, v.value, min)
- }
- }
-
- shrunk := area
- shrunk.Min.X, _ = numbers.MinMaxInts([]int{shrunk.Min.X + leftCells, shrunk.Max.X})
- _, shrunk.Max.X = numbers.MinMaxInts([]int{shrunk.Max.X - rightCells, shrunk.Min.X})
- shrunk.Min.Y, _ = numbers.MinMaxInts([]int{shrunk.Min.Y + topCells, shrunk.Max.Y})
- _, shrunk.Max.Y = numbers.MinMaxInts([]int{shrunk.Max.Y - bottomCells, shrunk.Min.Y})
-
- if shrunk.Dx() == 0 || shrunk.Dy() == 0 {
- return image.ZR, nil
- }
- return shrunk, nil
-}
-
-// ShrinkPercent returns a new area whose size is reduced by percentage of its
-// width or height. Can return a zero area if there is no space left in the area.
-// The topPerc and bottomPerc indicate the percentage of area's height.
-// The rightPerc and leftPerc indicate the percentage of area's width.
-// The percentages must be in range 0 <= v <= 100.
-func ShrinkPercent(area image.Rectangle, topPerc, rightPerc, bottomPerc, leftPerc int) (image.Rectangle, error) {
- for _, v := range []struct {
- name string
- value int
- }{
- {"topPerc", topPerc},
- {"rightPerc", rightPerc},
- {"bottomPerc", bottomPerc},
- {"leftPerc", leftPerc},
- } {
- if min, max := 0, 100; v.value < min || v.value > max {
- return image.ZR, fmt.Errorf("invalid %s(%d), must be in range %d <= value <= %d", v.name, v.value, min, max)
- }
- }
-
- top := area.Dy() * topPerc / 100
- bottom := area.Dy() * bottomPerc / 100
- right := area.Dx() * rightPerc / 100
- left := area.Dx() * leftPerc / 100
- return Shrink(area, top, right, bottom, left)
-}
-
-// MoveUp returns a new area that is moved up by the specified amount of cells.
-// Returns an error if the move would result in negative Y coordinates.
-// The values must be zero or positive integers.
-func MoveUp(area image.Rectangle, cells int) (image.Rectangle, error) {
- if min := 0; cells < min {
- return image.ZR, fmt.Errorf("cannot move area %v up by %d cells, must be in range %d <= value", area, cells, min)
- }
-
- if area.Min.Y < cells {
- return image.ZR, fmt.Errorf("cannot move area %v up by %d cells, would result in negative Y coordinate", area, cells)
- }
-
- moved := area
- moved.Min.Y -= cells
- moved.Max.Y -= cells
- return moved, nil
-}
-
-// MoveDown returns a new area that is moved down by the specified amount of
-// cells.
-// The values must be zero or positive integers.
-func MoveDown(area image.Rectangle, cells int) (image.Rectangle, error) {
- if min := 0; cells < min {
- return image.ZR, fmt.Errorf("cannot move area %v down by %d cells, must be in range %d <= value", area, cells, min)
- }
-
- moved := area
- moved.Min.Y += cells
- moved.Max.Y += cells
- return moved, nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/button/button.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/button/button.go
deleted file mode 100644
index d4e0601b8..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/button/button.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package button implements a state machine that tracks mouse button clicks.
-package button
-
-import (
- "image"
-
- "github.com/mum4k/termdash/mouse"
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-// State represents the state of the mouse button.
-type State int
-
-// String implements fmt.Stringer()
-func (s State) String() string {
- if n, ok := stateNames[s]; ok {
- return n
- }
- return "StateUnknown"
-}
-
-// stateNames maps State values to human readable names.
-var stateNames = map[State]string{
- Up: "StateUp",
- Down: "StateDown",
-}
-
-const (
- // Up is the default idle state of the mouse button.
- Up State = iota
-
- // Down is a state where the mouse button is pressed down and held.
- Down
-)
-
-// FSM implements a finite-state machine that tracks mouse clicks within an
-// area.
-//
-// Simplifies tracking of mouse button clicks, i.e. when the caller wants to
-// perform an action only if both the button press and release happen within
-// the specified area.
-//
-// This object is not thread-safe.
-type FSM struct {
- // button is the mouse button whose state this FSM tracks.
- button mouse.Button
-
- // area is the area provided to NewFSM.
- area image.Rectangle
-
- // state is the current state of the FSM.
- state stateFn
-}
-
-// NewFSM creates a new FSM instance that tracks the state of the specified
-// mouse button through button events that fall within the provided area.
-func NewFSM(button mouse.Button, area image.Rectangle) *FSM {
- return &FSM{
- button: button,
- area: area,
- state: wantPress,
- }
-}
-
-// Event is used to forward mouse events to the state machine.
-// Only events related to the button specified on a call to NewFSM are
-// processed.
-//
-// Returns a bool indicating if an action guarded by the button should be
-// performed and the state of the button after the provided event.
-// The bool is true if the button click should take an effect, i.e. if the
-// FSM saw both the button click and its release.
-func (fsm *FSM) Event(m *terminalapi.Mouse) (bool, State) {
- clicked, bs, next := fsm.state(fsm, m)
- fsm.state = next
- return clicked, bs
-}
-
-// UpdateArea informs FSM of an area change.
-// This method is idempotent.
-func (fsm *FSM) UpdateArea(area image.Rectangle) {
- fsm.area = area
-}
-
-// stateFn is a single state in the state machine.
-// Returns bool indicating if a click happened, the state of the button and the
-// next state of the FSM.
-type stateFn func(fsm *FSM, m *terminalapi.Mouse) (bool, State, stateFn)
-
-// wantPress is the initial state, expecting a button press inside the area.
-func wantPress(fsm *FSM, m *terminalapi.Mouse) (bool, State, stateFn) {
- if m.Button != fsm.button || !m.Position.In(fsm.area) {
- return false, Up, wantPress
- }
- return false, Down, wantRelease
-}
-
-// wantRelease waits for a mouse button release in the same area as
-// the press.
-func wantRelease(fsm *FSM, m *terminalapi.Mouse) (bool, State, stateFn) {
- switch m.Button {
- case fsm.button:
- if m.Position.In(fsm.area) {
- // Remain in the same state, since termbox reports move of mouse with
- // button held down as a series of clicks, one per position.
- return false, Down, wantRelease
- }
- return false, Up, wantPress
-
- case mouse.ButtonRelease:
- if m.Position.In(fsm.area) {
- // Seen both press and release, report a click.
- return true, Up, wantPress
- }
- // Release the button even if the release event happened outside of the area.
- return false, Up, wantPress
-
- default:
- return false, Up, wantPress
- }
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/braille/braille.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/braille/braille.go
deleted file mode 100644
index 7cd902f87..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/braille/braille.go
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/*
-Package braille provides a canvas that uses braille characters.
-
-This is inspired by https://github.com/asciimoo/drawille.
-
-The braille patterns documentation:
-http://www.alanwood.net/unicode/braille_patterns.html
-
-The use of braille characters gives additional points (higher resolution) on
-the canvas, each character cell now has eight pixels that can be set
-independently. Specifically each cell has the following pixels, the axes grow
-right and down.
-
-Each cell:
-
- X→ 0 1 Y
- ┌───┐ ↓
- │● ●│ 0
- │● ●│ 1
- │● ●│ 2
- │● ●│ 3
- └───┘
-
-When using the braille canvas, the coordinates address the sub-cell points
-rather then cells themselves. However all points in the cell still share the
-same cell options.
-*/
-package braille
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/canvas"
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-const (
- // ColMult is the resolution multiplier for the width, i.e. two pixels per cell.
- ColMult = 2
-
- // RowMult is the resolution multiplier for the height, i.e. four pixels per cell.
- RowMult = 4
-
- // brailleCharOffset is the offset of the braille pattern unicode characters.
- // From: http://www.alanwood.net/unicode/braille_patterns.html
- brailleCharOffset = 0x2800
-
- // brailleLastChar is the last braille pattern rune.
- brailleLastChar = 0x28FF
-)
-
-// pixelRunes maps points addressing individual pixels in a cell into character
-// offset. I.e. the correct character to set pixel(0,0) is
-// brailleCharOffset|pixelRunes[image.Point{0,0}].
-var pixelRunes = map[image.Point]rune{
- {0, 0}: 0x01, {1, 0}: 0x08,
- {0, 1}: 0x02, {1, 1}: 0x10,
- {0, 2}: 0x04, {1, 2}: 0x20,
- {0, 3}: 0x40, {1, 3}: 0x80,
-}
-
-// Canvas is a canvas that uses the braille patterns. It is two times wider
-// and four times taller than a regular canvas that uses just plain characters,
-// since each cell now has 2x4 pixels that can be independently set.
-//
-// The braille canvas is an abstraction built on top of a regular character
-// canvas. After setting and toggling pixels on the braille canvas, it should
-// be copied to a regular character canvas or applied to a terminal which
-// results in setting of braille pattern characters.
-// See the examples for more details.
-//
-// The created braille canvas can be smaller and even misaligned relatively to
-// the regular character canvas or terminal, allowing the callers to create a
-// "view" of just a portion of the canvas or terminal.
-type Canvas struct {
- // regular is the regular character canvas the braille canvas is based on.
- regular *canvas.Canvas
-}
-
-// New returns a new braille canvas for the provided area.
-func New(ar image.Rectangle) (*Canvas, error) {
- rc, err := canvas.New(ar)
- if err != nil {
- return nil, err
- }
- return &Canvas{
- regular: rc,
- }, nil
-}
-
-// Size returns the size of the braille canvas in pixels.
-func (c *Canvas) Size() image.Point {
- s := c.regular.Size()
- return image.Point{s.X * ColMult, s.Y * RowMult}
-}
-
-// CellArea returns the area of the underlying cell canvas in cells.
-func (c *Canvas) CellArea() image.Rectangle {
- return c.regular.Area()
-}
-
-// Area returns the area of the braille canvas in pixels.
-// This will be zero-based area that is two times wider and four times taller
-// than the area used to create the braille canvas.
-func (c *Canvas) Area() image.Rectangle {
- ar := c.regular.Area()
- return image.Rect(0, 0, ar.Dx()*ColMult, ar.Dy()*RowMult)
-}
-
-// Clear clears all the content on the canvas.
-func (c *Canvas) Clear() error {
- return c.regular.Clear()
-}
-
-// SetPixel turns on pixel at the specified point.
-// The provided cell options will be applied to the entire cell (all of its
-// pixels). This method is idempotent.
-func (c *Canvas) SetPixel(p image.Point, opts ...cell.Option) error {
- cp, err := c.cellPoint(p)
- if err != nil {
- return err
- }
- cell, err := c.regular.Cell(cp)
- if err != nil {
- return err
- }
-
- var r rune
- if isBraille(cell.Rune) {
- // If the cell already has a braille pattern rune, we will be adding
- // the pixel.
- r = cell.Rune
- } else {
- r = brailleCharOffset
- }
-
- r |= pixelRunes[pixelPoint(p)]
- if _, err := c.regular.SetCell(cp, r, opts...); err != nil {
- return err
- }
- return nil
-}
-
-// ClearPixel turns off pixel at the specified point.
-// The provided cell options will be applied to the entire cell (all of its
-// pixels). This method is idempotent.
-func (c *Canvas) ClearPixel(p image.Point, opts ...cell.Option) error {
- cp, err := c.cellPoint(p)
- if err != nil {
- return err
- }
- cell, err := c.regular.Cell(cp)
- if err != nil {
- return err
- }
-
- // Clear is idempotent.
- if !isBraille(cell.Rune) || !pixelSet(cell.Rune, p) {
- return nil
- }
-
- r := cell.Rune & ^pixelRunes[pixelPoint(p)]
- if _, err := c.regular.SetCell(cp, r, opts...); err != nil {
- return err
- }
- return nil
-}
-
-// TogglePixel toggles the state of the pixel at the specified point, i.e. it
-// either sets or clear it depending on its current state.
-// The provided cell options will be applied to the entire cell (all of its
-// pixels).
-func (c *Canvas) TogglePixel(p image.Point, opts ...cell.Option) error {
- cp, err := c.cellPoint(p)
- if err != nil {
- return err
- }
- curCell, err := c.regular.Cell(cp)
- if err != nil {
- return err
- }
-
- if isBraille(curCell.Rune) && pixelSet(curCell.Rune, p) {
- return c.ClearPixel(p, opts...)
- }
- return c.SetPixel(p, opts...)
-}
-
-// SetCellOpts sets options on the specified cell of the braille canvas without
-// modifying the content of the cell.
-// Sets the default cell options if no options are provided.
-// This method is idempotent.
-func (c *Canvas) SetCellOpts(cellPoint image.Point, opts ...cell.Option) error {
- curCell, err := c.regular.Cell(cellPoint)
- if err != nil {
- return err
- }
-
- if len(opts) == 0 {
- // Set the default options.
- opts = []cell.Option{
- cell.FgColor(cell.ColorDefault),
- cell.BgColor(cell.ColorDefault),
- }
- }
- if _, err := c.regular.SetCell(cellPoint, curCell.Rune, opts...); err != nil {
- return err
- }
- return nil
-}
-
-// SetAreaCellOpts is like SetCellOpts, but sets the specified options on all
-// the cells within the provided area.
-func (c *Canvas) SetAreaCellOpts(cellArea image.Rectangle, opts ...cell.Option) error {
- haveArea := c.regular.Area()
- if !cellArea.In(haveArea) {
- return fmt.Errorf("unable to set cell options in area %v, it must fit inside the available cell area is %v", cellArea, haveArea)
- }
- for col := cellArea.Min.X; col < cellArea.Max.X; col++ {
- for row := cellArea.Min.Y; row < cellArea.Max.Y; row++ {
- if err := c.SetCellOpts(image.Point{col, row}, opts...); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-// 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 c.regular.Apply(t)
-}
-
-// CopyTo copies the content of this canvas onto the destination canvas.
-// This canvas can have an offset when compared to the destination canvas, i.e.
-// the area of this canvas doesn't have to be zero-based.
-func (c *Canvas) CopyTo(dst *canvas.Canvas) error {
- return c.regular.CopyTo(dst)
-}
-
-// cellPoint determines the point (coordinate) of the character cell given
-// coordinates in pixels.
-func (c *Canvas) cellPoint(p image.Point) (image.Point, error) {
- if p.X < 0 || p.Y < 0 {
- return image.ZP, fmt.Errorf("pixels cannot have negative coordinates: %v", p)
- }
- cp := image.Point{p.X / ColMult, p.Y / RowMult}
- if ar := c.regular.Area(); !cp.In(ar) {
- return image.ZP, fmt.Errorf("pixel at%v would be in a character cell at%v which falls outside of the canvas area %v", p, cp, ar)
- }
- return cp, nil
-}
-
-// isBraille determines if the rune is a braille pattern rune.
-func isBraille(r rune) bool {
- return r >= brailleCharOffset && r <= brailleLastChar
-}
-
-// pixelSet returns true if the provided rune has the specified pixel set.
-func pixelSet(r rune, p image.Point) bool {
- return r&pixelRunes[pixelPoint(p)] > 0
-}
-
-// pixelPoint translates point within canvas to point within the target cell.
-func pixelPoint(p image.Point) image.Point {
- return image.Point{p.X % ColMult, p.Y % RowMult}
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/buffer/buffer.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/buffer/buffer.go
deleted file mode 100644
index 5c21dd0ba..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/buffer/buffer.go
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package buffer implements a 2-D buffer of cells.
-package buffer
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/area"
- "github.com/mum4k/termdash/private/runewidth"
-)
-
-// NewCells breaks the provided text into cells and applies the options.
-func NewCells(text string, opts ...cell.Option) []*Cell {
- var res []*Cell
- for _, r := range text {
- res = append(res, NewCell(r, opts...))
- }
- return res
-}
-
-// Cell represents a single cell on the terminal.
-type Cell struct {
- // Rune is the rune stored in the cell.
- Rune rune
-
- // Opts are the cell options.
- Opts *cell.Options
-}
-
-// String implements fmt.Stringer.
-func (c *Cell) String() string {
- return fmt.Sprintf("{%q}", c.Rune)
-}
-
-// NewCell returns a new cell.
-func NewCell(r rune, opts ...cell.Option) *Cell {
- return &Cell{
- Rune: r,
- Opts: cell.NewOptions(opts...),
- }
-}
-
-// Copy returns a copy the cell.
-func (c *Cell) Copy() *Cell {
- return &Cell{
- Rune: c.Rune,
- Opts: cell.NewOptions(c.Opts),
- }
-}
-
-// Apply applies the provided options to the cell.
-func (c *Cell) Apply(opts ...cell.Option) {
- for _, opt := range opts {
- opt.Set(c.Opts)
- }
-}
-
-// Buffer is a 2-D buffer of cells.
-// The axes increase right and down.
-// Uninitialized buffer is invalid, use New to create an instance.
-// Don't set cells directly, use the SetCell method instead which safely
-// handles limits and wide unicode characters.
-type Buffer [][]*Cell
-
-// New returns a new Buffer of the provided size.
-func New(size image.Point) (Buffer, error) {
- if size.X <= 0 {
- return nil, fmt.Errorf("invalid buffer width (size.X): %d, must be a positive number", size.X)
- }
- if size.Y <= 0 {
- return nil, fmt.Errorf("invalid buffer height (size.Y): %d, must be a positive number", size.Y)
- }
-
- b := make([][]*Cell, size.X)
- for col := range b {
- b[col] = make([]*Cell, size.Y)
- for row := range b[col] {
- b[col][row] = NewCell(0)
- }
- }
- return b, nil
-}
-
-// SetCell sets the rune of the specified cell in the buffer. Returns the
-// number of cells the rune occupies, wide runes can occupy multiple cells when
-// printed on the terminal. See http://www.unicode.org/reports/tr11/.
-// Use the options to specify which attributes to modify, if an attribute
-// option isn't specified, the attribute retains its previous value.
-func (b Buffer) SetCell(p image.Point, r rune, opts ...cell.Option) (int, error) {
- partial, err := b.IsPartial(p)
- if err != nil {
- return -1, err
- }
- if partial {
- return -1, fmt.Errorf("cannot set rune %q at point %v, it is a partial cell occupied by a wide rune in the previous cell", r, p)
- }
-
- remW, err := b.RemWidth(p)
- if err != nil {
- 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)
- }
-
- c := b[p.X][p.Y]
- c.Rune = r
- c.Apply(opts...)
- return rw, nil
-}
-
-// IsPartial returns true if the cell at the specified point holds a part of a
-// full width rune from a previous cell. See
-// http://www.unicode.org/reports/tr11/.
-func (b Buffer) IsPartial(p image.Point) (bool, error) {
- size := b.Size()
- ar, err := area.FromSize(size)
- if err != nil {
- return false, err
- }
-
- if !p.In(ar) {
- return false, fmt.Errorf("point %v falls outside of the area %v occupied by the buffer", p, ar)
- }
-
- if p.X == 0 && p.Y == 0 {
- return false, nil
- }
-
- prevP := image.Point{p.X - 1, p.Y}
- if prevP.X < 0 {
- prevP = image.Point{size.X - 1, p.Y - 1}
- }
-
- prevR := b[prevP.X][prevP.Y].Rune
- switch rw := runewidth.RuneWidth(prevR); rw {
- case 0, 1:
- return false, nil
- case 2:
- return true, nil
- default:
- return false, fmt.Errorf("buffer cell %v contains rune %q which has an unsupported rune with %d", prevP, prevR, rw)
- }
-}
-
-// RemWidth returns the remaining width (horizontal row of cells) available
-// from and inclusive of the specified point.
-func (b Buffer) RemWidth(p image.Point) (int, error) {
- size := b.Size()
- ar, err := area.FromSize(size)
- if err != nil {
- return -1, err
- }
-
- if !p.In(ar) {
- return -1, fmt.Errorf("point %v falls outside of the area %v occupied by the buffer", p, ar)
- }
- return size.X - p.X, nil
-}
-
-// Size returns the size of the buffer.
-func (b Buffer) Size() image.Point {
- return image.Point{
- len(b),
- len(b[0]),
- }
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/canvas.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/canvas.go
deleted file mode 100644
index 65a1e6963..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/canvas/canvas.go
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package canvas defines the canvas that the widgets draw on.
-package canvas
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/area"
- "github.com/mum4k/termdash/private/canvas/buffer"
- "github.com/mum4k/termdash/private/runewidth"
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-// 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.
- buffer buffer.Buffer
-}
-
-// New returns a new Canvas with a buffer for the provided 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)
- }
-
- b, err := buffer.New(area.Size(ar))
- if err != nil {
- return nil, err
- }
- return &Canvas{
- area: ar,
- buffer: b,
- }, nil
-}
-
-// Size returns the size of the 2-D canvas.
-func (c *Canvas) Size() image.Point {
- return c.buffer.Size()
-}
-
-// Area returns the area of the 2-D canvas.
-func (c *Canvas) Area() image.Rectangle {
- s := c.buffer.Size()
- return image.Rect(0, 0, s.X, s.Y)
-}
-
-// Clear clears all the content on the canvas.
-func (c *Canvas) Clear() error {
- b, err := buffer.New(c.Size())
- if err != nil {
- return err
- }
- c.buffer = b
- return nil
-}
-
-// SetCell sets the rune of the specified cell on the canvas. Returns the
-// number of cells the rune occupies, wide runes can occupy multiple cells when
-// printed on the terminal. See http://www.unicode.org/reports/tr11/.
-// 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) (int, error) {
- return c.buffer.SetCell(p, r, opts...)
-}
-
-// Cell returns a copy of the specified cell.
-func (c *Canvas) Cell(p image.Point) (*buffer.Cell, error) {
- ar, err := area.FromSize(c.Size())
- if err != nil {
- return nil, err
- }
- if !p.In(ar) {
- return nil, fmt.Errorf("point %v falls outside of the area %v occupied by the canvas", p, ar)
- }
-
- return c.buffer[p.X][p.Y].Copy(), nil
-}
-
-// SetCellOpts sets options on the specified cell of the canvas without
-// modifying the content of the cell.
-// Sets the default cell options if no options are provided.
-// This method is idempotent.
-func (c *Canvas) SetCellOpts(p image.Point, opts ...cell.Option) error {
- curCell, err := c.Cell(p)
- if err != nil {
- return err
- }
-
- if len(opts) == 0 {
- // Set the default options.
- opts = []cell.Option{
- cell.FgColor(cell.ColorDefault),
- cell.BgColor(cell.ColorDefault),
- }
- }
- if _, err := c.SetCell(p, curCell.Rune, opts...); err != nil {
- return err
- }
- return nil
-}
-
-// SetAreaCells is like SetCell, but sets the specified rune and options on all
-// the cells within the provided area.
-// This method is idempotent.
-func (c *Canvas) SetAreaCells(cellArea image.Rectangle, r rune, opts ...cell.Option) error {
- haveArea := c.Area()
- if !cellArea.In(haveArea) {
- return fmt.Errorf("unable to set cell runes in area %v, it must fit inside the available cell area is %v", cellArea, haveArea)
- }
-
- rw := runewidth.RuneWidth(r)
- for row := cellArea.Min.Y; row < cellArea.Max.Y; row++ {
- for col := cellArea.Min.X; col < cellArea.Max.X; {
- p := image.Point{col, row}
- if col+rw > cellArea.Max.X {
- break
- }
- cells, err := c.SetCell(p, r, opts...)
- if err != nil {
- return err
- }
- col += cells
- }
- }
- return nil
-}
-
-// SetAreaCellOpts is like SetCellOpts, but sets the specified options on all
-// the cells within the provided area.
-func (c *Canvas) SetAreaCellOpts(cellArea image.Rectangle, opts ...cell.Option) error {
- haveArea := c.Area()
- if !cellArea.In(haveArea) {
- return fmt.Errorf("unable to set cell options in area %v, it must fit inside the available cell area is %v", cellArea, haveArea)
- }
- for col := cellArea.Min.X; col < cellArea.Max.X; col++ {
- for row := cellArea.Min.Y; row < cellArea.Max.Y; row++ {
- if err := c.SetCellOpts(image.Point{col, row}, opts...); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-// setCellFunc is a function that sets cell content on a terminal or a canvas.
-type setCellFunc func(image.Point, rune, ...cell.Option) error
-
-// copyTo is the internal implementation of code that copies the content of a
-// canvas. If a non zero offset is provided, all the copied points are offset by
-// this amount.
-// The dstSetCell function is called for every point in this canvas when
-// copying it to the destination.
-func (c *Canvas) copyTo(offset image.Point, dstSetCell setCellFunc) error {
- for col := range c.buffer {
- for row := range c.buffer[col] {
- partial, err := c.buffer.IsPartial(image.Point{col, row})
- if err != nil {
- return err
- }
- if partial {
- // Skip over partial cells, i.e. cells that follow a cell
- // containing a full-width rune. A full-width rune takes only
- // one cell in the buffer, but two on the terminal.
- // See http://www.unicode.org/reports/tr11/.
- continue
- }
- cell := c.buffer[col][row]
- p := image.Point{col, row}.Add(offset)
- if err := dstSetCell(p, cell.Rune, cell.Opts); err != nil {
- return fmt.Errorf("setCellFunc%v => error: %v", p, err)
- }
- }
- }
- return nil
-}
-
-// 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 {
- 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)
- }
-
- // 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
- return c.copyTo(offset, t.SetCell)
-}
-
-// CopyTo copies the content of this canvas onto the destination canvas.
-// This canvas can have an offset when compared to the destination canvas, i.e.
-// the area of this canvas doesn't have to be zero-based.
-func (c *Canvas) CopyTo(dst *Canvas) error {
- if !c.area.In(dst.Area()) {
- return fmt.Errorf("the canvas area %v doesn't fit or lie inside the destination canvas area %v", c.area, dst.Area())
- }
-
- fn := setCellFunc(func(p image.Point, r rune, opts ...cell.Option) error {
- if _, err := dst.SetCell(p, r, opts...); err != nil {
- return fmt.Errorf("dst.SetCell => %v", err)
- }
- return nil
- })
-
- // Neither of the two canvases (source and destination) have to be zero
- // based. Canvas is not zero based if it is positioned elsewhere, i.e.
- // providing a smaller view of another canvas.
- // E.g. a widget can assign a smaller portion of its canvas to a component
- // in order to restrict drawing of this component to a smaller area. To do
- // this it can create a sub-canvas. This sub-canvas can have a specific
- // starting position other than image.Point{0, 0} relative to the parent
- // canvas. Copying this sub-canvas back onto the parent accounts for this
- // offset.
- offset := c.area.Min
- return c.copyTo(offset, fn)
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/border.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/border.go
deleted file mode 100644
index a19ec096c..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/border.go
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// border.go contains code that draws borders.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/align"
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/linestyle"
- "github.com/mum4k/termdash/private/alignfor"
- "github.com/mum4k/termdash/private/canvas"
-)
-
-// BorderOption is used to provide options to Border().
-type BorderOption interface {
- // set sets the provided option.
- set(*borderOptions)
-}
-
-// borderOptions stores the provided options.
-type borderOptions struct {
- cellOpts []cell.Option
- lineStyle linestyle.LineStyle
- title string
- titleOM OverrunMode
- titleCellOpts []cell.Option
- titleHAlign align.Horizontal
-}
-
-// borderOption implements BorderOption.
-type borderOption func(bOpts *borderOptions)
-
-// set implements BorderOption.set.
-func (bo borderOption) set(bOpts *borderOptions) {
- bo(bOpts)
-}
-
-// DefaultBorderLineStyle is the default value for the BorderLineStyle option.
-const DefaultBorderLineStyle = linestyle.Light
-
-// BorderLineStyle sets the style of the line used to draw the border.
-func BorderLineStyle(ls linestyle.LineStyle) BorderOption {
- return borderOption(func(bOpts *borderOptions) {
- bOpts.lineStyle = ls
- })
-}
-
-// BorderCellOpts sets options on the cells that create the border.
-func BorderCellOpts(opts ...cell.Option) BorderOption {
- return borderOption(func(bOpts *borderOptions) {
- bOpts.cellOpts = opts
- })
-}
-
-// BorderTitle sets a title for the border.
-func BorderTitle(title string, overrun OverrunMode, opts ...cell.Option) BorderOption {
- return borderOption(func(bOpts *borderOptions) {
- bOpts.title = title
- bOpts.titleOM = overrun
- bOpts.titleCellOpts = opts
- })
-}
-
-// BorderTitleAlign configures the horizontal alignment for the title.
-func BorderTitleAlign(h align.Horizontal) BorderOption {
- return borderOption(func(bOpts *borderOptions) {
- bOpts.titleHAlign = h
- })
-}
-
-// borderChar returns the correct border character from the parts for the use
-// at the specified point of the border. Returns -1 if no character should be at
-// this point.
-func borderChar(p image.Point, border image.Rectangle, parts map[linePart]rune) rune {
- switch {
- case p.X == border.Min.X && p.Y == border.Min.Y:
- return parts[topLeftCorner]
- case p.X == border.Max.X-1 && p.Y == border.Min.Y:
- return parts[topRightCorner]
- case p.X == border.Min.X && p.Y == border.Max.Y-1:
- return parts[bottomLeftCorner]
- case p.X == border.Max.X-1 && p.Y == border.Max.Y-1:
- return parts[bottomRightCorner]
- case p.X == border.Min.X || p.X == border.Max.X-1:
- return parts[vLine]
- case p.Y == border.Min.Y || p.Y == border.Max.Y-1:
- return parts[hLine]
- }
- return -1
-}
-
-// drawTitle draws a text title at the top of the border.
-func drawTitle(c *canvas.Canvas, border image.Rectangle, opt *borderOptions) error {
- // Don't attempt to draw the title if there isn't space for at least one rune.
- // The title must not overwrite any of the corner runes on the border so we
- // need the following minimum width.
- const minForTitle = 3
- if border.Dx() < minForTitle {
- return nil
- }
-
- available := image.Rect(
- border.Min.X+1, // One space for the top left corner char.
- border.Min.Y,
- border.Max.X-1, // One space for the top right corner char.
- border.Min.Y+1,
- )
- start, err := alignfor.Text(available, opt.title, opt.titleHAlign, align.VerticalTop)
- if err != nil {
- return err
- }
-
- return Text(
- c, opt.title, start,
- TextCellOpts(opt.titleCellOpts...),
- TextOverrunMode(opt.titleOM),
- TextMaxX(available.Max.X),
- )
-}
-
-// Border draws a border on the canvas.
-func Border(c *canvas.Canvas, border image.Rectangle, opts ...BorderOption) error {
- if ar := c.Area(); !border.In(ar) {
- return fmt.Errorf("the requested border %+v falls outside of the provided canvas %+v", border, ar)
- }
-
- const minSize = 2
- if border.Dx() < minSize || border.Dy() < minSize {
- return fmt.Errorf("the smallest supported border is %dx%d, got: %dx%d", minSize, minSize, border.Dx(), border.Dy())
- }
-
- opt := &borderOptions{
- lineStyle: DefaultBorderLineStyle,
- }
- for _, o := range opts {
- o.set(opt)
- }
-
- parts, err := lineParts(opt.lineStyle)
- if err != nil {
- return err
- }
-
- for col := border.Min.X; col < border.Max.X; col++ {
- for row := border.Min.Y; row < border.Max.Y; row++ {
- p := image.Point{col, row}
- r := borderChar(p, border, parts)
- if r == -1 {
- continue
- }
-
- cells, err := c.SetCell(p, r, opt.cellOpts...)
- if err != nil {
- return err
- }
- if cells != 1 {
- panic(fmt.Sprintf("invalid border rune %q, this rune occupies %d cells, border implementation only supports half-width runes that occupy exactly one cell", r, cells))
- }
- }
- }
-
- if opt.title != "" {
- return drawTitle(c, border, opt)
- }
- return nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_circle.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_circle.go
deleted file mode 100644
index d2b3b86bc..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_circle.go
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// braille_circle.go contains code that draws circles on a braille canvas.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/canvas/braille"
- "github.com/mum4k/termdash/private/numbers/trig"
-)
-
-// BrailleCircleOption is used to provide options to BrailleCircle.
-type BrailleCircleOption interface {
- // set sets the provided option.
- set(*brailleCircleOptions)
-}
-
-// brailleCircleOptions stores the provided options.
-type brailleCircleOptions struct {
- cellOpts []cell.Option
- filled bool
- pixelChange braillePixelChange
-
- arcOnly bool
- startDegree int
- endDegree int
-}
-
-// newBrailleCircleOptions returns a new brailleCircleOptions instance.
-func newBrailleCircleOptions() *brailleCircleOptions {
- return &brailleCircleOptions{
- pixelChange: braillePixelChangeSet,
- }
-}
-
-// validate validates the provided options.
-func (opts *brailleCircleOptions) validate() error {
- if !opts.arcOnly {
- return nil
- }
-
- if opts.startDegree == opts.endDegree {
- return fmt.Errorf("invalid degree range, start %d and end %d cannot be equal", opts.startDegree, opts.endDegree)
- }
- return nil
-}
-
-// brailleCircleOption implements BrailleCircleOption.
-type brailleCircleOption func(*brailleCircleOptions)
-
-// set implements BrailleCircleOption.set.
-func (o brailleCircleOption) set(opts *brailleCircleOptions) {
- o(opts)
-}
-
-// BrailleCircleCellOpts sets options on the cells that contain the circle.
-// Cell options on a braille canvas can only be set on the entire cell, not per
-// pixel.
-func BrailleCircleCellOpts(cOpts ...cell.Option) BrailleCircleOption {
- return brailleCircleOption(func(opts *brailleCircleOptions) {
- opts.cellOpts = cOpts
- })
-}
-
-// BrailleCircleFilled indicates that the drawn circle should be filled.
-func BrailleCircleFilled() BrailleCircleOption {
- return brailleCircleOption(func(opts *brailleCircleOptions) {
- opts.filled = true
- })
-}
-
-// BrailleCircleArcOnly indicates that only a portion of the circle should be drawn.
-// The arc will be between the two provided angles in degrees.
-// Each angle must be in range 0 <= angle <= 360. Start and end must not be equal.
-// The zero angle is on the X axis, angles grow counter-clockwise.
-func BrailleCircleArcOnly(startDegree, endDegree int) BrailleCircleOption {
- return brailleCircleOption(func(opts *brailleCircleOptions) {
- opts.arcOnly = true
- opts.startDegree = startDegree
- opts.endDegree = endDegree
-
- })
-}
-
-// BrailleCircleClearPixels changes the behavior of BrailleCircle, so that it
-// clears the pixels belonging to the circle instead of setting them.
-// Useful in order to "erase" a circle from the canvas as opposed to drawing one.
-func BrailleCircleClearPixels() BrailleCircleOption {
- return brailleCircleOption(func(opts *brailleCircleOptions) {
- opts.pixelChange = braillePixelChangeClear
- })
-}
-
-// BrailleCircle draws an approximated circle with the specified mid point and radius.
-// The mid point must be a valid pixel within the canvas.
-// All the points that form the circle must fit into the canvas.
-// The smallest valid radius is two.
-func BrailleCircle(bc *braille.Canvas, mid image.Point, radius int, opts ...BrailleCircleOption) error {
- if ar := bc.Area(); !mid.In(ar) {
- return fmt.Errorf("unable to draw circle with mid point %v which is outside of the braille canvas area %v", mid, ar)
- }
- if min := 2; radius < min {
- return fmt.Errorf("unable to draw circle with radius %d, must be in range %d <= radius", radius, min)
- }
-
- opt := newBrailleCircleOptions()
- for _, o := range opts {
- o.set(opt)
- }
-
- if err := opt.validate(); err != nil {
- return err
- }
-
- points := circlePoints(mid, radius)
- if opt.arcOnly {
- f, err := trig.FilterByAngle(points, mid, opt.startDegree, opt.endDegree)
- if err != nil {
- return err
- }
- points = f
- if opt.filled && (opt.startDegree != 0 || opt.endDegree != 360) {
- points = append(points, openingPoints(mid, radius, opt)...)
- }
- }
- if err := drawPoints(bc, points, opt); err != nil {
- return fmt.Errorf("failed to draw circle with mid:%v, radius:%d, start:%d degrees, end:%d degrees: %v", mid, radius, opt.startDegree, opt.endDegree, err)
- }
- if opt.filled {
- return fillCircle(bc, points, mid, radius, opt)
- }
- return nil
-}
-
-// drawPoints draws the points onto the canvas.
-func drawPoints(bc *braille.Canvas, points []image.Point, opt *brailleCircleOptions) error {
- for _, p := range points {
- switch opt.pixelChange {
- case braillePixelChangeSet:
- if err := bc.SetPixel(p, opt.cellOpts...); err != nil {
- return fmt.Errorf("SetPixel => %v", err)
- }
- case braillePixelChangeClear:
- if err := bc.ClearPixel(p, opt.cellOpts...); err != nil {
- return fmt.Errorf("ClearPixel => %v", err)
- }
-
- }
- }
- return nil
-}
-
-// fillCircle fills a circle that consists of the provided point and has the
-// mid point and radius.
-func fillCircle(bc *braille.Canvas, points []image.Point, mid image.Point, radius int, opt *brailleCircleOptions) error {
- lineOpts := []BrailleLineOption{
- BrailleLineCellOpts(opt.cellOpts...),
- }
- fillOpts := []BrailleFillOption{
- BrailleFillCellOpts(opt.cellOpts...),
- }
- if opt.pixelChange == braillePixelChangeClear {
- lineOpts = append(lineOpts, BrailleLineClearPixels())
- fillOpts = append(fillOpts, BrailleFillClearPixels())
- }
-
- // Determine a fill point that should be inside of the circle sector.
- midA, err := trig.RangeMid(opt.startDegree, opt.endDegree)
- if err != nil {
- return err
- }
- fp := trig.CirclePointAtAngle(midA, mid, radius-1)
-
- // Ensure the fill point falls inside the circle.
- // If drawing a partial circle, it must also fall within points belonging
- // to the opening.
- // This might not be true if drawing a partial circle and the arc is very
- // small.
- shape := points
- if opt.arcOnly {
- startP := trig.CirclePointAtAngle(opt.startDegree, mid, radius-1)
- endP := trig.CirclePointAtAngle(opt.endDegree, mid, radius-1)
- shape = append(shape, startP, endP)
- }
- if trig.PointIsIn(fp, shape) {
- if err := BrailleFill(bc, fp, points, fillOpts...); err != nil {
- return err
- }
- if err := BrailleLine(bc, mid, fp, lineOpts...); err != nil {
- return err
- }
- }
- return nil
-}
-
-// openingPoints returns points on the lines from the mid point to the circle
-// opening when drawing an incomplete circle.
-func openingPoints(mid image.Point, radius int, opt *brailleCircleOptions) []image.Point {
- var points []image.Point
- startP := trig.CirclePointAtAngle(opt.startDegree, mid, radius)
- endP := trig.CirclePointAtAngle(opt.endDegree, mid, radius)
- points = append(points, brailleLinePoints(mid, startP)...)
- points = append(points, brailleLinePoints(mid, endP)...)
- return points
-}
-
-// circlePoints returns a list of points that represent a circle with
-// the specified mid point and radius.
-func circlePoints(mid image.Point, radius int) []image.Point {
- var points []image.Point
-
- // Bresenham algorithm.
- // https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
- x := radius
- y := 0
- dx := 1
- dy := 1
- diff := dx - (radius << 1) // Cheap multiplication by two.
-
- for x >= y {
- points = append(
- points,
- image.Point{mid.X + x, mid.Y + y},
- image.Point{mid.X + y, mid.Y + x},
- image.Point{mid.X - y, mid.Y + x},
- image.Point{mid.X - x, mid.Y + y},
- image.Point{mid.X - x, mid.Y - y},
- image.Point{mid.X - y, mid.Y - x},
- image.Point{mid.X + y, mid.Y - x},
- image.Point{mid.X + x, mid.Y - y},
- )
-
- if diff <= 0 {
- y++
- diff += dy
- dy += 2
- }
-
- if diff > 0 {
- x--
- dx += 2
- diff += dx - (radius << 1)
- }
-
- }
- return points
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_fill.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_fill.go
deleted file mode 100644
index 8bb311f1c..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_fill.go
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// braille_fill.go implements the flood-fill algorithm for filling shapes on the braille canvas.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/canvas/braille"
-)
-
-// BrailleFillOption is used to provide options to BrailleFill.
-type BrailleFillOption interface {
- // set sets the provided option.
- set(*brailleFillOptions)
-}
-
-// brailleFillOptions stores the provided options.
-type brailleFillOptions struct {
- cellOpts []cell.Option
- pixelChange braillePixelChange
-}
-
-// newBrailleFillOptions returns a new brailleFillOptions instance.
-func newBrailleFillOptions() *brailleFillOptions {
- return &brailleFillOptions{
- pixelChange: braillePixelChangeSet,
- }
-}
-
-// brailleFillOption implements BrailleFillOption.
-type brailleFillOption func(*brailleFillOptions)
-
-// set implements BrailleFillOption.set.
-func (o brailleFillOption) set(opts *brailleFillOptions) {
- o(opts)
-}
-
-// BrailleFillCellOpts sets options on the cells that are set as part of
-// filling shapes.
-// Cell options on a braille canvas can only be set on the entire cell, not per
-// pixel.
-func BrailleFillCellOpts(cOpts ...cell.Option) BrailleFillOption {
- return brailleFillOption(func(opts *brailleFillOptions) {
- opts.cellOpts = cOpts
- })
-}
-
-// BrailleFillClearPixels changes the behavior of BrailleFill, so that it
-// clears the pixels instead of setting them.
-// Useful in order to "erase" the filled area as opposed to drawing one.
-func BrailleFillClearPixels() BrailleFillOption {
- return brailleFillOption(func(opts *brailleFillOptions) {
- opts.pixelChange = braillePixelChangeClear
- })
-}
-
-// BrailleFill fills the braille canvas starting at the specified point.
-// The function will not fill or cross over any points in the defined border.
-// The start point must be in the canvas.
-func BrailleFill(bc *braille.Canvas, start image.Point, border []image.Point, opts ...BrailleFillOption) error {
- if ar := bc.Area(); !start.In(ar) {
- return fmt.Errorf("unable to start filling canvas at point %v which is outside of the braille canvas area %v", start, ar)
- }
-
- opt := newBrailleFillOptions()
- for _, o := range opts {
- o.set(opt)
- }
-
- b := map[image.Point]struct{}{}
- for _, p := range border {
- b[p] = struct{}{}
- }
-
- v := newVisitable(bc.Area(), b)
- visitor := func(p image.Point) error {
- switch opt.pixelChange {
- case braillePixelChangeSet:
- return bc.SetPixel(p, opt.cellOpts...)
- case braillePixelChangeClear:
- return bc.ClearPixel(p, opt.cellOpts...)
- }
- return nil
- }
- return brailleDFS(v, start, visitor)
-}
-
-// visitable represents an area that can be visited.
-// It tracks nodes that are already visited.
-type visitable struct {
- area image.Rectangle
- visited map[image.Point]struct{}
-}
-
-// newVisitable returns a new visitable object initialized for the provided
-// area and already visited nodes.
-func newVisitable(ar image.Rectangle, visited map[image.Point]struct{}) *visitable {
- if visited == nil {
- visited = map[image.Point]struct{}{}
- }
- return &visitable{
- area: ar,
- visited: visited,
- }
-}
-
-// neighborsAt returns all valid neighbors for the specified point.
-func (v *visitable) neighborsAt(p image.Point) []image.Point {
- var res []image.Point
- for _, neigh := range []image.Point{
- {p.X - 1, p.Y}, // left
- {p.X + 1, p.Y}, // right
- {p.X, p.Y - 1}, // up
- {p.X, p.Y + 1}, // down
- } {
- if !neigh.In(v.area) {
- continue
- }
- if _, ok := v.visited[neigh]; ok {
- continue
- }
- v.visited[neigh] = struct{}{}
- res = append(res, neigh)
- }
- return res
-}
-
-// brailleDFS visits every point in the area and runs the visitor function.
-func brailleDFS(v *visitable, p image.Point, visitFn func(image.Point) error) error {
- neigh := v.neighborsAt(p)
- if len(neigh) == 0 {
- return nil
- }
-
- for _, n := range neigh {
- if err := visitFn(n); err != nil {
- return err
- }
- if err := brailleDFS(v, n, visitFn); err != nil {
- return err
- }
- }
- return nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_line.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_line.go
deleted file mode 100644
index c9f412321..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/braille_line.go
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// braille_line.go contains code that draws lines on a braille canvas.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/canvas/braille"
- "github.com/mum4k/termdash/private/numbers"
-)
-
-// braillePixelChange represents an action on a pixel on the braille canvas.
-type braillePixelChange int
-
-// String implements fmt.Stringer()
-func (bpc braillePixelChange) String() string {
- if n, ok := braillePixelChangeNames[bpc]; ok {
- return n
- }
- return "braillePixelChangeUnknown"
-}
-
-// braillePixelChangeNames maps braillePixelChange values to human readable names.
-var braillePixelChangeNames = map[braillePixelChange]string{
- braillePixelChangeSet: "braillePixelChangeSet",
- braillePixelChangeClear: "braillePixelChangeClear",
-}
-
-const (
- braillePixelChangeUnknown braillePixelChange = iota
-
- braillePixelChangeSet
- braillePixelChangeClear
-)
-
-// BrailleLineOption is used to provide options to BrailleLine().
-type BrailleLineOption interface {
- // set sets the provided option.
- set(*brailleLineOptions)
-}
-
-// brailleLineOptions stores the provided options.
-type brailleLineOptions struct {
- cellOpts []cell.Option
- pixelChange braillePixelChange
-}
-
-// newBrailleLineOptions returns a new brailleLineOptions instance.
-func newBrailleLineOptions() *brailleLineOptions {
- return &brailleLineOptions{
- pixelChange: braillePixelChangeSet,
- }
-}
-
-// brailleLineOption implements BrailleLineOption.
-type brailleLineOption func(*brailleLineOptions)
-
-// set implements BrailleLineOption.set.
-func (o brailleLineOption) set(opts *brailleLineOptions) {
- o(opts)
-}
-
-// BrailleLineCellOpts sets options on the cells that contain the line.
-// Cell options on a braille canvas can only be set on the entire cell, not per
-// pixel.
-func BrailleLineCellOpts(cOpts ...cell.Option) BrailleLineOption {
- return brailleLineOption(func(opts *brailleLineOptions) {
- opts.cellOpts = cOpts
- })
-}
-
-// BrailleLineClearPixels changes the behavior of BrailleLine, so that it
-// clears the pixels belonging to the line instead of setting them.
-// Useful in order to "erase" a line from the canvas as opposed to drawing one.
-func BrailleLineClearPixels() BrailleLineOption {
- return brailleLineOption(func(opts *brailleLineOptions) {
- opts.pixelChange = braillePixelChangeClear
- })
-}
-
-// BrailleLine draws an approximated line segment on the braille canvas between
-// the two provided points.
-// Both start and end must be valid points within the canvas. Start and end can
-// be the same point in which case only one pixel will be set on the braille
-// canvas.
-// The start or end coordinates must not be negative.
-func BrailleLine(bc *braille.Canvas, start, end image.Point, opts ...BrailleLineOption) error {
- if start.X < 0 || start.Y < 0 {
- return fmt.Errorf("the start coordinates cannot be negative, got: %v", start)
- }
- if end.X < 0 || end.Y < 0 {
- return fmt.Errorf("the end coordinates cannot be negative, got: %v", end)
- }
-
- opt := newBrailleLineOptions()
- for _, o := range opts {
- o.set(opt)
- }
-
- points := brailleLinePoints(start, end)
- for _, p := range points {
- switch opt.pixelChange {
- case braillePixelChangeSet:
- if err := bc.SetPixel(p, opt.cellOpts...); err != nil {
- return fmt.Errorf("bc.SetPixel(%v) => %v", p, err)
- }
- case braillePixelChangeClear:
- if err := bc.ClearPixel(p, opt.cellOpts...); err != nil {
- return fmt.Errorf("bc.ClearPixel(%v) => %v", p, err)
- }
- }
- }
- return nil
-}
-
-// brailleLinePoints returns the points to set when drawing the line.
-func brailleLinePoints(start, end image.Point) []image.Point {
- // Implements Bresenham's line algorithm.
- // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
-
- vertProj := numbers.Abs(end.Y - start.Y)
- horizProj := numbers.Abs(end.X - start.X)
- if vertProj < horizProj {
- if start.X > end.X {
- return lineLow(end.X, end.Y, start.X, start.Y)
- }
- return lineLow(start.X, start.Y, end.X, end.Y)
- }
- if start.Y > end.Y {
- return lineHigh(end.X, end.Y, start.X, start.Y)
- }
- return lineHigh(start.X, start.Y, end.X, end.Y)
-}
-
-// lineLow returns points that create a line whose horizontal projection
-// (end.X - start.X) is longer than its vertical projection
-// (end.Y - start.Y).
-func lineLow(x0, y0, x1, y1 int) []image.Point {
- deltaX := x1 - x0
- deltaY := y1 - y0
-
- stepY := 1
- if deltaY < 0 {
- stepY = -1
- deltaY = -deltaY
- }
-
- var res []image.Point
- diff := 2*deltaY - deltaX
- y := y0
- for x := x0; x <= x1; x++ {
- res = append(res, image.Point{x, y})
- if diff > 0 {
- y += stepY
- diff -= 2 * deltaX
- }
- diff += 2 * deltaY
- }
- return res
-}
-
-// lineHigh returns points that createa line whose vertical projection
-// (end.Y - start.Y) is longer than its horizontal projection
-// (end.X - start.X).
-func lineHigh(x0, y0, x1, y1 int) []image.Point {
- deltaX := x1 - x0
- deltaY := y1 - y0
-
- stepX := 1
- if deltaX < 0 {
- stepX = -1
- deltaX = -deltaX
- }
-
- var res []image.Point
- diff := 2*deltaX - deltaY
- x := x0
- for y := y0; y <= y1; y++ {
- res = append(res, image.Point{x, y})
-
- if diff > 0 {
- x += stepX
- diff -= 2 * deltaY
- }
- diff += 2 * deltaX
- }
- return res
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/draw.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/draw.go
deleted file mode 100644
index 37c01bf7e..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/draw.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package draw provides functions that draw lines, shapes, etc on 2-D terminal
-// like canvases.
-package draw
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line.go
deleted file mode 100644
index 35318f42d..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// hv_line.go contains code that draws horizontal and vertical lines.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/linestyle"
- "github.com/mum4k/termdash/private/canvas"
-)
-
-// HVLineOption is used to provide options to HVLine().
-type HVLineOption interface {
- // set sets the provided option.
- set(*hVLineOptions)
-}
-
-// hVLineOptions stores the provided options.
-type hVLineOptions struct {
- cellOpts []cell.Option
- lineStyle linestyle.LineStyle
-}
-
-// newHVLineOptions returns a new hVLineOptions instance.
-func newHVLineOptions() *hVLineOptions {
- return &hVLineOptions{
- lineStyle: DefaultLineStyle,
- }
-}
-
-// hVLineOption implements HVLineOption.
-type hVLineOption func(*hVLineOptions)
-
-// set implements HVLineOption.set.
-func (o hVLineOption) set(opts *hVLineOptions) {
- o(opts)
-}
-
-// DefaultLineStyle is the default value for the HVLineStyle option.
-const DefaultLineStyle = linestyle.Light
-
-// HVLineStyle sets the style of the line.
-// Defaults to DefaultLineStyle.
-func HVLineStyle(ls linestyle.LineStyle) HVLineOption {
- return hVLineOption(func(opts *hVLineOptions) {
- opts.lineStyle = ls
- })
-}
-
-// HVLineCellOpts sets options on the cells that contain the line.
-func HVLineCellOpts(cOpts ...cell.Option) HVLineOption {
- return hVLineOption(func(opts *hVLineOptions) {
- opts.cellOpts = cOpts
- })
-}
-
-// HVLine represents one horizontal or vertical line.
-type HVLine struct {
- // Start is the cell where the line starts.
- Start image.Point
- // End is the cell where the line ends.
- End image.Point
-}
-
-// HVLines draws horizontal or vertical lines. Handles drawing of the correct
-// characters for locations where any two lines cross (e.g. a corner, a T shape
-// or a cross). Each line must be at least two cells long. Both start and end
-// must be on the same horizontal (same X coordinate) or same vertical (same Y
-// coordinate) line.
-func HVLines(c *canvas.Canvas, lines []HVLine, opts ...HVLineOption) error {
- opt := newHVLineOptions()
- for _, o := range opts {
- o.set(opt)
- }
-
- g := newHVLineGraph()
- for _, l := range lines {
- line, err := newHVLine(c, l.Start, l.End, opt)
- if err != nil {
- return err
- }
- g.addLine(line)
-
- switch {
- case line.horizontal():
- for curX := line.start.X; ; curX++ {
- cur := image.Point{curX, line.start.Y}
- if _, err := c.SetCell(cur, line.mainPart, opt.cellOpts...); err != nil {
- return err
- }
-
- if curX == line.end.X {
- break
- }
- }
-
- case line.vertical():
- for curY := line.start.Y; ; curY++ {
- cur := image.Point{line.start.X, curY}
- if _, err := c.SetCell(cur, line.mainPart, opt.cellOpts...); err != nil {
- return err
- }
-
- if curY == line.end.Y {
- break
- }
- }
- }
- }
-
- for _, n := range g.multiEdgeNodes() {
- r, err := n.rune(opt.lineStyle)
- if err != nil {
- return err
- }
- if _, err := c.SetCell(n.p, r, opt.cellOpts...); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// hVLine represents a line that will be drawn on the canvas.
-type hVLine struct {
- // start is the starting point of the line.
- start image.Point
-
- // end is the ending point of the line.
- end image.Point
-
- // mainPart is either parts[vLine] or parts[hLine] depending on whether
- // this is horizontal or vertical line.
- mainPart rune
-
- // opts are the options provided in a call to HVLine().
- opts *hVLineOptions
-}
-
-// newHVLine creates a new hVLine instance.
-// Swaps start and end if necessary, so that horizontal drawing is always left
-// to right and vertical is always top down.
-func newHVLine(c *canvas.Canvas, start, end image.Point, opts *hVLineOptions) (*hVLine, error) {
- if ar := c.Area(); !start.In(ar) || !end.In(ar) {
- return nil, fmt.Errorf("both the start%v and the end%v must be in the canvas area: %v", start, end, ar)
- }
-
- parts, err := lineParts(opts.lineStyle)
- if err != nil {
- return nil, err
- }
-
- var mainPart rune
- switch {
- case start.X != end.X && start.Y != end.Y:
- return nil, fmt.Errorf("can only draw horizontal (same X coordinates) or vertical (same Y coordinates), got start:%v end:%v", start, end)
-
- case start.X == end.X && start.Y == end.Y:
- return nil, fmt.Errorf("the line must at least one cell long, got start%v, end%v", start, end)
-
- case start.X == end.X:
- mainPart = parts[vLine]
- if start.Y > end.Y {
- start, end = end, start
- }
-
- case start.Y == end.Y:
- mainPart = parts[hLine]
- if start.X > end.X {
- start, end = end, start
- }
-
- }
-
- return &hVLine{
- start: start,
- end: end,
- mainPart: mainPart,
- opts: opts,
- }, nil
-}
-
-// horizontal determines if this is a horizontal line.
-func (hvl *hVLine) horizontal() bool {
- return hvl.mainPart == lineStyleChars[hvl.opts.lineStyle][hLine]
-}
-
-// vertical determines if this is a vertical line.
-func (hvl *hVLine) vertical() bool {
- return hvl.mainPart == lineStyleChars[hvl.opts.lineStyle][vLine]
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line_graph.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line_graph.go
deleted file mode 100644
index ccbc72a57..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/hv_line_graph.go
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// hv_line_graph.go helps to keep track of locations where lines cross.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/linestyle"
-)
-
-// hVLineEdge is an edge between two points on the graph.
-type hVLineEdge struct {
- // from is the starting node of this edge.
- // From is guaranteed to be less than to.
- from image.Point
-
- // to is the ending point of this edge.
- to image.Point
-}
-
-// newHVLineEdge returns a new edge between the two points.
-func newHVLineEdge(from, to image.Point) hVLineEdge {
- return hVLineEdge{
- from: from,
- to: to,
- }
-}
-
-// hVLineNode represents one node in the graph.
-// I.e. one cell.
-type hVLineNode struct {
- // p is the point where this node is.
- p image.Point
-
- // edges are the edges between this node and the surrounding nodes.
- // The code only supports horizontal and vertical lines so there can only
- // ever be edges to nodes on these planes.
- edges map[hVLineEdge]bool
-}
-
-// newHVLineNode creates a new newHVLineNode.
-func newHVLineNode(p image.Point) *hVLineNode {
- return &hVLineNode{
- p: p,
- edges: map[hVLineEdge]bool{},
- }
-}
-
-// hasDown determines if this node has an edge to the one below it.
-func (n *hVLineNode) hasDown() bool {
- target := newHVLineEdge(n.p, image.Point{n.p.X, n.p.Y + 1})
- _, ok := n.edges[target]
- return ok
-}
-
-// hasUp determines if this node has an edge to the one above it.
-func (n *hVLineNode) hasUp() bool {
- target := newHVLineEdge(image.Point{n.p.X, n.p.Y - 1}, n.p)
- _, ok := n.edges[target]
- return ok
-}
-
-// hasLeft determines if this node has an edge to the next node on the left.
-func (n *hVLineNode) hasLeft() bool {
- target := newHVLineEdge(image.Point{n.p.X - 1, n.p.Y}, n.p)
- _, ok := n.edges[target]
- return ok
-}
-
-// hasRight determines if this node has an edge to the next node on the right.
-func (n *hVLineNode) hasRight() bool {
- target := newHVLineEdge(n.p, image.Point{n.p.X + 1, n.p.Y})
- _, ok := n.edges[target]
- return ok
-}
-
-// rune, given the selected line style returns the correct line character to
-// represent this node.
-// Only handles nodes with two or more edges, as returned by multiEdgeNodes().
-func (n *hVLineNode) rune(ls linestyle.LineStyle) (rune, error) {
- parts, err := lineParts(ls)
- if err != nil {
- return -1, err
- }
-
- switch len(n.edges) {
- case 2:
- switch {
- case n.hasLeft() && n.hasRight():
- return parts[hLine], nil
- case n.hasUp() && n.hasDown():
- return parts[vLine], nil
- case n.hasDown() && n.hasRight():
- return parts[topLeftCorner], nil
- case n.hasDown() && n.hasLeft():
- return parts[topRightCorner], nil
- case n.hasUp() && n.hasRight():
- return parts[bottomLeftCorner], nil
- case n.hasUp() && n.hasLeft():
- return parts[bottomRightCorner], nil
- default:
- return -1, fmt.Errorf("unexpected two edges in node representing point %v: %v", n.p, n.edges)
- }
-
- case 3:
- switch {
- case n.hasUp() && n.hasLeft() && n.hasRight():
- return parts[hAndUp], nil
- case n.hasDown() && n.hasLeft() && n.hasRight():
- return parts[hAndDown], nil
- case n.hasUp() && n.hasDown() && n.hasRight():
- return parts[vAndRight], nil
- case n.hasUp() && n.hasDown() && n.hasLeft():
- return parts[vAndLeft], nil
-
- default:
- return -1, fmt.Errorf("unexpected three edges in node representing point %v: %v", n.p, n.edges)
- }
-
- case 4:
- return parts[vAndH], nil
- default:
- return -1, fmt.Errorf("unexpected number of edges(%d) in node representing point %v", len(n.edges), n.p)
- }
-}
-
-// hVLineGraph represents lines on the canvas as a bidirectional graph of
-// nodes. Helps to determine the characters that should be used where multiple
-// lines cross.
-type hVLineGraph struct {
- nodes map[image.Point]*hVLineNode
-}
-
-// newHVLineGraph creates a new hVLineGraph.
-func newHVLineGraph() *hVLineGraph {
- return &hVLineGraph{
- nodes: make(map[image.Point]*hVLineNode),
- }
-}
-
-// getOrCreateNode gets an existing or creates a new node for the point.
-func (g *hVLineGraph) getOrCreateNode(p image.Point) *hVLineNode {
- if n, ok := g.nodes[p]; ok {
- return n
- }
- n := newHVLineNode(p)
- g.nodes[p] = n
- return n
-}
-
-// addLine adds a line to the graph.
-// This adds edges between all the points on the line.
-func (g *hVLineGraph) addLine(line *hVLine) {
- switch {
- case line.horizontal():
- for curX := line.start.X; curX < line.end.X; curX++ {
- from := image.Point{curX, line.start.Y}
- to := image.Point{curX + 1, line.start.Y}
- n1 := g.getOrCreateNode(from)
- n2 := g.getOrCreateNode(to)
- edge := newHVLineEdge(from, to)
- n1.edges[edge] = true
- n2.edges[edge] = true
- }
-
- case line.vertical():
- for curY := line.start.Y; curY < line.end.Y; curY++ {
- from := image.Point{line.start.X, curY}
- to := image.Point{line.start.X, curY + 1}
- n1 := g.getOrCreateNode(from)
- n2 := g.getOrCreateNode(to)
- edge := newHVLineEdge(from, to)
- n1.edges[edge] = true
- n2.edges[edge] = true
- }
- }
-}
-
-// multiEdgeNodes returns all nodes that have more than one edge. These are
-// the nodes where we might need to use different line characters to represent
-// the crossing of multiple lines.
-func (g *hVLineGraph) multiEdgeNodes() []*hVLineNode {
- var nodes []*hVLineNode
- for _, n := range g.nodes {
- if len(n.edges) <= 1 {
- continue
- }
- nodes = append(nodes, n)
- }
- return nodes
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/line_style.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/line_style.go
deleted file mode 100644
index 41f1df4ee..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/line_style.go
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-import (
- "fmt"
-
- "github.com/mum4k/termdash/linestyle"
- "github.com/mum4k/termdash/private/runewidth"
-)
-
-// line_style.go contains the Unicode characters used for drawing lines of
-// different styles.
-
-// lineStyleChars maps the line styles to the corresponding component characters.
-// Source: http://en.wikipedia.org/wiki/Box-drawing_character.
-var lineStyleChars = map[linestyle.LineStyle]map[linePart]rune{
- linestyle.Light: {
- hLine: '─',
- vLine: '│',
- topLeftCorner: '┌',
- topRightCorner: '┐',
- bottomLeftCorner: '└',
- bottomRightCorner: '┘',
- hAndUp: '┴',
- hAndDown: '┬',
- vAndLeft: '┤',
- vAndRight: '├',
- vAndH: '┼',
- },
- linestyle.Double: {
- hLine: '═',
- vLine: '║',
- topLeftCorner: '╔',
- topRightCorner: '╗',
- bottomLeftCorner: '╚',
- bottomRightCorner: '╝',
- hAndUp: '╩',
- hAndDown: '╦',
- vAndLeft: '╣',
- vAndRight: '╠',
- vAndH: '╬',
- },
- linestyle.Round: {
- hLine: '─',
- vLine: '│',
- topLeftCorner: '╭',
- topRightCorner: '╮',
- bottomLeftCorner: '╰',
- bottomRightCorner: '╯',
- hAndUp: '┴',
- hAndDown: '┬',
- vAndLeft: '┤',
- vAndRight: '├',
- vAndH: '┼',
- },
-}
-
-// init verifies that all line parts are half-width runes (occupy only one
-// cell).
-func init() {
- for ls, parts := range lineStyleChars {
- for part, r := range parts {
- if got := runewidth.RuneWidth(r); got > 1 {
- panic(fmt.Errorf("line style %v line part %v is a rune %c with width %v, all parts must be half-width runes (width of one)", ls, part, r, got))
- }
- }
- }
-}
-
-// lineParts returns the line component characters for the provided line style.
-func lineParts(ls linestyle.LineStyle) (map[linePart]rune, error) {
- parts, ok := lineStyleChars[ls]
- if !ok {
- return nil, fmt.Errorf("unsupported line style %d", ls)
- }
- return parts, nil
-}
-
-// linePart identifies individual line parts.
-type linePart int
-
-// String implements fmt.Stringer()
-func (lp linePart) String() string {
- if n, ok := linePartNames[lp]; ok {
- return n
- }
- return "linePartUnknown"
-}
-
-// linePartNames maps linePart values to human readable names.
-var linePartNames = map[linePart]string{
- vLine: "linePartVLine",
- topLeftCorner: "linePartTopLeftCorner",
- topRightCorner: "linePartTopRightCorner",
- bottomLeftCorner: "linePartBottomLeftCorner",
- bottomRightCorner: "linePartBottomRightCorner",
- hAndUp: "linePartHAndUp",
- hAndDown: "linePartHAndDown",
- vAndLeft: "linePartVAndLeft",
- vAndRight: "linePartVAndRight",
- vAndH: "linePartVAndH",
-}
-
-const (
- hLine linePart = iota
- vLine
- topLeftCorner
- topRightCorner
- bottomLeftCorner
- bottomRightCorner
- hAndUp
- hAndDown
- vAndLeft
- vAndRight
- vAndH
-)
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/rectangle.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/rectangle.go
deleted file mode 100644
index cd96ff715..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/rectangle.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// rectangle.go draws a rectangle.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/canvas"
-)
-
-// RectangleOption is used to provide options to the Rectangle function.
-type RectangleOption interface {
- // set sets the provided option.
- set(*rectOptions)
-}
-
-// rectOptions stores the provided options.
-type rectOptions struct {
- cellOpts []cell.Option
- char rune
-}
-
-// rectOption implements RectangleOption.
-type rectOption func(rOpts *rectOptions)
-
-// set implements RectangleOption.set.
-func (ro rectOption) set(rOpts *rectOptions) {
- ro(rOpts)
-}
-
-// RectCellOpts sets options on the cells that create the rectangle.
-func RectCellOpts(opts ...cell.Option) RectangleOption {
- return rectOption(func(rOpts *rectOptions) {
- rOpts.cellOpts = append(rOpts.cellOpts, opts...)
- })
-}
-
-// DefaultRectChar is the default value for the RectChar option.
-const DefaultRectChar = ' '
-
-// RectChar sets the character used in each of the cells of the rectangle.
-func RectChar(c rune) RectangleOption {
- return rectOption(func(rOpts *rectOptions) {
- rOpts.char = c
- })
-}
-
-// Rectangle draws a filled rectangle on the canvas.
-func Rectangle(c *canvas.Canvas, r image.Rectangle, opts ...RectangleOption) error {
- opt := &rectOptions{
- char: DefaultRectChar,
- }
- for _, o := range opts {
- o.set(opt)
- }
-
- if ar := c.Area(); !r.In(ar) {
- return fmt.Errorf("the requested rectangle %v doesn't fit the canvas area %v", r, ar)
- }
-
- if r.Dx() < 1 || r.Dy() < 1 {
- return fmt.Errorf("the rectangle must be at least 1x1 cell, got %v", r)
- }
-
- for col := r.Min.X; col < r.Max.X; col++ {
- for row := r.Min.Y; row < r.Max.Y; row++ {
- cells, err := c.SetCell(image.Point{col, row}, opt.char, opt.cellOpts...)
- if err != nil {
- return err
- }
- if cells != 1 {
- return fmt.Errorf("invalid rectangle character %q, this character occupies %d cells, the implementation only supports half-width runes that occupy exactly one cell", opt.char, cells)
- }
- }
- }
- return nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/text.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/text.go
deleted file mode 100644
index 17c4954a0..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/text.go
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// text.go contains code that prints UTF-8 encoded strings on the canvas.
-
-import (
- "fmt"
- "image"
- "strings"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/canvas"
- "github.com/mum4k/termdash/private/runewidth"
-)
-
-// OverrunMode represents
-type OverrunMode int
-
-// String implements fmt.Stringer()
-func (om OverrunMode) String() string {
- if n, ok := overrunModeNames[om]; ok {
- return n
- }
- return "OverrunModeUnknown"
-}
-
-// overrunModeNames maps OverrunMode values to human readable names.
-var overrunModeNames = map[OverrunMode]string{
- OverrunModeStrict: "OverrunModeStrict",
- OverrunModeTrim: "OverrunModeTrim",
- OverrunModeThreeDot: "OverrunModeThreeDot",
-}
-
-const (
- // OverrunModeStrict verifies that the drawn value fits the canvas and
- // returns an error if it doesn't.
- OverrunModeStrict OverrunMode = iota
-
- // OverrunModeTrim trims the part of the text that doesn't fit.
- OverrunModeTrim
-
- // OverrunModeThreeDot trims the text and places the horizontal ellipsis
- // '…' character at the end.
- OverrunModeThreeDot
-)
-
-// TextOption is used to provide options to Text().
-type TextOption interface {
- // set sets the provided option.
- set(*textOptions)
-}
-
-// textOptions stores the provided options.
-type textOptions struct {
- cellOpts []cell.Option
- maxX int
- overrunMode OverrunMode
-}
-
-// textOption implements TextOption.
-type textOption func(*textOptions)
-
-// set implements TextOption.set.
-func (to textOption) set(tOpts *textOptions) {
- to(tOpts)
-}
-
-// TextCellOpts sets options on the cells that contain the text.
-func TextCellOpts(opts ...cell.Option) TextOption {
- return textOption(func(tOpts *textOptions) {
- tOpts.cellOpts = opts
- })
-}
-
-// TextMaxX sets a limit on the X coordinate (column) of the drawn text.
-// The X coordinate of all cells used by the text must be within
-// start.X <= X < TextMaxX.
-// If not provided, the width of the canvas is used as TextMaxX.
-func TextMaxX(x int) TextOption {
- return textOption(func(tOpts *textOptions) {
- tOpts.maxX = x
- })
-}
-
-// TextOverrunMode indicates what to do with text that overruns the TextMaxX()
-// or the width of the canvas if TextMaxX() isn't specified.
-// Defaults to OverrunModeStrict.
-func TextOverrunMode(om OverrunMode) TextOption {
- return textOption(func(tOpts *textOptions) {
- tOpts.overrunMode = om
- })
-}
-
-// TrimText trims the provided text so that it fits the specified amount of cells.
-func TrimText(text string, maxCells int, om OverrunMode) (string, error) {
- if maxCells < 1 {
- return "", fmt.Errorf("maxCells(%d) cannot be less than one", maxCells)
- }
-
- textCells := runewidth.StringWidth(text)
- if textCells <= maxCells {
- // Nothing to do if the text fits.
- return text, nil
- }
-
- switch om {
- case OverrunModeStrict:
- return "", fmt.Errorf("the requested text %q takes %d cells to draw, space is available for only %d cells and overrun mode is %v", text, textCells, maxCells, om)
- case OverrunModeTrim, OverrunModeThreeDot:
- default:
- return "", fmt.Errorf("unsupported overrun mode %d", om)
- }
-
- var b strings.Builder
- cur := 0
- for _, r := range text {
- rw := runewidth.RuneWidth(r)
- if cur+rw >= maxCells {
- switch {
- case om == OverrunModeTrim:
- // Only write the rune if it still fits, i.e. don't cut
- // full-width runes in half.
- if cur+rw == maxCells {
- b.WriteRune(r)
- }
- case om == OverrunModeThreeDot:
- b.WriteRune('…')
- }
- break
- }
-
- b.WriteRune(r)
- cur += rw
- }
- return b.String(), nil
-}
-
-// Text prints the provided text on the canvas starting at the provided point.
-func Text(c *canvas.Canvas, text string, start image.Point, opts ...TextOption) error {
- ar := c.Area()
- if !start.In(ar) {
- return fmt.Errorf("the requested start point %v falls outside of the provided canvas %v", start, ar)
- }
-
- opt := &textOptions{}
- for _, o := range opts {
- o.set(opt)
- }
-
- if opt.maxX < 0 || opt.maxX > ar.Max.X {
- return fmt.Errorf("invalid TextMaxX(%v), must be a positive number that is <= canvas.width %v", opt.maxX, ar.Dx())
- }
-
- var wantMaxX int
- if opt.maxX == 0 {
- wantMaxX = ar.Max.X
- } else {
- wantMaxX = opt.maxX
- }
-
- maxCells := wantMaxX - start.X
- trimmed, err := TrimText(text, maxCells, opt.overrunMode)
- if err != nil {
- return err
- }
-
- cur := start
- for _, r := range trimmed {
- cells, err := c.SetCell(cur, r, opt.cellOpts...)
- if err != nil {
- return err
- }
- cur = image.Point{cur.X + cells, cur.Y}
- }
- return nil
-}
-
-// ResizeNeeded draws an unicode character indicating that the canvas size is
-// too small to draw meaningful content.
-func ResizeNeeded(cvs *canvas.Canvas) error {
- return Text(cvs, "⇄", image.Point{0, 0})
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/vertical_text.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/vertical_text.go
deleted file mode 100644
index 44aadc9e5..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/draw/vertical_text.go
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package draw
-
-// vertical_text.go contains code that prints UTF-8 encoded strings on the
-// canvas in vertical columns instead of lines.
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/canvas"
-)
-
-// VerticalTextOption is used to provide options to Text().
-type VerticalTextOption interface {
- // set sets the provided option.
- set(*verticalTextOptions)
-}
-
-// verticalTextOptions stores the provided options.
-type verticalTextOptions struct {
- cellOpts []cell.Option
- maxY int
- overrunMode OverrunMode
-}
-
-// verticalTextOption implements VerticalTextOption.
-type verticalTextOption func(*verticalTextOptions)
-
-// set implements VerticalTextOption.set.
-func (vto verticalTextOption) set(vtOpts *verticalTextOptions) {
- vto(vtOpts)
-}
-
-// VerticalTextCellOpts sets options on the cells that contain the text.
-func VerticalTextCellOpts(opts ...cell.Option) VerticalTextOption {
- return verticalTextOption(func(vtOpts *verticalTextOptions) {
- vtOpts.cellOpts = opts
- })
-}
-
-// VerticalTextMaxY sets a limit on the Y coordinate (row) of the drawn text.
-// The Y coordinate of all cells used by the vertical text must be within
-// start.Y <= Y < VerticalTextMaxY.
-// If not provided, the height of the canvas is used as VerticalTextMaxY.
-func VerticalTextMaxY(y int) VerticalTextOption {
- return verticalTextOption(func(vtOpts *verticalTextOptions) {
- vtOpts.maxY = y
- })
-}
-
-// VerticalTextOverrunMode indicates what to do with text that overruns the
-// VerticalTextMaxY() or the width of the canvas if VerticalTextMaxY() isn't
-// specified.
-// Defaults to OverrunModeStrict.
-func VerticalTextOverrunMode(om OverrunMode) VerticalTextOption {
- return verticalTextOption(func(vtOpts *verticalTextOptions) {
- vtOpts.overrunMode = om
- })
-}
-
-// VerticalText prints the provided text on the canvas starting at the provided point.
-// The text is printed in a vertical orientation, i.e:
-// H
-// e
-// l
-// l
-// o
-func VerticalText(c *canvas.Canvas, text string, start image.Point, opts ...VerticalTextOption) error {
- ar := c.Area()
- if !start.In(ar) {
- return fmt.Errorf("the requested start point %v falls outside of the provided canvas %v", start, ar)
- }
-
- opt := &verticalTextOptions{}
- for _, o := range opts {
- o.set(opt)
- }
-
- if opt.maxY < 0 || opt.maxY > ar.Max.Y {
- return fmt.Errorf("invalid VerticalTextMaxY(%v), must be a positive number that is <= canvas.width %v", opt.maxY, ar.Dy())
- }
-
- var wantMaxY int
- if opt.maxY == 0 {
- wantMaxY = ar.Max.Y
- } else {
- wantMaxY = opt.maxY
- }
-
- maxCells := wantMaxY - start.Y
- trimmed, err := TrimText(text, maxCells, opt.overrunMode)
- if err != nil {
- return err
- }
-
- cur := start
- for _, r := range trimmed {
- cells, err := c.SetCell(cur, r, opt.cellOpts...)
- if err != nil {
- return err
- }
- cur = image.Point{cur.X, cur.Y + cells}
- }
- return nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/event/event.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/event/event.go
deleted file mode 100644
index e9ef18dbb..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/event/event.go
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package event provides a non-blocking event distribution and subscription
-// system.
-package event
-
-import (
- "context"
- "reflect"
- "sync"
-
- "github.com/mum4k/termdash/private/event/eventqueue"
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-// Callback is a function provided by an event subscriber.
-// It gets called with each event that passed the subscription filter.
-// Implementations must be thread-safe, events come from a separate goroutine.
-// Implementation should be light-weight, otherwise a slow-processing
-// subscriber can build a long tail of events.
-type Callback func(terminalapi.Event)
-
-// queue is a queue of terminal events.
-type queue interface {
- Push(e terminalapi.Event)
- Pull(ctx context.Context) terminalapi.Event
- Close()
-}
-
-// subscriber represents a single subscriber.
-type subscriber struct {
- // cb is the callback the subscriber receives events on.
- cb Callback
-
- // filter filters events towards the subscriber.
- // An empty filter receives all events.
- filter map[reflect.Type]bool
-
- // queue is a queue of events towards the subscriber.
- queue queue
-
- // cancel when called terminates the goroutine that forwards events towards
- // this subscriber.
- cancel context.CancelFunc
-
- // processes is the number of events that were fully processed, i.e.
- // delivered to the callback.
- processed int
-
- // mu protects busy.
- mu sync.Mutex
-}
-
-// newSubscriber creates a new event subscriber.
-func newSubscriber(filter []terminalapi.Event, cb Callback, opts *subscribeOptions) *subscriber {
- f := map[reflect.Type]bool{}
- for _, ev := range filter {
- f[reflect.TypeOf(ev)] = true
- }
-
- ctx, cancel := context.WithCancel(context.Background())
- var q queue
- if opts.throttle {
- q = eventqueue.NewThrottled(opts.maxRep)
- } else {
- q = eventqueue.New()
- }
-
- s := &subscriber{
- cb: cb,
- filter: f,
- queue: q,
- cancel: cancel,
- }
-
- // Terminates when stop() is called.
- go s.run(ctx)
- return s
-}
-
-// callback sends the event to the callback.
-func (s *subscriber) callback(ev terminalapi.Event) {
- s.cb(ev)
-
- func() {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.processed++
- }()
-}
-
-// run periodically forwards events towards the subscriber.
-// Terminates when the context expires.
-func (s *subscriber) run(ctx context.Context) {
- for {
- ev := s.queue.Pull(ctx)
- if ev != nil {
- s.callback(ev)
- }
-
- select {
- case <-ctx.Done():
- return
- default:
- }
- }
-}
-
-// event forwards an event to the subscriber.
-func (s *subscriber) event(ev terminalapi.Event) {
- if len(s.filter) == 0 {
- s.queue.Push(ev)
- }
-
- t := reflect.TypeOf(ev)
- if s.filter[t] {
- s.queue.Push(ev)
- }
-}
-
-// processedEvents returns the number of events processed by this subscriber.
-func (s *subscriber) processedEvents() int {
- s.mu.Lock()
- defer s.mu.Unlock()
- return s.processed
-}
-
-// stop stops the event subscriber.
-func (s *subscriber) stop() {
- s.cancel()
- s.queue.Close()
-}
-
-// DistributionSystem distributes events to subscribers.
-//
-// Subscribers can request filtering of events they get based on event type or
-// subscribe to all events.
-//
-// The distribution system maintains a queue towards each subscriber, making
-// sure that a single slow subscriber only slows itself down, rather than the
-// entire application.
-//
-// This object is thread-safe.
-type DistributionSystem struct {
- // subscribers subscribe to events.
- // maps subscriber id to subscriber.
- subscribers map[int]*subscriber
-
- // nextID is id for the next subscriber.
- nextID int
-
- // mu protects the distribution system.
- mu sync.Mutex
-}
-
-// NewDistributionSystem creates a new event distribution system.
-func NewDistributionSystem() *DistributionSystem {
- return &DistributionSystem{
- subscribers: map[int]*subscriber{},
- }
-}
-
-// Event should be called with events coming from the terminal.
-// The distribution system will distribute these to all the subscribers.
-func (eds *DistributionSystem) Event(ev terminalapi.Event) {
- eds.mu.Lock()
- defer eds.mu.Unlock()
-
- for _, sub := range eds.subscribers {
- sub.event(ev)
- }
-}
-
-// StopFunc when called unsubscribes the subscriber from all events and
-// releases resources tied to the subscriber.
-type StopFunc func()
-
-// SubscribeOption is used to provide options to Subscribe.
-type SubscribeOption interface {
- // set sets the provided option.
- set(*subscribeOptions)
-}
-
-// subscribeOptions stores the provided options.
-type subscribeOptions struct {
- throttle bool
- maxRep int
-}
-
-// subscribeOption implements Option.
-type subscribeOption func(*subscribeOptions)
-
-// set implements SubscribeOption.set.
-func (o subscribeOption) set(sOpts *subscribeOptions) {
- o(sOpts)
-}
-
-// MaxRepetitive when provided, instructs the system to drop repetitive
-// events instead of delivering them.
-// The argument maxRep indicates the maximum number of repetitive events to
-// enqueue towards the subscriber.
-func MaxRepetitive(maxRep int) SubscribeOption {
- return subscribeOption(func(sOpts *subscribeOptions) {
- sOpts.throttle = true
- sOpts.maxRep = maxRep
- })
-}
-
-// Subscribe subscribes to events according to the filter.
-// An empty filter indicates that the subscriber wishes to receive events of
-// all kinds. If the filter is non-empty, only events of the provided type will
-// be sent to the subscriber.
-// Returns a function that allows the subscriber to unsubscribe.
-func (eds *DistributionSystem) Subscribe(filter []terminalapi.Event, cb Callback, opts ...SubscribeOption) StopFunc {
- eds.mu.Lock()
- defer eds.mu.Unlock()
-
- opt := &subscribeOptions{}
- for _, o := range opts {
- o.set(opt)
- }
-
- id := eds.nextID
- eds.nextID++
- sub := newSubscriber(filter, cb, opt)
- eds.subscribers[id] = sub
-
- return func() {
- eds.mu.Lock()
- defer eds.mu.Unlock()
-
- sub.stop()
- delete(eds.subscribers, id)
- }
-}
-
-// Processed returns the number of events that were fully processed, i.e.
-// delivered to all the subscribers and their callbacks returned.
-func (eds *DistributionSystem) Processed() int {
- eds.mu.Lock()
- defer eds.mu.Unlock()
-
- var res int
- for _, sub := range eds.subscribers {
- res += sub.processedEvents()
- }
- return res
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/event/eventqueue/eventqueue.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/event/eventqueue/eventqueue.go
deleted file mode 100644
index eb22d4f2c..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/event/eventqueue/eventqueue.go
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package eventqueue provides an unboud FIFO queue of events.
-package eventqueue
-
-import (
- "context"
- "reflect"
- "sync"
- "time"
-
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-// node is a single data item on the queue.
-type node struct {
- prev *node
- next *node
- event terminalapi.Event
-}
-
-// Unbound is an unbound FIFO queue of terminal events.
-// Unbound must not be copied, pass it by reference only.
-// This implementation is thread-safe.
-type Unbound struct {
- first *node
- last *node
- // mu protects first and last.
- mu sync.Mutex
-
- // cond is used to notify any callers waiting on a call to Pull().
- cond *sync.Cond
-
- // condMU protects cond.
- condMU sync.RWMutex
-
- // done is closed when the queue isn't needed anymore.
- done chan struct{}
-}
-
-// New returns a new Unbound queue of terminal events.
-// Call Close() when done with the queue.
-func New() *Unbound {
- u := &Unbound{
- done: make(chan (struct{})),
- }
- u.cond = sync.NewCond(&u.condMU)
- go u.wake() // Stops when Close() is called.
- return u
-}
-
-// wake periodically wakes up all goroutines waiting at Pull() so they can
-// check if the context expired.
-func (u *Unbound) wake() {
- const spinTime = 250 * time.Millisecond
- t := time.NewTicker(spinTime)
- defer t.Stop()
- for {
- select {
- case <-t.C:
- u.cond.Broadcast()
- case <-u.done:
- return
- }
- }
-}
-
-// Empty determines if the queue is empty.
-func (u *Unbound) Empty() bool {
- u.mu.Lock()
- defer u.mu.Unlock()
- return u.empty()
-}
-
-// empty determines if the queue is empty.
-func (u *Unbound) empty() bool {
- return u.first == nil
-}
-
-// Push pushes an event onto the queue.
-func (u *Unbound) Push(e terminalapi.Event) {
- u.mu.Lock()
- defer u.mu.Unlock()
- u.push(e)
-}
-
-// push is the implementation of Push.
-// Caller must hold u.mu.
-func (u *Unbound) push(e terminalapi.Event) {
- n := &node{
- event: e,
- }
- if u.empty() {
- u.first = n
- u.last = n
- } else {
- prev := u.last
- u.last.next = n
- u.last = n
- u.last.prev = prev
- }
- u.cond.Signal()
-}
-
-// Pop pops an event from the queue. Returns nil if the queue is empty.
-func (u *Unbound) Pop() terminalapi.Event {
- u.mu.Lock()
- defer u.mu.Unlock()
-
- if u.empty() {
- return nil
- }
-
- n := u.first
- u.first = u.first.next
-
- if u.empty() {
- u.last = nil
- }
- return n.event
-}
-
-// Pull is like Pop(), but blocks until an item is available or the context
-// expires. Returns a nil event if the context expired.
-func (u *Unbound) Pull(ctx context.Context) terminalapi.Event {
- if e := u.Pop(); e != nil {
- return e
- }
-
- u.cond.L.Lock()
- defer u.cond.L.Unlock()
- for {
- select {
- case <-ctx.Done():
- return nil
- default:
- }
-
- if e := u.Pop(); e != nil {
- return e
- }
- u.cond.Wait()
- }
-}
-
-// Close should be called when the queue isn't needed anymore.
-func (u *Unbound) Close() {
- close(u.done)
-}
-
-// Throttled is an unbound and throttled FIFO queue of terminal events.
-// Throttled must not be copied, pass it by reference only.
-// This implementation is thread-safe.
-type Throttled struct {
- queue *Unbound
- max int
-}
-
-// NewThrottled returns a new Throttled queue of terminal events.
-//
-// This queue scans the queue content on each Push call and won't Push the
-// event if there already is a continuous chain of exactly the same events
-// en queued. The argument maxRep specifies the maximum number of repetitive
-// events.
-//
-// Call Close() when done with the queue.
-func NewThrottled(maxRep int) *Throttled {
- t := &Throttled{
- queue: New(),
- max: maxRep,
- }
- return t
-}
-
-// Empty determines if the queue is empty.
-func (t *Throttled) Empty() bool {
- return t.queue.empty()
-}
-
-// Push pushes an event onto the queue.
-func (t *Throttled) Push(e terminalapi.Event) {
- t.queue.mu.Lock()
- defer t.queue.mu.Unlock()
-
- if t.queue.empty() {
- t.queue.push(e)
- return
- }
-
- var same int
- for n := t.queue.last; n != nil; n = n.prev {
- if reflect.DeepEqual(e, n.event) {
- same++
- } else {
- break
- }
-
- if same > t.max {
- return // Drop the repetitive event.
- }
- }
- t.queue.push(e)
-}
-
-// Pop pops an event from the queue. Returns nil if the queue is empty.
-func (t *Throttled) Pop() terminalapi.Event {
- return t.queue.Pop()
-}
-
-// Pull is like Pop(), but blocks until an item is available or the context
-// expires. Returns a nil event if the context expired.
-func (t *Throttled) Pull(ctx context.Context) terminalapi.Event {
- return t.queue.Pull(ctx)
-}
-
-// Close should be called when the queue isn't needed anymore.
-func (t *Throttled) Close() {
- close(t.queue.done)
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/numbers.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/numbers.go
deleted file mode 100644
index e91620f77..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/numbers.go
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package numbers implements various numerical functions.
-package numbers
-
-import (
- "image"
- "math"
-)
-
-// RoundToNonZeroPlaces rounds the float up, so that it has at least the provided
-// number of non-zero decimal places.
-// Returns the rounded float and the number of leading decimal places that
-// are zero. Returns the original float when places is zero. Negative places
-// are treated as positive, so that -2 == 2.
-func RoundToNonZeroPlaces(f float64, places int) (float64, int) {
- if f == 0 {
- return 0, 0
- }
-
- decOnly := zeroBeforeDecimal(f)
- if decOnly == 0 {
- return f, 0
- }
- nzMult := multToNonZero(decOnly)
- if places == 0 {
- return f, multToPlaces(nzMult)
- }
- plMult := placesToMult(places)
-
- m := float64(nzMult * plMult)
- return math.Ceil(f*m) / m, multToPlaces(nzMult)
-}
-
-// multToNonZero returns multiplier for the float, so that the first decimal
-// place is non-zero. The float must not be zero.
-func multToNonZero(f float64) int {
- v := f
- if v < 0 {
- v *= -1
- }
-
- mult := 1
- for v < 0.1 {
- v *= 10
- mult *= 10
- }
- return mult
-}
-
-// placesToMult translates the number of decimal places to a multiple of 10.
-func placesToMult(places int) int {
- if places < 0 {
- places *= -1
- }
-
- mult := 1
- for i := 0; i < places; i++ {
- mult *= 10
- }
- return mult
-}
-
-// multToPlaces translates the multiple of 10 to a number of decimal places.
-func multToPlaces(mult int) int {
- places := 0
- for mult > 1 {
- mult /= 10
- places++
- }
- return places
-}
-
-// zeroBeforeDecimal modifies the float so that it only has zero value before
-// the decimal point.
-func zeroBeforeDecimal(f float64) float64 {
- var sign float64 = 1
- if f < 0 {
- f *= -1
- sign = -1
- }
-
- floor := math.Floor(f)
- return (f - floor) * sign
-}
-
-// MinMax returns the smallest and the largest value among the provided values.
-// Returns (0, 0) if there are no values.
-// Ignores NaN values. Allowing NaN values could lead to a corner case where all
-// values can be NaN, in this case the function will return NaN as min and max.
-func MinMax(values []float64) (min, max float64) {
- if len(values) == 0 {
- return 0, 0
- }
- min = math.MaxFloat64
- max = -1 * math.MaxFloat64
- allNaN := true
- for _, v := range values {
- if math.IsNaN(v) {
- continue
- }
- allNaN = false
-
- if v < min {
- min = v
- }
- if v > max {
- max = v
- }
- }
-
- if allNaN {
- return math.NaN(), math.NaN()
- }
-
- return min, max
-}
-
-// MinMaxInts returns the smallest and the largest int value among the provided
-// values. Returns (0, 0) if there are no values.
-func MinMaxInts(values []int) (min, max int) {
- if len(values) == 0 {
- return 0, 0
- }
- min = math.MaxInt32
- max = -1 * math.MaxInt32
-
- for _, v := range values {
- if v < min {
- min = v
- }
- if v > max {
- max = v
- }
- }
- return min, max
-}
-
-// DegreesToRadians converts degrees to the equivalent in radians.
-func DegreesToRadians(degrees int) float64 {
- if degrees > 360 {
- degrees %= 360
- }
- return (float64(degrees) / 180) * math.Pi
-}
-
-// RadiansToDegrees converts radians to the equivalent in degrees.
-func RadiansToDegrees(radians float64) int {
- d := int(math.Round(radians * 180 / math.Pi))
- if d < 0 {
- d += 360
- }
- return d
-}
-
-// Abs returns the absolute value of x.
-func Abs(x int) int {
- if x < 0 {
- return -x
- }
- return x
-}
-
-// findGCF finds the greatest common factor of two integers.
-func findGCF(a, b int) int {
- if a == 0 || b == 0 {
- return 0
- }
- a = Abs(a)
- b = Abs(b)
-
- // https://en.wikipedia.org/wiki/Euclidean_algorithm
- for {
- rem := a % b
- a = b
- b = rem
-
- if b == 0 {
- break
- }
- }
- return a
-}
-
-// SimplifyRatio simplifies the given ratio.
-func SimplifyRatio(ratio image.Point) image.Point {
- gcf := findGCF(ratio.X, ratio.Y)
- if gcf == 0 {
- return image.ZP
- }
- return image.Point{
- X: ratio.X / gcf,
- Y: ratio.Y / gcf,
- }
-}
-
-// SplitByRatio splits the provided number by the specified ratio.
-func SplitByRatio(n int, ratio image.Point) image.Point {
- sr := SimplifyRatio(ratio)
- if sr.Eq(image.ZP) {
- return image.ZP
- }
- fn := float64(n)
- sum := float64(sr.X + sr.Y)
- fact := fn / sum
- return image.Point{
- int(math.Round(fact * float64(sr.X))),
- int(math.Round(fact * float64(sr.Y))),
- }
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/trig/trig.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/trig/trig.go
deleted file mode 100644
index 16d179d02..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/numbers/trig/trig.go
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package trig implements various trigonometrical calculations.
-package trig
-
-import (
- "fmt"
- "image"
- "math"
- "sort"
-
- "github.com/mum4k/termdash/private/numbers"
-)
-
-// CirclePointAtAngle given an angle in degrees and a circle midpoint and
-// radius, calculates coordinates of a point on the circle at that angle.
-// Angles are zero at the X axis and grow counter-clockwise.
-func CirclePointAtAngle(degrees int, mid image.Point, radius int) image.Point {
- angle := numbers.DegreesToRadians(degrees)
- r := float64(radius)
- x := mid.X + int(math.Round(r*math.Cos(angle)))
- // Y coordinates grow down on the canvas.
- y := mid.Y - int(math.Round(r*math.Sin(angle)))
- return image.Point{x, y}
-}
-
-// CircleAngleAtPoint given a point on a circle and its midpoint,
-// calculates the angle in degrees.
-// Angles are zero at the X axis and grow counter-clockwise.
-func CircleAngleAtPoint(point, mid image.Point) int {
- adj := float64(point.X - mid.X)
- opp := float64(mid.Y - point.Y)
- if opp != 0 {
- angle := math.Atan2(opp, adj)
- return numbers.RadiansToDegrees(angle)
- } else if adj >= 0 {
- return 0
- } else {
- return 180
- }
-}
-
-// PointIsIn asserts whether the provided point is inside of a shape outlined
-// with the provided points.
-// Does not verify that the shape is closed or complete, it merely counts the
-// number of intersections with the shape on one row.
-func PointIsIn(p image.Point, points []image.Point) bool {
- maxX := p.X
- set := map[image.Point]struct{}{}
- for _, sp := range points {
- set[sp] = struct{}{}
- if sp.X > maxX {
- maxX = sp.X
- }
- }
-
- if _, ok := set[p]; ok {
- // Not inside if it is on the shape.
- return false
- }
-
- byY := map[int][]int{} // maps y->x
- for p := range set {
- byY[p.Y] = append(byY[p.Y], p.X)
- }
- for y := range byY {
- sort.Ints(byY[y])
- }
-
- set = map[image.Point]struct{}{}
- for y, xses := range byY {
- set[image.Point{xses[0], y}] = struct{}{}
- if len(xses) == 1 {
- continue
- }
-
- for i := 1; i < len(xses); i++ {
- if xses[i] != xses[i-1]+1 {
- set[image.Point{xses[i], y}] = struct{}{}
- }
- }
- }
-
- crosses := 0
- for x := p.X; x <= maxX; x++ {
- if _, ok := set[image.Point{x, p.Y}]; ok {
- crosses++
- }
- }
- return crosses%2 != 0
-}
-
-const (
- // MinAngle is the smallest valid angle in degrees.
- MinAngle = 0
- // MaxAngle is the largest valid angle in degrees.
- MaxAngle = 360
-)
-
-// angleRange represents a range of angles in degrees.
-// The range includes all angles such that start <= angle <= end.
-type angleRange struct {
- // start is the start if the range.
- // This is always less or equal to the end.
- start int
-
- // end is the end of the range.
- end int
-}
-
-// contains asserts whether the specified angle is in the range.
-func (ar *angleRange) contains(angle int) bool {
- return angle >= ar.start && angle <= ar.end
-}
-
-// normalizeRange normalizes the start and end angles in degrees into ranges of
-// angles. Useful for cases where the 0/360 point falls within the range.
-// E.g:
-// 0,25 => angleRange{0, 26}
-// 0,360 => angleRange{0, 361}
-// 359,20 => angleRange{359, 361}, angleRange{0, 21}
-func normalizeRange(start, end int) ([]*angleRange, error) {
- if start < MinAngle || start > MaxAngle {
- return nil, fmt.Errorf("invalid start angle:%d, must be in range %d <= start <= %d", start, MinAngle, MaxAngle)
- }
- if end < MinAngle || end > MaxAngle {
- return nil, fmt.Errorf("invalid end angle:%d, must be in range %d <= end <= %d", end, MinAngle, MaxAngle)
- }
-
- if start == MaxAngle && end == 0 {
- start, end = end, start
- }
-
- if start <= end {
- return []*angleRange{
- {start, end},
- }, nil
- }
-
- // The range is crossing the 0/360 degree point.
- // Break it into multiple ranges.
- return []*angleRange{
- {start, MaxAngle},
- {0, end},
- }, nil
-}
-
-// RangeSize returns the size of the degree range.
-// E.g:
-// 0,25 => 25
-// 359,1 => 2
-func RangeSize(start, end int) (int, error) {
- ranges, err := normalizeRange(start, end)
- if err != nil {
- return 0, err
- }
- if len(ranges) == 1 {
- return end - start, nil
- }
- return MaxAngle - start + end, nil
-}
-
-// RangeMid returns an angle that lies in the middle between start and end.
-// E.g:
-// 0,10 => 5
-// 350,10 => 0
-func RangeMid(start, end int) (int, error) {
- ranges, err := normalizeRange(start, end)
- if err != nil {
- return 0, err
- }
- if len(ranges) == 1 {
- return start + ((end - start) / 2), nil
- }
-
- length := MaxAngle - start + end
- want := length / 2
- res := start + want
- return res % MaxAngle, nil
-}
-
-// FilterByAngle filters the provided points, returning only those that fall
-// within the starting and the ending angle on a circle with the provided mid
-// point.
-func FilterByAngle(points []image.Point, mid image.Point, start, end int) ([]image.Point, error) {
- var res []image.Point
- ranges, err := normalizeRange(start, end)
- if err != nil {
- return nil, err
- }
- if mid.X < 0 || mid.Y < 0 {
- return nil, fmt.Errorf("the mid point %v cannot have negative coordinates", mid)
- }
-
- for _, p := range points {
- angle := CircleAngleAtPoint(p, mid)
-
- // Edge case, this might mean 0 or 360.
- // Decide based on where we are starting.
- if angle == 0 && start > 0 {
- angle = MaxAngle
- }
-
- for _, r := range ranges {
- if r.contains(angle) {
- res = append(res, p)
- break
- }
- }
- }
- return res, nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/runewidth/runewidth.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/runewidth/runewidth.go
deleted file mode 100644
index 4f2f63a8f..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/runewidth/runewidth.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2019 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package runewidth is a wrapper over github.com/mattn/go-runewidth which
-// gives different treatment to certain runes with ambiguous width.
-package runewidth
-
-import runewidth "github.com/mattn/go-runewidth"
-
-// RuneWidth returns the number of cells needed to draw r.
-// Background in http://www.unicode.org/reports/tr11/.
-//
-// Treats runes used internally by termdash as single-cell (half-width) runes
-// regardless of the locale. I.e. runes that are used to draw lines, boxes,
-// indicate resize or text trimming was needed and runes used by the braille
-// canvas.
-//
-// This should be safe, since even in locales where these runes have ambiguous
-// width, we still place all the character content around them so they should
-// have be half-width.
-func RuneWidth(r rune) int {
- if inTable(r, exceptions) {
- return 1
- }
- return runewidth.RuneWidth(r)
-}
-
-// StringWidth is like RuneWidth, but returns the number of cells occupied by
-// all the runes in the string.
-func StringWidth(s string) int {
- var width int
- for _, r := range []rune(s) {
- width += RuneWidth(r)
- }
- return width
-}
-
-// inTable determines if the rune falls within the table.
-// Copied from github.com/mattn/go-runewidth/blob/master/runewidth.go.
-func inTable(r rune, t table) bool {
- // func (t table) IncludesRune(r rune) bool {
- if r < t[0].first {
- return false
- }
-
- bot := 0
- top := len(t) - 1
- for top >= bot {
- mid := (bot + top) >> 1
-
- switch {
- case t[mid].last < r:
- bot = mid + 1
- case t[mid].first > r:
- top = mid - 1
- default:
- return true
- }
- }
-
- return false
-}
-
-type interval struct {
- first rune
- last rune
-}
-
-type table []interval
-
-// exceptions runes defined here are always considered to be half-width even if
-// they might be ambiguous in some contexts.
-var exceptions = table{
- // Characters used by termdash to indicate text trim or scroll.
- {0x2026, 0x2026},
- {0x21c4, 0x21c4},
- {0x21e7, 0x21e7},
- {0x21e9, 0x21e9},
-
- // Box drawing, used as line-styles.
- // https://en.wikipedia.org/wiki/Box-drawing_character
- {0x2500, 0x257F},
-
- // Block elements used as sparks.
- // https://en.wikipedia.org/wiki/Box-drawing_character
- {0x2580, 0x258F},
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/private/wrap/wrap.go b/examples/go-dashboard/src/github.com/mum4k/termdash/private/wrap/wrap.go
deleted file mode 100644
index 5ee78a7a5..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/private/wrap/wrap.go
+++ /dev/null
@@ -1,409 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package wrap implements line wrapping at character or word boundaries.
-package wrap
-
-import (
- "errors"
- "fmt"
- "strings"
- "unicode"
-
- "github.com/mum4k/termdash/private/canvas/buffer"
- "github.com/mum4k/termdash/private/runewidth"
-)
-
-// Mode sets the wrapping mode.
-type Mode int
-
-// String implements fmt.Stringer()
-func (m Mode) String() string {
- if n, ok := modeNames[m]; ok {
- return n
- }
- return "ModeUnknown"
-}
-
-// modeNames maps Mode values to human readable names.
-var modeNames = map[Mode]string{
- Never: "WrapModeNever",
- AtRunes: "WrapModeAtRunes",
- AtWords: "WrapModeAtWords",
-}
-
-const (
- // Never is the default wrapping mode, which disables line wrapping.
- Never Mode = iota
-
- // AtRunes is a wrapping mode where if the width of the text crosses the
- // width of the canvas, wrapping is performed at rune boundaries.
- AtRunes
-
- // AtWords is a wrapping mode where if the width of the text crosses the
- // width of the canvas, wrapping is performed at word boundaries. The
- // wrapping still switches back to the AtRunes mode for any words that are
- // longer than the width.
- AtWords
-)
-
-// ValidText validates the provided text for wrapping.
-// The text must not be empty, contain any control or
-// space characters other than '\n' and ' '.
-func ValidText(text string) error {
- if text == "" {
- return errors.New("the text cannot be empty")
- }
-
- for _, c := range text {
- if c == ' ' || c == '\n' { // Allowed space and control runes.
- continue
- }
- if unicode.IsControl(c) {
- return fmt.Errorf("the provided text %q cannot contain control characters, found: %q", text, c)
- }
- if unicode.IsSpace(c) {
- return fmt.Errorf("the provided text %q cannot contain space character %q", text, c)
- }
- }
- return nil
-}
-
-// ValidCells validates the provided cells for wrapping.
-// The text in the cells must follow the same rules as described for ValidText.
-func ValidCells(cells []*buffer.Cell) error {
- var b strings.Builder
- for _, c := range cells {
- b.WriteRune(c.Rune)
- }
- return ValidText(b.String())
-}
-
-// Cells returns the cells wrapped into individual lines according to the
-// specified width and wrapping mode.
-//
-// This function consumes any cells that contain newline characters and uses
-// them to start new lines.
-//
-// If the mode is AtWords, this function also drops cells with leading space
-// character before a word at which the wrap occurs.
-func Cells(cells []*buffer.Cell, width int, m Mode) ([][]*buffer.Cell, error) {
- if err := ValidCells(cells); err != nil {
- return nil, err
- }
- switch m {
- case Never:
- case AtRunes:
- case AtWords:
- default:
- return nil, fmt.Errorf("unsupported wrapping mode %v(%d)", m, m)
- }
- if width <= 0 {
- return nil, nil
- }
-
- cs := newCellScanner(cells, width, m)
- for state := scanCellRunes; state != nil; state = state(cs) {
- }
- return cs.lines, nil
-}
-
-// cellScannerState is a state in the FSM that scans the input text and identifies
-// newlines.
-type cellScannerState func(*cellScanner) cellScannerState
-
-// cellScanner tracks the progress of scanning the input cells when finding
-// lines.
-type cellScanner struct {
- // cells are the cells being scanned.
- cells []*buffer.Cell
-
- // nextIdx is the index of the cell that will be returned by next.
- nextIdx int
-
- // wordStartIdx stores the starting index of the current word.
- // A starting position of a word includes any leading space characters.
- // E.g.: hello world
- // ^
- // lastWordIdx
- wordStartIdx int
- // wordEndIdx stores the ending index of the current word.
- // The word consists of all indexes that are
- // wordStartIdx <= idx < wordEndIdx.
- // A word also includes any punctuation after it.
- wordEndIdx int
-
- // width is the width of the canvas the text will be drawn on.
- width int
-
- // posX tracks the horizontal position of the current cell on the canvas.
- posX int
-
- // mode is the wrapping mode.
- mode Mode
-
- // atRunesInWord overrides the mode back to AtRunes.
- atRunesInWord bool
-
- // lines are the identified lines.
- lines [][]*buffer.Cell
-
- // line is the current line.
- line []*buffer.Cell
-}
-
-// newCellScanner returns a scanner of the provided cells.
-func newCellScanner(cells []*buffer.Cell, width int, m Mode) *cellScanner {
- return &cellScanner{
- cells: cells,
- width: width,
- mode: m,
- }
-}
-
-// next returns the next cell and advances the scanner.
-// Returns nil when there are no more cells to scan.
-func (cs *cellScanner) next() *buffer.Cell {
- c := cs.peek()
- if c != nil {
- cs.nextIdx++
- }
- return c
-}
-
-// peek returns the next cell without advancing the scanner's position.
-// Returns nil when there are no more cells to peek at.
-func (cs *cellScanner) peek() *buffer.Cell {
- if cs.nextIdx >= len(cs.cells) {
- return nil
- }
- return cs.cells[cs.nextIdx]
-}
-
-// peekPrev returns the previous cell without changing the scanner's position.
-// Returns nil if the scanner is at the first cell.
-func (cs *cellScanner) peekPrev() *buffer.Cell {
- if cs.nextIdx == 0 {
- return nil
- }
- return cs.cells[cs.nextIdx-1]
-}
-
-// wordCells returns all the cells that belong to the current word.
-func (cs *cellScanner) wordCells() []*buffer.Cell {
- return cs.cells[cs.wordStartIdx:cs.wordEndIdx]
-}
-
-// wordWidth returns the width of the current word in cells when printed on the
-// terminal.
-func (cs *cellScanner) wordWidth() int {
- var b strings.Builder
- for _, wc := range cs.wordCells() {
- b.WriteRune(wc.Rune)
- }
- return runewidth.StringWidth(b.String())
-}
-
-// isWordStart determines if the scanner is at the beginning of a word.
-func (cs *cellScanner) isWordStart() bool {
- if cs.mode != AtWords {
- return false
- }
-
- current := cs.peekPrev()
- next := cs.peek()
- if current == nil || next == nil {
- return false
- }
-
- switch nr := next.Rune; {
- case nr == '\n':
- case nr == ' ':
- default:
- return true
- }
- return false
-}
-
-// scanCellRunes scans the cells a rune at a time.
-func scanCellRunes(cs *cellScanner) cellScannerState {
- for {
- cell := cs.next()
- if cell == nil {
- return scanEOF
- }
-
- r := cell.Rune
- if r == '\n' {
- return newLineForLineBreak
- }
-
- if cs.mode == Never {
- return runeToCurrentLine
- }
-
- if cs.atRunesInWord && !isWordCell(cell) {
- cs.atRunesInWord = false
- }
-
- if !cs.atRunesInWord && cs.isWordStart() {
- return markWordStart
- }
-
- if runeWrapNeeded(r, cs.posX, cs.width) {
- return newLineForAtRunes
- }
-
- return runeToCurrentLine
- }
-}
-
-// runeToCurrentLine scans a single cell rune onto the current line.
-func runeToCurrentLine(cs *cellScanner) cellScannerState {
- cell := cs.peekPrev()
- // Move horizontally within the line for each scanned cell.
- cs.posX += runewidth.RuneWidth(cell.Rune)
-
- // Copy the cell into the current line.
- cs.line = append(cs.line, cell)
- return scanCellRunes
-}
-
-// newLineForLineBreak processes a newline character cell.
-func newLineForLineBreak(cs *cellScanner) cellScannerState {
- cs.lines = append(cs.lines, cs.line)
- cs.posX = 0
- cs.line = nil
- return scanCellRunes
-}
-
-// newLineForAtRunes processes a line wrap at rune boundaries due to canvas width.
-func newLineForAtRunes(cs *cellScanner) cellScannerState {
- // The character on which we wrapped will be printed and is the start of
- // new line.
- cs.lines = append(cs.lines, cs.line)
- cs.posX = runewidth.RuneWidth(cs.peekPrev().Rune)
- cs.line = []*buffer.Cell{cs.peekPrev()}
- return scanCellRunes
-}
-
-// scanEOF terminates the scanning.
-func scanEOF(cs *cellScanner) cellScannerState {
- // Need to add the current line if it isn't empty, or if the previous rune
- // was a newline.
- // Newlines aren't copied onto the lines so just checking for emptiness
- // isn't enough. We still want to include trailing empty newlines if
- // they are in the input text.
- if len(cs.line) > 0 || cs.peekPrev().Rune == '\n' {
- cs.lines = append(cs.lines, cs.line)
- }
- return nil
-}
-
-// markWordStart stores the starting position of the current word.
-func markWordStart(cs *cellScanner) cellScannerState {
- cs.wordStartIdx = cs.nextIdx - 1
- cs.wordEndIdx = cs.nextIdx
- return scanWord
-}
-
-// scanWord scans the entire word until it finds its end.
-func scanWord(cs *cellScanner) cellScannerState {
- for {
- if isWordCell(cs.peek()) {
- cs.next()
- cs.wordEndIdx++
- continue
- }
- return wordToCurrentLine
- }
-}
-
-// wordToCurrentLine decides how to place the word into the output.
-func wordToCurrentLine(cs *cellScanner) cellScannerState {
- wordCells := cs.wordCells()
- wordWidth := cs.wordWidth()
-
- if cs.posX+wordWidth <= cs.width {
- // Place the word onto the current line.
- cs.posX += wordWidth
- cs.line = append(cs.line, wordCells...)
- return scanCellRunes
- }
- return wrapWord
-}
-
-// wrapWord wraps the word onto the next line or lines.
-func wrapWord(cs *cellScanner) cellScannerState {
- // Edge-case - the word starts the line and immediately doesn't fit.
- if cs.posX > 0 {
- cs.lines = append(cs.lines, cs.line)
- cs.posX = 0
- cs.line = nil
- }
-
- for i, wc := range cs.wordCells() {
- if i == 0 && wc.Rune == ' ' {
- // Skip the leading space when word wrapping.
- continue
- }
-
- if !runeWrapNeeded(wc.Rune, cs.posX, cs.width) {
- cs.posX += runewidth.RuneWidth(wc.Rune)
- cs.line = append(cs.line, wc)
- continue
- }
-
- // Replace the last placed rune with a dash indicating we wrapped the
- // word. Only do this for half-width runes.
- lastIdx := len(cs.line) - 1
- last := cs.line[lastIdx]
- lastRW := runewidth.RuneWidth(last.Rune)
- if cs.width > 1 && lastRW == 1 {
- cs.line[lastIdx] = buffer.NewCell('-', last.Opts)
- // Reset the scanner's position back to start scanning at the first
- // rune of this word that wasn't placed.
- cs.nextIdx = cs.wordStartIdx + i - 1
- } else {
- // Edge-case width is one, no space to put the dash rune.
- cs.nextIdx = cs.wordStartIdx + i
- }
- cs.atRunesInWord = true
- return scanCellRunes
- }
-
- cs.nextIdx = cs.wordEndIdx
- return scanCellRunes
-}
-
-// isWordCell determines if the cell contains a rune that belongs to a word.
-func isWordCell(c *buffer.Cell) bool {
- if c == nil {
- return false
- }
- switch r := c.Rune; {
- case r == '\n':
- case r == ' ':
- default:
- return true
- }
- return false
-}
-
-// runeWrapNeeded returns true if wrapping is needed for the rune at the horizontal
-// position on the canvas that has the specified width.
-func runeWrapNeeded(r rune, posX, width int) bool {
- rw := runewidth.RuneWidth(r)
- return posX > width-rw
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/termdash.go b/examples/go-dashboard/src/github.com/mum4k/termdash/termdash.go
deleted file mode 100644
index 8103ee717..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/termdash.go
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-/*
-Package termdash implements a terminal based dashboard.
-
-While running, the terminal dashboard performs the following:
- - Periodic redrawing of the canvas and all the widgets.
- - Event based redrawing of the widgets (i.e. on Keyboard or Mouse events).
- - Forwards input events to widgets and optional subscribers.
- - Handles terminal resize events.
-*/
-package termdash
-
-import (
- "context"
- "errors"
- "fmt"
- "sync"
- "time"
-
- "github.com/mum4k/termdash/container"
- "github.com/mum4k/termdash/private/event"
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-// DefaultRedrawInterval is the default for the RedrawInterval option.
-const DefaultRedrawInterval = 250 * time.Millisecond
-
-// Option is used to provide options.
-type Option interface {
- // set sets the provided option.
- set(td *termdash)
-}
-
-// option implements Option.
-type option func(td *termdash)
-
-// set implements Option.set.
-func (o option) set(td *termdash) {
- o(td)
-}
-
-// RedrawInterval sets how often termdash redraws the container and all the widgets.
-// Defaults to DefaultRedrawInterval. Use the controller to disable the
-// periodic redraw.
-func RedrawInterval(t time.Duration) Option {
- return option(func(td *termdash) {
- td.redrawInterval = t
- })
-}
-
-// ErrorHandler is used to provide a function that will be called with all
-// errors that occur while the dashboard is running. If not provided, any
-// errors panic the application.
-// The provided function must be thread-safe.
-func ErrorHandler(f func(error)) Option {
- return option(func(td *termdash) {
- td.errorHandler = f
- })
-}
-
-// KeyboardSubscriber registers a subscriber for Keyboard events. Each
-// keyboard event is forwarded to the container and the registered subscriber.
-// The provided function must be thread-safe.
-func KeyboardSubscriber(f func(*terminalapi.Keyboard)) Option {
- return option(func(td *termdash) {
- td.keyboardSubscriber = f
- })
-}
-
-// MouseSubscriber registers a subscriber for Mouse events. Each mouse event
-// is forwarded to the container and the registered subscriber.
-// The provided function must be thread-safe.
-func MouseSubscriber(f func(*terminalapi.Mouse)) Option {
- return option(func(td *termdash) {
- td.mouseSubscriber = f
- })
-}
-
-// withEDS indicates that termdash should run with the provided event
-// distribution system instead of creating one.
-// Useful for tests.
-func withEDS(eds *event.DistributionSystem) Option {
- return option(func(td *termdash) {
- td.eds = eds
- })
-}
-
-// Run runs the terminal dashboard with the provided container on the terminal.
-// Redraws the terminal periodically. If you prefer a manual redraw, use the
-// Controller instead.
-// Blocks until the context expires.
-func Run(ctx context.Context, t terminalapi.Terminal, c *container.Container, opts ...Option) error {
- td := newTermdash(t, c, opts...)
-
- err := td.start(ctx)
- // Only return the status (error or nil) after the termdash event
- // processing goroutine actually exits.
- td.stop()
- return err
-}
-
-// Controller controls a termdash instance.
-// The controller instance is only valid until Close() is called.
-// The controller is not thread-safe.
-type Controller struct {
- td *termdash
- cancel context.CancelFunc
-}
-
-// NewController initializes termdash and returns an instance of the controller.
-// Periodic redrawing is disabled when using the controller, the RedrawInterval
-// option is ignored.
-// Close the controller when it isn't needed anymore.
-func NewController(t terminalapi.Terminal, c *container.Container, opts ...Option) (*Controller, error) {
- ctx, cancel := context.WithCancel(context.Background())
- ctrl := &Controller{
- td: newTermdash(t, c, opts...),
- cancel: cancel,
- }
-
- // stops when Close() is called.
- go ctrl.td.processEvents(ctx)
- if err := ctrl.td.periodicRedraw(); err != nil {
- return nil, err
- }
- return ctrl, nil
-}
-
-// Redraw triggers redraw of the terminal.
-func (c *Controller) Redraw() error {
- if c.td == nil {
- return errors.New("the termdash instance is no longer running, this controller is now invalid")
- }
-
- c.td.mu.Lock()
- defer c.td.mu.Unlock()
- return c.td.redraw()
-}
-
-// Close closes the Controller and its termdash instance.
-func (c *Controller) Close() {
- c.cancel()
- c.td.stop()
- c.td = nil
-}
-
-// termdash is a terminal based dashboard.
-// This object is thread-safe.
-type termdash struct {
- // term is the terminal the dashboard runs on.
- term terminalapi.Terminal
-
- // container maintains terminal splits and places widgets.
- container *container.Container
-
- // eds distributes input events to subscribers.
- eds *event.DistributionSystem
-
- // closeCh gets closed when Stop() is called, which tells the event
- // collecting goroutine to exit.
- closeCh chan struct{}
- // exitCh gets closed when the event collecting goroutine actually exits.
- exitCh chan struct{}
-
- // clearNeeded indicates if the terminal needs to be cleared next time
- // we're drawing it. Terminal needs to be cleared if its sized changed.
- clearNeeded bool
-
- // mu protects termdash.
- mu sync.Mutex
-
- // Options.
- redrawInterval time.Duration
- errorHandler func(error)
- mouseSubscriber func(*terminalapi.Mouse)
- keyboardSubscriber func(*terminalapi.Keyboard)
-}
-
-// newTermdash creates a new termdash.
-func newTermdash(t terminalapi.Terminal, c *container.Container, opts ...Option) *termdash {
- td := &termdash{
- term: t,
- container: c,
- eds: event.NewDistributionSystem(),
- closeCh: make(chan struct{}),
- exitCh: make(chan struct{}),
- redrawInterval: DefaultRedrawInterval,
- }
-
- for _, opt := range opts {
- opt.set(td)
- }
- td.subscribers()
- c.Subscribe(td.eds)
- return td
-}
-
-// subscribers subscribes event receivers that live in this package to EDS.
-func (td *termdash) subscribers() {
- // Handler for all errors that occur during input event processing.
- td.eds.Subscribe([]terminalapi.Event{terminalapi.NewError("")}, func(ev terminalapi.Event) {
- td.handleError(ev.(*terminalapi.Error).Error())
- })
-
- // Handles terminal resize events.
- td.eds.Subscribe([]terminalapi.Event{&terminalapi.Resize{}}, func(terminalapi.Event) {
- td.setClearNeeded()
- })
-
- // Redraws the screen on Keyboard and Mouse events.
- // These events very likely change the content of the widgets (e.g. zooming
- // a LineChart) so a redraw is needed to make that visible.
- td.eds.Subscribe([]terminalapi.Event{
- &terminalapi.Keyboard{},
- &terminalapi.Mouse{},
- }, func(terminalapi.Event) {
- td.evRedraw()
- }, event.MaxRepetitive(0)) // No repetitive events that cause terminal redraw.
-
- // Keyboard and Mouse subscribers specified via options.
- if td.keyboardSubscriber != nil {
- td.eds.Subscribe([]terminalapi.Event{&terminalapi.Keyboard{}}, func(ev terminalapi.Event) {
- td.keyboardSubscriber(ev.(*terminalapi.Keyboard))
- })
- }
- if td.mouseSubscriber != nil {
- td.eds.Subscribe([]terminalapi.Event{&terminalapi.Mouse{}}, func(ev terminalapi.Event) {
- td.mouseSubscriber(ev.(*terminalapi.Mouse))
- })
- }
-}
-
-// handleError forwards the error to the error handler if one was
-// provided or panics.
-func (td *termdash) handleError(err error) {
- if td.errorHandler != nil {
- td.errorHandler(err)
- } else {
- panic(err)
- }
-}
-
-// setClearNeeded flags that the terminal needs to be cleared next time we're
-// drawing it.
-func (td *termdash) setClearNeeded() {
- td.mu.Lock()
- defer td.mu.Unlock()
- td.clearNeeded = true
-}
-
-// redraw redraws the container and its widgets.
-// The caller must hold td.mu.
-func (td *termdash) redraw() error {
- if td.clearNeeded {
- if err := td.term.Clear(); err != nil {
- return fmt.Errorf("term.Clear => error: %v", err)
- }
- td.clearNeeded = false
- }
-
- if err := td.container.Draw(); err != nil {
- return fmt.Errorf("container.Draw => error: %v", err)
- }
-
- if err := td.term.Flush(); err != nil {
- return fmt.Errorf("term.Flush => error: %v", err)
- }
- return nil
-}
-
-// evRedraw redraws the container and its widgets.
-func (td *termdash) evRedraw() error {
- td.mu.Lock()
- defer td.mu.Unlock()
-
- // Don't redraw immediately, give widgets that are performing enough time
- // to update.
- // We don't want to actually synchronize until all widgets update, we are
- // purposefully leaving slow widgets behind.
- time.Sleep(25 * time.Millisecond)
- return td.redraw()
-}
-
-// periodicRedraw is called once each RedrawInterval.
-func (td *termdash) periodicRedraw() error {
- td.mu.Lock()
- defer td.mu.Unlock()
- return td.redraw()
-}
-
-// processEvents processes terminal input events.
-// This is the body of the event collecting goroutine.
-func (td *termdash) processEvents(ctx context.Context) {
- defer close(td.exitCh)
-
- for {
- ev := td.term.Event(ctx)
- if ev != nil {
- td.eds.Event(ev)
- }
-
- select {
- case <-ctx.Done():
- return
- default:
- }
- }
-}
-
-// start starts the terminal dashboard. Blocks until the context expires or
-// until stop() is called.
-func (td *termdash) start(ctx context.Context) error {
- // Redraw once to initialize the container sizes.
- if err := td.periodicRedraw(); err != nil {
- close(td.exitCh)
- return err
- }
-
- redrawTimer := time.NewTicker(td.redrawInterval)
- defer redrawTimer.Stop()
-
- ctx, cancel := context.WithCancel(ctx)
- defer cancel()
-
- // stops when stop() is called or the context expires.
- go td.processEvents(ctx)
-
- for {
- select {
- case <-redrawTimer.C:
- if err := td.periodicRedraw(); err != nil {
- return err
- }
-
- case <-ctx.Done():
- return nil
-
- case <-td.closeCh:
- return nil
- }
- }
-}
-
-// stop tells the event collecting goroutine to stop.
-// Blocks until it exits.
-func (td *termdash) stop() {
- close(td.closeCh)
- <-td.exitCh
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/cell_options.go b/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/cell_options.go
deleted file mode 100644
index 41ee76013..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/cell_options.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package termbox
-
-// cell_options.go converts termdash cell options to the termbox format.
-
-import (
- "github.com/mum4k/termdash/cell"
- tbx "github.com/nsf/termbox-go"
-)
-
-// cellColor converts termdash cell color to the termbox format.
-func cellColor(c cell.Color) tbx.Attribute {
- return tbx.Attribute(c)
-}
-
-// cellOptsToFg converts the cell options to the termbox foreground attribute.
-func cellOptsToFg(opts *cell.Options) tbx.Attribute {
- return cellColor(opts.FgColor)
-}
-
-// cellOptsToBg converts the cell options to the termbox background attribute.
-func cellOptsToBg(opts *cell.Options) tbx.Attribute {
- return cellColor(opts.BgColor)
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/color_mode.go b/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/color_mode.go
deleted file mode 100644
index 793f2a966..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/color_mode.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package termbox
-
-import (
- "fmt"
-
- "github.com/mum4k/termdash/terminal/terminalapi"
- tbx "github.com/nsf/termbox-go"
-)
-
-// colorMode converts termdash color modes to the termbox format.
-func colorMode(cm terminalapi.ColorMode) (tbx.OutputMode, error) {
- switch cm {
- case terminalapi.ColorModeNormal:
- return tbx.OutputNormal, nil
- case terminalapi.ColorMode256:
- return tbx.Output256, nil
- case terminalapi.ColorMode216:
- return tbx.Output216, nil
- case terminalapi.ColorModeGrayscale:
- return tbx.OutputGrayscale, nil
- default:
- return -1, fmt.Errorf("don't know how to convert color mode %v to the termbox format", cm)
- }
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/event.go b/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/event.go
deleted file mode 100644
index c26d88c18..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/event.go
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package termbox
-
-// event.go converts termbox events to the termdash format.
-
-import (
- "image"
-
- "github.com/mum4k/termdash/keyboard"
- "github.com/mum4k/termdash/mouse"
- "github.com/mum4k/termdash/terminal/terminalapi"
- tbx "github.com/nsf/termbox-go"
-)
-
-// tbxToTd maps termbox key values to the termdash format.
-var tbxToTd = map[tbx.Key]keyboard.Key{
- tbx.KeySpace: keyboard.KeySpace,
- tbx.KeyF1: keyboard.KeyF1,
- tbx.KeyF2: keyboard.KeyF2,
- tbx.KeyF3: keyboard.KeyF3,
- tbx.KeyF4: keyboard.KeyF4,
- tbx.KeyF5: keyboard.KeyF5,
- tbx.KeyF6: keyboard.KeyF6,
- tbx.KeyF7: keyboard.KeyF7,
- tbx.KeyF8: keyboard.KeyF8,
- tbx.KeyF9: keyboard.KeyF9,
- tbx.KeyF10: keyboard.KeyF10,
- tbx.KeyF11: keyboard.KeyF11,
- tbx.KeyF12: keyboard.KeyF12,
- tbx.KeyInsert: keyboard.KeyInsert,
- tbx.KeyDelete: keyboard.KeyDelete,
- tbx.KeyHome: keyboard.KeyHome,
- tbx.KeyEnd: keyboard.KeyEnd,
- tbx.KeyPgup: keyboard.KeyPgUp,
- tbx.KeyPgdn: keyboard.KeyPgDn,
- tbx.KeyArrowUp: keyboard.KeyArrowUp,
- tbx.KeyArrowDown: keyboard.KeyArrowDown,
- tbx.KeyArrowLeft: keyboard.KeyArrowLeft,
- tbx.KeyArrowRight: keyboard.KeyArrowRight,
- tbx.KeyCtrlTilde: keyboard.KeyCtrlTilde,
- tbx.KeyCtrlA: keyboard.KeyCtrlA,
- tbx.KeyCtrlB: keyboard.KeyCtrlB,
- tbx.KeyCtrlC: keyboard.KeyCtrlC,
- tbx.KeyCtrlD: keyboard.KeyCtrlD,
- tbx.KeyCtrlE: keyboard.KeyCtrlE,
- tbx.KeyCtrlF: keyboard.KeyCtrlF,
- tbx.KeyCtrlG: keyboard.KeyCtrlG,
- tbx.KeyBackspace: keyboard.KeyBackspace,
- tbx.KeyTab: keyboard.KeyTab,
- tbx.KeyCtrlJ: keyboard.KeyCtrlJ,
- tbx.KeyCtrlK: keyboard.KeyCtrlK,
- tbx.KeyCtrlL: keyboard.KeyCtrlL,
- tbx.KeyEnter: keyboard.KeyEnter,
- tbx.KeyCtrlN: keyboard.KeyCtrlN,
- tbx.KeyCtrlO: keyboard.KeyCtrlO,
- tbx.KeyCtrlP: keyboard.KeyCtrlP,
- tbx.KeyCtrlQ: keyboard.KeyCtrlQ,
- tbx.KeyCtrlR: keyboard.KeyCtrlR,
- tbx.KeyCtrlS: keyboard.KeyCtrlS,
- tbx.KeyCtrlT: keyboard.KeyCtrlT,
- tbx.KeyCtrlU: keyboard.KeyCtrlU,
- tbx.KeyCtrlV: keyboard.KeyCtrlV,
- tbx.KeyCtrlW: keyboard.KeyCtrlW,
- tbx.KeyCtrlX: keyboard.KeyCtrlX,
- tbx.KeyCtrlY: keyboard.KeyCtrlY,
- tbx.KeyCtrlZ: keyboard.KeyCtrlZ,
- tbx.KeyEsc: keyboard.KeyEsc,
- tbx.KeyCtrl4: keyboard.KeyCtrl4,
- tbx.KeyCtrl5: keyboard.KeyCtrl5,
- tbx.KeyCtrl6: keyboard.KeyCtrl6,
- tbx.KeyCtrl7: keyboard.KeyCtrl7,
- tbx.KeyBackspace2: keyboard.KeyBackspace2,
-}
-
-// convKey converts a termbox keyboard event to the termdash format.
-func convKey(tbxEv tbx.Event) terminalapi.Event {
- if tbxEv.Key != 0 && tbxEv.Ch != 0 {
- return terminalapi.NewErrorf("the key event contain both a key(%v) and a character(%v)", tbxEv.Key, tbxEv.Ch)
- }
-
- if tbxEv.Ch != 0 {
- return &terminalapi.Keyboard{
- Key: keyboard.Key(tbxEv.Ch),
- }
- }
-
- k, ok := tbxToTd[tbxEv.Key]
- if !ok {
- return terminalapi.NewErrorf("unknown keyboard key '%v' in a keyboard event", k)
- }
- return &terminalapi.Keyboard{
- Key: k,
- }
-}
-
-// convMouse converts a termbox mouse event to the termdash format.
-func convMouse(tbxEv tbx.Event) terminalapi.Event {
- var button mouse.Button
-
- switch k := tbxEv.Key; k {
- case tbx.MouseLeft:
- button = mouse.ButtonLeft
- case tbx.MouseMiddle:
- button = mouse.ButtonMiddle
- case tbx.MouseRight:
- button = mouse.ButtonRight
- case tbx.MouseRelease:
- button = mouse.ButtonRelease
- case tbx.MouseWheelUp:
- button = mouse.ButtonWheelUp
- case tbx.MouseWheelDown:
- button = mouse.ButtonWheelDown
- default:
- return terminalapi.NewErrorf("unknown mouse key %v in a mouse event", k)
- }
-
- return &terminalapi.Mouse{
- Position: image.Point{tbxEv.MouseX, tbxEv.MouseY},
- Button: button,
- }
-}
-
-// convResize converts a termbox resize event to the termdash format.
-func convResize(tbxEv tbx.Event) terminalapi.Event {
- size := image.Point{tbxEv.Width, tbxEv.Height}
- if size.X < 0 || size.Y < 0 {
- return terminalapi.NewErrorf("terminal resized to negative size: %v", size)
- }
- return &terminalapi.Resize{
- Size: size,
- }
-}
-
-// toTermdashEvents converts a termbox event to the termdash event format.
-func toTermdashEvents(tbxEv tbx.Event) []terminalapi.Event {
- switch t := tbxEv.Type; t {
- case tbx.EventInterrupt:
- return []terminalapi.Event{
- terminalapi.NewError("event type EventInterrupt isn't supported"),
- }
- case tbx.EventRaw:
- return []terminalapi.Event{
- terminalapi.NewError("event type EventRaw isn't supported"),
- }
- case tbx.EventNone:
- return []terminalapi.Event{
- terminalapi.NewError("event type EventNone isn't supported"),
- }
- case tbx.EventError:
- return []terminalapi.Event{
- terminalapi.NewErrorf("input error occurred: %v", tbxEv.Err),
- }
- case tbx.EventResize:
- return []terminalapi.Event{convResize(tbxEv)}
- case tbx.EventMouse:
- return []terminalapi.Event{convMouse(tbxEv)}
- case tbx.EventKey:
- return []terminalapi.Event{
- convKey(tbxEv),
- }
- default:
- return []terminalapi.Event{
- terminalapi.NewErrorf("unknown termbox event type: %v", t),
- }
- }
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/termbox.go b/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/termbox.go
deleted file mode 100644
index 4329e4686..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/termbox/termbox.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package termbox implements terminal using the nsf/termbox-go library.
-package termbox
-
-import (
- "context"
- "image"
-
- "github.com/mum4k/termdash/cell"
- "github.com/mum4k/termdash/private/event/eventqueue"
- "github.com/mum4k/termdash/terminal/terminalapi"
- tbx "github.com/nsf/termbox-go"
-)
-
-// Option is used to provide options.
-type Option interface {
- // set sets the provided option.
- set(*Terminal)
-}
-
-// option implements Option.
-type option func(*Terminal)
-
-// set implements Option.set.
-func (o option) set(t *Terminal) {
- o(t)
-}
-
-// DefaultColorMode is the default value for the ColorMode option.
-const DefaultColorMode = terminalapi.ColorMode256
-
-// ColorMode sets the terminal color mode.
-// Defaults to DefaultColorMode.
-func ColorMode(cm terminalapi.ColorMode) Option {
- return option(func(t *Terminal) {
- t.colorMode = cm
- })
-}
-
-// Terminal provides input and output to a real terminal. Wraps the
-// nsf/termbox-go terminal implementation. This object is not thread-safe.
-// Implements terminalapi.Terminal.
-type Terminal struct {
- // events is a queue of input events.
- events *eventqueue.Unbound
-
- // done gets closed when Close() is called.
- done chan struct{}
-
- // Options.
- colorMode terminalapi.ColorMode
-}
-
-// newTerminal creates the terminal and applies the options.
-func newTerminal(opts ...Option) *Terminal {
- t := &Terminal{
- events: eventqueue.New(),
- done: make(chan struct{}),
- colorMode: DefaultColorMode,
- }
- for _, opt := range opts {
- opt.set(t)
- }
- return t
-}
-
-// New returns a new termbox based Terminal.
-// Call Close() when the terminal isn't required anymore.
-func New(opts ...Option) (*Terminal, error) {
- if err := tbx.Init(); err != nil {
- return nil, err
- }
- tbx.SetInputMode(tbx.InputEsc | tbx.InputMouse)
-
- t := newTerminal(opts...)
- om, err := colorMode(t.colorMode)
- if err != nil {
- return nil, err
- }
- tbx.SetOutputMode(om)
-
- go t.pollEvents() // Stops when Close() is called.
- return t, nil
-}
-
-// Size implements terminalapi.Terminal.Size.
-func (t *Terminal) Size() image.Point {
- w, h := tbx.Size()
- return image.Point{w, h}
-}
-
-// Clear implements terminalapi.Terminal.Clear.
-func (t *Terminal) Clear(opts ...cell.Option) error {
- o := cell.NewOptions(opts...)
- return tbx.Clear(cellOptsToFg(o), cellOptsToBg(o))
-}
-
-// Flush implements terminalapi.Terminal.Flush.
-func (t *Terminal) Flush() error {
- return tbx.Flush()
-}
-
-// SetCursor implements terminalapi.Terminal.SetCursor.
-func (t *Terminal) SetCursor(p image.Point) {
- tbx.SetCursor(p.X, p.Y)
-}
-
-// HideCursor implements terminalapi.Terminal.HideCursor.
-func (t *Terminal) HideCursor() {
- tbx.HideCursor()
-}
-
-// SetCell implements terminalapi.Terminal.SetCell.
-func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
- o := cell.NewOptions(opts...)
- tbx.SetCell(p.X, p.Y, r, cellOptsToFg(o), cellOptsToBg(o))
- return nil
-}
-
-// pollEvents polls and enqueues the input events.
-func (t *Terminal) pollEvents() {
- for {
- select {
- case <-t.done:
- return
- default:
- }
-
- events := toTermdashEvents(tbx.PollEvent())
- for _, ev := range events {
- t.events.Push(ev)
- }
- }
-}
-
-// Event implements terminalapi.Terminal.Event.
-func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
- ev := t.events.Pull(ctx)
- if ev == nil {
- return nil
- }
- return ev
-}
-
-// Close closes the terminal, should be called when the terminal isn't required
-// anymore to return the screen to a sane state.
-// Implements terminalapi.Terminal.Close.
-func (t *Terminal) Close() {
- close(t.done)
- tbx.Close()
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/color_mode.go b/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/color_mode.go
deleted file mode 100644
index 28c93277f..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/color_mode.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package terminalapi
-
-// color_mode.go defines the terminal color modes.
-
-// ColorMode represents a color mode of a terminal.
-type ColorMode int
-
-// String implements fmt.Stringer()
-func (cm ColorMode) String() string {
- if n, ok := colorModeNames[cm]; ok {
- return n
- }
- return "ColorModeUnknown"
-}
-
-// colorModeNames maps ColorMode values to human readable names.
-var colorModeNames = map[ColorMode]string{
- ColorModeNormal: "ColorModeNormal",
- ColorMode256: "ColorMode256",
- ColorMode216: "ColorMode216",
- ColorModeGrayscale: "ColorModeGrayscale",
-}
-
-// Supported color modes.
-const (
- // ColorModeNormal supports 8 "system" colors.
- // These are defined as constants in the cell package.
- ColorModeNormal ColorMode = iota
-
- // ColorMode256 enables using any of the 256 terminal colors.
- // 0-7: the 8 "system" colors accessible in ColorModeNormal.
- // 8-15: the 8 "bright system" colors.
- // 16-231: the 216 different terminal colors.
- // 232-255: the 24 different shades of grey.
- ColorMode256
-
- // ColorMode216 supports only the third range of the ColorMode256, i.e the
- // 216 different terminal colors. However in this mode the colors are zero
- // based, so the caller doesn't need to provide an offset.
- ColorMode216
-
- // ColorModeGrayscale supports only the fourth range of the ColorMode256,
- // i.e the 24 different shades of grey. However in this mode the colors are
- // zero based, so the caller doesn't need to provide an offset.
- ColorModeGrayscale
-)
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/event.go b/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/event.go
deleted file mode 100644
index a543e8433..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/event.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package terminalapi
-
-import (
- "errors"
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/keyboard"
- "github.com/mum4k/termdash/mouse"
-)
-
-// event.go defines events that can be received through the terminal API.
-
-// Event represents an input event.
-type Event interface {
- isEvent()
-}
-
-// Keyboard is the event used when a key is pressed.
-// Implements terminalapi.Event.
-type Keyboard struct {
- // Key is the pressed key.
- Key keyboard.Key
-}
-
-func (*Keyboard) isEvent() {}
-
-// String implements fmt.Stringer.
-func (k Keyboard) String() string {
- return fmt.Sprintf("Keyboard{Key: %v}", k.Key)
-}
-
-// Resize is the event used when the terminal was resized.
-// Implements terminalapi.Event.
-type Resize struct {
- // Size is the new size of the terminal.
- Size image.Point
-}
-
-func (*Resize) isEvent() {}
-
-// String implements fmt.Stringer.
-func (r Resize) String() string {
- return fmt.Sprintf("Resize{Size: %v}", r.Size)
-}
-
-// Mouse is the event used when the mouse is moved or a mouse button is
-// pressed.
-// Implements terminalapi.Event.
-type Mouse struct {
- // Position of the mouse on the terminal.
- Position image.Point
- // Button identifies the pressed button if any.
- Button mouse.Button
-}
-
-func (*Mouse) isEvent() {}
-
-// String implements fmt.Stringer.
-func (m Mouse) String() string {
- return fmt.Sprintf("Mouse{Position: %v, Button: %v}", m.Position, m.Button)
-}
-
-// Error is an event indicating an error while processing input.
-type Error string
-
-// NewError returns a new Error event.
-func NewError(e string) *Error {
- err := Error(e)
- return &err
-}
-
-// NewErrorf returns a new Error event, arguments are similar to fmt.Sprintf.
-func NewErrorf(format string, args ...interface{}) *Error {
- err := Error(fmt.Sprintf(format, args...))
- return &err
-}
-
-func (*Error) isEvent() {}
-
-// Error returns the error that occurred.
-func (e *Error) Error() error {
- if e == nil || *e == "" {
- return nil
- }
- return errors.New(string(*e))
-}
-
-// String implements fmt.Stringer.
-func (e Error) String() string {
- return string(e)
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/terminalapi.go b/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/terminalapi.go
deleted file mode 100644
index 831abc169..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/terminal/terminalapi/terminalapi.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package terminalapi defines the API of all terminal implementations.
-package terminalapi
-
-import (
- "context"
- "image"
-
- "github.com/mum4k/termdash/cell"
-)
-
-// Terminal abstracts an implementation of a 2-D terminal.
-// A terminal consists of a number of cells.
-type Terminal interface {
- // Size returns the terminal width and height in cells.
- Size() image.Point
-
- // Clear clears the content of the internal back buffer, resetting all
- // cells to their default content and attributes. Sets the provided options
- // on all the cell.
- Clear(opts ...cell.Option) error
- // Flush flushes the internal back buffer to the terminal.
- Flush() error
-
- // SetCursor sets the position of the cursor.
- SetCursor(p image.Point)
- // HideCursos hides the cursor.
- HideCursor()
-
- // SetCell sets the value of the specified cell to the provided rune.
- // Use the options to specify which attributes to modify, if an attribute
- // option isn't specified, the attribute retains its previous value.
- SetCell(p image.Point, r rune, opts ...cell.Option) error
-
- // Event waits for the next event and returns it.
- // This call blocks until the next event or cancellation of the context.
- // Returns nil when the context gets canceled.
- Event(ctx context.Context) Event
-
- // Close closes the underlying terminal implementation and should be called when
- // the terminal isn't required anymore to return the screen to a sane state.
- Close()
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/widgetapi/widgetapi.go b/examples/go-dashboard/src/github.com/mum4k/termdash/widgetapi/widgetapi.go
deleted file mode 100644
index ee27136a1..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/widgetapi/widgetapi.go
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package widgetapi defines the API of a widget on the dashboard.
-package widgetapi
-
-import (
- "image"
-
- "github.com/mum4k/termdash/private/canvas"
- "github.com/mum4k/termdash/terminal/terminalapi"
-)
-
-// KeyScope indicates the scope at which the widget wants to receive keyboard
-// events.
-type KeyScope int
-
-// String implements fmt.Stringer()
-func (ks KeyScope) String() string {
- if n, ok := keyScopeNames[ks]; ok {
- return n
- }
- return "KeyScopeUnknown"
-}
-
-// keyScopeNames maps KeyScope values to human readable names.
-var keyScopeNames = map[KeyScope]string{
- KeyScopeNone: "KeyScopeNone",
- KeyScopeFocused: "KeyScopeFocused",
- KeyScopeGlobal: "KeyScopeGlobal",
-}
-
-const (
- // KeyScopeNone is used when the widget doesn't want to receive any
- // keyboard events.
- KeyScopeNone KeyScope = iota
-
- // KeyScopeFocused is used when the widget wants to only receive keyboard
- // events when its container is focused.
- KeyScopeFocused
-
- // KeyScopeGlobal is used when the widget wants to receive all keyboard
- // events regardless of which container is focused.
- KeyScopeGlobal
-)
-
-// MouseScope indicates the scope at which the widget wants to receive mouse
-// events.
-type MouseScope int
-
-// String implements fmt.Stringer()
-func (ms MouseScope) String() string {
- if n, ok := mouseScopeNames[ms]; ok {
- return n
- }
- return "MouseScopeUnknown"
-}
-
-// mouseScopeNames maps MouseScope values to human readable names.
-var mouseScopeNames = map[MouseScope]string{
- MouseScopeNone: "MouseScopeNone",
- MouseScopeWidget: "MouseScopeWidget",
- MouseScopeContainer: "MouseScopeContainer",
- MouseScopeGlobal: "MouseScopeGlobal",
-}
-
-const (
- // MouseScopeNone is used when the widget doesn't want to receive any mouse
- // events.
- MouseScopeNone MouseScope = iota
-
- // MouseScopeWidget is used when the widget only wants mouse events that
- // fall onto its canvas.
- // The position of these widgets is always relative to widget's canvas.
- MouseScopeWidget
-
- // MouseScopeContainer is used when the widget only wants mouse events that
- // fall onto its container. The area size of a container is always larger
- // or equal to the one of the widget's canvas. So a widget selecting
- // MouseScopeContainer will either receive the same or larger amount of
- // events as compared to MouseScopeWidget.
- // The position of mouse events that fall outside of widget's canvas is
- // reset to image.Point{-1, -1}.
- // The widgets are allowed to process the button event.
- MouseScopeContainer
-
- // MouseScopeGlobal is used when the widget wants to receive all mouse
- // events regardless on where on the terminal they land.
- // The position of mouse events that fall outside of widget's canvas is
- // reset to image.Point{-1, -1} and must not be used by the widgets.
- // The widgets are allowed to process the button event.
- MouseScopeGlobal
-)
-
-// Options contains registration options for a widget.
-// This is how the widget indicates its needs to the infrastructure.
-type Options struct {
- // Ratio allows a widget to request a canvas whose size will always have
- // the specified ratio of width:height (Ratio.X:Ratio.Y).
- // The zero value i.e. image.Point{0, 0} indicates that the widget accepts
- // canvas of any ratio.
- Ratio image.Point
-
- // MinimumSize allows a widget to specify the smallest allowed canvas size.
- // If the terminal size and/or splits cause the assigned canvas to be
- // smaller than this, the widget will be skipped. I.e. The Draw() method
- // won't be called until a resize above the specified minimum.
- MinimumSize image.Point
-
- // MaximumSize allows a widget to specify the largest allowed canvas size.
- // If the terminal size and/or splits cause the assigned canvas to be larger
- // than this, the widget will only receive a canvas of this size within its
- // container. Setting any of the two coordinates to zero indicates
- // unlimited.
- MaximumSize image.Point
-
- // WantKeyboard allows a widget to request keyboard events and specify
- // their desired scope. If set to KeyScopeNone, no keyboard events are
- // forwarded to the widget.
- WantKeyboard KeyScope
-
- // WantMouse allows a widget to request mouse events and specify their
- // desired scope. If set to MouseScopeNone, no mouse events are forwarded
- // to the widget.
- // Note that the widget is only able to see the position of the mouse event
- // if it falls onto its canvas. See the documentation next to individual
- // MouseScope values for details.
- WantMouse MouseScope
-}
-
-// Meta provide additional metadata to widgets.
-type Meta struct {
- // Focused asserts whether the widget's container is focused.
- Focused bool
-}
-
-// Widget is a single widget on the dashboard.
-// Implementations must be thread safe.
-type Widget interface {
- // When the infrastructure calls Draw(), the widget must block on the call
- // until it finishes drawing onto the provided canvas. When given the
- // canvas, the widget must first determine its size by calling
- // Canvas.Size(), then limit all its drawing to this area.
- //
- // The widget must not assume that the size of the canvas or its content
- // remains the same between calls.
- //
- // The argument meta is guaranteed to be valid (i.e. non-nil).
- Draw(cvs *canvas.Canvas, meta *Meta) error
-
- // Keyboard is called when the widget is focused on the dashboard and a key
- // shortcut the widget registered for was pressed. Only called if the widget
- // registered for keyboard events.
- Keyboard(k *terminalapi.Keyboard) error
-
- // Mouse is called when the widget is focused on the dashboard and a mouse
- // event happens on its canvas. Only called if the widget registered for mouse
- // events.
- Mouse(m *terminalapi.Mouse) error
-
- // Options returns registration options for the widget.
- // This is how the widget indicates to the infrastructure whether it is
- // interested in keyboard or mouse shortcuts, what is its minimum canvas
- // size, etc.
- //
- // Most widgets will return statically compiled options (minimum and
- // maximum size, etc.). If the returned options depend on the runtime state
- // of the widget (e.g. the user data provided to the widget), the widget
- // must protect against a case where the infrastructure calls the Draw
- // method with a canvas that doesn't meet the requested options. This is
- // because the data in the widget might change between calls to Options and
- // Draw.
- Options() Options
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/line_trim.go b/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/line_trim.go
deleted file mode 100644
index 6ca8c83aa..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/line_trim.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package text
-
-import (
- "fmt"
- "image"
-
- "github.com/mum4k/termdash/private/canvas"
- "github.com/mum4k/termdash/private/runewidth"
- "github.com/mum4k/termdash/private/wrap"
-)
-
-// line_trim.go contains code that trims lines that are too long.
-
-type trimResult struct {
- // trimmed is set to true if the current and the following runes on this
- // line are trimmed.
- trimmed bool
-
- // curPoint is the updated current point the drawing should continue on.
- curPoint image.Point
-}
-
-// drawTrimChar draws the horizontal ellipsis '…' character as the last
-// character in the canvas on the specified line.
-func drawTrimChar(cvs *canvas.Canvas, line int) error {
- lastPoint := image.Point{cvs.Area().Dx() - 1, line}
- // If the penultimate cell contains a full-width rune, we need to clear it
- // first. Otherwise the trim char would cover just half of it.
- if width := cvs.Area().Dx(); width > 1 {
- penUlt := image.Point{width - 2, line}
- prev, err := cvs.Cell(penUlt)
- if err != nil {
- return err
- }
-
- if runewidth.RuneWidth(prev.Rune) == 2 {
- if _, err := cvs.SetCell(penUlt, 0); err != nil {
- return err
- }
- }
- }
-
- cells, err := cvs.SetCell(lastPoint, '…')
- if err != nil {
- return err
- }
- if cells != 1 {
- panic(fmt.Errorf("invalid trim character, it occupies %d cells, the implementation only supports scroll markers that occupy exactly one cell", cells))
- }
- return nil
-}
-
-// lineTrim determines if the current line needs to be trimmed. The cvs is the
-// canvas assigned to the widget, the curPoint is the current point the widget
-// is going to place the curRune at. If line trimming is needed, this function
-// replaces the last character with the horizontal ellipsis '…' character.
-func lineTrim(cvs *canvas.Canvas, curPoint image.Point, curRune rune, opts *options) (*trimResult, error) {
- if opts.wrapMode == wrap.AtRunes {
- // Don't trim if the widget is configured to wrap lines.
- return &trimResult{
- trimmed: false,
- curPoint: curPoint,
- }, nil
- }
-
- // Newline characters are never trimmed, they start the next line.
- if curRune == '\n' {
- return &trimResult{
- trimmed: false,
- curPoint: curPoint,
- }, nil
- }
-
- width := cvs.Area().Dx()
- rw := runewidth.RuneWidth(curRune)
- switch {
- case rw == 1:
- if curPoint.X == width {
- if err := drawTrimChar(cvs, curPoint.Y); err != nil {
- return nil, err
- }
- }
-
- case rw == 2:
- if curPoint.X == width || curPoint.X == width-1 {
- if err := drawTrimChar(cvs, curPoint.Y); err != nil {
- return nil, err
- }
- }
-
- default:
- return nil, fmt.Errorf("unable to decide line trimming at position %v for rune %q which has an unsupported width %d", curPoint, curRune, rw)
- }
-
- trimmed := curPoint.X > width-rw
- if trimmed {
- curPoint = image.Point{curPoint.X + rw, curPoint.Y}
- }
- return &trimResult{
- trimmed: trimmed,
- curPoint: curPoint,
- }, nil
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/options.go b/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/options.go
deleted file mode 100644
index b91cec85e..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/options.go
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package text
-
-import (
- "fmt"
-
- "github.com/mum4k/termdash/keyboard"
- "github.com/mum4k/termdash/mouse"
- "github.com/mum4k/termdash/private/wrap"
-)
-
-// options.go contains configurable options for Text.
-
-// Option is used to provide options to New().
-type Option interface {
- // set sets the provided option.
- set(*options)
-}
-
-// options stores the provided options.
-type options struct {
- wrapMode wrap.Mode
- rollContent bool
- disableScrolling bool
- mouseUpButton mouse.Button
- mouseDownButton mouse.Button
- keyUp keyboard.Key
- keyDown keyboard.Key
- keyPgUp keyboard.Key
- keyPgDown keyboard.Key
-}
-
-// newOptions returns a new options instance.
-func newOptions(opts ...Option) *options {
- opt := &options{
- mouseUpButton: DefaultScrollMouseButtonUp,
- mouseDownButton: DefaultScrollMouseButtonDown,
- keyUp: DefaultScrollKeyUp,
- keyDown: DefaultScrollKeyDown,
- keyPgUp: DefaultScrollKeyPageUp,
- keyPgDown: DefaultScrollKeyPageDown,
- }
- for _, o := range opts {
- o.set(opt)
- }
- return opt
-}
-
-// validate validates the provided options.
-func (o *options) validate() error {
- keys := map[keyboard.Key]bool{
- o.keyUp: true,
- o.keyDown: true,
- o.keyPgUp: true,
- o.keyPgDown: true,
- }
- if len(keys) != 4 {
- return fmt.Errorf("invalid ScrollKeys(up:%v, down:%v, pageUp:%v, pageDown:%v), the keys must be unique", o.keyUp, o.keyDown, o.keyPgUp, o.keyPgDown)
- }
- if o.mouseUpButton == o.mouseDownButton {
- return fmt.Errorf("invalid ScrollMouseButtons(up:%v, down:%v), the buttons must be unique", o.mouseUpButton, o.mouseDownButton)
- }
- return nil
-}
-
-// option implements Option.
-type option func(*options)
-
-// set implements Option.set.
-func (o option) set(opts *options) {
- o(opts)
-}
-
-// WrapAtWords configures the text widget so that it automatically wraps lines
-// that are longer than the width of the widget at word boundaries. If not
-// provided, long lines are trimmed instead.
-func WrapAtWords() Option {
- return option(func(opts *options) {
- opts.wrapMode = wrap.AtWords
- })
-}
-
-// WrapAtRunes configures the text widget so that it automatically wraps lines
-// that are longer than the width of the widget at rune boundaries. If not
-// provided, long lines are trimmed instead.
-func WrapAtRunes() Option {
- return option(func(opts *options) {
- opts.wrapMode = wrap.AtRunes
- })
-}
-
-// RollContent configures the text widget so that it rolls the text content up
-// if more text than the size of the container is added. If not provided, the
-// content is trimmed instead.
-func RollContent() Option {
- return option(func(opts *options) {
- opts.rollContent = true
- })
-}
-
-// DisableScrolling disables the scrolling of the content using keyboard and
-// mouse.
-func DisableScrolling() Option {
- return option(func(opts *options) {
- opts.disableScrolling = true
- })
-}
-
-// The default mouse buttons for content scrolling.
-const (
- DefaultScrollMouseButtonUp = mouse.ButtonWheelUp
- DefaultScrollMouseButtonDown = mouse.ButtonWheelDown
-)
-
-// ScrollMouseButtons configures the mouse buttons that scroll the content.
-// The provided buttons must be unique, e.g. the same button cannot be both up
-// and down.
-func ScrollMouseButtons(up, down mouse.Button) Option {
- return option(func(opts *options) {
- opts.mouseUpButton = up
- opts.mouseDownButton = down
- })
-}
-
-// The default keys for content scrolling.
-const (
- DefaultScrollKeyUp = keyboard.KeyArrowUp
- DefaultScrollKeyDown = keyboard.KeyArrowDown
- DefaultScrollKeyPageUp = keyboard.KeyPgUp
- DefaultScrollKeyPageDown = keyboard.KeyPgDn
-)
-
-// ScrollKeys configures the keyboard keys that scroll the content.
-// The provided keys must be unique, e.g. the same key cannot be both up and
-// down.
-func ScrollKeys(up, down, pageUp, pageDown keyboard.Key) Option {
- return option(func(opts *options) {
- opts.keyUp = up
- opts.keyDown = down
- opts.keyPgUp = pageUp
- opts.keyPgDown = pageDown
- })
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/scroll.go b/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/scroll.go
deleted file mode 100644
index f63092fdb..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/scroll.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package text
-
-// scroll.go contains code that tracks the current scrolling position.
-
-import "math"
-
-// scrollTracker tracks the current scrolling position for the Text widget.
-//
-// The text widget displays the contained text buffer as lines of text that fit
-// the widget's canvas. The main goal of this object is to inform the text
-// widget which should be the first drawn line from the buffer. This depends on
-// two things, the scrolling position based on user inputs and whether the text
-// widget is configured to roll the content up as new text is added by the
-// client.
-//
-// The rolling Vs. scrolling state is tracked in an FSM implemented in this
-// file.
-//
-// The client can scroll the content by either a keyboard or a mouse event. The
-// widget receives these events concurrently with requests to redraw the
-// content, so this objects keeps a track of all the scrolling events that
-// happened since the last redraw and consumes them when calculating which is
-// the first drawn line on the next redraw event.
-//
-// This is not thread safe.
-type scrollTracker struct {
- // scroll stores user requests to scroll up (negative) or down (positive).
- // E.g. -1 means up by one line and 2 means down by two lines.
- scroll int
-
- // scrollPage stores user requests to scroll up (negative) or down
- // (positive) by a page of content. E.g. -1 means up by one page and 2
- // means down by two pages.
- scrollPage int
-
- // first tracks the first line that will be printed.
- first int
-
- // state is the state of the scrolling FSM.
- state rollState
-}
-
-// newScrollTracker returns a new scroll tracker.
-func newScrollTracker(opts *options) *scrollTracker {
- if opts.rollContent {
- return &scrollTracker{state: rollToEnd}
- }
- return &scrollTracker{state: rollingDisabled}
-}
-
-// upOneLine processes a user request to scroll up by one line.
-func (st *scrollTracker) upOneLine() {
- st.scroll--
-}
-
-// downOneLine processes a user request to scroll down by one line.
-func (st *scrollTracker) downOneLine() {
- st.scroll++
-}
-
-// upOnePage processes a user request to scroll up by one page.
-func (st *scrollTracker) upOnePage() {
- st.scrollPage--
-}
-
-// downOnePage processes a user request to scroll down by one page.
-func (st *scrollTracker) downOnePage() {
- st.scrollPage++
-}
-
-// doScroll processes any outstanding scroll requests and calculates the
-// resulting first line.
-func (st *scrollTracker) doScroll(lines, height int) int {
- first := st.first + st.scroll + st.scrollPage*height
- st.scroll = 0
- st.scrollPage = 0
- return normalizeScroll(first, lines, height)
-}
-
-// firstLine returns the number of the first line that should be drawn on a
-// canvas of the specified height if there is the provided number of lines of
-// text.
-func (st *scrollTracker) firstLine(lines, height int) int {
- // Execute the scrolling FSM.
- st.state = st.state(st, lines, height)
- return st.first
-}
-
-// rollState is a state in the scrolling FSM.
-type rollState func(st *scrollTracker, lines, height int) rollState
-
-// rollingDisabled is a state where content rolling was disabled by the
-// configuration of the Text widget.
-func rollingDisabled(st *scrollTracker, lines, height int) rollState {
- st.first = st.doScroll(lines, height)
- return rollingDisabled
-}
-
-// rollToEnd is a state in which the last line of the content is always
-// visible. When new content arrives, it is rolled upwards.
-func rollToEnd(st *scrollTracker, lines, height int) rollState {
- // If the user didn't scroll, just roll the content so that the last line
- // is visible.
- if st.scroll == 0 && st.scrollPage == 0 {
- st.first = normalizeScroll(math.MaxInt32, lines, height)
- return rollToEnd
- }
-
- st.first = st.doScroll(lines, height)
- if lastLineVisible(st.first, lines, height) {
- return rollToEnd
- }
- return rollingPaused
-}
-
-// rollingPaused is a state in which the user scrolled up and made the last
-// line scroll out of the view, so the content rolling is paused.
-func rollingPaused(st *scrollTracker, lines, height int) rollState {
- st.first = st.doScroll(lines, height)
- if lastLineVisible(st.first, lines, height) {
- return rollToEnd
- }
- return rollingPaused
-}
-
-// lastLineVisible returns true if the last text line from within the buffer of
-// the text widget is visible on the canvas when drawing of the text starts
-// from the specified start line, there is the provided total amount of lines
-// and the canvas has the height.
-func lastLineVisible(start, lines, height int) bool {
- return lines-start <= height
-}
-
-// normalizeScroll returns normalized position of the first line that should be
-// drawn when drawing the specified number of lines on a canvas with the
-// provided height.
-func normalizeScroll(first, lines, height int) int {
- if first < 0 || lines <= 0 || height <= 0 {
- return 0
- }
-
- if lines <= height {
- return 0 // Scrolling not necessary if the content fits.
- }
-
- max := lines - height
- if first > max {
- return max
- }
- return first
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/text.go b/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/text.go
deleted file mode 100644
index 0712cbcbe..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/text.go
+++ /dev/null
@@ -1,286 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package text contains a widget that displays textual data.
-package text
-
-import (
- "fmt"
- "image"
- "sync"
-
- "github.com/mum4k/termdash/private/canvas"
- "github.com/mum4k/termdash/private/canvas/buffer"
- "github.com/mum4k/termdash/private/wrap"
- "github.com/mum4k/termdash/terminal/terminalapi"
- "github.com/mum4k/termdash/widgetapi"
-)
-
-// Text displays a block of text.
-//
-// Each line of the text is either trimmed or wrapped according to the provided
-// options. The entire text content is either trimmed or rolled up through the
-// canvas according to the provided options.
-//
-// By default the widget supports scrolling of content with either the keyboard
-// or mouse. See the options for the default keys and mouse buttons.
-//
-// Implements widgetapi.Widget. This object is thread-safe.
-type Text struct {
- // content is the text content that will be displayed in the widget as
- // provided by the caller (i.e. not wrapped or pre-processed).
- content []*buffer.Cell
- // wrapped is the content wrapped to the current width of the canvas.
- wrapped [][]*buffer.Cell
-
- // scroll tracks scrolling the position.
- scroll *scrollTracker
-
- // lastWidth stores the width of the last canvas the widget drew on.
- // Used to determine if the previous line wrapping was invalidated.
- lastWidth int
- // contentChanged indicates if the text content of the widget changed since
- // the last drawing. Used to determine if the previous line wrapping was
- // invalidated.
- contentChanged bool
-
- // mu protects the Text widget.
- mu sync.Mutex
-
- // opts are the provided options.
- opts *options
-}
-
-// New returns a new text widget.
-func New(opts ...Option) (*Text, error) {
- opt := newOptions(opts...)
- if err := opt.validate(); err != nil {
- return nil, err
- }
- return &Text{
- scroll: newScrollTracker(opt),
- opts: opt,
- }, nil
-}
-
-// Reset resets the widget back to empty content.
-func (t *Text) Reset() {
- t.mu.Lock()
- defer t.mu.Unlock()
- t.reset()
-}
-
-// reset implements Reset, caller must hold t.mu.
-func (t *Text) reset() {
- t.content = nil
- t.wrapped = nil
- t.scroll = newScrollTracker(t.opts)
- t.lastWidth = 0
- t.contentChanged = true
-}
-
-// Write writes text for the widget to display. Multiple calls append
-// additional text. The text contain cannot control characters
-// (unicode.IsControl) or space character (unicode.IsSpace) other than:
-// ' ', '\n'
-// Any newline ('\n') characters are interpreted as newlines when displaying
-// the text.
-func (t *Text) Write(text string, wOpts ...WriteOption) error {
- t.mu.Lock()
- defer t.mu.Unlock()
-
- if err := wrap.ValidText(text); err != nil {
- return err
- }
-
- opts := newWriteOptions(wOpts...)
- if opts.replace {
- t.reset()
- }
- for _, r := range text {
- t.content = append(t.content, buffer.NewCell(r, opts.cellOpts))
- }
- t.contentChanged = true
- return nil
-}
-
-// minLinesForMarkers are the minimum amount of lines required on the canvas in
-// order to draw the scroll markers ('⇧' and '⇩').
-const minLinesForMarkers = 3
-
-// drawScrollUp draws the scroll up marker on the first line if there is more
-// text "above" the canvas due to the scrolling position. Returns true if the
-// marker was drawn.
-func (t *Text) drawScrollUp(cvs *canvas.Canvas, cur image.Point, fromLine int) (bool, error) {
- height := cvs.Area().Dy()
- if cur.Y == 0 && height >= minLinesForMarkers && fromLine > 0 {
- cells, err := cvs.SetCell(cur, '⇧')
- if err != nil {
- return false, err
- }
- if cells != 1 {
- panic(fmt.Errorf("invalid scroll up marker, it occupies %d cells, the implementation only supports scroll markers that occupy exactly one cell", cells))
- }
- return true, nil
- }
- return false, nil
-}
-
-// drawScrollDown draws the scroll down marker on the last line if there is
-// more text "below" the canvas due to the scrolling position. Returns true if
-// the marker was drawn.
-func (t *Text) drawScrollDown(cvs *canvas.Canvas, cur image.Point, fromLine int) (bool, error) {
- height := cvs.Area().Dy()
- lines := len(t.wrapped)
- if cur.Y == height-1 && height >= minLinesForMarkers && height < lines-fromLine {
- cells, err := cvs.SetCell(cur, '⇩')
- if err != nil {
- return false, err
- }
- if cells != 1 {
- panic(fmt.Errorf("invalid scroll down marker, it occupies %d cells, the implementation only supports scroll markers that occupy exactly one cell", cells))
- }
- return true, nil
- }
- return false, nil
-}
-
-// draw draws the text context on the canvas starting at the specified line.
-func (t *Text) draw(cvs *canvas.Canvas) error {
- var cur image.Point // Tracks the current drawing position on the canvas.
- height := cvs.Area().Dy()
- fromLine := t.scroll.firstLine(len(t.wrapped), height)
-
- for _, line := range t.wrapped[fromLine:] {
- // Scroll up marker.
- scrlUp, err := t.drawScrollUp(cvs, cur, fromLine)
- if err != nil {
- return err
- }
- if scrlUp {
- cur = image.Point{0, cur.Y + 1} // Move to the next line.
- // Skip one line of text, the marker replaced it.
- continue
- }
-
- // Scroll down marker.
- scrlDown, err := t.drawScrollDown(cvs, cur, fromLine)
- if err != nil {
- return err
- }
- if scrlDown || cur.Y >= height {
- break // Skip all lines falling after (under) the canvas.
- }
-
- for _, cell := range line {
- tr, err := lineTrim(cvs, cur, cell.Rune, t.opts)
- if err != nil {
- return err
- }
- cur = tr.curPoint
- if tr.trimmed {
- break // Skip over any characters trimmed on the current line.
- }
-
- cells, err := cvs.SetCell(cur, cell.Rune, cell.Opts)
- if err != nil {
- return err
- }
- cur = image.Point{cur.X + cells, cur.Y} // Move within the same line.
- }
- cur = image.Point{0, cur.Y + 1} // Move to the next line.
- }
- return nil
-}
-
-// Draw draws the text onto the canvas.
-// Implements widgetapi.Widget.Draw.
-func (t *Text) Draw(cvs *canvas.Canvas, meta *widgetapi.Meta) error {
- t.mu.Lock()
- defer t.mu.Unlock()
-
- width := cvs.Area().Dx()
- if len(t.content) > 0 && (t.contentChanged || t.lastWidth != width) {
- // The previous text preprocessing (line wrapping) is invalidated when
- // new text is added or the width of the canvas changed.
- wr, err := wrap.Cells(t.content, width, t.opts.wrapMode)
- if err != nil {
- return err
- }
- t.wrapped = wr
- }
- t.lastWidth = width
-
- if len(t.wrapped) == 0 {
- return nil // Nothing to draw if there's no text.
- }
-
- if err := t.draw(cvs); err != nil {
- return err
- }
- t.contentChanged = false
- return nil
-}
-
-// Keyboard implements widgetapi.Widget.Keyboard.
-func (t *Text) Keyboard(k *terminalapi.Keyboard) error {
- t.mu.Lock()
- defer t.mu.Unlock()
-
- switch {
- case k.Key == t.opts.keyUp:
- t.scroll.upOneLine()
- case k.Key == t.opts.keyDown:
- t.scroll.downOneLine()
- case k.Key == t.opts.keyPgUp:
- t.scroll.upOnePage()
- case k.Key == t.opts.keyPgDown:
- t.scroll.downOnePage()
- }
- return nil
-}
-
-// Mouse implements widgetapi.Widget.Mouse.
-func (t *Text) Mouse(m *terminalapi.Mouse) error {
- t.mu.Lock()
- defer t.mu.Unlock()
-
- switch b := m.Button; {
- case b == t.opts.mouseUpButton:
- t.scroll.upOneLine()
- case b == t.opts.mouseDownButton:
- t.scroll.downOneLine()
- }
- return nil
-}
-
-// Options of the widget
-func (t *Text) Options() widgetapi.Options {
- var ks widgetapi.KeyScope
- var ms widgetapi.MouseScope
- if t.opts.disableScrolling {
- ks = widgetapi.KeyScopeNone
- ms = widgetapi.MouseScopeNone
- } else {
- ks = widgetapi.KeyScopeFocused
- ms = widgetapi.MouseScopeWidget
- }
-
- return widgetapi.Options{
- // At least one line with at least one full-width rune.
- MinimumSize: image.Point{1, 1},
- WantMouse: ms,
- WantKeyboard: ks,
- }
-}
diff --git a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/write_options.go b/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/write_options.go
deleted file mode 100644
index ddb5c40bc..000000000
--- a/examples/go-dashboard/src/github.com/mum4k/termdash/widgets/text/write_options.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package text
-
-// write_options.go contains options used when writing content to the Text widget.
-
-import (
- "github.com/mum4k/termdash/cell"
-)
-
-// WriteOption is used to provide options to Write().
-type WriteOption interface {
- // set sets the provided option.
- set(*writeOptions)
-}
-
-// writeOptions stores the provided options.
-type writeOptions struct {
- cellOpts *cell.Options
- replace bool
-}
-
-// newWriteOptions returns new writeOptions instance.
-func newWriteOptions(wOpts ...WriteOption) *writeOptions {
- wo := &writeOptions{
- cellOpts: cell.NewOptions(),
- }
- for _, o := range wOpts {
- o.set(wo)
- }
- return wo
-}
-
-// writeOption implements WriteOption.
-type writeOption func(*writeOptions)
-
-// set implements WriteOption.set.
-func (wo writeOption) set(wOpts *writeOptions) {
- wo(wOpts)
-}
-
-// WriteCellOpts sets options on the cells that contain the text.
-func WriteCellOpts(opts ...cell.Option) WriteOption {
- return writeOption(func(wOpts *writeOptions) {
- wOpts.cellOpts = cell.NewOptions(opts...)
- })
-}
-
-// WriteReplace instructs the text widget to replace the entire text content on
-// this write instead of appending.
-func WriteReplace() WriteOption {
- return writeOption(func(wOpts *writeOptions) {
- wOpts.replace = true
- })
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/AUTHORS b/examples/go-dashboard/src/github.com/nsf/termbox-go/AUTHORS
deleted file mode 100644
index fe26fb0fb..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/AUTHORS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Please keep this file sorted.
-
-Georg Reinke <guelfey@googlemail.com>
-nsf <no.smile.face@gmail.com>
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/LICENSE b/examples/go-dashboard/src/github.com/nsf/termbox-go/LICENSE
deleted file mode 100644
index d9bc068ce..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2012 termbox-go authors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/README.md b/examples/go-dashboard/src/github.com/nsf/termbox-go/README.md
deleted file mode 100644
index a54d21878..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/README.md
+++ /dev/null
@@ -1,51 +0,0 @@
-[![GoDoc](https://godoc.org/github.com/nsf/termbox-go?status.svg)](http://godoc.org/github.com/nsf/termbox-go)
-
-## IMPORTANT
-
-This library is somewhat not maintained anymore. But I'm glad that it did what I wanted the most. It moved people away from "ncurses" mindset and these days we see both re-implementations of termbox API in various languages and even possibly better libs with similar API design. If you're looking for a Go lib that provides terminal-based user interface facilities, I've heard that https://github.com/gdamore/tcell is good (never used it myself). Also for more complicated interfaces and/or computer games I recommend you to consider using HTML-based UI. Having said that, termbox still somewhat works. In fact I'm writing this line of text right now in godit (which is a text editor written using termbox-go). So, be aware. Good luck and have a nice day.
-
-## Termbox
-Termbox is a library that provides a minimalistic API which allows the programmer to write text-based user interfaces. The library is crossplatform and has both terminal-based implementations on *nix operating systems and a winapi console based implementation for windows operating systems. The basic idea is an abstraction of the greatest common subset of features available on all major terminals and other terminal-like APIs in a minimalistic fashion. Small API means it is easy to implement, test, maintain and learn it, that's what makes the termbox a distinct library in its area.
-
-### Installation
-Install and update this go package with `go get -u github.com/nsf/termbox-go`
-
-### Examples
-For examples of what can be done take a look at demos in the _demos directory. You can try them with go run: `go run _demos/keyboard.go`
-
-There are also some interesting projects using termbox-go:
- - [godit](https://github.com/nsf/godit) is an emacsish lightweight text editor written using termbox.
- - [gotetris](https://github.com/jjinux/gotetris) is an implementation of Tetris.
- - [sokoban-go](https://github.com/rn2dy/sokoban-go) is an implementation of sokoban game.
- - [hecate](https://github.com/evanmiller/hecate) is a hex editor designed by Satan.
- - [httopd](https://github.com/verdverm/httopd) is top for httpd logs.
- - [mop](https://github.com/mop-tracker/mop) is stock market tracker for hackers.
- - [termui](https://github.com/gizak/termui) is a terminal dashboard.
- - [termdash](https://github.com/mum4k/termdash) is a terminal dashboard.
- - [termloop](https://github.com/JoelOtter/termloop) is a terminal game engine.
- - [xterm-color-chart](https://github.com/kutuluk/xterm-color-chart) is a XTerm 256 color chart.
- - [gocui](https://github.com/jroimartin/gocui) is a minimalist Go library aimed at creating console user interfaces.
- - [dry](https://github.com/moncho/dry) is an interactive cli to manage Docker containers.
- - [pxl](https://github.com/ichinaski/pxl) displays images in the terminal.
- - [snake-game](https://github.com/DyegoCosta/snake-game) is an implementation of the Snake game.
- - [gone](https://github.com/guillaumebreton/gone) is a CLI pomodoro® timer.
- - [Spoof.go](https://github.com/sabey/spoofgo) controllable movement spoofing from the cli
- - [lf](https://github.com/gokcehan/lf) is a terminal file manager
- - [rat](https://github.com/ericfreese/rat) lets you compose shell commands to build terminal applications.
- - [httplab](https://github.com/gchaincl/httplab) An interactive web server.
- - [tetris](https://github.com/MichaelS11/tetris) Go Tetris with AI option
- - [wot](https://github.com/kyu-suke/wot) Wait time during command is completed.
- - [2048-go](https://github.com/1984weed/2048-go) is 2048 in Go
- - [jv](https://github.com/maxzender/jv) helps you view JSON on the command-line.
- - [pinger](https://github.com/hirose31/pinger) helps you to monitor numerous hosts using ICMP ECHO_REQUEST.
- - [vixl44](https://github.com/sebashwa/vixl44) lets you create pixel art inside your terminal using vim movements
- - [zterm](https://github.com/varunrau/zterm) is a typing game inspired by http://zty.pe/
- - [gotypist](https://github.com/pb-/gotypist) is a fun touch-typing tutor following Steve Yegge's method.
- - [cointop](https://github.com/miguelmota/cointop) is an interactive terminal based UI application for tracking cryptocurrencies.
- - [pexpo](https://github.com/nnao45/pexpo) is a terminal sending ping tool written in Go.
- - [jid](https://github.com/simeji/jid) is an interactive JSON drill down tool using filtering queries like jq.
- - [nonograminGo](https://github.com/N0RM4L15T/nonograminGo) is a nonogram(aka. picross) in Go
- - [tower-of-go](https://github.com/kjirou/tower-of-go) is a tiny maze game that runs on the terminal.
-
-### API reference
-[godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/api.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/api.go
deleted file mode 100644
index 3adfdc635..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/api.go
+++ /dev/null
@@ -1,500 +0,0 @@
-// +build !windows
-
-package termbox
-
-import (
- "fmt"
- "os"
- "os/signal"
- "runtime"
- "syscall"
- "time"
-
- "github.com/mattn/go-runewidth"
-)
-
-// public API
-
-// Initializes termbox library. This function should be called before any other functions.
-// After successful initialization, the library must be finalized using 'Close' function.
-//
-// Example usage:
-// err := termbox.Init()
-// if err != nil {
-// panic(err)
-// }
-// defer termbox.Close()
-func Init() error {
- var err error
-
- if runtime.GOOS == "openbsd" || runtime.GOOS == "freebsd" {
- out, err = os.OpenFile("/dev/tty", os.O_RDWR, 0)
- if err != nil {
- return err
- }
- in = int(out.Fd())
- } else {
- out, err = os.OpenFile("/dev/tty", os.O_WRONLY, 0)
- if err != nil {
- return err
- }
- in, err = syscall.Open("/dev/tty", syscall.O_RDONLY, 0)
- if err != nil {
- return err
- }
- }
-
- err = setup_term()
- if err != nil {
- return fmt.Errorf("termbox: error while reading terminfo data: %v", err)
- }
-
- signal.Notify(sigwinch, syscall.SIGWINCH)
- signal.Notify(sigio, syscall.SIGIO)
-
- _, err = fcntl(in, syscall.F_SETFL, syscall.O_ASYNC|syscall.O_NONBLOCK)
- if err != nil {
- return err
- }
- _, err = fcntl(in, syscall.F_SETOWN, syscall.Getpid())
- if runtime.GOOS != "darwin" && err != nil {
- return err
- }
- err = tcgetattr(out.Fd(), &orig_tios)
- if err != nil {
- return err
- }
-
- tios := orig_tios
- tios.Iflag &^= syscall_IGNBRK | syscall_BRKINT | syscall_PARMRK |
- syscall_ISTRIP | syscall_INLCR | syscall_IGNCR |
- syscall_ICRNL | syscall_IXON
- tios.Lflag &^= syscall_ECHO | syscall_ECHONL | syscall_ICANON |
- syscall_ISIG | syscall_IEXTEN
- tios.Cflag &^= syscall_CSIZE | syscall_PARENB
- tios.Cflag |= syscall_CS8
- tios.Cc[syscall_VMIN] = 1
- tios.Cc[syscall_VTIME] = 0
-
- err = tcsetattr(out.Fd(), &tios)
- if err != nil {
- return err
- }
-
- out.WriteString(funcs[t_enter_ca])
- out.WriteString(funcs[t_enter_keypad])
- out.WriteString(funcs[t_hide_cursor])
- out.WriteString(funcs[t_clear_screen])
-
- termw, termh = get_term_size(out.Fd())
- back_buffer.init(termw, termh)
- front_buffer.init(termw, termh)
- back_buffer.clear()
- front_buffer.clear()
-
- go func() {
- buf := make([]byte, 128)
- for {
- select {
- case <-sigio:
- for {
- n, err := syscall.Read(in, buf)
- if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK {
- break
- }
- select {
- case input_comm <- input_event{buf[:n], err}:
- ie := <-input_comm
- buf = ie.data[:128]
- case <-quit:
- return
- }
- }
- case <-quit:
- return
- }
- }
- }()
-
- IsInit = true
- return nil
-}
-
-// Interrupt an in-progress call to PollEvent by causing it to return
-// EventInterrupt. Note that this function will block until the PollEvent
-// function has successfully been interrupted.
-func Interrupt() {
- interrupt_comm <- struct{}{}
-}
-
-// Finalizes termbox library, should be called after successful initialization
-// when termbox's functionality isn't required anymore.
-func Close() {
- quit <- 1
- out.WriteString(funcs[t_show_cursor])
- out.WriteString(funcs[t_sgr0])
- out.WriteString(funcs[t_clear_screen])
- out.WriteString(funcs[t_exit_ca])
- out.WriteString(funcs[t_exit_keypad])
- out.WriteString(funcs[t_exit_mouse])
- tcsetattr(out.Fd(), &orig_tios)
-
- out.Close()
- syscall.Close(in)
-
- // reset the state, so that on next Init() it will work again
- termw = 0
- termh = 0
- input_mode = InputEsc
- out = nil
- in = 0
- lastfg = attr_invalid
- lastbg = attr_invalid
- lastx = coord_invalid
- lasty = coord_invalid
- cursor_x = cursor_hidden
- cursor_y = cursor_hidden
- foreground = ColorDefault
- background = ColorDefault
- IsInit = false
-}
-
-// Synchronizes the internal back buffer with the terminal.
-func Flush() error {
- // invalidate cursor position
- lastx = coord_invalid
- lasty = coord_invalid
-
- update_size_maybe()
-
- for y := 0; y < front_buffer.height; y++ {
- line_offset := y * front_buffer.width
- for x := 0; x < front_buffer.width; {
- cell_offset := line_offset + x
- back := &back_buffer.cells[cell_offset]
- front := &front_buffer.cells[cell_offset]
- if back.Ch < ' ' {
- back.Ch = ' '
- }
- w := runewidth.RuneWidth(back.Ch)
- if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) {
- w = 1
- }
- if *back == *front {
- x += w
- continue
- }
- *front = *back
- send_attr(back.Fg, back.Bg)
-
- if w == 2 && x == front_buffer.width-1 {
- // there's not enough space for 2-cells rune,
- // let's just put a space in there
- send_char(x, y, ' ')
- } else {
- send_char(x, y, back.Ch)
- if w == 2 {
- next := cell_offset + 1
- front_buffer.cells[next] = Cell{
- Ch: 0,
- Fg: back.Fg,
- Bg: back.Bg,
- }
- }
- }
- x += w
- }
- }
- if !is_cursor_hidden(cursor_x, cursor_y) {
- write_cursor(cursor_x, cursor_y)
- }
- return flush()
-}
-
-// Sets the position of the cursor. See also HideCursor().
-func SetCursor(x, y int) {
- if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) {
- outbuf.WriteString(funcs[t_show_cursor])
- }
-
- if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) {
- outbuf.WriteString(funcs[t_hide_cursor])
- }
-
- cursor_x, cursor_y = x, y
- if !is_cursor_hidden(cursor_x, cursor_y) {
- write_cursor(cursor_x, cursor_y)
- }
-}
-
-// The shortcut for SetCursor(-1, -1).
-func HideCursor() {
- SetCursor(cursor_hidden, cursor_hidden)
-}
-
-// Changes cell's parameters in the internal back buffer at the specified
-// position.
-func SetCell(x, y int, ch rune, fg, bg Attribute) {
- if x < 0 || x >= back_buffer.width {
- return
- }
- if y < 0 || y >= back_buffer.height {
- return
- }
-
- back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg}
-}
-
-// Returns a slice into the termbox's back buffer. You can get its dimensions
-// using 'Size' function. The slice remains valid as long as no 'Clear' or
-// 'Flush' function calls were made after call to this function.
-func CellBuffer() []Cell {
- return back_buffer.cells
-}
-
-// After getting a raw event from PollRawEvent function call, you can parse it
-// again into an ordinary one using termbox logic. That is parse an event as
-// termbox would do it. Returned event in addition to usual Event struct fields
-// sets N field to the amount of bytes used within 'data' slice. If the length
-// of 'data' slice is zero or event cannot be parsed for some other reason, the
-// function will return a special event type: EventNone.
-//
-// IMPORTANT: EventNone may contain a non-zero N, which means you should skip
-// these bytes, because termbox cannot recognize them.
-//
-// NOTE: This API is experimental and may change in future.
-func ParseEvent(data []byte) Event {
- event := Event{Type: EventKey}
- status := extract_event(data, &event, false)
- if status != event_extracted {
- return Event{Type: EventNone, N: event.N}
- }
- return event
-}
-
-// Wait for an event and return it. This is a blocking function call. Instead
-// of EventKey and EventMouse it returns EventRaw events. Raw event is written
-// into `data` slice and Event's N field is set to the amount of bytes written.
-// The minimum required length of the 'data' slice is 1. This requirement may
-// vary on different platforms.
-//
-// NOTE: This API is experimental and may change in future.
-func PollRawEvent(data []byte) Event {
- if len(data) == 0 {
- panic("len(data) >= 1 is a requirement")
- }
-
- var event Event
- if extract_raw_event(data, &event) {
- return event
- }
-
- for {
- select {
- case ev := <-input_comm:
- if ev.err != nil {
- return Event{Type: EventError, Err: ev.err}
- }
-
- inbuf = append(inbuf, ev.data...)
- input_comm <- ev
- if extract_raw_event(data, &event) {
- return event
- }
- case <-interrupt_comm:
- event.Type = EventInterrupt
- return event
-
- case <-sigwinch:
- event.Type = EventResize
- event.Width, event.Height = get_term_size(out.Fd())
- return event
- }
- }
-}
-
-// Wait for an event and return it. This is a blocking function call.
-func PollEvent() Event {
- // Constant governing macOS specific behavior. See https://github.com/nsf/termbox-go/issues/132
- // This is an arbitrary delay which hopefully will be enough time for any lagging
- // partial escape sequences to come through.
- const esc_wait_delay = 100 * time.Millisecond
-
- var event Event
- var esc_wait_timer *time.Timer
- var esc_timeout <-chan time.Time
-
- // try to extract event from input buffer, return on success
- event.Type = EventKey
- status := extract_event(inbuf, &event, true)
- if event.N != 0 {
- copy(inbuf, inbuf[event.N:])
- inbuf = inbuf[:len(inbuf)-event.N]
- }
- if status == event_extracted {
- return event
- } else if status == esc_wait {
- esc_wait_timer = time.NewTimer(esc_wait_delay)
- esc_timeout = esc_wait_timer.C
- }
-
- for {
- select {
- case ev := <-input_comm:
- if esc_wait_timer != nil {
- if !esc_wait_timer.Stop() {
- <-esc_wait_timer.C
- }
- esc_wait_timer = nil
- }
-
- if ev.err != nil {
- return Event{Type: EventError, Err: ev.err}
- }
-
- inbuf = append(inbuf, ev.data...)
- input_comm <- ev
- status := extract_event(inbuf, &event, true)
- if event.N != 0 {
- copy(inbuf, inbuf[event.N:])
- inbuf = inbuf[:len(inbuf)-event.N]
- }
- if status == event_extracted {
- return event
- } else if status == esc_wait {
- esc_wait_timer = time.NewTimer(esc_wait_delay)
- esc_timeout = esc_wait_timer.C
- }
- case <-esc_timeout:
- esc_wait_timer = nil
-
- status := extract_event(inbuf, &event, false)
- if event.N != 0 {
- copy(inbuf, inbuf[event.N:])
- inbuf = inbuf[:len(inbuf)-event.N]
- }
- if status == event_extracted {
- return event
- }
- case <-interrupt_comm:
- event.Type = EventInterrupt
- return event
-
- case <-sigwinch:
- event.Type = EventResize
- event.Width, event.Height = get_term_size(out.Fd())
- return event
- }
- }
-}
-
-// Returns the size of the internal back buffer (which is mostly the same as
-// terminal's window size in characters). But it doesn't always match the size
-// of the terminal window, after the terminal size has changed, the internal
-// back buffer will get in sync only after Clear or Flush function calls.
-func Size() (width int, height int) {
- return termw, termh
-}
-
-// Clears the internal back buffer.
-func Clear(fg, bg Attribute) error {
- foreground, background = fg, bg
- err := update_size_maybe()
- back_buffer.clear()
- return err
-}
-
-// Sets termbox input mode. Termbox has two input modes:
-//
-// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match
-// any known sequence. ESC means KeyEsc. This is the default input mode.
-//
-// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match
-// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
-//
-// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
-// enable mouse button press/release and drag events.
-//
-// If 'mode' is InputCurrent, returns the current input mode. See also Input*
-// constants.
-func SetInputMode(mode InputMode) InputMode {
- if mode == InputCurrent {
- return input_mode
- }
- if mode&(InputEsc|InputAlt) == 0 {
- mode |= InputEsc
- }
- if mode&(InputEsc|InputAlt) == InputEsc|InputAlt {
- mode &^= InputAlt
- }
- if mode&InputMouse != 0 {
- out.WriteString(funcs[t_enter_mouse])
- } else {
- out.WriteString(funcs[t_exit_mouse])
- }
-
- input_mode = mode
- return input_mode
-}
-
-// Sets the termbox output mode. Termbox has four output options:
-//
-// 1. OutputNormal => [1..8]
-// This mode provides 8 different colors:
-// black, red, green, yellow, blue, magenta, cyan, white
-// Shortcut: ColorBlack, ColorRed, ...
-// Attributes: AttrBold, AttrUnderline, AttrReverse
-//
-// Example usage:
-// SetCell(x, y, '@', ColorBlack | AttrBold, ColorRed);
-//
-// 2. Output256 => [1..256]
-// In this mode you can leverage the 256 terminal mode:
-// 0x01 - 0x08: the 8 colors as in OutputNormal
-// 0x09 - 0x10: Color* | AttrBold
-// 0x11 - 0xe8: 216 different colors
-// 0xe9 - 0x1ff: 24 different shades of grey
-//
-// Example usage:
-// SetCell(x, y, '@', 184, 240);
-// SetCell(x, y, '@', 0xb8, 0xf0);
-//
-// 3. Output216 => [1..216]
-// This mode supports the 3rd range of the 256 mode only.
-// But you don't need to provide an offset.
-//
-// 4. OutputGrayscale => [1..26]
-// This mode supports the 4th range of the 256 mode
-// and black and white colors from 3th range of the 256 mode
-// But you don't need to provide an offset.
-//
-// In all modes, 0x00 represents the default color.
-//
-// `go run _demos/output.go` to see its impact on your terminal.
-//
-// If 'mode' is OutputCurrent, it returns the current output mode.
-//
-// Note that this may return a different OutputMode than the one requested,
-// as the requested mode may not be available on the target platform.
-func SetOutputMode(mode OutputMode) OutputMode {
- if mode == OutputCurrent {
- return output_mode
- }
-
- output_mode = mode
- return output_mode
-}
-
-// Sync comes handy when something causes desync between termbox's understanding
-// of a terminal buffer and the reality. Such as a third party process. Sync
-// forces a complete resync between the termbox and a terminal, it may not be
-// visually pretty though.
-func Sync() error {
- front_buffer.clear()
- err := send_clear()
- if err != nil {
- return err
- }
-
- return Flush()
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/api_common.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/api_common.go
deleted file mode 100644
index 5ca1371a5..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/api_common.go
+++ /dev/null
@@ -1,187 +0,0 @@
-// termbox is a library for creating cross-platform text-based interfaces
-package termbox
-
-// public API, common OS agnostic part
-
-type (
- InputMode int
- OutputMode int
- EventType uint8
- Modifier uint8
- Key uint16
- Attribute uint16
-)
-
-// This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are
-// valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if
-// 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError.
-type Event struct {
- Type EventType // one of Event* constants
- Mod Modifier // one of Mod* constants or 0
- Key Key // one of Key* constants, invalid if 'Ch' is not 0
- Ch rune // a unicode character
- Width int // width of the screen
- Height int // height of the screen
- Err error // error in case if input failed
- MouseX int // x coord of mouse
- MouseY int // y coord of mouse
- N int // number of bytes written when getting a raw event
-}
-
-// A cell, single conceptual entity on the screen. The screen is basically a 2d
-// array of cells. 'Ch' is a unicode character, 'Fg' and 'Bg' are foreground
-// and background attributes respectively.
-type Cell struct {
- Ch rune
- Fg Attribute
- Bg Attribute
-}
-
-// To know if termbox has been initialized or not
-var (
- IsInit bool = false
-)
-
-// Key constants, see Event.Key field.
-const (
- KeyF1 Key = 0xFFFF - iota
- KeyF2
- KeyF3
- KeyF4
- KeyF5
- KeyF6
- KeyF7
- KeyF8
- KeyF9
- KeyF10
- KeyF11
- KeyF12
- KeyInsert
- KeyDelete
- KeyHome
- KeyEnd
- KeyPgup
- KeyPgdn
- KeyArrowUp
- KeyArrowDown
- KeyArrowLeft
- KeyArrowRight
- key_min // see terminfo
- MouseLeft
- MouseMiddle
- MouseRight
- MouseRelease
- MouseWheelUp
- MouseWheelDown
-)
-
-const (
- KeyCtrlTilde Key = 0x00
- KeyCtrl2 Key = 0x00
- KeyCtrlSpace Key = 0x00
- KeyCtrlA Key = 0x01
- KeyCtrlB Key = 0x02
- KeyCtrlC Key = 0x03
- KeyCtrlD Key = 0x04
- KeyCtrlE Key = 0x05
- KeyCtrlF Key = 0x06
- KeyCtrlG Key = 0x07
- KeyBackspace Key = 0x08
- KeyCtrlH Key = 0x08
- KeyTab Key = 0x09
- KeyCtrlI Key = 0x09
- KeyCtrlJ Key = 0x0A
- KeyCtrlK Key = 0x0B
- KeyCtrlL Key = 0x0C
- KeyEnter Key = 0x0D
- KeyCtrlM Key = 0x0D
- KeyCtrlN Key = 0x0E
- KeyCtrlO Key = 0x0F
- KeyCtrlP Key = 0x10
- KeyCtrlQ Key = 0x11
- KeyCtrlR Key = 0x12
- KeyCtrlS Key = 0x13
- KeyCtrlT Key = 0x14
- KeyCtrlU Key = 0x15
- KeyCtrlV Key = 0x16
- KeyCtrlW Key = 0x17
- KeyCtrlX Key = 0x18
- KeyCtrlY Key = 0x19
- KeyCtrlZ Key = 0x1A
- KeyEsc Key = 0x1B
- KeyCtrlLsqBracket Key = 0x1B
- KeyCtrl3 Key = 0x1B
- KeyCtrl4 Key = 0x1C
- KeyCtrlBackslash Key = 0x1C
- KeyCtrl5 Key = 0x1D
- KeyCtrlRsqBracket Key = 0x1D
- KeyCtrl6 Key = 0x1E
- KeyCtrl7 Key = 0x1F
- KeyCtrlSlash Key = 0x1F
- KeyCtrlUnderscore Key = 0x1F
- KeySpace Key = 0x20
- KeyBackspace2 Key = 0x7F
- KeyCtrl8 Key = 0x7F
-)
-
-// Alt modifier constant, see Event.Mod field and SetInputMode function.
-const (
- ModAlt Modifier = 1 << iota
- ModMotion
-)
-
-// Cell colors, you can combine a color with multiple attributes using bitwise
-// OR ('|').
-const (
- ColorDefault Attribute = iota
- ColorBlack
- ColorRed
- ColorGreen
- ColorYellow
- ColorBlue
- ColorMagenta
- ColorCyan
- ColorWhite
-)
-
-// Cell attributes, it is possible to use multiple attributes by combining them
-// using bitwise OR ('|'). Although, colors cannot be combined. But you can
-// combine attributes and a single color.
-//
-// It's worth mentioning that some platforms don't support certain attributes.
-// For example windows console doesn't support AttrUnderline. And on some
-// terminals applying AttrBold to background may result in blinking text. Use
-// them with caution and test your code on various terminals.
-const (
- AttrBold Attribute = 1 << (iota + 9)
- AttrUnderline
- AttrReverse
-)
-
-// Input mode. See SetInputMode function.
-const (
- InputEsc InputMode = 1 << iota
- InputAlt
- InputMouse
- InputCurrent InputMode = 0
-)
-
-// Output mode. See SetOutputMode function.
-const (
- OutputCurrent OutputMode = iota
- OutputNormal
- Output256
- Output216
- OutputGrayscale
-)
-
-// Event type. See Event.Type field.
-const (
- EventKey EventType = iota
- EventResize
- EventMouse
- EventError
- EventInterrupt
- EventRaw
- EventNone
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/api_windows.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/api_windows.go
deleted file mode 100644
index 373e6c76c..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/api_windows.go
+++ /dev/null
@@ -1,257 +0,0 @@
-package termbox
-
-import (
- "syscall"
-
- "github.com/mattn/go-runewidth"
-)
-
-// public API
-
-// Initializes termbox library. This function should be called before any other functions.
-// After successful initialization, the library must be finalized using 'Close' function.
-//
-// Example usage:
-// err := termbox.Init()
-// if err != nil {
-// panic(err)
-// }
-// defer termbox.Close()
-func Init() error {
- var err error
-
- interrupt, err = create_event()
- if err != nil {
- return err
- }
-
- in, err = syscall.Open("CONIN$", syscall.O_RDWR, 0)
- if err != nil {
- return err
- }
- out, err = syscall.Open("CONOUT$", syscall.O_RDWR, 0)
- if err != nil {
- return err
- }
-
- err = get_console_mode(in, &orig_mode)
- if err != nil {
- return err
- }
-
- err = set_console_mode(in, enable_window_input)
- if err != nil {
- return err
- }
-
- orig_size, orig_window = get_term_size(out)
- win_size := get_win_size(out)
-
- err = set_console_screen_buffer_size(out, win_size)
- if err != nil {
- return err
- }
-
- err = fix_win_size(out, win_size)
- if err != nil {
- return err
- }
-
- err = get_console_cursor_info(out, &orig_cursor_info)
- if err != nil {
- return err
- }
-
- show_cursor(false)
- term_size, _ = get_term_size(out)
- back_buffer.init(int(term_size.x), int(term_size.y))
- front_buffer.init(int(term_size.x), int(term_size.y))
- back_buffer.clear()
- front_buffer.clear()
- clear()
-
- diffbuf = make([]diff_msg, 0, 32)
-
- go input_event_producer()
- IsInit = true
- return nil
-}
-
-// Finalizes termbox library, should be called after successful initialization
-// when termbox's functionality isn't required anymore.
-func Close() {
- // we ignore errors here, because we can't really do anything about them
- Clear(0, 0)
- Flush()
-
- // stop event producer
- cancel_comm <- true
- set_event(interrupt)
- select {
- case <-input_comm:
- default:
- }
- <-cancel_done_comm
-
- set_console_screen_buffer_size(out, orig_size)
- set_console_window_info(out, &orig_window)
- set_console_cursor_info(out, &orig_cursor_info)
- set_console_cursor_position(out, coord{})
- set_console_mode(in, orig_mode)
- syscall.Close(in)
- syscall.Close(out)
- syscall.Close(interrupt)
- IsInit = false
-}
-
-// Interrupt an in-progress call to PollEvent by causing it to return
-// EventInterrupt. Note that this function will block until the PollEvent
-// function has successfully been interrupted.
-func Interrupt() {
- interrupt_comm <- struct{}{}
-}
-
-// Synchronizes the internal back buffer with the terminal.
-func Flush() error {
- update_size_maybe()
- prepare_diff_messages()
- for _, diff := range diffbuf {
- chars := []char_info{}
- for _, char := range diff.chars {
- chars = append(chars, char)
- if runewidth.RuneWidth(rune(char.char)) > 1 {
- chars = append(chars, char_info{
- char: ' ',
- attr: char.attr,
- })
- }
- }
- r := small_rect{
- left: 0,
- top: diff.pos,
- right: term_size.x - 1,
- bottom: diff.pos + diff.lines - 1,
- }
- write_console_output(out, chars, r)
- }
- if !is_cursor_hidden(cursor_x, cursor_y) {
- move_cursor(cursor_x, cursor_y)
- }
- return nil
-}
-
-// Sets the position of the cursor. See also HideCursor().
-func SetCursor(x, y int) {
- if is_cursor_hidden(cursor_x, cursor_y) && !is_cursor_hidden(x, y) {
- show_cursor(true)
- }
-
- if !is_cursor_hidden(cursor_x, cursor_y) && is_cursor_hidden(x, y) {
- show_cursor(false)
- }
-
- cursor_x, cursor_y = x, y
- if !is_cursor_hidden(cursor_x, cursor_y) {
- move_cursor(cursor_x, cursor_y)
- }
-}
-
-// The shortcut for SetCursor(-1, -1).
-func HideCursor() {
- SetCursor(cursor_hidden, cursor_hidden)
-}
-
-// Changes cell's parameters in the internal back buffer at the specified
-// position.
-func SetCell(x, y int, ch rune, fg, bg Attribute) {
- if x < 0 || x >= back_buffer.width {
- return
- }
- if y < 0 || y >= back_buffer.height {
- return
- }
-
- back_buffer.cells[y*back_buffer.width+x] = Cell{ch, fg, bg}
-}
-
-// Returns a slice into the termbox's back buffer. You can get its dimensions
-// using 'Size' function. The slice remains valid as long as no 'Clear' or
-// 'Flush' function calls were made after call to this function.
-func CellBuffer() []Cell {
- return back_buffer.cells
-}
-
-// Wait for an event and return it. This is a blocking function call.
-func PollEvent() Event {
- select {
- case ev := <-input_comm:
- return ev
- case <-interrupt_comm:
- return Event{Type: EventInterrupt}
- }
-}
-
-// Returns the size of the internal back buffer (which is mostly the same as
-// console's window size in characters). But it doesn't always match the size
-// of the console window, after the console size has changed, the internal back
-// buffer will get in sync only after Clear or Flush function calls.
-func Size() (int, int) {
- return int(term_size.x), int(term_size.y)
-}
-
-// Clears the internal back buffer.
-func Clear(fg, bg Attribute) error {
- foreground, background = fg, bg
- update_size_maybe()
- back_buffer.clear()
- return nil
-}
-
-// Sets termbox input mode. Termbox has two input modes:
-//
-// 1. Esc input mode. When ESC sequence is in the buffer and it doesn't match
-// any known sequence. ESC means KeyEsc. This is the default input mode.
-//
-// 2. Alt input mode. When ESC sequence is in the buffer and it doesn't match
-// any known sequence. ESC enables ModAlt modifier for the next keyboard event.
-//
-// Both input modes can be OR'ed with Mouse mode. Setting Mouse mode bit up will
-// enable mouse button press/release and drag events.
-//
-// If 'mode' is InputCurrent, returns the current input mode. See also Input*
-// constants.
-func SetInputMode(mode InputMode) InputMode {
- if mode == InputCurrent {
- return input_mode
- }
- if mode&InputMouse != 0 {
- err := set_console_mode(in, enable_window_input|enable_mouse_input|enable_extended_flags)
- if err != nil {
- panic(err)
- }
- } else {
- err := set_console_mode(in, enable_window_input)
- if err != nil {
- panic(err)
- }
- }
-
- input_mode = mode
- return input_mode
-}
-
-// Sets the termbox output mode.
-//
-// Windows console does not support extra colour modes,
-// so this will always set and return OutputNormal.
-func SetOutputMode(mode OutputMode) OutputMode {
- return OutputNormal
-}
-
-// Sync comes handy when something causes desync between termbox's understanding
-// of a terminal buffer and the reality. Such as a third party process. Sync
-// forces a complete resync between the termbox and a terminal, it may not be
-// visually pretty though. At the moment on Windows it does nothing.
-func Sync() error {
- return nil
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/collect_terminfo.py b/examples/go-dashboard/src/github.com/nsf/termbox-go/collect_terminfo.py
deleted file mode 100644
index 5e50975e6..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/collect_terminfo.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python
-
-import sys, os, subprocess
-
-def escaped(s):
- return repr(s)[1:-1]
-
-def tput(term, name):
- try:
- return subprocess.check_output(['tput', '-T%s' % term, name]).decode()
- except subprocess.CalledProcessError as e:
- return e.output.decode()
-
-
-def w(s):
- if s == None:
- return
- sys.stdout.write(s)
-
-terminals = {
- 'xterm' : 'xterm',
- 'rxvt-256color' : 'rxvt_256color',
- 'rxvt-unicode' : 'rxvt_unicode',
- 'linux' : 'linux',
- 'Eterm' : 'eterm',
- 'screen' : 'screen'
-}
-
-keys = [
- "F1", "kf1",
- "F2", "kf2",
- "F3", "kf3",
- "F4", "kf4",
- "F5", "kf5",
- "F6", "kf6",
- "F7", "kf7",
- "F8", "kf8",
- "F9", "kf9",
- "F10", "kf10",
- "F11", "kf11",
- "F12", "kf12",
- "INSERT", "kich1",
- "DELETE", "kdch1",
- "HOME", "khome",
- "END", "kend",
- "PGUP", "kpp",
- "PGDN", "knp",
- "KEY_UP", "kcuu1",
- "KEY_DOWN", "kcud1",
- "KEY_LEFT", "kcub1",
- "KEY_RIGHT", "kcuf1"
-]
-
-funcs = [
- "T_ENTER_CA", "smcup",
- "T_EXIT_CA", "rmcup",
- "T_SHOW_CURSOR", "cnorm",
- "T_HIDE_CURSOR", "civis",
- "T_CLEAR_SCREEN", "clear",
- "T_SGR0", "sgr0",
- "T_UNDERLINE", "smul",
- "T_BOLD", "bold",
- "T_BLINK", "blink",
- "T_REVERSE", "rev",
- "T_ENTER_KEYPAD", "smkx",
- "T_EXIT_KEYPAD", "rmkx"
-]
-
-def iter_pairs(iterable):
- iterable = iter(iterable)
- while True:
- yield (next(iterable), next(iterable))
-
-def do_term(term, nick):
- w("// %s\n" % term)
- w("var %s_keys = []string{\n\t" % nick)
- for k, v in iter_pairs(keys):
- w('"')
- w(escaped(tput(term, v)))
- w('",')
- w("\n}\n")
- w("var %s_funcs = []string{\n\t" % nick)
- for k,v in iter_pairs(funcs):
- w('"')
- if v == "sgr":
- w("\\033[3%d;4%dm")
- elif v == "cup":
- w("\\033[%d;%dH")
- else:
- w(escaped(tput(term, v)))
- w('", ')
- w("\n}\n\n")
-
-def do_terms(d):
- w("var terms = []struct {\n")
- w("\tname string\n")
- w("\tkeys []string\n")
- w("\tfuncs []string\n")
- w("}{\n")
- for k, v in d.items():
- w('\t{"%s", %s_keys, %s_funcs},\n' % (k, v, v))
- w("}\n\n")
-
-w("// +build !windows\n\npackage termbox\n\n")
-
-for k,v in terminals.items():
- do_term(k, v)
-
-do_terms(terminals)
-
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/escwait.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/escwait.go
deleted file mode 100644
index b7bbb891f..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/escwait.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build !darwin
-
-package termbox
-
-// On all systems other than macOS, disable behavior which will wait before
-// deciding that the escape key was pressed, to account for partially send
-// escape sequences, especially with regard to lengthy mouse sequences.
-// See https://github.com/nsf/termbox-go/issues/132
-func enable_wait_for_escape_sequence() bool {
- return false
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/escwait_darwin.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/escwait_darwin.go
deleted file mode 100644
index dde69b6cb..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/escwait_darwin.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package termbox
-
-// On macOS, enable behavior which will wait before deciding that the escape
-// key was pressed, to account for partially send escape sequences, especially
-// with regard to lengthy mouse sequences.
-// See https://github.com/nsf/termbox-go/issues/132
-func enable_wait_for_escape_sequence() bool {
- return true
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin.go
deleted file mode 100644
index 25b78f7ab..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin.go
+++ /dev/null
@@ -1,41 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs syscalls.go
-
-// +build !amd64
-
-package termbox
-
-type syscall_Termios struct {
- Iflag uint32
- Oflag uint32
- Cflag uint32
- Lflag uint32
- Cc [20]uint8
- Ispeed uint32
- Ospeed uint32
-}
-
-const (
- syscall_IGNBRK = 0x1
- syscall_BRKINT = 0x2
- syscall_PARMRK = 0x8
- syscall_ISTRIP = 0x20
- syscall_INLCR = 0x40
- syscall_IGNCR = 0x80
- syscall_ICRNL = 0x100
- syscall_IXON = 0x200
- syscall_OPOST = 0x1
- syscall_ECHO = 0x8
- syscall_ECHONL = 0x10
- syscall_ICANON = 0x100
- syscall_ISIG = 0x80
- syscall_IEXTEN = 0x400
- syscall_CSIZE = 0x300
- syscall_PARENB = 0x1000
- syscall_CS8 = 0x300
- syscall_VMIN = 0x10
- syscall_VTIME = 0x11
-
- syscall_TCGETS = 0x402c7413
- syscall_TCSETS = 0x802c7414
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
deleted file mode 100644
index 11f25be79..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs syscalls.go
-
-package termbox
-
-type syscall_Termios struct {
- Iflag uint64
- Oflag uint64
- Cflag uint64
- Lflag uint64
- Cc [20]uint8
- Pad_cgo_0 [4]byte
- Ispeed uint64
- Ospeed uint64
-}
-
-const (
- syscall_IGNBRK = 0x1
- syscall_BRKINT = 0x2
- syscall_PARMRK = 0x8
- syscall_ISTRIP = 0x20
- syscall_INLCR = 0x40
- syscall_IGNCR = 0x80
- syscall_ICRNL = 0x100
- syscall_IXON = 0x200
- syscall_OPOST = 0x1
- syscall_ECHO = 0x8
- syscall_ECHONL = 0x10
- syscall_ICANON = 0x100
- syscall_ISIG = 0x80
- syscall_IEXTEN = 0x400
- syscall_CSIZE = 0x300
- syscall_PARENB = 0x1000
- syscall_CS8 = 0x300
- syscall_VMIN = 0x10
- syscall_VTIME = 0x11
-
- syscall_TCGETS = 0x40487413
- syscall_TCSETS = 0x80487414
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_dragonfly.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_dragonfly.go
deleted file mode 100644
index e03624ebc..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_dragonfly.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs syscalls.go
-
-package termbox
-
-type syscall_Termios struct {
- Iflag uint32
- Oflag uint32
- Cflag uint32
- Lflag uint32
- Cc [20]uint8
- Ispeed uint32
- Ospeed uint32
-}
-
-const (
- syscall_IGNBRK = 0x1
- syscall_BRKINT = 0x2
- syscall_PARMRK = 0x8
- syscall_ISTRIP = 0x20
- syscall_INLCR = 0x40
- syscall_IGNCR = 0x80
- syscall_ICRNL = 0x100
- syscall_IXON = 0x200
- syscall_OPOST = 0x1
- syscall_ECHO = 0x8
- syscall_ECHONL = 0x10
- syscall_ICANON = 0x100
- syscall_ISIG = 0x80
- syscall_IEXTEN = 0x400
- syscall_CSIZE = 0x300
- syscall_PARENB = 0x1000
- syscall_CS8 = 0x300
- syscall_VMIN = 0x10
- syscall_VTIME = 0x11
-
- syscall_TCGETS = 0x402c7413
- syscall_TCSETS = 0x802c7414
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_freebsd.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_freebsd.go
deleted file mode 100644
index e03624ebc..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_freebsd.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs syscalls.go
-
-package termbox
-
-type syscall_Termios struct {
- Iflag uint32
- Oflag uint32
- Cflag uint32
- Lflag uint32
- Cc [20]uint8
- Ispeed uint32
- Ospeed uint32
-}
-
-const (
- syscall_IGNBRK = 0x1
- syscall_BRKINT = 0x2
- syscall_PARMRK = 0x8
- syscall_ISTRIP = 0x20
- syscall_INLCR = 0x40
- syscall_IGNCR = 0x80
- syscall_ICRNL = 0x100
- syscall_IXON = 0x200
- syscall_OPOST = 0x1
- syscall_ECHO = 0x8
- syscall_ECHONL = 0x10
- syscall_ICANON = 0x100
- syscall_ISIG = 0x80
- syscall_IEXTEN = 0x400
- syscall_CSIZE = 0x300
- syscall_PARENB = 0x1000
- syscall_CS8 = 0x300
- syscall_VMIN = 0x10
- syscall_VTIME = 0x11
-
- syscall_TCGETS = 0x402c7413
- syscall_TCSETS = 0x802c7414
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_linux.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_linux.go
deleted file mode 100644
index b88960de6..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_linux.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs syscalls.go
-
-package termbox
-
-import "syscall"
-
-type syscall_Termios syscall.Termios
-
-const (
- syscall_IGNBRK = syscall.IGNBRK
- syscall_BRKINT = syscall.BRKINT
- syscall_PARMRK = syscall.PARMRK
- syscall_ISTRIP = syscall.ISTRIP
- syscall_INLCR = syscall.INLCR
- syscall_IGNCR = syscall.IGNCR
- syscall_ICRNL = syscall.ICRNL
- syscall_IXON = syscall.IXON
- syscall_OPOST = syscall.OPOST
- syscall_ECHO = syscall.ECHO
- syscall_ECHONL = syscall.ECHONL
- syscall_ICANON = syscall.ICANON
- syscall_ISIG = syscall.ISIG
- syscall_IEXTEN = syscall.IEXTEN
- syscall_CSIZE = syscall.CSIZE
- syscall_PARENB = syscall.PARENB
- syscall_CS8 = syscall.CS8
- syscall_VMIN = syscall.VMIN
- syscall_VTIME = syscall.VTIME
-
- syscall_TCGETS = syscall.TCGETS
- syscall_TCSETS = syscall.TCSETS
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_netbsd.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_netbsd.go
deleted file mode 100644
index 49a3355b9..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_netbsd.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs syscalls.go
-
-package termbox
-
-type syscall_Termios struct {
- Iflag uint32
- Oflag uint32
- Cflag uint32
- Lflag uint32
- Cc [20]uint8
- Ispeed int32
- Ospeed int32
-}
-
-const (
- syscall_IGNBRK = 0x1
- syscall_BRKINT = 0x2
- syscall_PARMRK = 0x8
- syscall_ISTRIP = 0x20
- syscall_INLCR = 0x40
- syscall_IGNCR = 0x80
- syscall_ICRNL = 0x100
- syscall_IXON = 0x200
- syscall_OPOST = 0x1
- syscall_ECHO = 0x8
- syscall_ECHONL = 0x10
- syscall_ICANON = 0x100
- syscall_ISIG = 0x80
- syscall_IEXTEN = 0x400
- syscall_CSIZE = 0x300
- syscall_PARENB = 0x1000
- syscall_CS8 = 0x300
- syscall_VMIN = 0x10
- syscall_VTIME = 0x11
-
- syscall_TCGETS = 0x402c7413
- syscall_TCSETS = 0x802c7414
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_openbsd.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_openbsd.go
deleted file mode 100644
index 49a3355b9..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_openbsd.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs syscalls.go
-
-package termbox
-
-type syscall_Termios struct {
- Iflag uint32
- Oflag uint32
- Cflag uint32
- Lflag uint32
- Cc [20]uint8
- Ispeed int32
- Ospeed int32
-}
-
-const (
- syscall_IGNBRK = 0x1
- syscall_BRKINT = 0x2
- syscall_PARMRK = 0x8
- syscall_ISTRIP = 0x20
- syscall_INLCR = 0x40
- syscall_IGNCR = 0x80
- syscall_ICRNL = 0x100
- syscall_IXON = 0x200
- syscall_OPOST = 0x1
- syscall_ECHO = 0x8
- syscall_ECHONL = 0x10
- syscall_ICANON = 0x100
- syscall_ISIG = 0x80
- syscall_IEXTEN = 0x400
- syscall_CSIZE = 0x300
- syscall_PARENB = 0x1000
- syscall_CS8 = 0x300
- syscall_VMIN = 0x10
- syscall_VTIME = 0x11
-
- syscall_TCGETS = 0x402c7413
- syscall_TCSETS = 0x802c7414
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_windows.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_windows.go
deleted file mode 100644
index 472d002a5..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/syscalls_windows.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs -- -DUNICODE syscalls.go
-
-package termbox
-
-const (
- foreground_blue = 0x1
- foreground_green = 0x2
- foreground_red = 0x4
- foreground_intensity = 0x8
- background_blue = 0x10
- background_green = 0x20
- background_red = 0x40
- background_intensity = 0x80
- std_input_handle = -0xa
- std_output_handle = -0xb
- key_event = 0x1
- mouse_event = 0x2
- window_buffer_size_event = 0x4
- enable_window_input = 0x8
- enable_mouse_input = 0x10
- enable_extended_flags = 0x80
-
- vk_f1 = 0x70
- vk_f2 = 0x71
- vk_f3 = 0x72
- vk_f4 = 0x73
- vk_f5 = 0x74
- vk_f6 = 0x75
- vk_f7 = 0x76
- vk_f8 = 0x77
- vk_f9 = 0x78
- vk_f10 = 0x79
- vk_f11 = 0x7a
- vk_f12 = 0x7b
- vk_insert = 0x2d
- vk_delete = 0x2e
- vk_home = 0x24
- vk_end = 0x23
- vk_pgup = 0x21
- vk_pgdn = 0x22
- vk_arrow_up = 0x26
- vk_arrow_down = 0x28
- vk_arrow_left = 0x25
- vk_arrow_right = 0x27
- vk_backspace = 0x8
- vk_tab = 0x9
- vk_enter = 0xd
- vk_esc = 0x1b
- vk_space = 0x20
-
- left_alt_pressed = 0x2
- left_ctrl_pressed = 0x8
- right_alt_pressed = 0x1
- right_ctrl_pressed = 0x4
- shift_pressed = 0x10
-
- generic_read = 0x80000000
- generic_write = 0x40000000
- console_textmode_buffer = 0x1
-)
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox.go
deleted file mode 100644
index fbe4c3de9..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox.go
+++ /dev/null
@@ -1,529 +0,0 @@
-// +build !windows
-
-package termbox
-
-import "unicode/utf8"
-import "bytes"
-import "syscall"
-import "unsafe"
-import "strings"
-import "strconv"
-import "os"
-import "io"
-
-// private API
-
-const (
- t_enter_ca = iota
- t_exit_ca
- t_show_cursor
- t_hide_cursor
- t_clear_screen
- t_sgr0
- t_underline
- t_bold
- t_blink
- t_reverse
- t_enter_keypad
- t_exit_keypad
- t_enter_mouse
- t_exit_mouse
- t_max_funcs
-)
-
-const (
- coord_invalid = -2
- attr_invalid = Attribute(0xFFFF)
-)
-
-type input_event struct {
- data []byte
- err error
-}
-
-type extract_event_res int
-
-const (
- event_not_extracted extract_event_res = iota
- event_extracted
- esc_wait
-)
-
-var (
- // term specific sequences
- keys []string
- funcs []string
-
- // termbox inner state
- orig_tios syscall_Termios
- back_buffer cellbuf
- front_buffer cellbuf
- termw int
- termh int
- input_mode = InputEsc
- output_mode = OutputNormal
- out *os.File
- in int
- lastfg = attr_invalid
- lastbg = attr_invalid
- lastx = coord_invalid
- lasty = coord_invalid
- cursor_x = cursor_hidden
- cursor_y = cursor_hidden
- foreground = ColorDefault
- background = ColorDefault
- inbuf = make([]byte, 0, 64)
- outbuf bytes.Buffer
- sigwinch = make(chan os.Signal, 1)
- sigio = make(chan os.Signal, 1)
- quit = make(chan int)
- input_comm = make(chan input_event)
- interrupt_comm = make(chan struct{})
- intbuf = make([]byte, 0, 16)
-
- // grayscale indexes
- grayscale = []Attribute{
- 0, 17, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
- 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 232,
- }
-)
-
-func write_cursor(x, y int) {
- outbuf.WriteString("\033[")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(y+1), 10))
- outbuf.WriteString(";")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(x+1), 10))
- outbuf.WriteString("H")
-}
-
-func write_sgr_fg(a Attribute) {
- switch output_mode {
- case Output256, Output216, OutputGrayscale:
- outbuf.WriteString("\033[38;5;")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
- outbuf.WriteString("m")
- default:
- outbuf.WriteString("\033[3")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
- outbuf.WriteString("m")
- }
-}
-
-func write_sgr_bg(a Attribute) {
- switch output_mode {
- case Output256, Output216, OutputGrayscale:
- outbuf.WriteString("\033[48;5;")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
- outbuf.WriteString("m")
- default:
- outbuf.WriteString("\033[4")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(a-1), 10))
- outbuf.WriteString("m")
- }
-}
-
-func write_sgr(fg, bg Attribute) {
- switch output_mode {
- case Output256, Output216, OutputGrayscale:
- outbuf.WriteString("\033[38;5;")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10))
- outbuf.WriteString("m")
- outbuf.WriteString("\033[48;5;")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10))
- outbuf.WriteString("m")
- default:
- outbuf.WriteString("\033[3")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(fg-1), 10))
- outbuf.WriteString(";4")
- outbuf.Write(strconv.AppendUint(intbuf, uint64(bg-1), 10))
- outbuf.WriteString("m")
- }
-}
-
-type winsize struct {
- rows uint16
- cols uint16
- xpixels uint16
- ypixels uint16
-}
-
-func get_term_size(fd uintptr) (int, int) {
- var sz winsize
- _, _, _ = syscall.Syscall(syscall.SYS_IOCTL,
- fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz)))
- return int(sz.cols), int(sz.rows)
-}
-
-func send_attr(fg, bg Attribute) {
- if fg == lastfg && bg == lastbg {
- return
- }
-
- outbuf.WriteString(funcs[t_sgr0])
-
- var fgcol, bgcol Attribute
-
- switch output_mode {
- case Output256:
- fgcol = fg & 0x1FF
- bgcol = bg & 0x1FF
- case Output216:
- fgcol = fg & 0xFF
- bgcol = bg & 0xFF
- if fgcol > 216 {
- fgcol = ColorDefault
- }
- if bgcol > 216 {
- bgcol = ColorDefault
- }
- if fgcol != ColorDefault {
- fgcol += 0x10
- }
- if bgcol != ColorDefault {
- bgcol += 0x10
- }
- case OutputGrayscale:
- fgcol = fg & 0x1F
- bgcol = bg & 0x1F
- if fgcol > 26 {
- fgcol = ColorDefault
- }
- if bgcol > 26 {
- bgcol = ColorDefault
- }
- if fgcol != ColorDefault {
- fgcol = grayscale[fgcol]
- }
- if bgcol != ColorDefault {
- bgcol = grayscale[bgcol]
- }
- default:
- fgcol = fg & 0x0F
- bgcol = bg & 0x0F
- }
-
- if fgcol != ColorDefault {
- if bgcol != ColorDefault {
- write_sgr(fgcol, bgcol)
- } else {
- write_sgr_fg(fgcol)
- }
- } else if bgcol != ColorDefault {
- write_sgr_bg(bgcol)
- }
-
- if fg&AttrBold != 0 {
- outbuf.WriteString(funcs[t_bold])
- }
- if bg&AttrBold != 0 {
- outbuf.WriteString(funcs[t_blink])
- }
- if fg&AttrUnderline != 0 {
- outbuf.WriteString(funcs[t_underline])
- }
- if fg&AttrReverse|bg&AttrReverse != 0 {
- outbuf.WriteString(funcs[t_reverse])
- }
-
- lastfg, lastbg = fg, bg
-}
-
-func send_char(x, y int, ch rune) {
- var buf [8]byte
- n := utf8.EncodeRune(buf[:], ch)
- if x-1 != lastx || y != lasty {
- write_cursor(x, y)
- }
- lastx, lasty = x, y
- outbuf.Write(buf[:n])
-}
-
-func flush() error {
- _, err := io.Copy(out, &outbuf)
- outbuf.Reset()
- return err
-}
-
-func send_clear() error {
- send_attr(foreground, background)
- outbuf.WriteString(funcs[t_clear_screen])
- if !is_cursor_hidden(cursor_x, cursor_y) {
- write_cursor(cursor_x, cursor_y)
- }
-
- // we need to invalidate cursor position too and these two vars are
- // used only for simple cursor positioning optimization, cursor
- // actually may be in the correct place, but we simply discard
- // optimization once and it gives us simple solution for the case when
- // cursor moved
- lastx = coord_invalid
- lasty = coord_invalid
-
- return flush()
-}
-
-func update_size_maybe() error {
- w, h := get_term_size(out.Fd())
- if w != termw || h != termh {
- termw, termh = w, h
- back_buffer.resize(termw, termh)
- front_buffer.resize(termw, termh)
- front_buffer.clear()
- return send_clear()
- }
- return nil
-}
-
-func tcsetattr(fd uintptr, termios *syscall_Termios) error {
- r, _, e := syscall.Syscall(syscall.SYS_IOCTL,
- fd, uintptr(syscall_TCSETS), uintptr(unsafe.Pointer(termios)))
- if r != 0 {
- return os.NewSyscallError("SYS_IOCTL", e)
- }
- return nil
-}
-
-func tcgetattr(fd uintptr, termios *syscall_Termios) error {
- r, _, e := syscall.Syscall(syscall.SYS_IOCTL,
- fd, uintptr(syscall_TCGETS), uintptr(unsafe.Pointer(termios)))
- if r != 0 {
- return os.NewSyscallError("SYS_IOCTL", e)
- }
- return nil
-}
-
-func parse_mouse_event(event *Event, buf string) (int, bool) {
- if strings.HasPrefix(buf, "\033[M") && len(buf) >= 6 {
- // X10 mouse encoding, the simplest one
- // \033 [ M Cb Cx Cy
- b := buf[3] - 32
- switch b & 3 {
- case 0:
- if b&64 != 0 {
- event.Key = MouseWheelUp
- } else {
- event.Key = MouseLeft
- }
- case 1:
- if b&64 != 0 {
- event.Key = MouseWheelDown
- } else {
- event.Key = MouseMiddle
- }
- case 2:
- event.Key = MouseRight
- case 3:
- event.Key = MouseRelease
- default:
- return 6, false
- }
- event.Type = EventMouse // KeyEvent by default
- if b&32 != 0 {
- event.Mod |= ModMotion
- }
-
- // the coord is 1,1 for upper left
- event.MouseX = int(buf[4]) - 1 - 32
- event.MouseY = int(buf[5]) - 1 - 32
- return 6, true
- } else if strings.HasPrefix(buf, "\033[<") || strings.HasPrefix(buf, "\033[") {
- // xterm 1006 extended mode or urxvt 1015 extended mode
- // xterm: \033 [ < Cb ; Cx ; Cy (M or m)
- // urxvt: \033 [ Cb ; Cx ; Cy M
-
- // find the first M or m, that's where we stop
- mi := strings.IndexAny(buf, "Mm")
- if mi == -1 {
- return 0, false
- }
-
- // whether it's a capital M or not
- isM := buf[mi] == 'M'
-
- // whether it's urxvt or not
- isU := false
-
- // buf[2] is safe here, because having M or m found means we have at
- // least 3 bytes in a string
- if buf[2] == '<' {
- buf = buf[3:mi]
- } else {
- isU = true
- buf = buf[2:mi]
- }
-
- s1 := strings.Index(buf, ";")
- s2 := strings.LastIndex(buf, ";")
- // not found or only one ';'
- if s1 == -1 || s2 == -1 || s1 == s2 {
- return 0, false
- }
-
- n1, err := strconv.ParseInt(buf[0:s1], 10, 64)
- if err != nil {
- return 0, false
- }
- n2, err := strconv.ParseInt(buf[s1+1:s2], 10, 64)
- if err != nil {
- return 0, false
- }
- n3, err := strconv.ParseInt(buf[s2+1:], 10, 64)
- if err != nil {
- return 0, false
- }
-
- // on urxvt, first number is encoded exactly as in X10, but we need to
- // make it zero-based, on xterm it is zero-based already
- if isU {
- n1 -= 32
- }
- switch n1 & 3 {
- case 0:
- if n1&64 != 0 {
- event.Key = MouseWheelUp
- } else {
- event.Key = MouseLeft
- }
- case 1:
- if n1&64 != 0 {
- event.Key = MouseWheelDown
- } else {
- event.Key = MouseMiddle
- }
- case 2:
- event.Key = MouseRight
- case 3:
- event.Key = MouseRelease
- default:
- return mi + 1, false
- }
- if !isM {
- // on xterm mouse release is signaled by lowercase m
- event.Key = MouseRelease
- }
-
- event.Type = EventMouse // KeyEvent by default
- if n1&32 != 0 {
- event.Mod |= ModMotion
- }
-
- event.MouseX = int(n2) - 1
- event.MouseY = int(n3) - 1
- return mi + 1, true
- }
-
- return 0, false
-}
-
-func parse_escape_sequence(event *Event, buf []byte) (int, bool) {
- bufstr := string(buf)
- for i, key := range keys {
- if strings.HasPrefix(bufstr, key) {
- event.Ch = 0
- event.Key = Key(0xFFFF - i)
- return len(key), true
- }
- }
-
- // if none of the keys match, let's try mouse sequences
- return parse_mouse_event(event, bufstr)
-}
-
-func extract_raw_event(data []byte, event *Event) bool {
- if len(inbuf) == 0 {
- return false
- }
-
- n := len(data)
- if n == 0 {
- return false
- }
-
- n = copy(data, inbuf)
- copy(inbuf, inbuf[n:])
- inbuf = inbuf[:len(inbuf)-n]
-
- event.N = n
- event.Type = EventRaw
- return true
-}
-
-func extract_event(inbuf []byte, event *Event, allow_esc_wait bool) extract_event_res {
- if len(inbuf) == 0 {
- event.N = 0
- return event_not_extracted
- }
-
- if inbuf[0] == '\033' {
- // possible escape sequence
- if n, ok := parse_escape_sequence(event, inbuf); n != 0 {
- event.N = n
- if ok {
- return event_extracted
- } else {
- return event_not_extracted
- }
- }
-
- // possible partially read escape sequence; trigger a wait if appropriate
- if enable_wait_for_escape_sequence() && allow_esc_wait {
- event.N = 0
- return esc_wait
- }
-
- // it's not escape sequence, then it's Alt or Esc, check input_mode
- switch {
- case input_mode&InputEsc != 0:
- // if we're in escape mode, fill Esc event, pop buffer, return success
- event.Ch = 0
- event.Key = KeyEsc
- event.Mod = 0
- event.N = 1
- return event_extracted
- case input_mode&InputAlt != 0:
- // if we're in alt mode, set Alt modifier to event and redo parsing
- event.Mod = ModAlt
- status := extract_event(inbuf[1:], event, false)
- if status == event_extracted {
- event.N++
- } else {
- event.N = 0
- }
- return status
- default:
- panic("unreachable")
- }
- }
-
- // if we're here, this is not an escape sequence and not an alt sequence
- // so, it's a FUNCTIONAL KEY or a UNICODE character
-
- // first of all check if it's a functional key
- if Key(inbuf[0]) <= KeySpace || Key(inbuf[0]) == KeyBackspace2 {
- // fill event, pop buffer, return success
- event.Ch = 0
- event.Key = Key(inbuf[0])
- event.N = 1
- return event_extracted
- }
-
- // the only possible option is utf8 rune
- if r, n := utf8.DecodeRune(inbuf); r != utf8.RuneError {
- event.Ch = r
- event.Key = 0
- event.N = n
- return event_extracted
- }
-
- return event_not_extracted
-}
-
-func fcntl(fd int, cmd int, arg int) (val int, err error) {
- r, _, e := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), uintptr(cmd),
- uintptr(arg))
- val = int(r)
- if e != 0 {
- err = e
- }
- return
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_common.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_common.go
deleted file mode 100644
index c3355cc25..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_common.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package termbox
-
-// private API, common OS agnostic part
-
-type cellbuf struct {
- width int
- height int
- cells []Cell
-}
-
-func (this *cellbuf) init(width, height int) {
- this.width = width
- this.height = height
- this.cells = make([]Cell, width*height)
-}
-
-func (this *cellbuf) resize(width, height int) {
- if this.width == width && this.height == height {
- return
- }
-
- oldw := this.width
- oldh := this.height
- oldcells := this.cells
-
- this.init(width, height)
- this.clear()
-
- minw, minh := oldw, oldh
-
- if width < minw {
- minw = width
- }
- if height < minh {
- minh = height
- }
-
- for i := 0; i < minh; i++ {
- srco, dsto := i*oldw, i*width
- src := oldcells[srco : srco+minw]
- dst := this.cells[dsto : dsto+minw]
- copy(dst, src)
- }
-}
-
-func (this *cellbuf) clear() {
- for i := range this.cells {
- c := &this.cells[i]
- c.Ch = ' '
- c.Fg = foreground
- c.Bg = background
- }
-}
-
-const cursor_hidden = -1
-
-func is_cursor_hidden(x, y int) bool {
- return x == cursor_hidden || y == cursor_hidden
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_windows.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_windows.go
deleted file mode 100644
index d46eb043e..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/termbox_windows.go
+++ /dev/null
@@ -1,952 +0,0 @@
-package termbox
-
-import "math"
-import "syscall"
-import "unsafe"
-import "unicode/utf16"
-import "github.com/mattn/go-runewidth"
-
-type (
- wchar uint16
- short int16
- dword uint32
- word uint16
- char_info struct {
- char wchar
- attr word
- }
- coord struct {
- x short
- y short
- }
- small_rect struct {
- left short
- top short
- right short
- bottom short
- }
- console_screen_buffer_info struct {
- size coord
- cursor_position coord
- attributes word
- window small_rect
- maximum_window_size coord
- }
- console_cursor_info struct {
- size dword
- visible int32
- }
- input_record struct {
- event_type word
- _ [2]byte
- event [16]byte
- }
- key_event_record struct {
- key_down int32
- repeat_count word
- virtual_key_code word
- virtual_scan_code word
- unicode_char wchar
- control_key_state dword
- }
- window_buffer_size_record struct {
- size coord
- }
- mouse_event_record struct {
- mouse_pos coord
- button_state dword
- control_key_state dword
- event_flags dword
- }
- console_font_info struct {
- font uint32
- font_size coord
- }
-)
-
-const (
- mouse_lmb = 0x1
- mouse_rmb = 0x2
- mouse_mmb = 0x4 | 0x8 | 0x10
- SM_CXMIN = 28
- SM_CYMIN = 29
-)
-
-func (this coord) uintptr() uintptr {
- return uintptr(*(*int32)(unsafe.Pointer(&this)))
-}
-
-func (this *small_rect) uintptr() uintptr {
- return uintptr(unsafe.Pointer(this))
-}
-
-var kernel32 = syscall.NewLazyDLL("kernel32.dll")
-var moduser32 = syscall.NewLazyDLL("user32.dll")
-var is_cjk = runewidth.IsEastAsian()
-
-var (
- proc_set_console_active_screen_buffer = kernel32.NewProc("SetConsoleActiveScreenBuffer")
- proc_set_console_screen_buffer_size = kernel32.NewProc("SetConsoleScreenBufferSize")
- proc_set_console_window_info = kernel32.NewProc("SetConsoleWindowInfo")
- proc_create_console_screen_buffer = kernel32.NewProc("CreateConsoleScreenBuffer")
- proc_get_console_screen_buffer_info = kernel32.NewProc("GetConsoleScreenBufferInfo")
- proc_write_console_output = kernel32.NewProc("WriteConsoleOutputW")
- proc_write_console_output_character = kernel32.NewProc("WriteConsoleOutputCharacterW")
- proc_write_console_output_attribute = kernel32.NewProc("WriteConsoleOutputAttribute")
- proc_set_console_cursor_info = kernel32.NewProc("SetConsoleCursorInfo")
- proc_set_console_cursor_position = kernel32.NewProc("SetConsoleCursorPosition")
- proc_get_console_cursor_info = kernel32.NewProc("GetConsoleCursorInfo")
- proc_read_console_input = kernel32.NewProc("ReadConsoleInputW")
- proc_get_console_mode = kernel32.NewProc("GetConsoleMode")
- proc_set_console_mode = kernel32.NewProc("SetConsoleMode")
- proc_fill_console_output_character = kernel32.NewProc("FillConsoleOutputCharacterW")
- proc_fill_console_output_attribute = kernel32.NewProc("FillConsoleOutputAttribute")
- proc_create_event = kernel32.NewProc("CreateEventW")
- proc_wait_for_multiple_objects = kernel32.NewProc("WaitForMultipleObjects")
- proc_set_event = kernel32.NewProc("SetEvent")
- proc_get_current_console_font = kernel32.NewProc("GetCurrentConsoleFont")
- get_system_metrics = moduser32.NewProc("GetSystemMetrics")
-)
-
-func set_console_active_screen_buffer(h syscall.Handle) (err error) {
- r0, _, e1 := syscall.Syscall(proc_set_console_active_screen_buffer.Addr(),
- 1, uintptr(h), 0, 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func set_console_screen_buffer_size(h syscall.Handle, size coord) (err error) {
- r0, _, e1 := syscall.Syscall(proc_set_console_screen_buffer_size.Addr(),
- 2, uintptr(h), size.uintptr(), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func set_console_window_info(h syscall.Handle, window *small_rect) (err error) {
- var absolute uint32
- absolute = 1
- r0, _, e1 := syscall.Syscall(proc_set_console_window_info.Addr(),
- 3, uintptr(h), uintptr(absolute), window.uintptr())
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func create_console_screen_buffer() (h syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall6(proc_create_console_screen_buffer.Addr(),
- 5, uintptr(generic_read|generic_write), 0, 0, console_textmode_buffer, 0, 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return syscall.Handle(r0), err
-}
-
-func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) {
- r0, _, e1 := syscall.Syscall(proc_get_console_screen_buffer_info.Addr(),
- 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func write_console_output(h syscall.Handle, chars []char_info, dst small_rect) (err error) {
- tmp_coord = coord{dst.right - dst.left + 1, dst.bottom - dst.top + 1}
- tmp_rect = dst
- r0, _, e1 := syscall.Syscall6(proc_write_console_output.Addr(),
- 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), tmp_coord.uintptr(),
- tmp_coord0.uintptr(), uintptr(unsafe.Pointer(&tmp_rect)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func write_console_output_character(h syscall.Handle, chars []wchar, pos coord) (err error) {
- r0, _, e1 := syscall.Syscall6(proc_write_console_output_character.Addr(),
- 5, uintptr(h), uintptr(unsafe.Pointer(&chars[0])), uintptr(len(chars)),
- pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func write_console_output_attribute(h syscall.Handle, attrs []word, pos coord) (err error) {
- r0, _, e1 := syscall.Syscall6(proc_write_console_output_attribute.Addr(),
- 5, uintptr(h), uintptr(unsafe.Pointer(&attrs[0])), uintptr(len(attrs)),
- pos.uintptr(), uintptr(unsafe.Pointer(&tmp_arg)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func set_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) {
- r0, _, e1 := syscall.Syscall(proc_set_console_cursor_info.Addr(),
- 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func get_console_cursor_info(h syscall.Handle, info *console_cursor_info) (err error) {
- r0, _, e1 := syscall.Syscall(proc_get_console_cursor_info.Addr(),
- 2, uintptr(h), uintptr(unsafe.Pointer(info)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func set_console_cursor_position(h syscall.Handle, pos coord) (err error) {
- r0, _, e1 := syscall.Syscall(proc_set_console_cursor_position.Addr(),
- 2, uintptr(h), pos.uintptr(), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func read_console_input(h syscall.Handle, record *input_record) (err error) {
- r0, _, e1 := syscall.Syscall6(proc_read_console_input.Addr(),
- 4, uintptr(h), uintptr(unsafe.Pointer(record)), 1, uintptr(unsafe.Pointer(&tmp_arg)), 0, 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func get_console_mode(h syscall.Handle, mode *dword) (err error) {
- r0, _, e1 := syscall.Syscall(proc_get_console_mode.Addr(),
- 2, uintptr(h), uintptr(unsafe.Pointer(mode)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func set_console_mode(h syscall.Handle, mode dword) (err error) {
- r0, _, e1 := syscall.Syscall(proc_set_console_mode.Addr(),
- 2, uintptr(h), uintptr(mode), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func fill_console_output_character(h syscall.Handle, char wchar, n int) (err error) {
- tmp_coord = coord{0, 0}
- r0, _, e1 := syscall.Syscall6(proc_fill_console_output_character.Addr(),
- 5, uintptr(h), uintptr(char), uintptr(n), tmp_coord.uintptr(),
- uintptr(unsafe.Pointer(&tmp_arg)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func fill_console_output_attribute(h syscall.Handle, attr word, n int) (err error) {
- tmp_coord = coord{0, 0}
- r0, _, e1 := syscall.Syscall6(proc_fill_console_output_attribute.Addr(),
- 5, uintptr(h), uintptr(attr), uintptr(n), tmp_coord.uintptr(),
- uintptr(unsafe.Pointer(&tmp_arg)), 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func create_event() (out syscall.Handle, err error) {
- r0, _, e1 := syscall.Syscall6(proc_create_event.Addr(),
- 4, 0, 0, 0, 0, 0, 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return syscall.Handle(r0), err
-}
-
-func wait_for_multiple_objects(objects []syscall.Handle) (err error) {
- r0, _, e1 := syscall.Syscall6(proc_wait_for_multiple_objects.Addr(),
- 4, uintptr(len(objects)), uintptr(unsafe.Pointer(&objects[0])),
- 0, 0xFFFFFFFF, 0, 0)
- if uint32(r0) == 0xFFFFFFFF {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func set_event(ev syscall.Handle) (err error) {
- r0, _, e1 := syscall.Syscall(proc_set_event.Addr(),
- 1, uintptr(ev), 0, 0)
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-func get_current_console_font(h syscall.Handle, info *console_font_info) (err error) {
- r0, _, e1 := syscall.Syscall(proc_get_current_console_font.Addr(),
- 3, uintptr(h), 0, uintptr(unsafe.Pointer(info)))
- if int(r0) == 0 {
- if e1 != 0 {
- err = error(e1)
- } else {
- err = syscall.EINVAL
- }
- }
- return
-}
-
-type diff_msg struct {
- pos short
- lines short
- chars []char_info
-}
-
-type input_event struct {
- event Event
- err error
-}
-
-var (
- orig_cursor_info console_cursor_info
- orig_size coord
- orig_window small_rect
- orig_mode dword
- orig_screen syscall.Handle
- back_buffer cellbuf
- front_buffer cellbuf
- term_size coord
- input_mode = InputEsc
- cursor_x = cursor_hidden
- cursor_y = cursor_hidden
- foreground = ColorDefault
- background = ColorDefault
- in syscall.Handle
- out syscall.Handle
- interrupt syscall.Handle
- charbuf []char_info
- diffbuf []diff_msg
- beg_x = -1
- beg_y = -1
- beg_i = -1
- input_comm = make(chan Event)
- interrupt_comm = make(chan struct{})
- cancel_comm = make(chan bool, 1)
- cancel_done_comm = make(chan bool)
- alt_mode_esc = false
-
- // these ones just to prevent heap allocs at all costs
- tmp_info console_screen_buffer_info
- tmp_arg dword
- tmp_coord0 = coord{0, 0}
- tmp_coord = coord{0, 0}
- tmp_rect = small_rect{0, 0, 0, 0}
- tmp_finfo console_font_info
-)
-
-func get_cursor_position(out syscall.Handle) coord {
- err := get_console_screen_buffer_info(out, &tmp_info)
- if err != nil {
- panic(err)
- }
- return tmp_info.cursor_position
-}
-
-func get_term_size(out syscall.Handle) (coord, small_rect) {
- err := get_console_screen_buffer_info(out, &tmp_info)
- if err != nil {
- panic(err)
- }
- return tmp_info.size, tmp_info.window
-}
-
-func get_win_min_size(out syscall.Handle) coord {
- x, _, err := get_system_metrics.Call(SM_CXMIN)
- y, _, err := get_system_metrics.Call(SM_CYMIN)
-
- if x == 0 || y == 0 {
- if err != nil {
- panic(err)
- }
- }
-
- err1 := get_current_console_font(out, &tmp_finfo)
- if err1 != nil {
- panic(err1)
- }
-
- return coord{
- x: short(math.Ceil(float64(x) / float64(tmp_finfo.font_size.x))),
- y: short(math.Ceil(float64(y) / float64(tmp_finfo.font_size.y))),
- }
-}
-
-func get_win_size(out syscall.Handle) coord {
- err := get_console_screen_buffer_info(out, &tmp_info)
- if err != nil {
- panic(err)
- }
-
- min_size := get_win_min_size(out)
-
- size := coord{
- x: tmp_info.window.right - tmp_info.window.left + 1,
- y: tmp_info.window.bottom - tmp_info.window.top + 1,
- }
-
- if size.x < min_size.x {
- size.x = min_size.x
- }
-
- if size.y < min_size.y {
- size.y = min_size.y
- }
-
- return size
-}
-
-func fix_win_size(out syscall.Handle, size coord) (err error) {
- window := small_rect{}
- window.top = 0
- window.bottom = size.y - 1
- window.left = 0
- window.right = size.x - 1
- return set_console_window_info(out, &window)
-}
-
-func update_size_maybe() {
- size := get_win_size(out)
- if size.x != term_size.x || size.y != term_size.y {
- set_console_screen_buffer_size(out, size)
- fix_win_size(out, size)
- term_size = size
- back_buffer.resize(int(size.x), int(size.y))
- front_buffer.resize(int(size.x), int(size.y))
- front_buffer.clear()
- clear()
-
- area := int(size.x) * int(size.y)
- if cap(charbuf) < area {
- charbuf = make([]char_info, 0, area)
- }
- }
-}
-
-var color_table_bg = []word{
- 0, // default (black)
- 0, // black
- background_red,
- background_green,
- background_red | background_green, // yellow
- background_blue,
- background_red | background_blue, // magenta
- background_green | background_blue, // cyan
- background_red | background_blue | background_green, // white
-}
-
-var color_table_fg = []word{
- foreground_red | foreground_blue | foreground_green, // default (white)
- 0,
- foreground_red,
- foreground_green,
- foreground_red | foreground_green, // yellow
- foreground_blue,
- foreground_red | foreground_blue, // magenta
- foreground_green | foreground_blue, // cyan
- foreground_red | foreground_blue | foreground_green, // white
-}
-
-const (
- replacement_char = '\uFFFD'
- max_rune = '\U0010FFFF'
- surr1 = 0xd800
- surr2 = 0xdc00
- surr3 = 0xe000
- surr_self = 0x10000
-)
-
-func append_diff_line(y int) int {
- n := 0
- for x := 0; x < front_buffer.width; {
- cell_offset := y*front_buffer.width + x
- back := &back_buffer.cells[cell_offset]
- front := &front_buffer.cells[cell_offset]
- attr, char := cell_to_char_info(*back)
- charbuf = append(charbuf, char_info{attr: attr, char: char[0]})
- *front = *back
- n++
- w := runewidth.RuneWidth(back.Ch)
- if w == 0 || w == 2 && runewidth.IsAmbiguousWidth(back.Ch) {
- w = 1
- }
- x += w
- // If not CJK, fill trailing space with whitespace
- if !is_cjk && w == 2 {
- charbuf = append(charbuf, char_info{attr: attr, char: ' '})
- }
- }
- return n
-}
-
-// compares 'back_buffer' with 'front_buffer' and prepares all changes in the form of
-// 'diff_msg's in the 'diff_buf'
-func prepare_diff_messages() {
- // clear buffers
- diffbuf = diffbuf[:0]
- charbuf = charbuf[:0]
-
- var diff diff_msg
- gbeg := 0
- for y := 0; y < front_buffer.height; y++ {
- same := true
- line_offset := y * front_buffer.width
- for x := 0; x < front_buffer.width; x++ {
- cell_offset := line_offset + x
- back := &back_buffer.cells[cell_offset]
- front := &front_buffer.cells[cell_offset]
- if *back != *front {
- same = false
- break
- }
- }
- if same && diff.lines > 0 {
- diffbuf = append(diffbuf, diff)
- diff = diff_msg{}
- }
- if !same {
- beg := len(charbuf)
- end := beg + append_diff_line(y)
- if diff.lines == 0 {
- diff.pos = short(y)
- gbeg = beg
- }
- diff.lines++
- diff.chars = charbuf[gbeg:end]
- }
- }
- if diff.lines > 0 {
- diffbuf = append(diffbuf, diff)
- diff = diff_msg{}
- }
-}
-
-func get_ct(table []word, idx int) word {
- idx = idx & 0x0F
- if idx >= len(table) {
- idx = len(table) - 1
- }
- return table[idx]
-}
-
-func cell_to_char_info(c Cell) (attr word, wc [2]wchar) {
- attr = get_ct(color_table_fg, int(c.Fg)) | get_ct(color_table_bg, int(c.Bg))
- if c.Fg&AttrReverse|c.Bg&AttrReverse != 0 {
- attr = (attr&0xF0)>>4 | (attr&0x0F)<<4
- }
- if c.Fg&AttrBold != 0 {
- attr |= foreground_intensity
- }
- if c.Bg&AttrBold != 0 {
- attr |= background_intensity
- }
-
- r0, r1 := utf16.EncodeRune(c.Ch)
- if r0 == 0xFFFD {
- wc[0] = wchar(c.Ch)
- wc[1] = ' '
- } else {
- wc[0] = wchar(r0)
- wc[1] = wchar(r1)
- }
- return
-}
-
-func move_cursor(x, y int) {
- err := set_console_cursor_position(out, coord{short(x), short(y)})
- if err != nil {
- panic(err)
- }
-}
-
-func show_cursor(visible bool) {
- var v int32
- if visible {
- v = 1
- }
-
- var info console_cursor_info
- info.size = 100
- info.visible = v
- err := set_console_cursor_info(out, &info)
- if err != nil {
- panic(err)
- }
-}
-
-func clear() {
- var err error
- attr, char := cell_to_char_info(Cell{
- ' ',
- foreground,
- background,
- })
-
- area := int(term_size.x) * int(term_size.y)
- err = fill_console_output_attribute(out, attr, area)
- if err != nil {
- panic(err)
- }
- err = fill_console_output_character(out, char[0], area)
- if err != nil {
- panic(err)
- }
- if !is_cursor_hidden(cursor_x, cursor_y) {
- move_cursor(cursor_x, cursor_y)
- }
-}
-
-func key_event_record_to_event(r *key_event_record) (Event, bool) {
- if r.key_down == 0 {
- return Event{}, false
- }
-
- e := Event{Type: EventKey}
- if input_mode&InputAlt != 0 {
- if alt_mode_esc {
- e.Mod = ModAlt
- alt_mode_esc = false
- }
- if r.control_key_state&(left_alt_pressed|right_alt_pressed) != 0 {
- e.Mod = ModAlt
- }
- }
-
- ctrlpressed := r.control_key_state&(left_ctrl_pressed|right_ctrl_pressed) != 0
-
- if r.virtual_key_code >= vk_f1 && r.virtual_key_code <= vk_f12 {
- switch r.virtual_key_code {
- case vk_f1:
- e.Key = KeyF1
- case vk_f2:
- e.Key = KeyF2
- case vk_f3:
- e.Key = KeyF3
- case vk_f4:
- e.Key = KeyF4
- case vk_f5:
- e.Key = KeyF5
- case vk_f6:
- e.Key = KeyF6
- case vk_f7:
- e.Key = KeyF7
- case vk_f8:
- e.Key = KeyF8
- case vk_f9:
- e.Key = KeyF9
- case vk_f10:
- e.Key = KeyF10
- case vk_f11:
- e.Key = KeyF11
- case vk_f12:
- e.Key = KeyF12
- default:
- panic("unreachable")
- }
-
- return e, true
- }
-
- if r.virtual_key_code <= vk_delete {
- switch r.virtual_key_code {
- case vk_insert:
- e.Key = KeyInsert
- case vk_delete:
- e.Key = KeyDelete
- case vk_home:
- e.Key = KeyHome
- case vk_end:
- e.Key = KeyEnd
- case vk_pgup:
- e.Key = KeyPgup
- case vk_pgdn:
- e.Key = KeyPgdn
- case vk_arrow_up:
- e.Key = KeyArrowUp
- case vk_arrow_down:
- e.Key = KeyArrowDown
- case vk_arrow_left:
- e.Key = KeyArrowLeft
- case vk_arrow_right:
- e.Key = KeyArrowRight
- case vk_backspace:
- if ctrlpressed {
- e.Key = KeyBackspace2
- } else {
- e.Key = KeyBackspace
- }
- case vk_tab:
- e.Key = KeyTab
- case vk_enter:
- if ctrlpressed {
- e.Key = KeyCtrlJ
- } else {
- e.Key = KeyEnter
- }
- case vk_esc:
- switch {
- case input_mode&InputEsc != 0:
- e.Key = KeyEsc
- case input_mode&InputAlt != 0:
- alt_mode_esc = true
- return Event{}, false
- }
- case vk_space:
- if ctrlpressed {
- // manual return here, because KeyCtrlSpace is zero
- e.Key = KeyCtrlSpace
- return e, true
- } else {
- e.Key = KeySpace
- }
- }
-
- if e.Key != 0 {
- return e, true
- }
- }
-
- if ctrlpressed {
- if Key(r.unicode_char) >= KeyCtrlA && Key(r.unicode_char) <= KeyCtrlRsqBracket {
- e.Key = Key(r.unicode_char)
- if input_mode&InputAlt != 0 && e.Key == KeyEsc {
- alt_mode_esc = true
- return Event{}, false
- }
- return e, true
- }
- switch r.virtual_key_code {
- case 192, 50:
- // manual return here, because KeyCtrl2 is zero
- e.Key = KeyCtrl2
- return e, true
- case 51:
- if input_mode&InputAlt != 0 {
- alt_mode_esc = true
- return Event{}, false
- }
- e.Key = KeyCtrl3
- case 52:
- e.Key = KeyCtrl4
- case 53:
- e.Key = KeyCtrl5
- case 54:
- e.Key = KeyCtrl6
- case 189, 191, 55:
- e.Key = KeyCtrl7
- case 8, 56:
- e.Key = KeyCtrl8
- }
-
- if e.Key != 0 {
- return e, true
- }
- }
-
- if r.unicode_char != 0 {
- e.Ch = rune(r.unicode_char)
- return e, true
- }
-
- return Event{}, false
-}
-
-func input_event_producer() {
- var r input_record
- var err error
- var last_button Key
- var last_button_pressed Key
- var last_state = dword(0)
- var last_x, last_y = -1, -1
- handles := []syscall.Handle{in, interrupt}
- for {
- err = wait_for_multiple_objects(handles)
- if err != nil {
- input_comm <- Event{Type: EventError, Err: err}
- }
-
- select {
- case <-cancel_comm:
- cancel_done_comm <- true
- return
- default:
- }
-
- err = read_console_input(in, &r)
- if err != nil {
- input_comm <- Event{Type: EventError, Err: err}
- }
-
- switch r.event_type {
- case key_event:
- kr := (*key_event_record)(unsafe.Pointer(&r.event))
- ev, ok := key_event_record_to_event(kr)
- if ok {
- for i := 0; i < int(kr.repeat_count); i++ {
- input_comm <- ev
- }
- }
- case window_buffer_size_event:
- sr := *(*window_buffer_size_record)(unsafe.Pointer(&r.event))
- input_comm <- Event{
- Type: EventResize,
- Width: int(sr.size.x),
- Height: int(sr.size.y),
- }
- case mouse_event:
- mr := *(*mouse_event_record)(unsafe.Pointer(&r.event))
- ev := Event{Type: EventMouse}
- switch mr.event_flags {
- case 0, 2:
- // single or double click
- cur_state := mr.button_state
- switch {
- case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0:
- last_button = MouseLeft
- last_button_pressed = last_button
- case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0:
- last_button = MouseRight
- last_button_pressed = last_button
- case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0:
- last_button = MouseMiddle
- last_button_pressed = last_button
- case last_state&mouse_lmb != 0 && cur_state&mouse_lmb == 0:
- last_button = MouseRelease
- case last_state&mouse_rmb != 0 && cur_state&mouse_rmb == 0:
- last_button = MouseRelease
- case last_state&mouse_mmb != 0 && cur_state&mouse_mmb == 0:
- last_button = MouseRelease
- default:
- last_state = cur_state
- continue
- }
- last_state = cur_state
- ev.Key = last_button
- last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
- ev.MouseX = last_x
- ev.MouseY = last_y
- case 1:
- // mouse motion
- x, y := int(mr.mouse_pos.x), int(mr.mouse_pos.y)
- if last_state != 0 && (last_x != x || last_y != y) {
- ev.Key = last_button_pressed
- ev.Mod = ModMotion
- ev.MouseX = x
- ev.MouseY = y
- last_x, last_y = x, y
- } else {
- ev.Type = EventNone
- }
- case 4:
- // mouse wheel
- n := int16(mr.button_state >> 16)
- if n > 0 {
- ev.Key = MouseWheelUp
- } else {
- ev.Key = MouseWheelDown
- }
- last_x, last_y = int(mr.mouse_pos.x), int(mr.mouse_pos.y)
- ev.MouseX = last_x
- ev.MouseY = last_y
- default:
- ev.Type = EventNone
- }
- if ev.Type != EventNone {
- input_comm <- ev
- }
- }
- }
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo.go
deleted file mode 100644
index ab2e7a198..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo.go
+++ /dev/null
@@ -1,232 +0,0 @@
-// +build !windows
-// This file contains a simple and incomplete implementation of the terminfo
-// database. Information was taken from the ncurses manpages term(5) and
-// terminfo(5). Currently, only the string capabilities for special keys and for
-// functions without parameters are actually used. Colors are still done with
-// ANSI escape sequences. Other special features that are not (yet?) supported
-// are reading from ~/.terminfo, the TERMINFO_DIRS variable, Berkeley database
-// format and extended capabilities.
-
-package termbox
-
-import (
- "bytes"
- "encoding/binary"
- "encoding/hex"
- "errors"
- "fmt"
- "io/ioutil"
- "os"
- "strings"
-)
-
-const (
- ti_magic = 0432
- ti_header_length = 12
- ti_mouse_enter = "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h"
- ti_mouse_leave = "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l"
-)
-
-func load_terminfo() ([]byte, error) {
- var data []byte
- var err error
-
- term := os.Getenv("TERM")
- if term == "" {
- return nil, fmt.Errorf("termbox: TERM not set")
- }
-
- // The following behaviour follows the one described in terminfo(5) as
- // distributed by ncurses.
-
- terminfo := os.Getenv("TERMINFO")
- if terminfo != "" {
- // if TERMINFO is set, no other directory should be searched
- return ti_try_path(terminfo)
- }
-
- // next, consider ~/.terminfo
- home := os.Getenv("HOME")
- if home != "" {
- data, err = ti_try_path(home + "/.terminfo")
- if err == nil {
- return data, nil
- }
- }
-
- // next, TERMINFO_DIRS
- dirs := os.Getenv("TERMINFO_DIRS")
- if dirs != "" {
- for _, dir := range strings.Split(dirs, ":") {
- if dir == "" {
- // "" -> "/usr/share/terminfo"
- dir = "/usr/share/terminfo"
- }
- data, err = ti_try_path(dir)
- if err == nil {
- return data, nil
- }
- }
- }
-
- // next, /lib/terminfo
- data, err = ti_try_path("/lib/terminfo")
- if err == nil {
- return data, nil
- }
-
- // fall back to /usr/share/terminfo
- return ti_try_path("/usr/share/terminfo")
-}
-
-func ti_try_path(path string) (data []byte, err error) {
- // load_terminfo already made sure it is set
- term := os.Getenv("TERM")
-
- // first try, the typical *nix path
- terminfo := path + "/" + term[0:1] + "/" + term
- data, err = ioutil.ReadFile(terminfo)
- if err == nil {
- return
- }
-
- // fallback to darwin specific dirs structure
- terminfo = path + "/" + hex.EncodeToString([]byte(term[:1])) + "/" + term
- data, err = ioutil.ReadFile(terminfo)
- return
-}
-
-func setup_term_builtin() error {
- name := os.Getenv("TERM")
- if name == "" {
- return errors.New("termbox: TERM environment variable not set")
- }
-
- for _, t := range terms {
- if t.name == name {
- keys = t.keys
- funcs = t.funcs
- return nil
- }
- }
-
- compat_table := []struct {
- partial string
- keys []string
- funcs []string
- }{
- {"xterm", xterm_keys, xterm_funcs},
- {"rxvt", rxvt_unicode_keys, rxvt_unicode_funcs},
- {"linux", linux_keys, linux_funcs},
- {"Eterm", eterm_keys, eterm_funcs},
- {"screen", screen_keys, screen_funcs},
- // let's assume that 'cygwin' is xterm compatible
- {"cygwin", xterm_keys, xterm_funcs},
- {"st", xterm_keys, xterm_funcs},
- }
-
- // try compatibility variants
- for _, it := range compat_table {
- if strings.Contains(name, it.partial) {
- keys = it.keys
- funcs = it.funcs
- return nil
- }
- }
-
- return errors.New("termbox: unsupported terminal")
-}
-
-func setup_term() (err error) {
- var data []byte
- var header [6]int16
- var str_offset, table_offset int16
-
- data, err = load_terminfo()
- if err != nil {
- return setup_term_builtin()
- }
-
- rd := bytes.NewReader(data)
- // 0: magic number, 1: size of names section, 2: size of boolean section, 3:
- // size of numbers section (in integers), 4: size of the strings section (in
- // integers), 5: size of the string table
-
- err = binary.Read(rd, binary.LittleEndian, header[:])
- if err != nil {
- return
- }
-
- number_sec_len := int16(2)
- if header[0] == 542 { // doc says it should be octal 0542, but what I see it terminfo files is 542, learn to program please... thank you..
- number_sec_len = 4
- }
-
- if (header[1]+header[2])%2 != 0 {
- // old quirk to align everything on word boundaries
- header[2] += 1
- }
- str_offset = ti_header_length + header[1] + header[2] + number_sec_len*header[3]
- table_offset = str_offset + 2*header[4]
-
- keys = make([]string, 0xFFFF-key_min)
- for i, _ := range keys {
- keys[i], err = ti_read_string(rd, str_offset+2*ti_keys[i], table_offset)
- if err != nil {
- return
- }
- }
- funcs = make([]string, t_max_funcs)
- // the last two entries are reserved for mouse. because the table offset is
- // not there, the two entries have to fill in manually
- for i, _ := range funcs[:len(funcs)-2] {
- funcs[i], err = ti_read_string(rd, str_offset+2*ti_funcs[i], table_offset)
- if err != nil {
- return
- }
- }
- funcs[t_max_funcs-2] = ti_mouse_enter
- funcs[t_max_funcs-1] = ti_mouse_leave
- return nil
-}
-
-func ti_read_string(rd *bytes.Reader, str_off, table int16) (string, error) {
- var off int16
-
- _, err := rd.Seek(int64(str_off), 0)
- if err != nil {
- return "", err
- }
- err = binary.Read(rd, binary.LittleEndian, &off)
- if err != nil {
- return "", err
- }
- _, err = rd.Seek(int64(table+off), 0)
- if err != nil {
- return "", err
- }
- var bs []byte
- for {
- b, err := rd.ReadByte()
- if err != nil {
- return "", err
- }
- if b == byte(0x00) {
- break
- }
- bs = append(bs, b)
- }
- return string(bs), nil
-}
-
-// "Maps" the function constants from termbox.go to the number of the respective
-// string capability in the terminfo file. Taken from (ncurses) term.h.
-var ti_funcs = []int16{
- 28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88,
-}
-
-// Same as above for the special keys.
-var ti_keys = []int16{
- 66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69, 70,
- 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61, 79, 83,
-}
diff --git a/examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo_builtin.go b/examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo_builtin.go
deleted file mode 100644
index a94866067..000000000
--- a/examples/go-dashboard/src/github.com/nsf/termbox-go/terminfo_builtin.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// +build !windows
-
-package termbox
-
-// Eterm
-var eterm_keys = []string{
- "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
-}
-var eterm_funcs = []string{
- "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "",
-}
-
-// screen
-var screen_keys = []string{
- "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
-}
-var screen_funcs = []string{
- "\x1b[?1049h", "\x1b[?1049l", "\x1b[34h\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave,
-}
-
-// xterm
-var xterm_keys = []string{
- "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1bOH", "\x1bOF", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
-}
-var xterm_funcs = []string{
- "\x1b[?1049h", "\x1b[?1049l", "\x1b[?12l\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b(B\x1b[m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", ti_mouse_enter, ti_mouse_leave,
-}
-
-// rxvt-unicode
-var rxvt_unicode_keys = []string{
- "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
-}
-var rxvt_unicode_funcs = []string{
- "\x1b[?1049h", "\x1b[r\x1b[?1049l", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x1b(B", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave,
-}
-
-// linux
-var linux_keys = []string{
- "\x1b[[A", "\x1b[[B", "\x1b[[C", "\x1b[[D", "\x1b[[E", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
-}
-var linux_funcs = []string{
- "", "", "\x1b[?25h\x1b[?0c", "\x1b[?25l\x1b[?1c", "\x1b[H\x1b[J", "\x1b[0;10m", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "",
-}
-
-// rxvt-256color
-var rxvt_256color_keys = []string{
- "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
-}
-var rxvt_256color_funcs = []string{
- "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b=", "\x1b>", ti_mouse_enter, ti_mouse_leave,
-}
-
-var terms = []struct {
- name string
- keys []string
- funcs []string
-}{
- {"Eterm", eterm_keys, eterm_funcs},
- {"screen", screen_keys, screen_funcs},
- {"xterm", xterm_keys, xterm_funcs},
- {"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs},
- {"linux", linux_keys, linux_funcs},
- {"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs},
-}
diff --git a/examples/go-dashboard/src/ui/go.mod b/examples/go-dashboard/src/ui/go.mod
deleted file mode 100644
index 358d49b79..000000000
--- a/examples/go-dashboard/src/ui/go.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-module github.com/lnslbrty/nDPId/examples/go-dashboard/ui
-
-go 1.14
-
-require (
- github.com/mum4k/termdash v0.12.3-0.20200901030524-fe3e97353191
- github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 // indirect
-)
diff --git a/examples/go-dashboard/src/ui/ui.go b/examples/go-dashboard/src/ui/ui.go
deleted file mode 100644
index 8a42803dd..000000000
--- a/examples/go-dashboard/src/ui/ui.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package ui
-
-import (
- "context"
- "time"
-
- "github.com/mum4k/termdash"
- "github.com/mum4k/termdash/container"
- "github.com/mum4k/termdash/keyboard"
- "github.com/mum4k/termdash/linestyle"
- "github.com/mum4k/termdash/terminal/termbox"
- "github.com/mum4k/termdash/terminal/terminalapi"
- "github.com/mum4k/termdash/widgets/text"
-)
-
-const rootID = "root"
-const redrawInterval = 250 * time.Millisecond
-
-type Tui struct {
- Term terminalapi.Terminal
- Context context.Context
- Cancel context.CancelFunc
- Container *container.Container
- MainTicker *time.Ticker
-}
-
-type Widgets struct {
- Menu *text.Text
- RawJson *text.Text
-}
-
-func newWidgets(ctx context.Context) (*Widgets, error) {
- menu, err := text.New()
- if err != nil {
- panic(err)
- }
-
- rawJson, err := text.New(text.RollContent(), text.WrapAtWords())
- if err != nil {
- panic(err)
- }
-
- return &Widgets{
- Menu: menu,
- RawJson: rawJson,
- }, nil
-}
-
-func Init() (*Tui, *Widgets) {
- var err error
-
- ui := Tui{}
-
- ui.Term, err = termbox.New(termbox.ColorMode(terminalapi.ColorMode256))
- if err != nil {
- panic(err)
- }
-
- ui.Context, ui.Cancel = context.WithCancel(context.Background())
-
- wdgts, err := newWidgets(ui.Context)
- if err != nil {
- panic(err)
- }
-
- ui.Container, err = container.New(ui.Term,
- container.Border(linestyle.None),
- container.BorderTitle("[ESC to Quit]"),
- container.SplitHorizontal(
- container.Top(
- container.Border(linestyle.Light),
- container.BorderTitle("Go nDPId Dashboard"),
- container.PlaceWidget(wdgts.Menu),
- ),
- container.Bottom(
- container.Border(linestyle.Light),
- container.BorderTitle("Raw JSON"),
- container.PlaceWidget(wdgts.RawJson),
- ),
- container.SplitFixed(3),
- ),
- )
- if err != nil {
- panic(err)
- }
-
- ui.MainTicker = time.NewTicker(1 * time.Second)
-
- return &ui, wdgts
-}
-
-func Run(ui *Tui) {
- defer ui.Term.Close()
-
- quitter := func(k *terminalapi.Keyboard) {
- if k.Key == keyboard.KeyEsc || k.Key == keyboard.KeyCtrlC {
- ui.Cancel()
- }
- }
-
- if err := termdash.Run(ui.Context, ui.Term, ui.Container, termdash.KeyboardSubscriber(quitter), termdash.RedrawInterval(redrawInterval)); err != nil {
- panic(err)
- }
-}
diff --git a/examples/go-dashboard/src/ui/ui/go.mod b/examples/go-dashboard/src/ui/ui/go.mod
deleted file mode 100644
index 358d49b79..000000000
--- a/examples/go-dashboard/src/ui/ui/go.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-module github.com/lnslbrty/nDPId/examples/go-dashboard/ui
-
-go 1.14
-
-require (
- github.com/mum4k/termdash v0.12.3-0.20200901030524-fe3e97353191
- github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 // indirect
-)
diff --git a/examples/go-dashboard/src/ui/ui/ui.go b/examples/go-dashboard/src/ui/ui/ui.go
deleted file mode 100644
index 8a42803dd..000000000
--- a/examples/go-dashboard/src/ui/ui/ui.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package ui
-
-import (
- "context"
- "time"
-
- "github.com/mum4k/termdash"
- "github.com/mum4k/termdash/container"
- "github.com/mum4k/termdash/keyboard"
- "github.com/mum4k/termdash/linestyle"
- "github.com/mum4k/termdash/terminal/termbox"
- "github.com/mum4k/termdash/terminal/terminalapi"
- "github.com/mum4k/termdash/widgets/text"
-)
-
-const rootID = "root"
-const redrawInterval = 250 * time.Millisecond
-
-type Tui struct {
- Term terminalapi.Terminal
- Context context.Context
- Cancel context.CancelFunc
- Container *container.Container
- MainTicker *time.Ticker
-}
-
-type Widgets struct {
- Menu *text.Text
- RawJson *text.Text
-}
-
-func newWidgets(ctx context.Context) (*Widgets, error) {
- menu, err := text.New()
- if err != nil {
- panic(err)
- }
-
- rawJson, err := text.New(text.RollContent(), text.WrapAtWords())
- if err != nil {
- panic(err)
- }
-
- return &Widgets{
- Menu: menu,
- RawJson: rawJson,
- }, nil
-}
-
-func Init() (*Tui, *Widgets) {
- var err error
-
- ui := Tui{}
-
- ui.Term, err = termbox.New(termbox.ColorMode(terminalapi.ColorMode256))
- if err != nil {
- panic(err)
- }
-
- ui.Context, ui.Cancel = context.WithCancel(context.Background())
-
- wdgts, err := newWidgets(ui.Context)
- if err != nil {
- panic(err)
- }
-
- ui.Container, err = container.New(ui.Term,
- container.Border(linestyle.None),
- container.BorderTitle("[ESC to Quit]"),
- container.SplitHorizontal(
- container.Top(
- container.Border(linestyle.Light),
- container.BorderTitle("Go nDPId Dashboard"),
- container.PlaceWidget(wdgts.Menu),
- ),
- container.Bottom(
- container.Border(linestyle.Light),
- container.BorderTitle("Raw JSON"),
- container.PlaceWidget(wdgts.RawJson),
- ),
- container.SplitFixed(3),
- ),
- )
- if err != nil {
- panic(err)
- }
-
- ui.MainTicker = time.NewTicker(1 * time.Second)
-
- return &ui, wdgts
-}
-
-func Run(ui *Tui) {
- defer ui.Term.Close()
-
- quitter := func(k *terminalapi.Keyboard) {
- if k.Key == keyboard.KeyEsc || k.Key == keyboard.KeyCtrlC {
- ui.Cancel()
- }
- }
-
- if err := termdash.Run(ui.Context, ui.Term, ui.Container, termdash.KeyboardSubscriber(quitter), termdash.RedrawInterval(redrawInterval)); err != nil {
- panic(err)
- }
-}