vendor gocui

Michael Muré created

Change summary

Gopkg.lock                                                |   20 
vendor/github.com/jroimartin/gocui/.gitignore             |    1 
vendor/github.com/jroimartin/gocui/AUTHORS                |   24 
vendor/github.com/jroimartin/gocui/LICENSE                |   23 
vendor/github.com/jroimartin/gocui/README.md              |   91 
vendor/github.com/jroimartin/gocui/attribute.go           |   32 
vendor/github.com/jroimartin/gocui/doc.go                 |  116 
vendor/github.com/jroimartin/gocui/edit.go                |  341 ++
vendor/github.com/jroimartin/gocui/escape.go              |  168 +
vendor/github.com/jroimartin/gocui/gui.go                 |  646 ++++
vendor/github.com/jroimartin/gocui/keybinding.go          |  141 +
vendor/github.com/jroimartin/gocui/view.go                |  474 +++
vendor/github.com/mattn/go-runewidth/.travis.yml          |    8 
vendor/github.com/mattn/go-runewidth/LICENSE              |   21 
vendor/github.com/mattn/go-runewidth/README.mkd           |   27 
vendor/github.com/mattn/go-runewidth/runewidth.go         | 1223 +++++++++
vendor/github.com/mattn/go-runewidth/runewidth_js.go      |    8 
vendor/github.com/mattn/go-runewidth/runewidth_posix.go   |   77 
vendor/github.com/mattn/go-runewidth/runewidth_windows.go |   25 
vendor/github.com/nsf/termbox-go/AUTHORS                  |    4 
vendor/github.com/nsf/termbox-go/LICENSE                  |   19 
vendor/github.com/nsf/termbox-go/README.md                |   43 
vendor/github.com/nsf/termbox-go/api.go                   |  489 +++
vendor/github.com/nsf/termbox-go/api_common.go            |  187 +
vendor/github.com/nsf/termbox-go/api_windows.go           |  239 +
vendor/github.com/nsf/termbox-go/collect_terminfo.py      |  110 
vendor/github.com/nsf/termbox-go/escwait.go               |   11 
vendor/github.com/nsf/termbox-go/escwait_darwin.go        |    9 
vendor/github.com/nsf/termbox-go/syscalls.go              |   39 
vendor/github.com/nsf/termbox-go/syscalls_darwin.go       |   41 
vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go |   40 
vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go    |   39 
vendor/github.com/nsf/termbox-go/syscalls_freebsd.go      |   39 
vendor/github.com/nsf/termbox-go/syscalls_linux.go        |   33 
vendor/github.com/nsf/termbox-go/syscalls_netbsd.go       |   39 
vendor/github.com/nsf/termbox-go/syscalls_openbsd.go      |   39 
vendor/github.com/nsf/termbox-go/syscalls_windows.go      |   61 
vendor/github.com/nsf/termbox-go/termbox.go               |  529 +++
vendor/github.com/nsf/termbox-go/termbox_common.go        |   59 
vendor/github.com/nsf/termbox-go/termbox_windows.go       |  915 ++++++
vendor/github.com/nsf/termbox-go/terminfo.go              |  232 +
vendor/github.com/nsf/termbox-go/terminfo_builtin.go      |   64 
42 files changed, 6,745 insertions(+), 1 deletion(-)

Detailed changes

Gopkg.lock 🔗

@@ -49,6 +49,12 @@
   revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
   version = "v1.0"
 
+[[projects]]
+  name = "github.com/jroimartin/gocui"
+  packages = ["."]
+  revision = "4e9ce9a8e26f2ef33dfe297dbdfca148733b6b9b"
+  version = "v0.3.0"
+
 [[projects]]
   name = "github.com/mattn/go-colorable"
   packages = ["."]
@@ -61,6 +67,18 @@
   revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
   version = "v0.0.3"
 
+[[projects]]
+  name = "github.com/mattn/go-runewidth"
+  packages = ["."]
+  revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
+  version = "v0.0.2"
+
+[[projects]]
+  branch = "master"
+  name = "github.com/nsf/termbox-go"
+  packages = ["."]
+  revision = "5c94acc5e6eb520f1bcd183974e01171cc4c23b3"
+
 [[projects]]
   name = "github.com/phayes/freeport"
   packages = ["."]
@@ -136,6 +154,6 @@
 [solve-meta]
   analyzer-name = "dep"
   analyzer-version = 1
-  inputs-digest = "8eef4e36cf2c25bf253e53fb2a2a276a39715a847a6a05bb329870fe39af15a7"
+  inputs-digest = "793e41ab4418f9961ea3328a0233107af12a470e5237888891a7d52bd125c001"
   solver-name = "gps-cdcl"
   solver-version = 1

vendor/github.com/jroimartin/gocui/AUTHORS 🔗

@@ -0,0 +1,24 @@
+# This is the official list of gocui authors for copyright purposes.
+
+# Names should be added to this file as
+#	Name or Organization <email address> contribution
+#		Contribution
+# The email address is not required for organizations.
+
+Roi Martin <jroi.martin@gmail.com>
+	Main developer
+
+Ryan Sullivan <kayoticsully@gmail.com>
+	Toggleable view frames
+
+Matthieu Rakotojaona <matthieu.rakotojaona@gmail.com>
+	Wrapped views
+
+Harry Lawrence <hazbo@gmx.com>
+	Basic mouse support
+
+Danny Tylman <dtylman@gmail.com>
+	Masked views
+
+Frederik Deweerdt <frederik.deweerdt@gmail.com>
+	Colored fonts

vendor/github.com/jroimartin/gocui/LICENSE 🔗

@@ -0,0 +1,23 @@
+Copyright (c) 2014 The gocui Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the gocui Authors nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

vendor/github.com/jroimartin/gocui/README.md 🔗

@@ -0,0 +1,91 @@
+# GOCUI - Go Console User Interface
+
+[![GoDoc](https://godoc.org/github.com/jroimartin/gocui?status.svg)](https://godoc.org/github.com/jroimartin/gocui)
+
+Minimalist Go package aimed at creating Console User Interfaces.
+
+## Features
+
+* Minimalist API.
+* Views (the "windows" in the GUI) implement the interface io.ReadWriter.
+* Support for overlapping views.
+* The GUI can be modified at runtime (concurrent-safe).
+* Global and view-level keybindings.
+* Mouse support.
+* Colored text.
+* Customizable edition mode.
+
+## Installation
+
+Execute:
+
+```
+$ go get github.com/jroimartin/gocui
+```
+
+## Documentation
+
+Execute:
+
+```
+$ go doc github.com/jroimartin/gocui
+```
+
+Or visit [godoc.org](https://godoc.org/github.com/jroimartin/gocui) to read it
+online.
+
+## Example
+
+```go
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "Hello world!")
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+```
+
+## Screenshots
+
+_examples/demo.go:
+
+![_examples/demo.go](https://cloud.githubusercontent.com/assets/1223476/5992750/720b84f0-aa36-11e4-88ec-296fa3247b52.png)
+
+_examples/dynamic.go:
+
+![_examples/dynamic.go](https://cloud.githubusercontent.com/assets/1223476/5992751/76ad5cc2-aa36-11e4-8204-6a90269db827.png)

vendor/github.com/jroimartin/gocui/attribute.go 🔗

@@ -0,0 +1,32 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "github.com/nsf/termbox-go"
+
+// Attribute represents a terminal attribute, like color, font style, etc. They
+// can be combined using bitwise OR (|). Note that it is not possible to
+// combine multiple color attributes.
+type Attribute termbox.Attribute
+
+// Color attributes.
+const (
+	ColorDefault Attribute = Attribute(termbox.ColorDefault)
+	ColorBlack             = Attribute(termbox.ColorBlack)
+	ColorRed               = Attribute(termbox.ColorRed)
+	ColorGreen             = Attribute(termbox.ColorGreen)
+	ColorYellow            = Attribute(termbox.ColorYellow)
+	ColorBlue              = Attribute(termbox.ColorBlue)
+	ColorMagenta           = Attribute(termbox.ColorMagenta)
+	ColorCyan              = Attribute(termbox.ColorCyan)
+	ColorWhite             = Attribute(termbox.ColorWhite)
+)
+
+// Text style attributes.
+const (
+	AttrBold      Attribute = Attribute(termbox.AttrBold)
+	AttrUnderline           = Attribute(termbox.AttrUnderline)
+	AttrReverse             = Attribute(termbox.AttrReverse)
+)

vendor/github.com/jroimartin/gocui/doc.go 🔗

@@ -0,0 +1,116 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package gocui allows to create console user interfaces.
+
+Create a new GUI:
+
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		// handle error
+	}
+	defer g.Close()
+
+	// Set layout and key bindings
+	// ...
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		// handle error
+	}
+
+Set the layout function:
+
+	g.SetLayout(fcn)
+
+On each iteration of the GUI's main loop, the "layout function" is executed.
+These layout functions can be used to set-up and update the application's main
+views, being possible to freely switch between them. Also, it is important to
+mention that a main loop iteration is executed on each reported event
+(key-press, mouse event, window resize, etc).
+
+GUIs are composed by Views, you can think of it as buffers. Views implement the
+io.ReadWriter interface, so you can just write to them if you want to modify
+their content. The same is valid for reading.
+
+Create and initialize a view with absolute coordinates:
+
+	if v, err := g.SetView("viewname", 2, 2, 22, 7); err != nil {
+		if err != gocui.ErrUnknownView {
+			// handle error
+		}
+		fmt.Fprintln(v, "This is a new view")
+		// ...
+	}
+
+Views can also be created using relative coordinates:
+
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("viewname", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
+		// ...
+	}
+
+Configure keybindings:
+
+	if err := g.SetKeybinding("viewname", gocui.KeyEnter, gocui.ModNone, fcn); err != nil {
+		// handle error
+	}
+
+gocui implements full mouse support that can be enabled with:
+
+	g.Mouse = true
+
+Mouse events are handled like any other keybinding:
+
+	if err := g.SetKeybinding("viewname", gocui.MouseLeft, gocui.ModNone, fcn); err != nil {
+		// handle error
+	}
+
+IMPORTANT: Views can only be created, destroyed or updated in three ways: from
+layout functions, from keybinding callbacks or via *Gui.Execute(). The reason
+for this is that it allows gocui to be conccurent-safe. So, if you want to
+update your GUI from a goroutine, you must use *Gui.Execute(). For example:
+
+	g.Execute(func(g *gocui.Gui) error {
+		v, err := g.View("viewname")
+		if err != nil {
+			// handle error
+		}
+		v.Clear()
+		fmt.Fprintln(v, "Writing from different goroutines")
+		return nil
+	})
+
+By default, gocui provides a basic edition mode. This mode can be extended
+and customized creating a new Editor and assigning it to *Gui.Editor:
+
+	type Editor interface {
+		Edit(v *View, key Key, ch rune, mod Modifier)
+	}
+
+DefaultEditor can be taken as example to create your own custom Editor:
+
+	var DefaultEditor Editor = EditorFunc(simpleEditor)
+
+	func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
+		switch {
+		case ch != 0 && mod == 0:
+			v.EditWrite(ch)
+		case key == KeySpace:
+			v.EditWrite(' ')
+		case key == KeyBackspace || key == KeyBackspace2:
+			v.EditDelete(true)
+		// ...
+		}
+	}
+
+Colored text:
+
+Views allow to add colored text using ANSI colors. For example:
+
+	fmt.Fprintln(v, "\x1b[0;31mHello world")
+
+For more information, see the examples in folder "_examples/".
+*/
+package gocui

vendor/github.com/jroimartin/gocui/edit.go 🔗

@@ -0,0 +1,341 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "errors"
+
+const maxInt = int(^uint(0) >> 1)
+
+// Editor interface must be satisfied by gocui editors.
+type Editor interface {
+	Edit(v *View, key Key, ch rune, mod Modifier)
+}
+
+// The EditorFunc type is an adapter to allow the use of ordinary functions as
+// Editors. If f is a function with the appropriate signature, EditorFunc(f)
+// is an Editor object that calls f.
+type EditorFunc func(v *View, key Key, ch rune, mod Modifier)
+
+// Edit calls f(v, key, ch, mod)
+func (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) {
+	f(v, key, ch, mod)
+}
+
+// DefaultEditor is the default editor.
+var DefaultEditor Editor = EditorFunc(simpleEditor)
+
+// simpleEditor is used as the default gocui editor.
+func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
+	switch {
+	case ch != 0 && mod == 0:
+		v.EditWrite(ch)
+	case key == KeySpace:
+		v.EditWrite(' ')
+	case key == KeyBackspace || key == KeyBackspace2:
+		v.EditDelete(true)
+	case key == KeyDelete:
+		v.EditDelete(false)
+	case key == KeyInsert:
+		v.Overwrite = !v.Overwrite
+	case key == KeyEnter:
+		v.EditNewLine()
+	case key == KeyArrowDown:
+		v.MoveCursor(0, 1, false)
+	case key == KeyArrowUp:
+		v.MoveCursor(0, -1, false)
+	case key == KeyArrowLeft:
+		v.MoveCursor(-1, 0, false)
+	case key == KeyArrowRight:
+		v.MoveCursor(1, 0, false)
+	}
+}
+
+// EditWrite writes a rune at the cursor position.
+func (v *View) EditWrite(ch rune) {
+	v.writeRune(v.cx, v.cy, ch)
+	v.MoveCursor(1, 0, true)
+}
+
+// EditDelete deletes a rune at the cursor position. back determines the
+// direction.
+func (v *View) EditDelete(back bool) {
+	x, y := v.ox+v.cx, v.oy+v.cy
+	if y < 0 {
+		return
+	} else if y >= len(v.viewLines) {
+		v.MoveCursor(-1, 0, true)
+		return
+	}
+
+	maxX, _ := v.Size()
+	if back {
+		if x == 0 { // start of the line
+			if y < 1 {
+				return
+			}
+
+			var maxPrevWidth int
+			if v.Wrap {
+				maxPrevWidth = maxX
+			} else {
+				maxPrevWidth = maxInt
+			}
+
+			if v.viewLines[y].linesX == 0 { // regular line
+				v.mergeLines(v.cy - 1)
+				if len(v.viewLines[y-1].line) < maxPrevWidth {
+					v.MoveCursor(-1, 0, true)
+				}
+			} else { // wrapped line
+				v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
+				v.MoveCursor(-1, 0, true)
+			}
+		} else { // middle/end of the line
+			v.deleteRune(v.cx-1, v.cy)
+			v.MoveCursor(-1, 0, true)
+		}
+	} else {
+		if x == len(v.viewLines[y].line) { // end of the line
+			v.mergeLines(v.cy)
+		} else { // start/middle of the line
+			v.deleteRune(v.cx, v.cy)
+		}
+	}
+}
+
+// EditNewLine inserts a new line under the cursor.
+func (v *View) EditNewLine() {
+	v.breakLine(v.cx, v.cy)
+
+	y := v.oy + v.cy
+	if y >= len(v.viewLines) || (y >= 0 && y < len(v.viewLines) &&
+		!(v.Wrap && v.cx == 0 && v.viewLines[y].linesX > 0)) {
+		// new line at the end of the buffer or
+		// cursor is not at the beginning of a wrapped line
+		v.ox = 0
+		v.cx = 0
+		v.MoveCursor(0, 1, true)
+	}
+}
+
+// MoveCursor moves the cursor taking into account the width of the line/view,
+// displacing the origin if necessary.
+func (v *View) MoveCursor(dx, dy int, writeMode bool) {
+	maxX, maxY := v.Size()
+	cx, cy := v.cx+dx, v.cy+dy
+	x, y := v.ox+cx, v.oy+cy
+
+	var curLineWidth, prevLineWidth int
+	// get the width of the current line
+	if writeMode {
+		if v.Wrap {
+			curLineWidth = maxX - 1
+		} else {
+			curLineWidth = maxInt
+		}
+	} else {
+		if y >= 0 && y < len(v.viewLines) {
+			curLineWidth = len(v.viewLines[y].line)
+			if v.Wrap && curLineWidth >= maxX {
+				curLineWidth = maxX - 1
+			}
+		} else {
+			curLineWidth = 0
+		}
+	}
+	// get the width of the previous line
+	if y-1 >= 0 && y-1 < len(v.viewLines) {
+		prevLineWidth = len(v.viewLines[y-1].line)
+	} else {
+		prevLineWidth = 0
+	}
+
+	// adjust cursor's x position and view's x origin
+	if x > curLineWidth { // move to next line
+		if dx > 0 { // horizontal movement
+			if !v.Wrap {
+				v.ox = 0
+			}
+			v.cx = 0
+			cy++
+		} else { // vertical movement
+			if curLineWidth > 0 { // move cursor to the EOL
+				if v.Wrap {
+					v.cx = curLineWidth
+				} else {
+					ncx := curLineWidth - v.ox
+					if ncx < 0 {
+						v.ox += ncx
+						if v.ox < 0 {
+							v.ox = 0
+						}
+						v.cx = 0
+					} else {
+						v.cx = ncx
+					}
+				}
+			} else {
+				if !v.Wrap {
+					v.ox = 0
+				}
+				v.cx = 0
+			}
+		}
+	} else if cx < 0 {
+		if !v.Wrap && v.ox > 0 { // move origin to the left
+			v.ox--
+		} else { // move to previous line
+			if prevLineWidth > 0 {
+				if !v.Wrap { // set origin so the EOL is visible
+					nox := prevLineWidth - maxX + 1
+					if nox < 0 {
+						v.ox = 0
+					} else {
+						v.ox = nox
+					}
+				}
+				v.cx = prevLineWidth
+			} else {
+				if !v.Wrap {
+					v.ox = 0
+				}
+				v.cx = 0
+			}
+			cy--
+		}
+	} else { // stay on the same line
+		if v.Wrap {
+			v.cx = cx
+		} else {
+			if cx >= maxX {
+				v.ox++
+			} else {
+				v.cx = cx
+			}
+		}
+	}
+
+	// adjust cursor's y position and view's y origin
+	if cy >= maxY {
+		v.oy++
+	} else if cy < 0 {
+		if v.oy > 0 {
+			v.oy--
+		}
+	} else {
+		v.cy = cy
+	}
+}
+
+// writeRune writes a rune into the view's internal buffer, at the
+// position corresponding to the point (x, y). The length of the internal
+// buffer is increased if the point is out of bounds. Overwrite mode is
+// governed by the value of View.overwrite.
+func (v *View) writeRune(x, y int, ch rune) error {
+	v.tainted = true
+
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return err
+	}
+
+	if x < 0 || y < 0 {
+		return errors.New("invalid point")
+	}
+
+	if y >= len(v.lines) {
+		s := make([][]cell, y-len(v.lines)+1)
+		v.lines = append(v.lines, s...)
+	}
+
+	olen := len(v.lines[y])
+	if x >= len(v.lines[y]) {
+		s := make([]cell, x-len(v.lines[y])+1)
+		v.lines[y] = append(v.lines[y], s...)
+	}
+
+	c := cell{
+		fgColor: v.FgColor,
+		bgColor: v.BgColor,
+	}
+	if !v.Overwrite || (v.Overwrite && x >= olen-1) {
+		c.chr = '\x00'
+		v.lines[y] = append(v.lines[y], c)
+		copy(v.lines[y][x+1:], v.lines[y][x:])
+	}
+	c.chr = ch
+	v.lines[y][x] = c
+	return nil
+}
+
+// deleteRune removes a rune from the view's internal buffer, at the
+// position corresponding to the point (x, y).
+func (v *View) deleteRune(x, y int) error {
+	v.tainted = true
+
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return err
+	}
+
+	if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
+		return errors.New("invalid point")
+	}
+	v.lines[y] = append(v.lines[y][:x], v.lines[y][x+1:]...)
+	return nil
+}
+
+// mergeLines merges the lines "y" and "y+1" if possible.
+func (v *View) mergeLines(y int) error {
+	v.tainted = true
+
+	_, y, err := v.realPosition(0, y)
+	if err != nil {
+		return err
+	}
+
+	if y < 0 || y >= len(v.lines) {
+		return errors.New("invalid point")
+	}
+
+	if y < len(v.lines)-1 { // otherwise we don't need to merge anything
+		v.lines[y] = append(v.lines[y], v.lines[y+1]...)
+		v.lines = append(v.lines[:y+1], v.lines[y+2:]...)
+	}
+	return nil
+}
+
+// breakLine breaks a line of the internal buffer at the position corresponding
+// to the point (x, y).
+func (v *View) breakLine(x, y int) error {
+	v.tainted = true
+
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return err
+	}
+
+	if y < 0 || y >= len(v.lines) {
+		return errors.New("invalid point")
+	}
+
+	var left, right []cell
+	if x < len(v.lines[y]) { // break line
+		left = make([]cell, len(v.lines[y][:x]))
+		copy(left, v.lines[y][:x])
+		right = make([]cell, len(v.lines[y][x:]))
+		copy(right, v.lines[y][x:])
+	} else { // new empty line
+		left = v.lines[y]
+	}
+
+	lines := make([][]cell, len(v.lines)+1)
+	lines[y] = left
+	lines[y+1] = right
+	copy(lines, v.lines[:y])
+	copy(lines[y+2:], v.lines[y+1:])
+	v.lines = lines
+	return nil
+}

vendor/github.com/jroimartin/gocui/escape.go 🔗

@@ -0,0 +1,168 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+	"errors"
+	"strconv"
+)
+
+type escapeInterpreter struct {
+	state                  escapeState
+	curch                  rune
+	csiParam               []string
+	curFgColor, curBgColor Attribute
+}
+
+type escapeState int
+
+const (
+	stateNone escapeState = iota
+	stateEscape
+	stateCSI
+	stateParams
+)
+
+var (
+	errNotCSI        = errors.New("Not a CSI escape sequence")
+	errCSINotANumber = errors.New("CSI escape sequence was expecting a number or a ;")
+	errCSIParseError = errors.New("CSI escape sequence parsing error")
+	errCSITooLong    = errors.New("CSI escape sequence is too long")
+)
+
+// runes in case of error will output the non-parsed runes as a string.
+func (ei *escapeInterpreter) runes() []rune {
+	switch ei.state {
+	case stateNone:
+		return []rune{0x1b}
+	case stateEscape:
+		return []rune{0x1b, ei.curch}
+	case stateCSI:
+		return []rune{0x1b, '[', ei.curch}
+	case stateParams:
+		ret := []rune{0x1b, '['}
+		for _, s := range ei.csiParam {
+			ret = append(ret, []rune(s)...)
+			ret = append(ret, ';')
+		}
+		return append(ret, ei.curch)
+	}
+	return nil
+}
+
+// newEscapeInterpreter returns an escapeInterpreter that will be able to parse
+// terminal escape sequences.
+func newEscapeInterpreter() *escapeInterpreter {
+	ei := &escapeInterpreter{
+		state:      stateNone,
+		curFgColor: ColorDefault,
+		curBgColor: ColorDefault,
+	}
+	return ei
+}
+
+// reset sets the escapeInterpreter in initial state.
+func (ei *escapeInterpreter) reset() {
+	ei.state = stateNone
+	ei.curFgColor = ColorDefault
+	ei.curBgColor = ColorDefault
+	ei.csiParam = nil
+}
+
+// paramToColor returns an attribute given a terminfo coloring.
+func paramToColor(p int) Attribute {
+	switch p {
+	case 0:
+		return ColorBlack
+	case 1:
+		return ColorRed
+	case 2:
+		return ColorGreen
+	case 3:
+		return ColorYellow
+	case 4:
+		return ColorBlue
+	case 5:
+		return ColorMagenta
+	case 6:
+		return ColorCyan
+	case 7:
+		return ColorWhite
+	}
+	return ColorDefault
+}
+
+// parseOne parses a rune. If isEscape is true, it means that the rune is part
+// of an escape sequence, and as such should not be printed verbatim. Otherwise,
+// it's not an escape sequence.
+func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) {
+	// Sanity checks to make sure we're not parsing something totally bogus.
+	if len(ei.csiParam) > 20 {
+		return false, errCSITooLong
+	}
+	if len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 {
+		return false, errCSITooLong
+	}
+	ei.curch = ch
+	switch ei.state {
+	case stateNone:
+		if ch == 0x1b {
+			ei.state = stateEscape
+			return true, nil
+		}
+		return false, nil
+	case stateEscape:
+		if ch == '[' {
+			ei.state = stateCSI
+			return true, nil
+		}
+		return false, errNotCSI
+	case stateCSI:
+		if ch >= '0' && ch <= '9' {
+			ei.state = stateParams
+			ei.csiParam = append(ei.csiParam, string(ch))
+			return true, nil
+		}
+		return false, errCSINotANumber
+	case stateParams:
+		switch {
+		case ch >= '0' && ch <= '9':
+			ei.csiParam[len(ei.csiParam)-1] += string(ch)
+			return true, nil
+		case ch == ';':
+			ei.csiParam = append(ei.csiParam, "")
+			return true, nil
+		case ch == 'm':
+			if len(ei.csiParam) < 1 {
+				return false, errCSIParseError
+			}
+			for _, param := range ei.csiParam {
+				p, err := strconv.Atoi(param)
+				if err != nil {
+					return false, errCSIParseError
+				}
+				switch {
+				case p >= 30 && p <= 37:
+					ei.curFgColor = paramToColor(p - 30)
+				case p >= 40 && p <= 47:
+					ei.curBgColor = paramToColor(p - 40)
+				case p == 1:
+					ei.curFgColor |= AttrBold
+				case p == 4:
+					ei.curFgColor |= AttrUnderline
+				case p == 7:
+					ei.curFgColor |= AttrReverse
+				case p == 0 || p == 39:
+					ei.curFgColor = ColorDefault
+					ei.curBgColor = ColorDefault
+				}
+			}
+			ei.state = stateNone
+			ei.csiParam = nil
+			return true, nil
+		}
+	}
+	return false, nil
+}

vendor/github.com/jroimartin/gocui/gui.go 🔗

@@ -0,0 +1,646 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+	"errors"
+
+	"github.com/nsf/termbox-go"
+)
+
+// Handler represents a handler that can be used to update or modify the GUI.
+type Handler func(*Gui) error
+
+// userEvent represents an event triggered by the user.
+type userEvent struct {
+	h Handler
+}
+
+var (
+	// ErrQuit is used to decide if the MainLoop finished successfully.
+	ErrQuit = errors.New("quit")
+
+	// ErrUnknownView allows to assert if a View must be initialized.
+	ErrUnknownView = errors.New("unknown view")
+)
+
+// Gui represents the whole User Interface, including the views, layouts
+// and keybindings.
+type Gui struct {
+	tbEvents    chan termbox.Event
+	userEvents  chan userEvent
+	views       []*View
+	currentView *View
+	layout      Handler
+	keybindings []*keybinding
+	maxX, maxY  int
+
+	// BgColor and FgColor allow to configure the background and foreground
+	// colors of the GUI.
+	BgColor, FgColor Attribute
+
+	// SelBgColor and SelFgColor are used to configure the background and
+	// foreground colors of the selected line, when it is highlighted.
+	SelBgColor, SelFgColor Attribute
+
+	// If Cursor is true then the cursor is enabled.
+	Cursor bool
+
+	// If Mouse is true then mouse events will be enabled.
+	Mouse bool
+
+	// If InputEsc is true, when ESC sequence is in the buffer and it doesn't
+	// match any known sequence, ESC means KeyEsc.
+	InputEsc bool
+
+	// Editor allows to define the editor that manages the edition mode,
+	// including keybindings or cursor behaviour. DefaultEditor is used by
+	// default.
+	Editor Editor
+}
+
+// NewGui returns a new Gui object.
+func NewGui() *Gui {
+	return &Gui{}
+}
+
+// Init initializes the library. This function must be called before
+// any other functions.
+func (g *Gui) Init() error {
+	if err := termbox.Init(); err != nil {
+		return err
+	}
+	g.tbEvents = make(chan termbox.Event, 20)
+	g.userEvents = make(chan userEvent, 20)
+	g.maxX, g.maxY = termbox.Size()
+	g.BgColor = ColorBlack
+	g.FgColor = ColorWhite
+	g.Editor = DefaultEditor
+	return nil
+}
+
+// Close finalizes the library. It should be called after a successful
+// initialization and when gocui is not needed anymore.
+func (g *Gui) Close() {
+	termbox.Close()
+}
+
+// Size returns the terminal's size.
+func (g *Gui) Size() (x, y int) {
+	return g.maxX, g.maxY
+}
+
+// SetRune writes a rune at the given point, relative to the top-left
+// corner of the terminal. It checks if the position is valid and applies
+// the gui's colors.
+func (g *Gui) SetRune(x, y int, ch rune) error {
+	if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+		return errors.New("invalid point")
+	}
+	termbox.SetCell(x, y, ch, termbox.Attribute(g.FgColor), termbox.Attribute(g.BgColor))
+	return nil
+}
+
+// Rune returns the rune contained in the cell at the given position.
+// It checks if the position is valid.
+func (g *Gui) Rune(x, y int) (rune, error) {
+	if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+		return ' ', errors.New("invalid point")
+	}
+	c := termbox.CellBuffer()[y*g.maxX+x]
+	return c.Ch, nil
+}
+
+// SetView creates a new view with its top-left corner at (x0, y0)
+// and the bottom-right one at (x1, y1). If a view with the same name
+// already exists, its dimensions are updated; otherwise, the error
+// ErrUnknownView is returned, which allows to assert if the View must
+// be initialized. It checks if the position is valid.
+func (g *Gui) SetView(name string, x0, y0, x1, y1 int) (*View, error) {
+	if x0 >= x1 || y0 >= y1 {
+		return nil, errors.New("invalid dimensions")
+	}
+	if name == "" {
+		return nil, errors.New("invalid name")
+	}
+
+	if v, err := g.View(name); err == nil {
+		v.x0 = x0
+		v.y0 = y0
+		v.x1 = x1
+		v.y1 = y1
+		v.tainted = true
+		return v, nil
+	}
+
+	v := newView(name, x0, y0, x1, y1)
+	v.BgColor, v.FgColor = g.BgColor, g.FgColor
+	v.SelBgColor, v.SelFgColor = g.SelBgColor, g.SelFgColor
+	g.views = append(g.views, v)
+	return v, ErrUnknownView
+}
+
+// SetViewOnTop sets the given view on top of the existing ones.
+func (g *Gui) SetViewOnTop(name string) (*View, error) {
+	for i, v := range g.views {
+		if v.name == name {
+			s := append(g.views[:i], g.views[i+1:]...)
+			g.views = append(s, v)
+			return v, nil
+		}
+	}
+	return nil, ErrUnknownView
+}
+
+// View returns a pointer to the view with the given name, or error
+// ErrUnknownView if a view with that name does not exist.
+func (g *Gui) View(name string) (*View, error) {
+	for _, v := range g.views {
+		if v.name == name {
+			return v, nil
+		}
+	}
+	return nil, ErrUnknownView
+}
+
+// ViewByPosition returns a pointer to a view matching the given position, or
+// error ErrUnknownView if a view in that position does not exist.
+func (g *Gui) ViewByPosition(x, y int) (*View, error) {
+	for _, v := range g.views {
+		if x > v.x0 && x < v.x1 && y > v.y0 && y < v.y1 {
+			return v, nil
+		}
+	}
+	return nil, ErrUnknownView
+}
+
+// ViewPosition returns the coordinates of the view with the given name, or
+// error ErrUnknownView if a view with that name does not exist.
+func (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) {
+	for _, v := range g.views {
+		if v.name == name {
+			return v.x0, v.y0, v.x1, v.y1, nil
+		}
+	}
+	return 0, 0, 0, 0, ErrUnknownView
+}
+
+// DeleteView deletes a view by name.
+func (g *Gui) DeleteView(name string) error {
+	for i, v := range g.views {
+		if v.name == name {
+			g.views = append(g.views[:i], g.views[i+1:]...)
+			return nil
+		}
+	}
+	return ErrUnknownView
+}
+
+// SetCurrentView gives the focus to a given view.
+func (g *Gui) SetCurrentView(name string) error {
+	for _, v := range g.views {
+		if v.name == name {
+			g.currentView = v
+			return nil
+		}
+	}
+	return ErrUnknownView
+}
+
+// CurrentView returns the currently focused view, or nil if no view
+// owns the focus.
+func (g *Gui) CurrentView() *View {
+	return g.currentView
+}
+
+// SetKeybinding creates a new keybinding. If viewname equals to ""
+// (empty string) then the keybinding will apply to all views. key must
+// be a rune or a Key.
+func (g *Gui) SetKeybinding(viewname string, key interface{}, mod Modifier, h KeybindingHandler) error {
+	var kb *keybinding
+
+	k, ch, err := getKey(key)
+	if err != nil {
+		return err
+	}
+	kb = newKeybinding(viewname, k, ch, mod, h)
+	g.keybindings = append(g.keybindings, kb)
+	return nil
+}
+
+// DeleteKeybinding deletes a keybinding.
+func (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod Modifier) error {
+	k, ch, err := getKey(key)
+	if err != nil {
+		return err
+	}
+
+	for i, kb := range g.keybindings {
+		if kb.viewName == viewname && kb.ch == ch && kb.key == k && kb.mod == mod {
+			g.keybindings = append(g.keybindings[:i], g.keybindings[i+1:]...)
+			return nil
+		}
+	}
+	return errors.New("keybinding not found")
+}
+
+// DeleteKeybindings deletes all keybindings of view.
+func (g *Gui) DeleteKeybindings(viewname string) {
+	var s []*keybinding
+	for _, kb := range g.keybindings {
+		if kb.viewName != viewname {
+			s = append(s, kb)
+		}
+	}
+	g.keybindings = s
+}
+
+// getKey takes an empty interface with a key and returns the corresponding
+// typed Key or rune.
+func getKey(key interface{}) (Key, rune, error) {
+	switch t := key.(type) {
+	case Key:
+		return t, 0, nil
+	case rune:
+		return 0, t, nil
+	default:
+		return 0, 0, errors.New("unknown type")
+	}
+}
+
+// Execute executes the given handler. This function can be called safely from
+// a goroutine in order to update the GUI. It is important to note that it
+// won't be executed immediately, instead it will be added to the user events
+// queue.
+func (g *Gui) Execute(h Handler) {
+	go func() { g.userEvents <- userEvent{h: h} }()
+}
+
+// SetLayout sets the current layout. A layout is a function that
+// will be called every time the gui is redrawn, it must contain
+// the base views and its initializations.
+func (g *Gui) SetLayout(layout Handler) {
+	g.layout = layout
+	g.currentView = nil
+	g.views = nil
+	go func() { g.tbEvents <- termbox.Event{Type: termbox.EventResize} }()
+}
+
+// MainLoop runs the main loop until an error is returned. A successful
+// finish should return ErrQuit.
+func (g *Gui) MainLoop() error {
+	go func() {
+		for {
+			g.tbEvents <- termbox.PollEvent()
+		}
+	}()
+
+	inputMode := termbox.InputAlt
+	if g.InputEsc {
+		inputMode = termbox.InputEsc
+	}
+	if g.Mouse {
+		inputMode |= termbox.InputMouse
+	}
+	termbox.SetInputMode(inputMode)
+
+	if err := g.flush(); err != nil {
+		return err
+	}
+	for {
+		select {
+		case ev := <-g.tbEvents:
+			if err := g.handleEvent(&ev); err != nil {
+				return err
+			}
+		case ev := <-g.userEvents:
+			if err := ev.h(g); err != nil {
+				return err
+			}
+		}
+		if err := g.consumeevents(); err != nil {
+			return err
+		}
+		if err := g.flush(); err != nil {
+			return err
+		}
+	}
+}
+
+// consumeevents handles the remaining events in the events pool.
+func (g *Gui) consumeevents() error {
+	for {
+		select {
+		case ev := <-g.tbEvents:
+			if err := g.handleEvent(&ev); err != nil {
+				return err
+			}
+		case ev := <-g.userEvents:
+			if err := ev.h(g); err != nil {
+				return err
+			}
+		default:
+			return nil
+		}
+	}
+}
+
+// handleEvent handles an event, based on its type (key-press, error,
+// etc.)
+func (g *Gui) handleEvent(ev *termbox.Event) error {
+	switch ev.Type {
+	case termbox.EventKey, termbox.EventMouse:
+		return g.onKey(ev)
+	case termbox.EventError:
+		return ev.Err
+	default:
+		return nil
+	}
+}
+
+// flush updates the gui, re-drawing frames and buffers.
+func (g *Gui) flush() error {
+	if g.layout == nil {
+		return errors.New("Null layout")
+	}
+
+	termbox.Clear(termbox.Attribute(g.FgColor), termbox.Attribute(g.BgColor))
+
+	maxX, maxY := termbox.Size()
+	// if GUI's size has changed, we need to redraw all views
+	if maxX != g.maxX || maxY != g.maxY {
+		for _, v := range g.views {
+			v.tainted = true
+		}
+	}
+	g.maxX, g.maxY = maxX, maxY
+
+	if err := g.layout(g); err != nil {
+		return err
+	}
+	for _, v := range g.views {
+		if v.Frame {
+			if err := g.drawFrame(v); err != nil {
+				return err
+			}
+			if err := g.drawCorners(v); err != nil {
+				return err
+			}
+			if v.Title != "" {
+				if err := g.drawTitle(v); err != nil {
+					return err
+				}
+			}
+		}
+
+		if err := g.draw(v); err != nil {
+			return err
+		}
+	}
+	if err := g.drawIntersections(); err != nil {
+		return err
+	}
+	termbox.Flush()
+	return nil
+
+}
+
+// drawFrame draws the horizontal and vertical edges of a view.
+func (g *Gui) drawFrame(v *View) error {
+	for x := v.x0 + 1; x < v.x1 && x < g.maxX; x++ {
+		if x < 0 {
+			continue
+		}
+		if v.y0 > -1 && v.y0 < g.maxY {
+			if err := g.SetRune(x, v.y0, '─'); err != nil {
+				return err
+			}
+		}
+		if v.y1 > -1 && v.y1 < g.maxY {
+			if err := g.SetRune(x, v.y1, '─'); err != nil {
+				return err
+			}
+		}
+	}
+	for y := v.y0 + 1; y < v.y1 && y < g.maxY; y++ {
+		if y < 0 {
+			continue
+		}
+		if v.x0 > -1 && v.x0 < g.maxX {
+			if err := g.SetRune(v.x0, y, '│'); err != nil {
+				return err
+			}
+		}
+		if v.x1 > -1 && v.x1 < g.maxX {
+			if err := g.SetRune(v.x1, y, '│'); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// drawCorners draws the corners of the view.
+func (g *Gui) drawCorners(v *View) error {
+	if v.x0 >= 0 && v.y0 >= 0 && v.x0 < g.maxX && v.y0 < g.maxY {
+		if err := g.SetRune(v.x0, v.y0, '┌'); err != nil {
+			return err
+		}
+	}
+	if v.x1 >= 0 && v.y0 >= 0 && v.x1 < g.maxX && v.y0 < g.maxY {
+		if err := g.SetRune(v.x1, v.y0, '┐'); err != nil {
+			return err
+		}
+	}
+	if v.x0 >= 0 && v.y1 >= 0 && v.x0 < g.maxX && v.y1 < g.maxY {
+		if err := g.SetRune(v.x0, v.y1, '└'); err != nil {
+			return err
+		}
+	}
+	if v.x1 >= 0 && v.y1 >= 0 && v.x1 < g.maxX && v.y1 < g.maxY {
+		if err := g.SetRune(v.x1, v.y1, '┘'); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// drawTitle draws the title of the view.
+func (g *Gui) drawTitle(v *View) error {
+	if v.y0 < 0 || v.y0 >= g.maxY {
+		return nil
+	}
+
+	for i, ch := range v.Title {
+		x := v.x0 + i + 2
+		if x < 0 {
+			continue
+		} else if x > v.x1-2 || x >= g.maxX {
+			break
+		}
+		if err := g.SetRune(x, v.y0, ch); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// draw manages the cursor and calls the draw function of a view.
+func (g *Gui) draw(v *View) error {
+	if g.Cursor {
+		if v := g.currentView; v != nil {
+			vMaxX, vMaxY := v.Size()
+			if v.cx < 0 {
+				v.cx = 0
+			} else if v.cx >= vMaxX {
+				v.cx = vMaxX - 1
+			}
+			if v.cy < 0 {
+				v.cy = 0
+			} else if v.cy >= vMaxY {
+				v.cy = vMaxY - 1
+			}
+
+			gMaxX, gMaxY := g.Size()
+			cx, cy := v.x0+v.cx+1, v.y0+v.cy+1
+			if cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY {
+				termbox.SetCursor(cx, cy)
+			} else {
+				termbox.HideCursor()
+			}
+		}
+	} else {
+		termbox.HideCursor()
+	}
+
+	v.clearRunes()
+	if err := v.draw(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// drawIntersections draws the corners of each view, based on the type
+// of the edges that converge at these points.
+func (g *Gui) drawIntersections() error {
+	for _, v := range g.views {
+		if ch, ok := g.intersectionRune(v.x0, v.y0); ok {
+			if err := g.SetRune(v.x0, v.y0, ch); err != nil {
+				return err
+			}
+		}
+		if ch, ok := g.intersectionRune(v.x0, v.y1); ok {
+			if err := g.SetRune(v.x0, v.y1, ch); err != nil {
+				return err
+			}
+		}
+		if ch, ok := g.intersectionRune(v.x1, v.y0); ok {
+			if err := g.SetRune(v.x1, v.y0, ch); err != nil {
+				return err
+			}
+		}
+		if ch, ok := g.intersectionRune(v.x1, v.y1); ok {
+			if err := g.SetRune(v.x1, v.y1, ch); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// intersectionRune returns the correct intersection rune at a given
+// point.
+func (g *Gui) intersectionRune(x, y int) (rune, bool) {
+	if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+		return ' ', false
+	}
+
+	chTop, _ := g.Rune(x, y-1)
+	top := verticalRune(chTop)
+	chBottom, _ := g.Rune(x, y+1)
+	bottom := verticalRune(chBottom)
+	chLeft, _ := g.Rune(x-1, y)
+	left := horizontalRune(chLeft)
+	chRight, _ := g.Rune(x+1, y)
+	right := horizontalRune(chRight)
+
+	var ch rune
+	switch {
+	case top && bottom && left && right:
+		ch = '┼'
+	case top && bottom && !left && right:
+		ch = '├'
+	case top && bottom && left && !right:
+		ch = '┤'
+	case !top && bottom && left && right:
+		ch = '┬'
+	case top && !bottom && left && right:
+		ch = '┴'
+	default:
+		return ' ', false
+	}
+	return ch, true
+}
+
+// verticalRune returns if the given character is a vertical rune.
+func verticalRune(ch rune) bool {
+	if ch == '│' || ch == '┼' || ch == '├' || ch == '┤' {
+		return true
+	}
+	return false
+}
+
+// verticalRune returns if the given character is a horizontal rune.
+func horizontalRune(ch rune) bool {
+	if ch == '─' || ch == '┼' || ch == '┬' || ch == '┴' {
+		return true
+	}
+	return false
+}
+
+// onKey manages key-press events. A keybinding handler is called when
+// a key-press or mouse event satisfies a configured keybinding. Furthermore,
+// currentView's internal buffer is modified if currentView.Editable is true.
+func (g *Gui) onKey(ev *termbox.Event) error {
+	switch ev.Type {
+	case termbox.EventKey:
+		if err := g.execKeybindings(g.currentView, ev); err != nil {
+			return err
+		}
+		if g.currentView != nil && g.currentView.Editable && g.Editor != nil {
+			g.Editor.Edit(g.currentView, Key(ev.Key), ev.Ch, Modifier(ev.Mod))
+		}
+	case termbox.EventMouse:
+		mx, my := ev.MouseX, ev.MouseY
+		v, err := g.ViewByPosition(mx, my)
+		if err != nil {
+			break
+		}
+		if err := v.SetCursor(mx-v.x0-1, my-v.y0-1); err != nil {
+			return err
+		}
+		if err := g.execKeybindings(v, ev); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// execKeybindings executes the keybinding handlers that match the passed view
+// and event.
+func (g *Gui) execKeybindings(v *View, ev *termbox.Event) error {
+	for _, kb := range g.keybindings {
+		if kb.h == nil {
+			continue
+		}
+		if kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) && kb.matchView(v) {
+			if err := kb.h(g, v); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}

vendor/github.com/jroimartin/gocui/keybinding.go 🔗

@@ -0,0 +1,141 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "github.com/nsf/termbox-go"
+
+type (
+	// Key represents special keys or keys combinations.
+	Key termbox.Key
+
+	// Modifier allows to define special keys combinations. They can be used
+	// in combination with Keys or Runes when a new keybinding is defined.
+	Modifier termbox.Modifier
+
+	// KeybindingHandler represents the handler linked to a specific
+	// keybindings. The handler is called when a key-press event satisfies a
+	// configured keybinding.
+	KeybindingHandler func(*Gui, *View) error
+)
+
+// Special keys.
+const (
+	KeyF1         Key = Key(termbox.KeyF1)
+	KeyF2             = Key(termbox.KeyF2)
+	KeyF3             = Key(termbox.KeyF3)
+	KeyF4             = Key(termbox.KeyF4)
+	KeyF5             = Key(termbox.KeyF5)
+	KeyF6             = Key(termbox.KeyF6)
+	KeyF7             = Key(termbox.KeyF7)
+	KeyF8             = Key(termbox.KeyF8)
+	KeyF9             = Key(termbox.KeyF9)
+	KeyF10            = Key(termbox.KeyF10)
+	KeyF11            = Key(termbox.KeyF11)
+	KeyF12            = Key(termbox.KeyF12)
+	KeyInsert         = Key(termbox.KeyInsert)
+	KeyDelete         = Key(termbox.KeyDelete)
+	KeyHome           = Key(termbox.KeyHome)
+	KeyEnd            = Key(termbox.KeyEnd)
+	KeyPgup           = Key(termbox.KeyPgup)
+	KeyPgdn           = Key(termbox.KeyPgdn)
+	KeyArrowUp        = Key(termbox.KeyArrowUp)
+	KeyArrowDown      = Key(termbox.KeyArrowDown)
+	KeyArrowLeft      = Key(termbox.KeyArrowLeft)
+	KeyArrowRight     = Key(termbox.KeyArrowRight)
+
+	MouseLeft   = Key(termbox.MouseLeft)
+	MouseMiddle = Key(termbox.MouseMiddle)
+	MouseRight  = Key(termbox.MouseRight)
+)
+
+// Keys combinations.
+const (
+	KeyCtrlTilde      Key = Key(termbox.KeyCtrlTilde)
+	KeyCtrl2              = Key(termbox.KeyCtrl2)
+	KeyCtrlSpace          = Key(termbox.KeyCtrlSpace)
+	KeyCtrlA              = Key(termbox.KeyCtrlA)
+	KeyCtrlB              = Key(termbox.KeyCtrlB)
+	KeyCtrlC              = Key(termbox.KeyCtrlC)
+	KeyCtrlD              = Key(termbox.KeyCtrlD)
+	KeyCtrlE              = Key(termbox.KeyCtrlE)
+	KeyCtrlF              = Key(termbox.KeyCtrlF)
+	KeyCtrlG              = Key(termbox.KeyCtrlG)
+	KeyBackspace          = Key(termbox.KeyBackspace)
+	KeyCtrlH              = Key(termbox.KeyCtrlH)
+	KeyTab                = Key(termbox.KeyTab)
+	KeyCtrlI              = Key(termbox.KeyCtrlI)
+	KeyCtrlJ              = Key(termbox.KeyCtrlJ)
+	KeyCtrlK              = Key(termbox.KeyCtrlK)
+	KeyCtrlL              = Key(termbox.KeyCtrlL)
+	KeyEnter              = Key(termbox.KeyEnter)
+	KeyCtrlM              = Key(termbox.KeyCtrlM)
+	KeyCtrlN              = Key(termbox.KeyCtrlN)
+	KeyCtrlO              = Key(termbox.KeyCtrlO)
+	KeyCtrlP              = Key(termbox.KeyCtrlP)
+	KeyCtrlQ              = Key(termbox.KeyCtrlQ)
+	KeyCtrlR              = Key(termbox.KeyCtrlR)
+	KeyCtrlS              = Key(termbox.KeyCtrlS)
+	KeyCtrlT              = Key(termbox.KeyCtrlT)
+	KeyCtrlU              = Key(termbox.KeyCtrlU)
+	KeyCtrlV              = Key(termbox.KeyCtrlV)
+	KeyCtrlW              = Key(termbox.KeyCtrlW)
+	KeyCtrlX              = Key(termbox.KeyCtrlX)
+	KeyCtrlY              = Key(termbox.KeyCtrlY)
+	KeyCtrlZ              = Key(termbox.KeyCtrlZ)
+	KeyEsc                = Key(termbox.KeyEsc)
+	KeyCtrlLsqBracket     = Key(termbox.KeyCtrlLsqBracket)
+	KeyCtrl3              = Key(termbox.KeyCtrl3)
+	KeyCtrl4              = Key(termbox.KeyCtrl4)
+	KeyCtrlBackslash      = Key(termbox.KeyCtrlBackslash)
+	KeyCtrl5              = Key(termbox.KeyCtrl5)
+	KeyCtrlRsqBracket     = Key(termbox.KeyCtrlRsqBracket)
+	KeyCtrl6              = Key(termbox.KeyCtrl6)
+	KeyCtrl7              = Key(termbox.KeyCtrl7)
+	KeyCtrlSlash          = Key(termbox.KeyCtrlSlash)
+	KeyCtrlUnderscore     = Key(termbox.KeyCtrlUnderscore)
+	KeySpace              = Key(termbox.KeySpace)
+	KeyBackspace2         = Key(termbox.KeyBackspace2)
+	KeyCtrl8              = Key(termbox.KeyCtrl8)
+)
+
+// Modifiers.
+const (
+	ModNone Modifier = Modifier(0)
+	ModAlt           = Modifier(termbox.ModAlt)
+)
+
+// Keybidings are used to link a given key-press event with a handler.
+type keybinding struct {
+	viewName string
+	key      Key
+	ch       rune
+	mod      Modifier
+	h        KeybindingHandler
+}
+
+// newKeybinding returns a new Keybinding object.
+func newKeybinding(viewname string, key Key, ch rune, mod Modifier, h KeybindingHandler) (kb *keybinding) {
+	kb = &keybinding{
+		viewName: viewname,
+		key:      key,
+		ch:       ch,
+		mod:      mod,
+		h:        h,
+	}
+	return kb
+}
+
+// matchKeypress returns if the keybinding matches the keypress.
+func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool {
+	return kb.key == key && kb.ch == ch && kb.mod == mod
+}
+
+// matchView returns if the keybinding matches the current view.
+func (kb *keybinding) matchView(v *View) bool {
+	if kb.viewName == "" {
+		return true
+	}
+	return v != nil && kb.viewName == v.name
+}

vendor/github.com/jroimartin/gocui/view.go 🔗

@@ -0,0 +1,474 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"strings"
+
+	"github.com/nsf/termbox-go"
+)
+
+// A View is a window. It maintains its own internal buffer and cursor
+// position.
+type View struct {
+	name           string
+	x0, y0, x1, y1 int
+	ox, oy         int
+	cx, cy         int
+	lines          [][]cell
+	readOffset     int
+	readCache      string
+
+	tainted   bool       // marks if the viewBuffer must be updated
+	viewLines []viewLine // internal representation of the view's buffer
+
+	ei *escapeInterpreter // used to decode ESC sequences on Write
+
+	// BgColor and FgColor allow to configure the background and foreground
+	// colors of the View.
+	BgColor, FgColor Attribute
+
+	// SelBgColor and SelFgColor are used to configure the background and
+	// foreground colors of the selected line, when it is highlighted.
+	SelBgColor, SelFgColor Attribute
+
+	// If Editable is true, keystrokes will be added to the view's internal
+	// buffer at the cursor position.
+	Editable bool
+
+	// Overwrite enables or disables the overwrite mode of the view.
+	Overwrite bool
+
+	// If Highlight is true, Sel{Bg,Fg}Colors will be used
+	// for the line under the cursor position.
+	Highlight bool
+
+	// If Frame is true, a border will be drawn around the view.
+	Frame bool
+
+	// If Wrap is true, the content that is written to this View is
+	// automatically wrapped when it is longer than its width. If true the
+	// view's x-origin will be ignored.
+	Wrap bool
+
+	// If Autoscroll is true, the View will automatically scroll down when the
+	// text overflows. If true the view's y-origin will be ignored.
+	Autoscroll bool
+
+	// If Frame is true, Title allows to configure a title for the view.
+	Title string
+
+	// If Mask is true, the View will display the mask instead of the real
+	// content
+	Mask rune
+}
+
+type viewLine struct {
+	linesX, linesY int // coordinates relative to v.lines
+	line           []cell
+}
+
+type cell struct {
+	chr              rune
+	bgColor, fgColor Attribute
+}
+
+type lineType []cell
+
+// String returns a string from a given cell slice.
+func (l lineType) String() string {
+	str := ""
+	for _, c := range l {
+		str += string(c.chr)
+	}
+	return str
+}
+
+// newView returns a new View object.
+func newView(name string, x0, y0, x1, y1 int) *View {
+	v := &View{
+		name:    name,
+		x0:      x0,
+		y0:      y0,
+		x1:      x1,
+		y1:      y1,
+		Frame:   true,
+		tainted: true,
+		ei:      newEscapeInterpreter(),
+	}
+	return v
+}
+
+// Size returns the number of visible columns and rows in the View.
+func (v *View) Size() (x, y int) {
+	return v.x1 - v.x0 - 1, v.y1 - v.y0 - 1
+}
+
+// Name returns the name of the view.
+func (v *View) Name() string {
+	return v.name
+}
+
+// setRune sets a rune at the given point relative to the view. It applies the
+// specified colors, taking into account if the cell must be highlighted. Also,
+// it checks if the position is valid.
+func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
+	maxX, maxY := v.Size()
+	if x < 0 || x >= maxX || y < 0 || y >= maxY {
+		return errors.New("invalid point")
+	}
+
+	var (
+		ry, rcy int
+		err     error
+	)
+	if v.Highlight {
+		_, ry, err = v.realPosition(x, y)
+		if err != nil {
+			return err
+		}
+		_, rcy, err = v.realPosition(v.cx, v.cy)
+		if err != nil {
+			return err
+		}
+	}
+
+	if v.Mask != 0 {
+		fgColor = v.FgColor
+		bgColor = v.BgColor
+		ch = v.Mask
+	} else if v.Highlight && ry == rcy {
+		fgColor = v.SelFgColor
+		bgColor = v.SelBgColor
+	}
+
+	termbox.SetCell(v.x0+x+1, v.y0+y+1, ch,
+		termbox.Attribute(fgColor), termbox.Attribute(bgColor))
+
+	return nil
+}
+
+// SetCursor sets the cursor position of the view at the given point,
+// relative to the view. It checks if the position is valid.
+func (v *View) SetCursor(x, y int) error {
+	maxX, maxY := v.Size()
+	if x < 0 || x >= maxX || y < 0 || y >= maxY {
+		return errors.New("invalid point")
+	}
+	v.cx = x
+	v.cy = y
+	return nil
+}
+
+// Cursor returns the cursor position of the view.
+func (v *View) Cursor() (x, y int) {
+	return v.cx, v.cy
+}
+
+// SetOrigin sets the origin position of the view's internal buffer,
+// so the buffer starts to be printed from this point, which means that
+// it is linked with the origin point of view. It can be used to
+// implement Horizontal and Vertical scrolling with just incrementing
+// or decrementing ox and oy.
+func (v *View) SetOrigin(x, y int) error {
+	if x < 0 || y < 0 {
+		return errors.New("invalid point")
+	}
+	v.ox = x
+	v.oy = y
+	return nil
+}
+
+// Origin returns the origin position of the view.
+func (v *View) Origin() (x, y int) {
+	return v.ox, v.oy
+}
+
+// Write appends a byte slice into the view's internal buffer. Because
+// View implements the io.Writer interface, it can be passed as parameter
+// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
+// be called to clear the view's buffer.
+func (v *View) Write(p []byte) (n int, err error) {
+	v.tainted = true
+
+	for _, ch := range bytes.Runes(p) {
+		switch ch {
+		case '\n':
+			v.lines = append(v.lines, nil)
+		case '\r':
+			nl := len(v.lines)
+			if nl > 0 {
+				v.lines[nl-1] = nil
+			} else {
+				v.lines = make([][]cell, 1)
+			}
+		default:
+			cells := v.parseInput(ch)
+			if cells == nil {
+				continue
+			}
+
+			nl := len(v.lines)
+			if nl > 0 {
+				v.lines[nl-1] = append(v.lines[nl-1], cells...)
+			} else {
+				v.lines = append(v.lines, cells)
+			}
+		}
+	}
+	return len(p), nil
+}
+
+// parseInput parses char by char the input written to the View. It returns nil
+// while processing ESC sequences. Otherwise, it returns a cell slice that
+// contains the processed data.
+func (v *View) parseInput(ch rune) []cell {
+	cells := []cell{}
+
+	isEscape, err := v.ei.parseOne(ch)
+	if err != nil {
+		for _, r := range v.ei.runes() {
+			c := cell{
+				fgColor: v.FgColor,
+				bgColor: v.BgColor,
+				chr:     r,
+			}
+			cells = append(cells, c)
+		}
+		v.ei.reset()
+	} else {
+		if isEscape {
+			return nil
+		}
+		c := cell{
+			fgColor: v.ei.curFgColor,
+			bgColor: v.ei.curBgColor,
+			chr:     ch,
+		}
+		cells = append(cells, c)
+	}
+
+	return cells
+}
+
+// Read reads data into p. It returns the number of bytes read into p.
+// At EOF, err will be io.EOF. Calling Read() after Rewind() makes the
+// cache to be refreshed with the contents of the view.
+func (v *View) Read(p []byte) (n int, err error) {
+	if v.readOffset == 0 {
+		v.readCache = v.Buffer()
+	}
+	if v.readOffset < len(v.readCache) {
+		n = copy(p, v.readCache[v.readOffset:])
+		v.readOffset += n
+	} else {
+		err = io.EOF
+	}
+	return
+}
+
+// Rewind sets the offset for the next Read to 0, which also refresh the
+// read cache.
+func (v *View) Rewind() {
+	v.readOffset = 0
+}
+
+// draw re-draws the view's contents.
+func (v *View) draw() error {
+	maxX, maxY := v.Size()
+
+	if v.Wrap {
+		if maxX == 0 {
+			return errors.New("X size of the view cannot be 0")
+		}
+		v.ox = 0
+	}
+	if v.tainted {
+		v.viewLines = nil
+		for i, line := range v.lines {
+			if v.Wrap {
+				if len(line) <= maxX {
+					vline := viewLine{linesX: 0, linesY: i, line: line}
+					v.viewLines = append(v.viewLines, vline)
+					continue
+				} else {
+					vline := viewLine{linesX: 0, linesY: i, line: line[:maxX]}
+					v.viewLines = append(v.viewLines, vline)
+				}
+				// Append remaining lines
+				for n := maxX; n < len(line); n += maxX {
+					if len(line[n:]) <= maxX {
+						vline := viewLine{linesX: n, linesY: i, line: line[n:]}
+						v.viewLines = append(v.viewLines, vline)
+					} else {
+						vline := viewLine{linesX: n, linesY: i, line: line[n : n+maxX]}
+						v.viewLines = append(v.viewLines, vline)
+					}
+				}
+			} else {
+				vline := viewLine{linesX: 0, linesY: i, line: line}
+				v.viewLines = append(v.viewLines, vline)
+			}
+		}
+		v.tainted = false
+	}
+
+	if v.Autoscroll && len(v.viewLines) > maxY {
+		v.oy = len(v.viewLines) - maxY
+	}
+	y := 0
+	for i, vline := range v.viewLines {
+		if i < v.oy {
+			continue
+		}
+		if y >= maxY {
+			break
+		}
+		x := 0
+		for j, c := range vline.line {
+			if j < v.ox {
+				continue
+			}
+			if x >= maxX {
+				break
+			}
+
+			fgColor := c.fgColor
+			if fgColor == ColorDefault {
+				fgColor = v.FgColor
+			}
+			bgColor := c.bgColor
+			if bgColor == ColorDefault {
+				bgColor = v.BgColor
+			}
+
+			if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {
+				return err
+			}
+			x++
+		}
+		y++
+	}
+	return nil
+}
+
+// realPosition returns the position in the internal buffer corresponding to the
+// point (x, y) of the view.
+func (v *View) realPosition(vx, vy int) (x, y int, err error) {
+	vx = v.ox + vx
+	vy = v.oy + vy
+
+	if vx < 0 || vy < 0 {
+		return 0, 0, errors.New("invalid point")
+	}
+
+	if len(v.viewLines) == 0 {
+		return vx, vy, nil
+	}
+
+	if vy < len(v.viewLines) {
+		vline := v.viewLines[vy]
+		x = vline.linesX + vx
+		y = vline.linesY
+	} else {
+		vline := v.viewLines[len(v.viewLines)-1]
+		x = vx
+		y = vline.linesY + vy - len(v.viewLines) + 1
+	}
+
+	return x, y, nil
+}
+
+// Clear empties the view's internal buffer.
+func (v *View) Clear() {
+	v.tainted = true
+
+	v.lines = nil
+	v.clearRunes()
+}
+
+// clearRunes erases all the cells in the view.
+func (v *View) clearRunes() {
+	maxX, maxY := v.Size()
+	for x := 0; x < maxX; x++ {
+		for y := 0; y < maxY; y++ {
+			termbox.SetCell(v.x0+x+1, v.y0+y+1, ' ',
+				termbox.Attribute(v.FgColor), termbox.Attribute(v.BgColor))
+		}
+	}
+}
+
+// Buffer returns a string with the contents of the view's internal
+// buffer.
+func (v *View) Buffer() string {
+	str := ""
+	for _, l := range v.lines {
+		str += lineType(l).String() + "\n"
+	}
+	return strings.Replace(str, "\x00", " ", -1)
+}
+
+// ViewBuffer returns a string with the contents of the view's buffer that is
+// shown to the user.
+func (v *View) ViewBuffer() string {
+	str := ""
+	for _, l := range v.viewLines {
+		str += lineType(l.line).String() + "\n"
+	}
+	return strings.Replace(str, "\x00", " ", -1)
+}
+
+// Line returns a string with the line of the view's internal buffer
+// at the position corresponding to the point (x, y).
+func (v *View) Line(y int) (string, error) {
+	_, y, err := v.realPosition(0, y)
+	if err != nil {
+		return "", err
+	}
+
+	if y < 0 || y >= len(v.lines) {
+		return "", errors.New("invalid point")
+	}
+
+	return lineType(v.lines[y]).String(), nil
+}
+
+// Word returns a string with the word of the view's internal buffer
+// at the position corresponding to the point (x, y).
+func (v *View) Word(x, y int) (string, error) {
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return "", err
+	}
+
+	if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
+		return "", errors.New("invalid point")
+	}
+
+	str := lineType(v.lines[y]).String()
+
+	nl := strings.LastIndexFunc(str[:x], indexFunc)
+	if nl == -1 {
+		nl = 0
+	} else {
+		nl = nl + 1
+	}
+	nr := strings.IndexFunc(str[x:], indexFunc)
+	if nr == -1 {
+		nr = len(str)
+	} else {
+		nr = nr + x
+	}
+	return string(str[nl:nr]), nil
+}
+
+// indexFunc allows to split lines by words taking into account spaces
+// and 0.
+func indexFunc(r rune) bool {
+	return r == ' ' || r == 0
+}

vendor/github.com/mattn/go-runewidth/.travis.yml 🔗

@@ -0,0 +1,8 @@
+language: go
+go:
+  - tip
+before_install:
+  - go get github.com/mattn/goveralls
+  - go get golang.org/x/tools/cmd/cover
+script:
+    - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL

vendor/github.com/mattn/go-runewidth/LICENSE 🔗

@@ -0,0 +1,21 @@
+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.

vendor/github.com/mattn/go-runewidth/README.mkd 🔗

@@ -0,0 +1,27 @@
+go-runewidth
+============
+
+[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth)
+[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD)
+[![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

vendor/github.com/mattn/go-runewidth/runewidth.go 🔗

@@ -0,0 +1,1223 @@
+package runewidth
+
+var (
+	// EastAsianWidth will be set true if the current locale is CJK
+	EastAsianWidth = IsEastAsian()
+
+	// DefaultCondition is a condition in current locale
+	DefaultCondition = &Condition{EastAsianWidth}
+)
+
+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 {
+	// 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) / 2
+
+		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},
+	{0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF},
+	{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF},
+}
+
+var combining = table{
+	{0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD},
+	{0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5},
+	{0x05C7, 0x05C7}, {0x0610, 0x061A}, {0x064B, 0x065F},
+	{0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DF, 0x06E4},
+	{0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x0711, 0x0711},
+	{0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3},
+	{0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827},
+	{0x0829, 0x082D}, {0x0859, 0x085B}, {0x08D4, 0x08E1},
+	{0x08E3, 0x0903}, {0x093A, 0x093C}, {0x093E, 0x094F},
+	{0x0951, 0x0957}, {0x0962, 0x0963}, {0x0981, 0x0983},
+	{0x09BC, 0x09BC}, {0x09BE, 0x09C4}, {0x09C7, 0x09C8},
+	{0x09CB, 0x09CD}, {0x09D7, 0x09D7}, {0x09E2, 0x09E3},
+	{0x0A01, 0x0A03}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42},
+	{0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
+	{0x0A70, 0x0A71}, {0x0A75, 0x0A75}, {0x0A81, 0x0A83},
+	{0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9},
+	{0x0ACB, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B03},
+	{0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48},
+	{0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, {0x0B62, 0x0B63},
+	{0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8},
+	{0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C03},
+	{0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
+	{0x0C55, 0x0C56}, {0x0C62, 0x0C63}, {0x0C81, 0x0C83},
+	{0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8},
+	{0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3},
+	{0x0D01, 0x0D03}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48},
+	{0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63},
+	{0x0D82, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4},
+	{0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3},
+	{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
+	{0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
+	{0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
+	{0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F},
+	{0x0F71, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97},
+	{0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102B, 0x103E},
+	{0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064},
+	{0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D},
+	{0x108F, 0x108F}, {0x109A, 0x109D}, {0x135D, 0x135F},
+	{0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
+	{0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD},
+	{0x180B, 0x180D}, {0x1885, 0x1886}, {0x18A9, 0x18A9},
+	{0x1920, 0x192B}, {0x1930, 0x193B}, {0x1A17, 0x1A1B},
+	{0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A7F},
+	{0x1AB0, 0x1ABE}, {0x1B00, 0x1B04}, {0x1B34, 0x1B44},
+	{0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD},
+	{0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, {0x1CD0, 0x1CD2},
+	{0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF2, 0x1CF4},
+	{0x1CF8, 0x1CF9}, {0x1DC0, 0x1DF5}, {0x1DFB, 0x1DFF},
+	{0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F},
+	{0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A},
+	{0xA66F, 0xA672}, {0xA674, 0xA67D}, {0xA69E, 0xA69F},
+	{0xA6F0, 0xA6F1}, {0xA802, 0xA802}, {0xA806, 0xA806},
+	{0xA80B, 0xA80B}, {0xA823, 0xA827}, {0xA880, 0xA881},
+	{0xA8B4, 0xA8C5}, {0xA8E0, 0xA8F1}, {0xA926, 0xA92D},
+	{0xA947, 0xA953}, {0xA980, 0xA983}, {0xA9B3, 0xA9C0},
+	{0xA9E5, 0xA9E5}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43},
+	{0xAA4C, 0xAA4D}, {0xAA7B, 0xAA7D}, {0xAAB0, 0xAAB0},
+	{0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, {0xAABE, 0xAABF},
+	{0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, {0xAAF5, 0xAAF6},
+	{0xABE3, 0xABEA}, {0xABEC, 0xABED}, {0xFB1E, 0xFB1E},
+	{0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD},
+	{0x102E0, 0x102E0}, {0x10376, 0x1037A}, {0x10A01, 0x10A03},
+	{0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A},
+	{0x10A3F, 0x10A3F}, {0x10AE5, 0x10AE6}, {0x11000, 0x11002},
+	{0x11038, 0x11046}, {0x1107F, 0x11082}, {0x110B0, 0x110BA},
+	{0x11100, 0x11102}, {0x11127, 0x11134}, {0x11173, 0x11173},
+	{0x11180, 0x11182}, {0x111B3, 0x111C0}, {0x111CA, 0x111CC},
+	{0x1122C, 0x11237}, {0x1123E, 0x1123E}, {0x112DF, 0x112EA},
+	{0x11300, 0x11303}, {0x1133C, 0x1133C}, {0x1133E, 0x11344},
+	{0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357},
+	{0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
+	{0x11435, 0x11446}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5},
+	{0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640},
+	{0x116AB, 0x116B7}, {0x1171D, 0x1172B}, {0x11C2F, 0x11C36},
+	{0x11C38, 0x11C3F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6},
+	{0x16AF0, 0x16AF4}, {0x16B30, 0x16B36}, {0x16F51, 0x16F7E},
+	{0x16F8F, 0x16F92}, {0x1BC9D, 0x1BC9E}, {0x1D165, 0x1D169},
+	{0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B},
+	{0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36},
+	{0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84},
+	{0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
+	{0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
+	{0x1E026, 0x1E02A}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A},
+	{0xE0100, 0xE01EF},
+}
+
+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, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA},
+	{0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247},
+	{0x3250, 0x32FE}, {0x3300, 0x4DBF}, {0x4E00, 0xA48C},
+	{0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3},
+	{0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52},
+	{0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60},
+	{0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE0}, {0x17000, 0x187EC},
+	{0x18800, 0x18AF2}, {0x1B000, 0x1B001}, {0x1F004, 0x1F004},
+	{0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A},
+	{0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248},
+	{0x1F250, 0x1F251}, {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}, {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6F6},
+	{0x1F910, 0x1F91E}, {0x1F920, 0x1F927}, {0x1F930, 0x1F930},
+	{0x1F933, 0x1F93E}, {0x1F940, 0x1F94B}, {0x1F950, 0x1F95E},
+	{0x1F980, 0x1F991}, {0x1F9C0, 0x1F9C0}, {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 emoji = table{
+	{0x1F1E6, 0x1F1FF}, {0x1F321, 0x1F321}, {0x1F324, 0x1F32C},
+	{0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, {0x1F396, 0x1F397},
+	{0x1F399, 0x1F39B}, {0x1F39E, 0x1F39F}, {0x1F3CB, 0x1F3CE},
+	{0x1F3D4, 0x1F3DF}, {0x1F3F3, 0x1F3F5}, {0x1F3F7, 0x1F3F7},
+	{0x1F43F, 0x1F43F}, {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FD},
+	{0x1F549, 0x1F54A}, {0x1F56F, 0x1F570}, {0x1F573, 0x1F579},
+	{0x1F587, 0x1F587}, {0x1F58A, 0x1F58D}, {0x1F590, 0x1F590},
+	{0x1F5A5, 0x1F5A5}, {0x1F5A8, 0x1F5A8}, {0x1F5B1, 0x1F5B2},
+	{0x1F5BC, 0x1F5BC}, {0x1F5C2, 0x1F5C4}, {0x1F5D1, 0x1F5D3},
+	{0x1F5DC, 0x1F5DE}, {0x1F5E1, 0x1F5E1}, {0x1F5E3, 0x1F5E3},
+	{0x1F5E8, 0x1F5E8}, {0x1F5EF, 0x1F5EF}, {0x1F5F3, 0x1F5F3},
+	{0x1F5FA, 0x1F5FA}, {0x1F6CB, 0x1F6CF}, {0x1F6E0, 0x1F6E5},
+	{0x1F6E9, 0x1F6E9}, {0x1F6F0, 0x1F6F0}, {0x1F6F3, 0x1F6F3},
+}
+
+var notassigned = table{
+	{0x0378, 0x0379}, {0x0380, 0x0383}, {0x038B, 0x038B},
+	{0x038D, 0x038D}, {0x03A2, 0x03A2}, {0x0530, 0x0530},
+	{0x0557, 0x0558}, {0x0560, 0x0560}, {0x0588, 0x0588},
+	{0x058B, 0x058C}, {0x0590, 0x0590}, {0x05C8, 0x05CF},
+	{0x05EB, 0x05EF}, {0x05F5, 0x05FF}, {0x061D, 0x061D},
+	{0x070E, 0x070E}, {0x074B, 0x074C}, {0x07B2, 0x07BF},
+	{0x07FB, 0x07FF}, {0x082E, 0x082F}, {0x083F, 0x083F},
+	{0x085C, 0x085D}, {0x085F, 0x089F}, {0x08B5, 0x08B5},
+	{0x08BE, 0x08D3}, {0x0984, 0x0984}, {0x098D, 0x098E},
+	{0x0991, 0x0992}, {0x09A9, 0x09A9}, {0x09B1, 0x09B1},
+	{0x09B3, 0x09B5}, {0x09BA, 0x09BB}, {0x09C5, 0x09C6},
+	{0x09C9, 0x09CA}, {0x09CF, 0x09D6}, {0x09D8, 0x09DB},
+	{0x09DE, 0x09DE}, {0x09E4, 0x09E5}, {0x09FC, 0x0A00},
+	{0x0A04, 0x0A04}, {0x0A0B, 0x0A0E}, {0x0A11, 0x0A12},
+	{0x0A29, 0x0A29}, {0x0A31, 0x0A31}, {0x0A34, 0x0A34},
+	{0x0A37, 0x0A37}, {0x0A3A, 0x0A3B}, {0x0A3D, 0x0A3D},
+	{0x0A43, 0x0A46}, {0x0A49, 0x0A4A}, {0x0A4E, 0x0A50},
+	{0x0A52, 0x0A58}, {0x0A5D, 0x0A5D}, {0x0A5F, 0x0A65},
+	{0x0A76, 0x0A80}, {0x0A84, 0x0A84}, {0x0A8E, 0x0A8E},
+	{0x0A92, 0x0A92}, {0x0AA9, 0x0AA9}, {0x0AB1, 0x0AB1},
+	{0x0AB4, 0x0AB4}, {0x0ABA, 0x0ABB}, {0x0AC6, 0x0AC6},
+	{0x0ACA, 0x0ACA}, {0x0ACE, 0x0ACF}, {0x0AD1, 0x0ADF},
+	{0x0AE4, 0x0AE5}, {0x0AF2, 0x0AF8}, {0x0AFA, 0x0B00},
+	{0x0B04, 0x0B04}, {0x0B0D, 0x0B0E}, {0x0B11, 0x0B12},
+	{0x0B29, 0x0B29}, {0x0B31, 0x0B31}, {0x0B34, 0x0B34},
+	{0x0B3A, 0x0B3B}, {0x0B45, 0x0B46}, {0x0B49, 0x0B4A},
+	{0x0B4E, 0x0B55}, {0x0B58, 0x0B5B}, {0x0B5E, 0x0B5E},
+	{0x0B64, 0x0B65}, {0x0B78, 0x0B81}, {0x0B84, 0x0B84},
+	{0x0B8B, 0x0B8D}, {0x0B91, 0x0B91}, {0x0B96, 0x0B98},
+	{0x0B9B, 0x0B9B}, {0x0B9D, 0x0B9D}, {0x0BA0, 0x0BA2},
+	{0x0BA5, 0x0BA7}, {0x0BAB, 0x0BAD}, {0x0BBA, 0x0BBD},
+	{0x0BC3, 0x0BC5}, {0x0BC9, 0x0BC9}, {0x0BCE, 0x0BCF},
+	{0x0BD1, 0x0BD6}, {0x0BD8, 0x0BE5}, {0x0BFB, 0x0BFF},
+	{0x0C04, 0x0C04}, {0x0C0D, 0x0C0D}, {0x0C11, 0x0C11},
+	{0x0C29, 0x0C29}, {0x0C3A, 0x0C3C}, {0x0C45, 0x0C45},
+	{0x0C49, 0x0C49}, {0x0C4E, 0x0C54}, {0x0C57, 0x0C57},
+	{0x0C5B, 0x0C5F}, {0x0C64, 0x0C65}, {0x0C70, 0x0C77},
+	{0x0C84, 0x0C84}, {0x0C8D, 0x0C8D}, {0x0C91, 0x0C91},
+	{0x0CA9, 0x0CA9}, {0x0CB4, 0x0CB4}, {0x0CBA, 0x0CBB},
+	{0x0CC5, 0x0CC5}, {0x0CC9, 0x0CC9}, {0x0CCE, 0x0CD4},
+	{0x0CD7, 0x0CDD}, {0x0CDF, 0x0CDF}, {0x0CE4, 0x0CE5},
+	{0x0CF0, 0x0CF0}, {0x0CF3, 0x0D00}, {0x0D04, 0x0D04},
+	{0x0D0D, 0x0D0D}, {0x0D11, 0x0D11}, {0x0D3B, 0x0D3C},
+	{0x0D45, 0x0D45}, {0x0D49, 0x0D49}, {0x0D50, 0x0D53},
+	{0x0D64, 0x0D65}, {0x0D80, 0x0D81}, {0x0D84, 0x0D84},
+	{0x0D97, 0x0D99}, {0x0DB2, 0x0DB2}, {0x0DBC, 0x0DBC},
+	{0x0DBE, 0x0DBF}, {0x0DC7, 0x0DC9}, {0x0DCB, 0x0DCE},
+	{0x0DD5, 0x0DD5}, {0x0DD7, 0x0DD7}, {0x0DE0, 0x0DE5},
+	{0x0DF0, 0x0DF1}, {0x0DF5, 0x0E00}, {0x0E3B, 0x0E3E},
+	{0x0E5C, 0x0E80}, {0x0E83, 0x0E83}, {0x0E85, 0x0E86},
+	{0x0E89, 0x0E89}, {0x0E8B, 0x0E8C}, {0x0E8E, 0x0E93},
+	{0x0E98, 0x0E98}, {0x0EA0, 0x0EA0}, {0x0EA4, 0x0EA4},
+	{0x0EA6, 0x0EA6}, {0x0EA8, 0x0EA9}, {0x0EAC, 0x0EAC},
+	{0x0EBA, 0x0EBA}, {0x0EBE, 0x0EBF}, {0x0EC5, 0x0EC5},
+	{0x0EC7, 0x0EC7}, {0x0ECE, 0x0ECF}, {0x0EDA, 0x0EDB},
+	{0x0EE0, 0x0EFF}, {0x0F48, 0x0F48}, {0x0F6D, 0x0F70},
+	{0x0F98, 0x0F98}, {0x0FBD, 0x0FBD}, {0x0FCD, 0x0FCD},
+	{0x0FDB, 0x0FFF}, {0x10C6, 0x10C6}, {0x10C8, 0x10CC},
+	{0x10CE, 0x10CF}, {0x1249, 0x1249}, {0x124E, 0x124F},
+	{0x1257, 0x1257}, {0x1259, 0x1259}, {0x125E, 0x125F},
+	{0x1289, 0x1289}, {0x128E, 0x128F}, {0x12B1, 0x12B1},
+	{0x12B6, 0x12B7}, {0x12BF, 0x12BF}, {0x12C1, 0x12C1},
+	{0x12C6, 0x12C7}, {0x12D7, 0x12D7}, {0x1311, 0x1311},
+	{0x1316, 0x1317}, {0x135B, 0x135C}, {0x137D, 0x137F},
+	{0x139A, 0x139F}, {0x13F6, 0x13F7}, {0x13FE, 0x13FF},
+	{0x169D, 0x169F}, {0x16F9, 0x16FF}, {0x170D, 0x170D},
+	{0x1715, 0x171F}, {0x1737, 0x173F}, {0x1754, 0x175F},
+	{0x176D, 0x176D}, {0x1771, 0x1771}, {0x1774, 0x177F},
+	{0x17DE, 0x17DF}, {0x17EA, 0x17EF}, {0x17FA, 0x17FF},
+	{0x180F, 0x180F}, {0x181A, 0x181F}, {0x1878, 0x187F},
+	{0x18AB, 0x18AF}, {0x18F6, 0x18FF}, {0x191F, 0x191F},
+	{0x192C, 0x192F}, {0x193C, 0x193F}, {0x1941, 0x1943},
+	{0x196E, 0x196F}, {0x1975, 0x197F}, {0x19AC, 0x19AF},
+	{0x19CA, 0x19CF}, {0x19DB, 0x19DD}, {0x1A1C, 0x1A1D},
+	{0x1A5F, 0x1A5F}, {0x1A7D, 0x1A7E}, {0x1A8A, 0x1A8F},
+	{0x1A9A, 0x1A9F}, {0x1AAE, 0x1AAF}, {0x1ABF, 0x1AFF},
+	{0x1B4C, 0x1B4F}, {0x1B7D, 0x1B7F}, {0x1BF4, 0x1BFB},
+	{0x1C38, 0x1C3A}, {0x1C4A, 0x1C4C}, {0x1C89, 0x1CBF},
+	{0x1CC8, 0x1CCF}, {0x1CF7, 0x1CF7}, {0x1CFA, 0x1CFF},
+	{0x1DF6, 0x1DFA}, {0x1F16, 0x1F17}, {0x1F1E, 0x1F1F},
+	{0x1F46, 0x1F47}, {0x1F4E, 0x1F4F}, {0x1F58, 0x1F58},
+	{0x1F5A, 0x1F5A}, {0x1F5C, 0x1F5C}, {0x1F5E, 0x1F5E},
+	{0x1F7E, 0x1F7F}, {0x1FB5, 0x1FB5}, {0x1FC5, 0x1FC5},
+	{0x1FD4, 0x1FD5}, {0x1FDC, 0x1FDC}, {0x1FF0, 0x1FF1},
+	{0x1FF5, 0x1FF5}, {0x1FFF, 0x1FFF}, {0x2065, 0x2065},
+	{0x2072, 0x2073}, {0x208F, 0x208F}, {0x209D, 0x209F},
+	{0x20BF, 0x20CF}, {0x20F1, 0x20FF}, {0x218C, 0x218F},
+	{0x23FF, 0x23FF}, {0x2427, 0x243F}, {0x244B, 0x245F},
+	{0x2B74, 0x2B75}, {0x2B96, 0x2B97}, {0x2BBA, 0x2BBC},
+	{0x2BC9, 0x2BC9}, {0x2BD2, 0x2BEB}, {0x2BF0, 0x2BFF},
+	{0x2C2F, 0x2C2F}, {0x2C5F, 0x2C5F}, {0x2CF4, 0x2CF8},
+	{0x2D26, 0x2D26}, {0x2D28, 0x2D2C}, {0x2D2E, 0x2D2F},
+	{0x2D68, 0x2D6E}, {0x2D71, 0x2D7E}, {0x2D97, 0x2D9F},
+	{0x2DA7, 0x2DA7}, {0x2DAF, 0x2DAF}, {0x2DB7, 0x2DB7},
+	{0x2DBF, 0x2DBF}, {0x2DC7, 0x2DC7}, {0x2DCF, 0x2DCF},
+	{0x2DD7, 0x2DD7}, {0x2DDF, 0x2DDF}, {0x2E45, 0x2E7F},
+	{0x2E9A, 0x2E9A}, {0x2EF4, 0x2EFF}, {0x2FD6, 0x2FEF},
+	{0x2FFC, 0x2FFF}, {0x3040, 0x3040}, {0x3097, 0x3098},
+	{0x3100, 0x3104}, {0x312E, 0x3130}, {0x318F, 0x318F},
+	{0x31BB, 0x31BF}, {0x31E4, 0x31EF}, {0x321F, 0x321F},
+	{0x32FF, 0x32FF}, {0x4DB6, 0x4DBF}, {0x9FD6, 0x9FFF},
+	{0xA48D, 0xA48F}, {0xA4C7, 0xA4CF}, {0xA62C, 0xA63F},
+	{0xA6F8, 0xA6FF}, {0xA7AF, 0xA7AF}, {0xA7B8, 0xA7F6},
+	{0xA82C, 0xA82F}, {0xA83A, 0xA83F}, {0xA878, 0xA87F},
+	{0xA8C6, 0xA8CD}, {0xA8DA, 0xA8DF}, {0xA8FE, 0xA8FF},
+	{0xA954, 0xA95E}, {0xA97D, 0xA97F}, {0xA9CE, 0xA9CE},
+	{0xA9DA, 0xA9DD}, {0xA9FF, 0xA9FF}, {0xAA37, 0xAA3F},
+	{0xAA4E, 0xAA4F}, {0xAA5A, 0xAA5B}, {0xAAC3, 0xAADA},
+	{0xAAF7, 0xAB00}, {0xAB07, 0xAB08}, {0xAB0F, 0xAB10},
+	{0xAB17, 0xAB1F}, {0xAB27, 0xAB27}, {0xAB2F, 0xAB2F},
+	{0xAB66, 0xAB6F}, {0xABEE, 0xABEF}, {0xABFA, 0xABFF},
+	{0xD7A4, 0xD7AF}, {0xD7C7, 0xD7CA}, {0xD7FC, 0xD7FF},
+	{0xFA6E, 0xFA6F}, {0xFADA, 0xFAFF}, {0xFB07, 0xFB12},
+	{0xFB18, 0xFB1C}, {0xFB37, 0xFB37}, {0xFB3D, 0xFB3D},
+	{0xFB3F, 0xFB3F}, {0xFB42, 0xFB42}, {0xFB45, 0xFB45},
+	{0xFBC2, 0xFBD2}, {0xFD40, 0xFD4F}, {0xFD90, 0xFD91},
+	{0xFDC8, 0xFDEF}, {0xFDFE, 0xFDFF}, {0xFE1A, 0xFE1F},
+	{0xFE53, 0xFE53}, {0xFE67, 0xFE67}, {0xFE6C, 0xFE6F},
+	{0xFE75, 0xFE75}, {0xFEFD, 0xFEFE}, {0xFF00, 0xFF00},
+	{0xFFBF, 0xFFC1}, {0xFFC8, 0xFFC9}, {0xFFD0, 0xFFD1},
+	{0xFFD8, 0xFFD9}, {0xFFDD, 0xFFDF}, {0xFFE7, 0xFFE7},
+	{0xFFEF, 0xFFF8}, {0xFFFE, 0xFFFF}, {0x1000C, 0x1000C},
+	{0x10027, 0x10027}, {0x1003B, 0x1003B}, {0x1003E, 0x1003E},
+	{0x1004E, 0x1004F}, {0x1005E, 0x1007F}, {0x100FB, 0x100FF},
+	{0x10103, 0x10106}, {0x10134, 0x10136}, {0x1018F, 0x1018F},
+	{0x1019C, 0x1019F}, {0x101A1, 0x101CF}, {0x101FE, 0x1027F},
+	{0x1029D, 0x1029F}, {0x102D1, 0x102DF}, {0x102FC, 0x102FF},
+	{0x10324, 0x1032F}, {0x1034B, 0x1034F}, {0x1037B, 0x1037F},
+	{0x1039E, 0x1039E}, {0x103C4, 0x103C7}, {0x103D6, 0x103FF},
+	{0x1049E, 0x1049F}, {0x104AA, 0x104AF}, {0x104D4, 0x104D7},
+	{0x104FC, 0x104FF}, {0x10528, 0x1052F}, {0x10564, 0x1056E},
+	{0x10570, 0x105FF}, {0x10737, 0x1073F}, {0x10756, 0x1075F},
+	{0x10768, 0x107FF}, {0x10806, 0x10807}, {0x10809, 0x10809},
+	{0x10836, 0x10836}, {0x10839, 0x1083B}, {0x1083D, 0x1083E},
+	{0x10856, 0x10856}, {0x1089F, 0x108A6}, {0x108B0, 0x108DF},
+	{0x108F3, 0x108F3}, {0x108F6, 0x108FA}, {0x1091C, 0x1091E},
+	{0x1093A, 0x1093E}, {0x10940, 0x1097F}, {0x109B8, 0x109BB},
+	{0x109D0, 0x109D1}, {0x10A04, 0x10A04}, {0x10A07, 0x10A0B},
+	{0x10A14, 0x10A14}, {0x10A18, 0x10A18}, {0x10A34, 0x10A37},
+	{0x10A3B, 0x10A3E}, {0x10A48, 0x10A4F}, {0x10A59, 0x10A5F},
+	{0x10AA0, 0x10ABF}, {0x10AE7, 0x10AEA}, {0x10AF7, 0x10AFF},
+	{0x10B36, 0x10B38}, {0x10B56, 0x10B57}, {0x10B73, 0x10B77},
+	{0x10B92, 0x10B98}, {0x10B9D, 0x10BA8}, {0x10BB0, 0x10BFF},
+	{0x10C49, 0x10C7F}, {0x10CB3, 0x10CBF}, {0x10CF3, 0x10CF9},
+	{0x10D00, 0x10E5F}, {0x10E7F, 0x10FFF}, {0x1104E, 0x11051},
+	{0x11070, 0x1107E}, {0x110C2, 0x110CF}, {0x110E9, 0x110EF},
+	{0x110FA, 0x110FF}, {0x11135, 0x11135}, {0x11144, 0x1114F},
+	{0x11177, 0x1117F}, {0x111CE, 0x111CF}, {0x111E0, 0x111E0},
+	{0x111F5, 0x111FF}, {0x11212, 0x11212}, {0x1123F, 0x1127F},
+	{0x11287, 0x11287}, {0x11289, 0x11289}, {0x1128E, 0x1128E},
+	{0x1129E, 0x1129E}, {0x112AA, 0x112AF}, {0x112EB, 0x112EF},
+	{0x112FA, 0x112FF}, {0x11304, 0x11304}, {0x1130D, 0x1130E},
+	{0x11311, 0x11312}, {0x11329, 0x11329}, {0x11331, 0x11331},
+	{0x11334, 0x11334}, {0x1133A, 0x1133B}, {0x11345, 0x11346},
+	{0x11349, 0x1134A}, {0x1134E, 0x1134F}, {0x11351, 0x11356},
+	{0x11358, 0x1135C}, {0x11364, 0x11365}, {0x1136D, 0x1136F},
+	{0x11375, 0x113FF}, {0x1145A, 0x1145A}, {0x1145C, 0x1145C},
+	{0x1145E, 0x1147F}, {0x114C8, 0x114CF}, {0x114DA, 0x1157F},
+	{0x115B6, 0x115B7}, {0x115DE, 0x115FF}, {0x11645, 0x1164F},
+	{0x1165A, 0x1165F}, {0x1166D, 0x1167F}, {0x116B8, 0x116BF},
+	{0x116CA, 0x116FF}, {0x1171A, 0x1171C}, {0x1172C, 0x1172F},
+	{0x11740, 0x1189F}, {0x118F3, 0x118FE}, {0x11900, 0x11ABF},
+	{0x11AF9, 0x11BFF}, {0x11C09, 0x11C09}, {0x11C37, 0x11C37},
+	{0x11C46, 0x11C4F}, {0x11C6D, 0x11C6F}, {0x11C90, 0x11C91},
+	{0x11CA8, 0x11CA8}, {0x11CB7, 0x11FFF}, {0x1239A, 0x123FF},
+	{0x1246F, 0x1246F}, {0x12475, 0x1247F}, {0x12544, 0x12FFF},
+	{0x1342F, 0x143FF}, {0x14647, 0x167FF}, {0x16A39, 0x16A3F},
+	{0x16A5F, 0x16A5F}, {0x16A6A, 0x16A6D}, {0x16A70, 0x16ACF},
+	{0x16AEE, 0x16AEF}, {0x16AF6, 0x16AFF}, {0x16B46, 0x16B4F},
+	{0x16B5A, 0x16B5A}, {0x16B62, 0x16B62}, {0x16B78, 0x16B7C},
+	{0x16B90, 0x16EFF}, {0x16F45, 0x16F4F}, {0x16F7F, 0x16F8E},
+	{0x16FA0, 0x16FDF}, {0x16FE1, 0x16FFF}, {0x187ED, 0x187FF},
+	{0x18AF3, 0x1AFFF}, {0x1B002, 0x1BBFF}, {0x1BC6B, 0x1BC6F},
+	{0x1BC7D, 0x1BC7F}, {0x1BC89, 0x1BC8F}, {0x1BC9A, 0x1BC9B},
+	{0x1BCA4, 0x1CFFF}, {0x1D0F6, 0x1D0FF}, {0x1D127, 0x1D128},
+	{0x1D1E9, 0x1D1FF}, {0x1D246, 0x1D2FF}, {0x1D357, 0x1D35F},
+	{0x1D372, 0x1D3FF}, {0x1D455, 0x1D455}, {0x1D49D, 0x1D49D},
+	{0x1D4A0, 0x1D4A1}, {0x1D4A3, 0x1D4A4}, {0x1D4A7, 0x1D4A8},
+	{0x1D4AD, 0x1D4AD}, {0x1D4BA, 0x1D4BA}, {0x1D4BC, 0x1D4BC},
+	{0x1D4C4, 0x1D4C4}, {0x1D506, 0x1D506}, {0x1D50B, 0x1D50C},
+	{0x1D515, 0x1D515}, {0x1D51D, 0x1D51D}, {0x1D53A, 0x1D53A},
+	{0x1D53F, 0x1D53F}, {0x1D545, 0x1D545}, {0x1D547, 0x1D549},
+	{0x1D551, 0x1D551}, {0x1D6A6, 0x1D6A7}, {0x1D7CC, 0x1D7CD},
+	{0x1DA8C, 0x1DA9A}, {0x1DAA0, 0x1DAA0}, {0x1DAB0, 0x1DFFF},
+	{0x1E007, 0x1E007}, {0x1E019, 0x1E01A}, {0x1E022, 0x1E022},
+	{0x1E025, 0x1E025}, {0x1E02B, 0x1E7FF}, {0x1E8C5, 0x1E8C6},
+	{0x1E8D7, 0x1E8FF}, {0x1E94B, 0x1E94F}, {0x1E95A, 0x1E95D},
+	{0x1E960, 0x1EDFF}, {0x1EE04, 0x1EE04}, {0x1EE20, 0x1EE20},
+	{0x1EE23, 0x1EE23}, {0x1EE25, 0x1EE26}, {0x1EE28, 0x1EE28},
+	{0x1EE33, 0x1EE33}, {0x1EE38, 0x1EE38}, {0x1EE3A, 0x1EE3A},
+	{0x1EE3C, 0x1EE41}, {0x1EE43, 0x1EE46}, {0x1EE48, 0x1EE48},
+	{0x1EE4A, 0x1EE4A}, {0x1EE4C, 0x1EE4C}, {0x1EE50, 0x1EE50},
+	{0x1EE53, 0x1EE53}, {0x1EE55, 0x1EE56}, {0x1EE58, 0x1EE58},
+	{0x1EE5A, 0x1EE5A}, {0x1EE5C, 0x1EE5C}, {0x1EE5E, 0x1EE5E},
+	{0x1EE60, 0x1EE60}, {0x1EE63, 0x1EE63}, {0x1EE65, 0x1EE66},
+	{0x1EE6B, 0x1EE6B}, {0x1EE73, 0x1EE73}, {0x1EE78, 0x1EE78},
+	{0x1EE7D, 0x1EE7D}, {0x1EE7F, 0x1EE7F}, {0x1EE8A, 0x1EE8A},
+	{0x1EE9C, 0x1EEA0}, {0x1EEA4, 0x1EEA4}, {0x1EEAA, 0x1EEAA},
+	{0x1EEBC, 0x1EEEF}, {0x1EEF2, 0x1EFFF}, {0x1F02C, 0x1F02F},
+	{0x1F094, 0x1F09F}, {0x1F0AF, 0x1F0B0}, {0x1F0C0, 0x1F0C0},
+	{0x1F0D0, 0x1F0D0}, {0x1F0F6, 0x1F0FF}, {0x1F10D, 0x1F10F},
+	{0x1F12F, 0x1F12F}, {0x1F16C, 0x1F16F}, {0x1F1AD, 0x1F1E5},
+	{0x1F203, 0x1F20F}, {0x1F23C, 0x1F23F}, {0x1F249, 0x1F24F},
+	{0x1F252, 0x1F2FF}, {0x1F6D3, 0x1F6DF}, {0x1F6ED, 0x1F6EF},
+	{0x1F6F7, 0x1F6FF}, {0x1F774, 0x1F77F}, {0x1F7D5, 0x1F7FF},
+	{0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F}, {0x1F85A, 0x1F85F},
+	{0x1F888, 0x1F88F}, {0x1F8AE, 0x1F90F}, {0x1F91F, 0x1F91F},
+	{0x1F928, 0x1F92F}, {0x1F931, 0x1F932}, {0x1F93F, 0x1F93F},
+	{0x1F94C, 0x1F94F}, {0x1F95F, 0x1F97F}, {0x1F992, 0x1F9BF},
+	{0x1F9C1, 0x1FFFF}, {0x2A6D7, 0x2A6FF}, {0x2B735, 0x2B73F},
+	{0x2B81E, 0x2B81F}, {0x2CEA2, 0x2F7FF}, {0x2FA1E, 0xE0000},
+	{0xE0002, 0xE001F}, {0xE0080, 0xE00FF}, {0xE01F0, 0xEFFFF},
+	{0xFFFFE, 0xFFFFF},
+}
+
+var neutral = table{
+	{0x0000, 0x001F}, {0x007F, 0x007F}, {0x0080, 0x009F},
+	{0x00A0, 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, 0x00FF},
+	{0x0100, 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, 0x017F}, {0x0180, 0x01BA}, {0x01BB, 0x01BB},
+	{0x01BC, 0x01BF}, {0x01C0, 0x01C3}, {0x01C4, 0x01CD},
+	{0x01CF, 0x01CF}, {0x01D1, 0x01D1}, {0x01D3, 0x01D3},
+	{0x01D5, 0x01D5}, {0x01D7, 0x01D7}, {0x01D9, 0x01D9},
+	{0x01DB, 0x01DB}, {0x01DD, 0x024F}, {0x0250, 0x0250},
+	{0x0252, 0x0260}, {0x0262, 0x0293}, {0x0294, 0x0294},
+	{0x0295, 0x02AF}, {0x02B0, 0x02C1}, {0x02C2, 0x02C3},
+	{0x02C5, 0x02C5}, {0x02C6, 0x02C6}, {0x02C8, 0x02C8},
+	{0x02CC, 0x02CC}, {0x02CE, 0x02CF}, {0x02D1, 0x02D1},
+	{0x02D2, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE},
+	{0x02E0, 0x02E4}, {0x02E5, 0x02EB}, {0x02EC, 0x02EC},
+	{0x02ED, 0x02ED}, {0x02EE, 0x02EE}, {0x02EF, 0x02FF},
+	{0x0370, 0x0373}, {0x0374, 0x0374}, {0x0375, 0x0375},
+	{0x0376, 0x0377}, {0x037A, 0x037A}, {0x037B, 0x037D},
+	{0x037E, 0x037E}, {0x037F, 0x037F}, {0x0384, 0x0385},
+	{0x0386, 0x0386}, {0x0387, 0x0387}, {0x0388, 0x038A},
+	{0x038C, 0x038C}, {0x038E, 0x0390}, {0x03AA, 0x03B0},
+	{0x03C2, 0x03C2}, {0x03CA, 0x03F5}, {0x03F6, 0x03F6},
+	{0x03F7, 0x03FF}, {0x0400, 0x0400}, {0x0402, 0x040F},
+	{0x0450, 0x0450}, {0x0452, 0x0481}, {0x0482, 0x0482},
+	{0x0483, 0x0487}, {0x0488, 0x0489}, {0x048A, 0x04FF},
+	{0x0500, 0x052F}, {0x0531, 0x0556}, {0x0559, 0x0559},
+	{0x055A, 0x055F}, {0x0561, 0x0587}, {0x0589, 0x0589},
+	{0x058A, 0x058A}, {0x058D, 0x058E}, {0x058F, 0x058F},
+	{0x0591, 0x05BD}, {0x05BE, 0x05BE}, {0x05BF, 0x05BF},
+	{0x05C0, 0x05C0}, {0x05C1, 0x05C2}, {0x05C3, 0x05C3},
+	{0x05C4, 0x05C5}, {0x05C6, 0x05C6}, {0x05C7, 0x05C7},
+	{0x05D0, 0x05EA}, {0x05F0, 0x05F2}, {0x05F3, 0x05F4},
+	{0x0600, 0x0605}, {0x0606, 0x0608}, {0x0609, 0x060A},
+	{0x060B, 0x060B}, {0x060C, 0x060D}, {0x060E, 0x060F},
+	{0x0610, 0x061A}, {0x061B, 0x061B}, {0x061C, 0x061C},
+	{0x061E, 0x061F}, {0x0620, 0x063F}, {0x0640, 0x0640},
+	{0x0641, 0x064A}, {0x064B, 0x065F}, {0x0660, 0x0669},
+	{0x066A, 0x066D}, {0x066E, 0x066F}, {0x0670, 0x0670},
+	{0x0671, 0x06D3}, {0x06D4, 0x06D4}, {0x06D5, 0x06D5},
+	{0x06D6, 0x06DC}, {0x06DD, 0x06DD}, {0x06DE, 0x06DE},
+	{0x06DF, 0x06E4}, {0x06E5, 0x06E6}, {0x06E7, 0x06E8},
+	{0x06E9, 0x06E9}, {0x06EA, 0x06ED}, {0x06EE, 0x06EF},
+	{0x06F0, 0x06F9}, {0x06FA, 0x06FC}, {0x06FD, 0x06FE},
+	{0x06FF, 0x06FF}, {0x0700, 0x070D}, {0x070F, 0x070F},
+	{0x0710, 0x0710}, {0x0711, 0x0711}, {0x0712, 0x072F},
+	{0x0730, 0x074A}, {0x074D, 0x074F}, {0x0750, 0x077F},
+	{0x0780, 0x07A5}, {0x07A6, 0x07B0}, {0x07B1, 0x07B1},
+	{0x07C0, 0x07C9}, {0x07CA, 0x07EA}, {0x07EB, 0x07F3},
+	{0x07F4, 0x07F5}, {0x07F6, 0x07F6}, {0x07F7, 0x07F9},
+	{0x07FA, 0x07FA}, {0x0800, 0x0815}, {0x0816, 0x0819},
+	{0x081A, 0x081A}, {0x081B, 0x0823}, {0x0824, 0x0824},
+	{0x0825, 0x0827}, {0x0828, 0x0828}, {0x0829, 0x082D},
+	{0x0830, 0x083E}, {0x0840, 0x0858}, {0x0859, 0x085B},
+	{0x085E, 0x085E}, {0x08A0, 0x08B4}, {0x08B6, 0x08BD},
+	{0x08D4, 0x08E1}, {0x08E2, 0x08E2}, {0x08E3, 0x08FF},
+	{0x0900, 0x0902}, {0x0903, 0x0903}, {0x0904, 0x0939},
+	{0x093A, 0x093A}, {0x093B, 0x093B}, {0x093C, 0x093C},
+	{0x093D, 0x093D}, {0x093E, 0x0940}, {0x0941, 0x0948},
+	{0x0949, 0x094C}, {0x094D, 0x094D}, {0x094E, 0x094F},
+	{0x0950, 0x0950}, {0x0951, 0x0957}, {0x0958, 0x0961},
+	{0x0962, 0x0963}, {0x0964, 0x0965}, {0x0966, 0x096F},
+	{0x0970, 0x0970}, {0x0971, 0x0971}, {0x0972, 0x097F},
+	{0x0980, 0x0980}, {0x0981, 0x0981}, {0x0982, 0x0983},
+	{0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8},
+	{0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9},
+	{0x09BC, 0x09BC}, {0x09BD, 0x09BD}, {0x09BE, 0x09C0},
+	{0x09C1, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CC},
+	{0x09CD, 0x09CD}, {0x09CE, 0x09CE}, {0x09D7, 0x09D7},
+	{0x09DC, 0x09DD}, {0x09DF, 0x09E1}, {0x09E2, 0x09E3},
+	{0x09E6, 0x09EF}, {0x09F0, 0x09F1}, {0x09F2, 0x09F3},
+	{0x09F4, 0x09F9}, {0x09FA, 0x09FA}, {0x09FB, 0x09FB},
+	{0x0A01, 0x0A02}, {0x0A03, 0x0A03}, {0x0A05, 0x0A0A},
+	{0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30},
+	{0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39},
+	{0x0A3C, 0x0A3C}, {0x0A3E, 0x0A40}, {0x0A41, 0x0A42},
+	{0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51},
+	{0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A6F},
+	{0x0A70, 0x0A71}, {0x0A72, 0x0A74}, {0x0A75, 0x0A75},
+	{0x0A81, 0x0A82}, {0x0A83, 0x0A83}, {0x0A85, 0x0A8D},
+	{0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0},
+	{0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABC, 0x0ABC},
+	{0x0ABD, 0x0ABD}, {0x0ABE, 0x0AC0}, {0x0AC1, 0x0AC5},
+	{0x0AC7, 0x0AC8}, {0x0AC9, 0x0AC9}, {0x0ACB, 0x0ACC},
+	{0x0ACD, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE1},
+	{0x0AE2, 0x0AE3}, {0x0AE6, 0x0AEF}, {0x0AF0, 0x0AF0},
+	{0x0AF1, 0x0AF1}, {0x0AF9, 0x0AF9}, {0x0B01, 0x0B01},
+	{0x0B02, 0x0B03}, {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10},
+	{0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33},
+	{0x0B35, 0x0B39}, {0x0B3C, 0x0B3C}, {0x0B3D, 0x0B3D},
+	{0x0B3E, 0x0B3E}, {0x0B3F, 0x0B3F}, {0x0B40, 0x0B40},
+	{0x0B41, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4C},
+	{0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B57, 0x0B57},
+	{0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B62, 0x0B63},
+	{0x0B66, 0x0B6F}, {0x0B70, 0x0B70}, {0x0B71, 0x0B71},
+	{0x0B72, 0x0B77}, {0x0B82, 0x0B82}, {0x0B83, 0x0B83},
+	{0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, {0x0B92, 0x0B95},
+	{0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F},
+	{0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9},
+	{0x0BBE, 0x0BBF}, {0x0BC0, 0x0BC0}, {0x0BC1, 0x0BC2},
+	{0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCC}, {0x0BCD, 0x0BCD},
+	{0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BEF},
+	{0x0BF0, 0x0BF2}, {0x0BF3, 0x0BF8}, {0x0BF9, 0x0BF9},
+	{0x0BFA, 0x0BFA}, {0x0C00, 0x0C00}, {0x0C01, 0x0C03},
+	{0x0C05, 0x0C0C}, {0x0C0E, 0x0C10}, {0x0C12, 0x0C28},
+	{0x0C2A, 0x0C39}, {0x0C3D, 0x0C3D}, {0x0C3E, 0x0C40},
+	{0x0C41, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
+	{0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C61},
+	{0x0C62, 0x0C63}, {0x0C66, 0x0C6F}, {0x0C78, 0x0C7E},
+	{0x0C7F, 0x0C7F}, {0x0C80, 0x0C80}, {0x0C81, 0x0C81},
+	{0x0C82, 0x0C83}, {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90},
+	{0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9},
+	{0x0CBC, 0x0CBC}, {0x0CBD, 0x0CBD}, {0x0CBE, 0x0CBE},
+	{0x0CBF, 0x0CBF}, {0x0CC0, 0x0CC4}, {0x0CC6, 0x0CC6},
+	{0x0CC7, 0x0CC8}, {0x0CCA, 0x0CCB}, {0x0CCC, 0x0CCD},
+	{0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE1},
+	{0x0CE2, 0x0CE3}, {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2},
+	{0x0D01, 0x0D01}, {0x0D02, 0x0D03}, {0x0D05, 0x0D0C},
+	{0x0D0E, 0x0D10}, {0x0D12, 0x0D3A}, {0x0D3D, 0x0D3D},
+	{0x0D3E, 0x0D40}, {0x0D41, 0x0D44}, {0x0D46, 0x0D48},
+	{0x0D4A, 0x0D4C}, {0x0D4D, 0x0D4D}, {0x0D4E, 0x0D4E},
+	{0x0D4F, 0x0D4F}, {0x0D54, 0x0D56}, {0x0D57, 0x0D57},
+	{0x0D58, 0x0D5E}, {0x0D5F, 0x0D61}, {0x0D62, 0x0D63},
+	{0x0D66, 0x0D6F}, {0x0D70, 0x0D78}, {0x0D79, 0x0D79},
+	{0x0D7A, 0x0D7F}, {0x0D82, 0x0D83}, {0x0D85, 0x0D96},
+	{0x0D9A, 0x0DB1}, {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD},
+	{0x0DC0, 0x0DC6}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD1},
+	{0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF},
+	{0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF3}, {0x0DF4, 0x0DF4},
+	{0x0E01, 0x0E30}, {0x0E31, 0x0E31}, {0x0E32, 0x0E33},
+	{0x0E34, 0x0E3A}, {0x0E3F, 0x0E3F}, {0x0E40, 0x0E45},
+	{0x0E46, 0x0E46}, {0x0E47, 0x0E4E}, {0x0E4F, 0x0E4F},
+	{0x0E50, 0x0E59}, {0x0E5A, 0x0E5B}, {0x0E81, 0x0E82},
+	{0x0E84, 0x0E84}, {0x0E87, 0x0E88}, {0x0E8A, 0x0E8A},
+	{0x0E8D, 0x0E8D}, {0x0E94, 0x0E97}, {0x0E99, 0x0E9F},
+	{0x0EA1, 0x0EA3}, {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EA7},
+	{0x0EAA, 0x0EAB}, {0x0EAD, 0x0EB0}, {0x0EB1, 0x0EB1},
+	{0x0EB2, 0x0EB3}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
+	{0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, {0x0EC6, 0x0EC6},
+	{0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, {0x0EDC, 0x0EDF},
+	{0x0F00, 0x0F00}, {0x0F01, 0x0F03}, {0x0F04, 0x0F12},
+	{0x0F13, 0x0F13}, {0x0F14, 0x0F14}, {0x0F15, 0x0F17},
+	{0x0F18, 0x0F19}, {0x0F1A, 0x0F1F}, {0x0F20, 0x0F29},
+	{0x0F2A, 0x0F33}, {0x0F34, 0x0F34}, {0x0F35, 0x0F35},
+	{0x0F36, 0x0F36}, {0x0F37, 0x0F37}, {0x0F38, 0x0F38},
+	{0x0F39, 0x0F39}, {0x0F3A, 0x0F3A}, {0x0F3B, 0x0F3B},
+	{0x0F3C, 0x0F3C}, {0x0F3D, 0x0F3D}, {0x0F3E, 0x0F3F},
+	{0x0F40, 0x0F47}, {0x0F49, 0x0F6C}, {0x0F71, 0x0F7E},
+	{0x0F7F, 0x0F7F}, {0x0F80, 0x0F84}, {0x0F85, 0x0F85},
+	{0x0F86, 0x0F87}, {0x0F88, 0x0F8C}, {0x0F8D, 0x0F97},
+	{0x0F99, 0x0FBC}, {0x0FBE, 0x0FC5}, {0x0FC6, 0x0FC6},
+	{0x0FC7, 0x0FCC}, {0x0FCE, 0x0FCF}, {0x0FD0, 0x0FD4},
+	{0x0FD5, 0x0FD8}, {0x0FD9, 0x0FDA}, {0x1000, 0x102A},
+	{0x102B, 0x102C}, {0x102D, 0x1030}, {0x1031, 0x1031},
+	{0x1032, 0x1037}, {0x1038, 0x1038}, {0x1039, 0x103A},
+	{0x103B, 0x103C}, {0x103D, 0x103E}, {0x103F, 0x103F},
+	{0x1040, 0x1049}, {0x104A, 0x104F}, {0x1050, 0x1055},
+	{0x1056, 0x1057}, {0x1058, 0x1059}, {0x105A, 0x105D},
+	{0x105E, 0x1060}, {0x1061, 0x1061}, {0x1062, 0x1064},
+	{0x1065, 0x1066}, {0x1067, 0x106D}, {0x106E, 0x1070},
+	{0x1071, 0x1074}, {0x1075, 0x1081}, {0x1082, 0x1082},
+	{0x1083, 0x1084}, {0x1085, 0x1086}, {0x1087, 0x108C},
+	{0x108D, 0x108D}, {0x108E, 0x108E}, {0x108F, 0x108F},
+	{0x1090, 0x1099}, {0x109A, 0x109C}, {0x109D, 0x109D},
+	{0x109E, 0x109F}, {0x10A0, 0x10C5}, {0x10C7, 0x10C7},
+	{0x10CD, 0x10CD}, {0x10D0, 0x10FA}, {0x10FB, 0x10FB},
+	{0x10FC, 0x10FC}, {0x10FD, 0x10FF}, {0x1160, 0x11FF},
+	{0x1200, 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, 0x135F}, {0x1360, 0x1368},
+	{0x1369, 0x137C}, {0x1380, 0x138F}, {0x1390, 0x1399},
+	{0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1400, 0x1400},
+	{0x1401, 0x166C}, {0x166D, 0x166E}, {0x166F, 0x167F},
+	{0x1680, 0x1680}, {0x1681, 0x169A}, {0x169B, 0x169B},
+	{0x169C, 0x169C}, {0x16A0, 0x16EA}, {0x16EB, 0x16ED},
+	{0x16EE, 0x16F0}, {0x16F1, 0x16F8}, {0x1700, 0x170C},
+	{0x170E, 0x1711}, {0x1712, 0x1714}, {0x1720, 0x1731},
+	{0x1732, 0x1734}, {0x1735, 0x1736}, {0x1740, 0x1751},
+	{0x1752, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770},
+	{0x1772, 0x1773}, {0x1780, 0x17B3}, {0x17B4, 0x17B5},
+	{0x17B6, 0x17B6}, {0x17B7, 0x17BD}, {0x17BE, 0x17C5},
+	{0x17C6, 0x17C6}, {0x17C7, 0x17C8}, {0x17C9, 0x17D3},
+	{0x17D4, 0x17D6}, {0x17D7, 0x17D7}, {0x17D8, 0x17DA},
+	{0x17DB, 0x17DB}, {0x17DC, 0x17DC}, {0x17DD, 0x17DD},
+	{0x17E0, 0x17E9}, {0x17F0, 0x17F9}, {0x1800, 0x1805},
+	{0x1806, 0x1806}, {0x1807, 0x180A}, {0x180B, 0x180D},
+	{0x180E, 0x180E}, {0x1810, 0x1819}, {0x1820, 0x1842},
+	{0x1843, 0x1843}, {0x1844, 0x1877}, {0x1880, 0x1884},
+	{0x1885, 0x1886}, {0x1887, 0x18A8}, {0x18A9, 0x18A9},
+	{0x18AA, 0x18AA}, {0x18B0, 0x18F5}, {0x1900, 0x191E},
+	{0x1920, 0x1922}, {0x1923, 0x1926}, {0x1927, 0x1928},
+	{0x1929, 0x192B}, {0x1930, 0x1931}, {0x1932, 0x1932},
+	{0x1933, 0x1938}, {0x1939, 0x193B}, {0x1940, 0x1940},
+	{0x1944, 0x1945}, {0x1946, 0x194F}, {0x1950, 0x196D},
+	{0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9},
+	{0x19D0, 0x19D9}, {0x19DA, 0x19DA}, {0x19DE, 0x19DF},
+	{0x19E0, 0x19FF}, {0x1A00, 0x1A16}, {0x1A17, 0x1A18},
+	{0x1A19, 0x1A1A}, {0x1A1B, 0x1A1B}, {0x1A1E, 0x1A1F},
+	{0x1A20, 0x1A54}, {0x1A55, 0x1A55}, {0x1A56, 0x1A56},
+	{0x1A57, 0x1A57}, {0x1A58, 0x1A5E}, {0x1A60, 0x1A60},
+	{0x1A61, 0x1A61}, {0x1A62, 0x1A62}, {0x1A63, 0x1A64},
+	{0x1A65, 0x1A6C}, {0x1A6D, 0x1A72}, {0x1A73, 0x1A7C},
+	{0x1A7F, 0x1A7F}, {0x1A80, 0x1A89}, {0x1A90, 0x1A99},
+	{0x1AA0, 0x1AA6}, {0x1AA7, 0x1AA7}, {0x1AA8, 0x1AAD},
+	{0x1AB0, 0x1ABD}, {0x1ABE, 0x1ABE}, {0x1B00, 0x1B03},
+	{0x1B04, 0x1B04}, {0x1B05, 0x1B33}, {0x1B34, 0x1B34},
+	{0x1B35, 0x1B35}, {0x1B36, 0x1B3A}, {0x1B3B, 0x1B3B},
+	{0x1B3C, 0x1B3C}, {0x1B3D, 0x1B41}, {0x1B42, 0x1B42},
+	{0x1B43, 0x1B44}, {0x1B45, 0x1B4B}, {0x1B50, 0x1B59},
+	{0x1B5A, 0x1B60}, {0x1B61, 0x1B6A}, {0x1B6B, 0x1B73},
+	{0x1B74, 0x1B7C}, {0x1B80, 0x1B81}, {0x1B82, 0x1B82},
+	{0x1B83, 0x1BA0}, {0x1BA1, 0x1BA1}, {0x1BA2, 0x1BA5},
+	{0x1BA6, 0x1BA7}, {0x1BA8, 0x1BA9}, {0x1BAA, 0x1BAA},
+	{0x1BAB, 0x1BAD}, {0x1BAE, 0x1BAF}, {0x1BB0, 0x1BB9},
+	{0x1BBA, 0x1BBF}, {0x1BC0, 0x1BE5}, {0x1BE6, 0x1BE6},
+	{0x1BE7, 0x1BE7}, {0x1BE8, 0x1BE9}, {0x1BEA, 0x1BEC},
+	{0x1BED, 0x1BED}, {0x1BEE, 0x1BEE}, {0x1BEF, 0x1BF1},
+	{0x1BF2, 0x1BF3}, {0x1BFC, 0x1BFF}, {0x1C00, 0x1C23},
+	{0x1C24, 0x1C2B}, {0x1C2C, 0x1C33}, {0x1C34, 0x1C35},
+	{0x1C36, 0x1C37}, {0x1C3B, 0x1C3F}, {0x1C40, 0x1C49},
+	{0x1C4D, 0x1C4F}, {0x1C50, 0x1C59}, {0x1C5A, 0x1C77},
+	{0x1C78, 0x1C7D}, {0x1C7E, 0x1C7F}, {0x1C80, 0x1C88},
+	{0x1CC0, 0x1CC7}, {0x1CD0, 0x1CD2}, {0x1CD3, 0x1CD3},
+	{0x1CD4, 0x1CE0}, {0x1CE1, 0x1CE1}, {0x1CE2, 0x1CE8},
+	{0x1CE9, 0x1CEC}, {0x1CED, 0x1CED}, {0x1CEE, 0x1CF1},
+	{0x1CF2, 0x1CF3}, {0x1CF4, 0x1CF4}, {0x1CF5, 0x1CF6},
+	{0x1CF8, 0x1CF9}, {0x1D00, 0x1D2B}, {0x1D2C, 0x1D6A},
+	{0x1D6B, 0x1D77}, {0x1D78, 0x1D78}, {0x1D79, 0x1D7F},
+	{0x1D80, 0x1D9A}, {0x1D9B, 0x1DBF}, {0x1DC0, 0x1DF5},
+	{0x1DFB, 0x1DFF}, {0x1E00, 0x1EFF}, {0x1F00, 0x1F15},
+	{0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
+	{0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B},
+	{0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4},
+	{0x1FB6, 0x1FBC}, {0x1FBD, 0x1FBD}, {0x1FBE, 0x1FBE},
+	{0x1FBF, 0x1FC1}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC},
+	{0x1FCD, 0x1FCF}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB},
+	{0x1FDD, 0x1FDF}, {0x1FE0, 0x1FEC}, {0x1FED, 0x1FEF},
+	{0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x1FFD, 0x1FFE},
+	{0x2000, 0x200A}, {0x200B, 0x200F}, {0x2011, 0x2012},
+	{0x2017, 0x2017}, {0x201A, 0x201A}, {0x201B, 0x201B},
+	{0x201E, 0x201E}, {0x201F, 0x201F}, {0x2023, 0x2023},
+	{0x2028, 0x2028}, {0x2029, 0x2029}, {0x202A, 0x202E},
+	{0x202F, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034},
+	{0x2036, 0x2038}, {0x2039, 0x2039}, {0x203A, 0x203A},
+	{0x203C, 0x203D}, {0x203F, 0x2040}, {0x2041, 0x2043},
+	{0x2044, 0x2044}, {0x2045, 0x2045}, {0x2046, 0x2046},
+	{0x2047, 0x2051}, {0x2052, 0x2052}, {0x2053, 0x2053},
+	{0x2054, 0x2054}, {0x2055, 0x205E}, {0x205F, 0x205F},
+	{0x2060, 0x2064}, {0x2066, 0x206F}, {0x2070, 0x2070},
+	{0x2071, 0x2071}, {0x2075, 0x2079}, {0x207A, 0x207C},
+	{0x207D, 0x207D}, {0x207E, 0x207E}, {0x2080, 0x2080},
+	{0x2085, 0x2089}, {0x208A, 0x208C}, {0x208D, 0x208D},
+	{0x208E, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8},
+	{0x20AA, 0x20AB}, {0x20AD, 0x20BE}, {0x20D0, 0x20DC},
+	{0x20DD, 0x20E0}, {0x20E1, 0x20E1}, {0x20E2, 0x20E4},
+	{0x20E5, 0x20F0}, {0x2100, 0x2101}, {0x2102, 0x2102},
+	{0x2104, 0x2104}, {0x2106, 0x2106}, {0x2107, 0x2107},
+	{0x2108, 0x2108}, {0x210A, 0x2112}, {0x2114, 0x2114},
+	{0x2115, 0x2115}, {0x2117, 0x2117}, {0x2118, 0x2118},
+	{0x2119, 0x211D}, {0x211E, 0x2120}, {0x2123, 0x2123},
+	{0x2124, 0x2124}, {0x2125, 0x2125}, {0x2127, 0x2127},
+	{0x2128, 0x2128}, {0x2129, 0x2129}, {0x212A, 0x212A},
+	{0x212C, 0x212D}, {0x212E, 0x212E}, {0x212F, 0x2134},
+	{0x2135, 0x2138}, {0x2139, 0x2139}, {0x213A, 0x213B},
+	{0x213C, 0x213F}, {0x2140, 0x2144}, {0x2145, 0x2149},
+	{0x214A, 0x214A}, {0x214B, 0x214B}, {0x214C, 0x214D},
+	{0x214E, 0x214E}, {0x214F, 0x214F}, {0x2150, 0x2152},
+	{0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F},
+	{0x217A, 0x2182}, {0x2183, 0x2184}, {0x2185, 0x2188},
+	{0x218A, 0x218B}, {0x219A, 0x219B}, {0x219C, 0x219F},
+	{0x21A0, 0x21A0}, {0x21A1, 0x21A2}, {0x21A3, 0x21A3},
+	{0x21A4, 0x21A5}, {0x21A6, 0x21A6}, {0x21A7, 0x21AD},
+	{0x21AE, 0x21AE}, {0x21AF, 0x21B7}, {0x21BA, 0x21CD},
+	{0x21CE, 0x21CF}, {0x21D0, 0x21D1}, {0x21D3, 0x21D3},
+	{0x21D5, 0x21E6}, {0x21E8, 0x21F3}, {0x21F4, 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, 0x22FF}, {0x2300, 0x2307}, {0x2308, 0x2308},
+	{0x2309, 0x2309}, {0x230A, 0x230A}, {0x230B, 0x230B},
+	{0x230C, 0x2311}, {0x2313, 0x2319}, {0x231C, 0x231F},
+	{0x2320, 0x2321}, {0x2322, 0x2328}, {0x232B, 0x237B},
+	{0x237C, 0x237C}, {0x237D, 0x239A}, {0x239B, 0x23B3},
+	{0x23B4, 0x23DB}, {0x23DC, 0x23E1}, {0x23E2, 0x23E8},
+	{0x23ED, 0x23EF}, {0x23F1, 0x23F2}, {0x23F4, 0x23FE},
+	{0x2400, 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, 0x25F7},
+	{0x25F8, 0x25FC}, {0x25FF, 0x25FF}, {0x2600, 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, 0x2767}, {0x2768, 0x2768}, {0x2769, 0x2769},
+	{0x276A, 0x276A}, {0x276B, 0x276B}, {0x276C, 0x276C},
+	{0x276D, 0x276D}, {0x276E, 0x276E}, {0x276F, 0x276F},
+	{0x2770, 0x2770}, {0x2771, 0x2771}, {0x2772, 0x2772},
+	{0x2773, 0x2773}, {0x2774, 0x2774}, {0x2775, 0x2775},
+	{0x2780, 0x2793}, {0x2794, 0x2794}, {0x2798, 0x27AF},
+	{0x27B1, 0x27BE}, {0x27C0, 0x27C4}, {0x27C5, 0x27C5},
+	{0x27C6, 0x27C6}, {0x27C7, 0x27E5}, {0x27EE, 0x27EE},
+	{0x27EF, 0x27EF}, {0x27F0, 0x27FF}, {0x2800, 0x28FF},
+	{0x2900, 0x297F}, {0x2980, 0x2982}, {0x2983, 0x2983},
+	{0x2984, 0x2984}, {0x2987, 0x2987}, {0x2988, 0x2988},
+	{0x2989, 0x2989}, {0x298A, 0x298A}, {0x298B, 0x298B},
+	{0x298C, 0x298C}, {0x298D, 0x298D}, {0x298E, 0x298E},
+	{0x298F, 0x298F}, {0x2990, 0x2990}, {0x2991, 0x2991},
+	{0x2992, 0x2992}, {0x2993, 0x2993}, {0x2994, 0x2994},
+	{0x2995, 0x2995}, {0x2996, 0x2996}, {0x2997, 0x2997},
+	{0x2998, 0x2998}, {0x2999, 0x29D7}, {0x29D8, 0x29D8},
+	{0x29D9, 0x29D9}, {0x29DA, 0x29DA}, {0x29DB, 0x29DB},
+	{0x29DC, 0x29FB}, {0x29FC, 0x29FC}, {0x29FD, 0x29FD},
+	{0x29FE, 0x29FF}, {0x2A00, 0x2AFF}, {0x2B00, 0x2B1A},
+	{0x2B1D, 0x2B2F}, {0x2B30, 0x2B44}, {0x2B45, 0x2B46},
+	{0x2B47, 0x2B4C}, {0x2B4D, 0x2B4F}, {0x2B51, 0x2B54},
+	{0x2B5A, 0x2B73}, {0x2B76, 0x2B95}, {0x2B98, 0x2BB9},
+	{0x2BBD, 0x2BC8}, {0x2BCA, 0x2BD1}, {0x2BEC, 0x2BEF},
+	{0x2C00, 0x2C2E}, {0x2C30, 0x2C5E}, {0x2C60, 0x2C7B},
+	{0x2C7C, 0x2C7D}, {0x2C7E, 0x2C7F}, {0x2C80, 0x2CE4},
+	{0x2CE5, 0x2CEA}, {0x2CEB, 0x2CEE}, {0x2CEF, 0x2CF1},
+	{0x2CF2, 0x2CF3}, {0x2CF9, 0x2CFC}, {0x2CFD, 0x2CFD},
+	{0x2CFE, 0x2CFF}, {0x2D00, 0x2D25}, {0x2D27, 0x2D27},
+	{0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D6F},
+	{0x2D70, 0x2D70}, {0x2D7F, 0x2D7F}, {0x2D80, 0x2D96},
+	{0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6},
+	{0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE},
+	{0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x2DE0, 0x2DFF},
+	{0x2E00, 0x2E01}, {0x2E02, 0x2E02}, {0x2E03, 0x2E03},
+	{0x2E04, 0x2E04}, {0x2E05, 0x2E05}, {0x2E06, 0x2E08},
+	{0x2E09, 0x2E09}, {0x2E0A, 0x2E0A}, {0x2E0B, 0x2E0B},
+	{0x2E0C, 0x2E0C}, {0x2E0D, 0x2E0D}, {0x2E0E, 0x2E16},
+	{0x2E17, 0x2E17}, {0x2E18, 0x2E19}, {0x2E1A, 0x2E1A},
+	{0x2E1B, 0x2E1B}, {0x2E1C, 0x2E1C}, {0x2E1D, 0x2E1D},
+	{0x2E1E, 0x2E1F}, {0x2E20, 0x2E20}, {0x2E21, 0x2E21},
+	{0x2E22, 0x2E22}, {0x2E23, 0x2E23}, {0x2E24, 0x2E24},
+	{0x2E25, 0x2E25}, {0x2E26, 0x2E26}, {0x2E27, 0x2E27},
+	{0x2E28, 0x2E28}, {0x2E29, 0x2E29}, {0x2E2A, 0x2E2E},
+	{0x2E2F, 0x2E2F}, {0x2E30, 0x2E39}, {0x2E3A, 0x2E3B},
+	{0x2E3C, 0x2E3F}, {0x2E40, 0x2E40}, {0x2E41, 0x2E41},
+	{0x2E42, 0x2E42}, {0x2E43, 0x2E44}, {0x303F, 0x303F},
+	{0x4DC0, 0x4DFF}, {0xA4D0, 0xA4F7}, {0xA4F8, 0xA4FD},
+	{0xA4FE, 0xA4FF}, {0xA500, 0xA60B}, {0xA60C, 0xA60C},
+	{0xA60D, 0xA60F}, {0xA610, 0xA61F}, {0xA620, 0xA629},
+	{0xA62A, 0xA62B}, {0xA640, 0xA66D}, {0xA66E, 0xA66E},
+	{0xA66F, 0xA66F}, {0xA670, 0xA672}, {0xA673, 0xA673},
+	{0xA674, 0xA67D}, {0xA67E, 0xA67E}, {0xA67F, 0xA67F},
+	{0xA680, 0xA69B}, {0xA69C, 0xA69D}, {0xA69E, 0xA69F},
+	{0xA6A0, 0xA6E5}, {0xA6E6, 0xA6EF}, {0xA6F0, 0xA6F1},
+	{0xA6F2, 0xA6F7}, {0xA700, 0xA716}, {0xA717, 0xA71F},
+	{0xA720, 0xA721}, {0xA722, 0xA76F}, {0xA770, 0xA770},
+	{0xA771, 0xA787}, {0xA788, 0xA788}, {0xA789, 0xA78A},
+	{0xA78B, 0xA78E}, {0xA78F, 0xA78F}, {0xA790, 0xA7AE},
+	{0xA7B0, 0xA7B7}, {0xA7F7, 0xA7F7}, {0xA7F8, 0xA7F9},
+	{0xA7FA, 0xA7FA}, {0xA7FB, 0xA7FF}, {0xA800, 0xA801},
+	{0xA802, 0xA802}, {0xA803, 0xA805}, {0xA806, 0xA806},
+	{0xA807, 0xA80A}, {0xA80B, 0xA80B}, {0xA80C, 0xA822},
+	{0xA823, 0xA824}, {0xA825, 0xA826}, {0xA827, 0xA827},
+	{0xA828, 0xA82B}, {0xA830, 0xA835}, {0xA836, 0xA837},
+	{0xA838, 0xA838}, {0xA839, 0xA839}, {0xA840, 0xA873},
+	{0xA874, 0xA877}, {0xA880, 0xA881}, {0xA882, 0xA8B3},
+	{0xA8B4, 0xA8C3}, {0xA8C4, 0xA8C5}, {0xA8CE, 0xA8CF},
+	{0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1}, {0xA8F2, 0xA8F7},
+	{0xA8F8, 0xA8FA}, {0xA8FB, 0xA8FB}, {0xA8FC, 0xA8FC},
+	{0xA8FD, 0xA8FD}, {0xA900, 0xA909}, {0xA90A, 0xA925},
+	{0xA926, 0xA92D}, {0xA92E, 0xA92F}, {0xA930, 0xA946},
+	{0xA947, 0xA951}, {0xA952, 0xA953}, {0xA95F, 0xA95F},
+	{0xA980, 0xA982}, {0xA983, 0xA983}, {0xA984, 0xA9B2},
+	{0xA9B3, 0xA9B3}, {0xA9B4, 0xA9B5}, {0xA9B6, 0xA9B9},
+	{0xA9BA, 0xA9BB}, {0xA9BC, 0xA9BC}, {0xA9BD, 0xA9C0},
+	{0xA9C1, 0xA9CD}, {0xA9CF, 0xA9CF}, {0xA9D0, 0xA9D9},
+	{0xA9DE, 0xA9DF}, {0xA9E0, 0xA9E4}, {0xA9E5, 0xA9E5},
+	{0xA9E6, 0xA9E6}, {0xA9E7, 0xA9EF}, {0xA9F0, 0xA9F9},
+	{0xA9FA, 0xA9FE}, {0xAA00, 0xAA28}, {0xAA29, 0xAA2E},
+	{0xAA2F, 0xAA30}, {0xAA31, 0xAA32}, {0xAA33, 0xAA34},
+	{0xAA35, 0xAA36}, {0xAA40, 0xAA42}, {0xAA43, 0xAA43},
+	{0xAA44, 0xAA4B}, {0xAA4C, 0xAA4C}, {0xAA4D, 0xAA4D},
+	{0xAA50, 0xAA59}, {0xAA5C, 0xAA5F}, {0xAA60, 0xAA6F},
+	{0xAA70, 0xAA70}, {0xAA71, 0xAA76}, {0xAA77, 0xAA79},
+	{0xAA7A, 0xAA7A}, {0xAA7B, 0xAA7B}, {0xAA7C, 0xAA7C},
+	{0xAA7D, 0xAA7D}, {0xAA7E, 0xAA7F}, {0xAA80, 0xAAAF},
+	{0xAAB0, 0xAAB0}, {0xAAB1, 0xAAB1}, {0xAAB2, 0xAAB4},
+	{0xAAB5, 0xAAB6}, {0xAAB7, 0xAAB8}, {0xAAB9, 0xAABD},
+	{0xAABE, 0xAABF}, {0xAAC0, 0xAAC0}, {0xAAC1, 0xAAC1},
+	{0xAAC2, 0xAAC2}, {0xAADB, 0xAADC}, {0xAADD, 0xAADD},
+	{0xAADE, 0xAADF}, {0xAAE0, 0xAAEA}, {0xAAEB, 0xAAEB},
+	{0xAAEC, 0xAAED}, {0xAAEE, 0xAAEF}, {0xAAF0, 0xAAF1},
+	{0xAAF2, 0xAAF2}, {0xAAF3, 0xAAF4}, {0xAAF5, 0xAAF5},
+	{0xAAF6, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E},
+	{0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E},
+	{0xAB30, 0xAB5A}, {0xAB5B, 0xAB5B}, {0xAB5C, 0xAB5F},
+	{0xAB60, 0xAB65}, {0xAB70, 0xABBF}, {0xABC0, 0xABE2},
+	{0xABE3, 0xABE4}, {0xABE5, 0xABE5}, {0xABE6, 0xABE7},
+	{0xABE8, 0xABE8}, {0xABE9, 0xABEA}, {0xABEB, 0xABEB},
+	{0xABEC, 0xABEC}, {0xABED, 0xABED}, {0xABF0, 0xABF9},
+	{0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDB7F},
+	{0xDB80, 0xDBFF}, {0xDC00, 0xDFFF}, {0xFB00, 0xFB06},
+	{0xFB13, 0xFB17}, {0xFB1D, 0xFB1D}, {0xFB1E, 0xFB1E},
+	{0xFB1F, 0xFB28}, {0xFB29, 0xFB29}, {0xFB2A, 0xFB36},
+	{0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41},
+	{0xFB43, 0xFB44}, {0xFB46, 0xFB4F}, {0xFB50, 0xFBB1},
+	{0xFBB2, 0xFBC1}, {0xFBD3, 0xFD3D}, {0xFD3E, 0xFD3E},
+	{0xFD3F, 0xFD3F}, {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7},
+	{0xFDF0, 0xFDFB}, {0xFDFC, 0xFDFC}, {0xFDFD, 0xFDFD},
+	{0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC},
+	{0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFC, 0xFFFC},
+	{0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A},
+	{0x1003C, 0x1003D}, {0x1003F, 0x1004D}, {0x10050, 0x1005D},
+	{0x10080, 0x100FA}, {0x10100, 0x10102}, {0x10107, 0x10133},
+	{0x10137, 0x1013F}, {0x10140, 0x10174}, {0x10175, 0x10178},
+	{0x10179, 0x10189}, {0x1018A, 0x1018B}, {0x1018C, 0x1018E},
+	{0x10190, 0x1019B}, {0x101A0, 0x101A0}, {0x101D0, 0x101FC},
+	{0x101FD, 0x101FD}, {0x10280, 0x1029C}, {0x102A0, 0x102D0},
+	{0x102E0, 0x102E0}, {0x102E1, 0x102FB}, {0x10300, 0x1031F},
+	{0x10320, 0x10323}, {0x10330, 0x10340}, {0x10341, 0x10341},
+	{0x10342, 0x10349}, {0x1034A, 0x1034A}, {0x10350, 0x10375},
+	{0x10376, 0x1037A}, {0x10380, 0x1039D}, {0x1039F, 0x1039F},
+	{0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x103D0, 0x103D0},
+	{0x103D1, 0x103D5}, {0x10400, 0x1044F}, {0x10450, 0x1047F},
+	{0x10480, 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, 0x1083F}, {0x10840, 0x10855}, {0x10857, 0x10857},
+	{0x10858, 0x1085F}, {0x10860, 0x10876}, {0x10877, 0x10878},
+	{0x10879, 0x1087F}, {0x10880, 0x1089E}, {0x108A7, 0x108AF},
+	{0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x108FF},
+	{0x10900, 0x10915}, {0x10916, 0x1091B}, {0x1091F, 0x1091F},
+	{0x10920, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x1099F},
+	{0x109A0, 0x109B7}, {0x109BC, 0x109BD}, {0x109BE, 0x109BF},
+	{0x109C0, 0x109CF}, {0x109D2, 0x109FF}, {0x10A00, 0x10A00},
+	{0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
+	{0x10A10, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A33},
+	{0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x10A40, 0x10A47},
+	{0x10A50, 0x10A58}, {0x10A60, 0x10A7C}, {0x10A7D, 0x10A7E},
+	{0x10A7F, 0x10A7F}, {0x10A80, 0x10A9C}, {0x10A9D, 0x10A9F},
+	{0x10AC0, 0x10AC7}, {0x10AC8, 0x10AC8}, {0x10AC9, 0x10AE4},
+	{0x10AE5, 0x10AE6}, {0x10AEB, 0x10AEF}, {0x10AF0, 0x10AF6},
+	{0x10B00, 0x10B35}, {0x10B39, 0x10B3F}, {0x10B40, 0x10B55},
+	{0x10B58, 0x10B5F}, {0x10B60, 0x10B72}, {0x10B78, 0x10B7F},
+	{0x10B80, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF},
+	{0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2},
+	{0x10CFA, 0x10CFF}, {0x10E60, 0x10E7E}, {0x11000, 0x11000},
+	{0x11001, 0x11001}, {0x11002, 0x11002}, {0x11003, 0x11037},
+	{0x11038, 0x11046}, {0x11047, 0x1104D}, {0x11052, 0x11065},
+	{0x11066, 0x1106F}, {0x1107F, 0x1107F}, {0x11080, 0x11081},
+	{0x11082, 0x11082}, {0x11083, 0x110AF}, {0x110B0, 0x110B2},
+	{0x110B3, 0x110B6}, {0x110B7, 0x110B8}, {0x110B9, 0x110BA},
+	{0x110BB, 0x110BC}, {0x110BD, 0x110BD}, {0x110BE, 0x110C1},
+	{0x110D0, 0x110E8}, {0x110F0, 0x110F9}, {0x11100, 0x11102},
+	{0x11103, 0x11126}, {0x11127, 0x1112B}, {0x1112C, 0x1112C},
+	{0x1112D, 0x11134}, {0x11136, 0x1113F}, {0x11140, 0x11143},
+	{0x11150, 0x11172}, {0x11173, 0x11173}, {0x11174, 0x11175},
+	{0x11176, 0x11176}, {0x11180, 0x11181}, {0x11182, 0x11182},
+	{0x11183, 0x111B2}, {0x111B3, 0x111B5}, {0x111B6, 0x111BE},
+	{0x111BF, 0x111C0}, {0x111C1, 0x111C4}, {0x111C5, 0x111C9},
+	{0x111CA, 0x111CC}, {0x111CD, 0x111CD}, {0x111D0, 0x111D9},
+	{0x111DA, 0x111DA}, {0x111DB, 0x111DB}, {0x111DC, 0x111DC},
+	{0x111DD, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211},
+	{0x11213, 0x1122B}, {0x1122C, 0x1122E}, {0x1122F, 0x11231},
+	{0x11232, 0x11233}, {0x11234, 0x11234}, {0x11235, 0x11235},
+	{0x11236, 0x11237}, {0x11238, 0x1123D}, {0x1123E, 0x1123E},
+	{0x11280, 0x11286}, {0x11288, 0x11288}, {0x1128A, 0x1128D},
+	{0x1128F, 0x1129D}, {0x1129F, 0x112A8}, {0x112A9, 0x112A9},
+	{0x112B0, 0x112DE}, {0x112DF, 0x112DF}, {0x112E0, 0x112E2},
+	{0x112E3, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11301},
+	{0x11302, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310},
+	{0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333},
+	{0x11335, 0x11339}, {0x1133C, 0x1133C}, {0x1133D, 0x1133D},
+	{0x1133E, 0x1133F}, {0x11340, 0x11340}, {0x11341, 0x11344},
+	{0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11350, 0x11350},
+	{0x11357, 0x11357}, {0x1135D, 0x11361}, {0x11362, 0x11363},
+	{0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11400, 0x11434},
+	{0x11435, 0x11437}, {0x11438, 0x1143F}, {0x11440, 0x11441},
+	{0x11442, 0x11444}, {0x11445, 0x11445}, {0x11446, 0x11446},
+	{0x11447, 0x1144A}, {0x1144B, 0x1144F}, {0x11450, 0x11459},
+	{0x1145B, 0x1145B}, {0x1145D, 0x1145D}, {0x11480, 0x114AF},
+	{0x114B0, 0x114B2}, {0x114B3, 0x114B8}, {0x114B9, 0x114B9},
+	{0x114BA, 0x114BA}, {0x114BB, 0x114BE}, {0x114BF, 0x114C0},
+	{0x114C1, 0x114C1}, {0x114C2, 0x114C3}, {0x114C4, 0x114C5},
+	{0x114C6, 0x114C6}, {0x114C7, 0x114C7}, {0x114D0, 0x114D9},
+	{0x11580, 0x115AE}, {0x115AF, 0x115B1}, {0x115B2, 0x115B5},
+	{0x115B8, 0x115BB}, {0x115BC, 0x115BD}, {0x115BE, 0x115BE},
+	{0x115BF, 0x115C0}, {0x115C1, 0x115D7}, {0x115D8, 0x115DB},
+	{0x115DC, 0x115DD}, {0x11600, 0x1162F}, {0x11630, 0x11632},
+	{0x11633, 0x1163A}, {0x1163B, 0x1163C}, {0x1163D, 0x1163D},
+	{0x1163E, 0x1163E}, {0x1163F, 0x11640}, {0x11641, 0x11643},
+	{0x11644, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C},
+	{0x11680, 0x116AA}, {0x116AB, 0x116AB}, {0x116AC, 0x116AC},
+	{0x116AD, 0x116AD}, {0x116AE, 0x116AF}, {0x116B0, 0x116B5},
+	{0x116B6, 0x116B6}, {0x116B7, 0x116B7}, {0x116C0, 0x116C9},
+	{0x11700, 0x11719}, {0x1171D, 0x1171F}, {0x11720, 0x11721},
+	{0x11722, 0x11725}, {0x11726, 0x11726}, {0x11727, 0x1172B},
+	{0x11730, 0x11739}, {0x1173A, 0x1173B}, {0x1173C, 0x1173E},
+	{0x1173F, 0x1173F}, {0x118A0, 0x118DF}, {0x118E0, 0x118E9},
+	{0x118EA, 0x118F2}, {0x118FF, 0x118FF}, {0x11AC0, 0x11AF8},
+	{0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C2F, 0x11C2F},
+	{0x11C30, 0x11C36}, {0x11C38, 0x11C3D}, {0x11C3E, 0x11C3E},
+	{0x11C3F, 0x11C3F}, {0x11C40, 0x11C40}, {0x11C41, 0x11C45},
+	{0x11C50, 0x11C59}, {0x11C5A, 0x11C6C}, {0x11C70, 0x11C71},
+	{0x11C72, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CA9},
+	{0x11CAA, 0x11CB0}, {0x11CB1, 0x11CB1}, {0x11CB2, 0x11CB3},
+	{0x11CB4, 0x11CB4}, {0x11CB5, 0x11CB6}, {0x12000, 0x12399},
+	{0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543},
+	{0x13000, 0x1342E}, {0x14400, 0x14646}, {0x16800, 0x16A38},
+	{0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, {0x16A6E, 0x16A6F},
+	{0x16AD0, 0x16AED}, {0x16AF0, 0x16AF4}, {0x16AF5, 0x16AF5},
+	{0x16B00, 0x16B2F}, {0x16B30, 0x16B36}, {0x16B37, 0x16B3B},
+	{0x16B3C, 0x16B3F}, {0x16B40, 0x16B43}, {0x16B44, 0x16B44},
+	{0x16B45, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61},
+	{0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16F00, 0x16F44},
+	{0x16F50, 0x16F50}, {0x16F51, 0x16F7E}, {0x16F8F, 0x16F92},
+	{0x16F93, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C},
+	{0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BC9C},
+	{0x1BC9D, 0x1BC9E}, {0x1BC9F, 0x1BC9F}, {0x1BCA0, 0x1BCA3},
+	{0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D164},
+	{0x1D165, 0x1D166}, {0x1D167, 0x1D169}, {0x1D16A, 0x1D16C},
+	{0x1D16D, 0x1D172}, {0x1D173, 0x1D17A}, {0x1D17B, 0x1D182},
+	{0x1D183, 0x1D184}, {0x1D185, 0x1D18B}, {0x1D18C, 0x1D1A9},
+	{0x1D1AA, 0x1D1AD}, {0x1D1AE, 0x1D1E8}, {0x1D200, 0x1D241},
+	{0x1D242, 0x1D244}, {0x1D245, 0x1D245}, {0x1D300, 0x1D356},
+	{0x1D360, 0x1D371}, {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, 0x1D6C0},
+	{0x1D6C1, 0x1D6C1}, {0x1D6C2, 0x1D6DA}, {0x1D6DB, 0x1D6DB},
+	{0x1D6DC, 0x1D6FA}, {0x1D6FB, 0x1D6FB}, {0x1D6FC, 0x1D714},
+	{0x1D715, 0x1D715}, {0x1D716, 0x1D734}, {0x1D735, 0x1D735},
+	{0x1D736, 0x1D74E}, {0x1D74F, 0x1D74F}, {0x1D750, 0x1D76E},
+	{0x1D76F, 0x1D76F}, {0x1D770, 0x1D788}, {0x1D789, 0x1D789},
+	{0x1D78A, 0x1D7A8}, {0x1D7A9, 0x1D7A9}, {0x1D7AA, 0x1D7C2},
+	{0x1D7C3, 0x1D7C3}, {0x1D7C4, 0x1D7CB}, {0x1D7CE, 0x1D7FF},
+	{0x1D800, 0x1D9FF}, {0x1DA00, 0x1DA36}, {0x1DA37, 0x1DA3A},
+	{0x1DA3B, 0x1DA6C}, {0x1DA6D, 0x1DA74}, {0x1DA75, 0x1DA75},
+	{0x1DA76, 0x1DA83}, {0x1DA84, 0x1DA84}, {0x1DA85, 0x1DA86},
+	{0x1DA87, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF},
+	{0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021},
+	{0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E800, 0x1E8C4},
+	{0x1E8C7, 0x1E8CF}, {0x1E8D0, 0x1E8D6}, {0x1E900, 0x1E943},
+	{0x1E944, 0x1E94A}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F},
+	{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, 0x1F10C},
+	{0x1F12E, 0x1F12E}, {0x1F16A, 0x1F16B}, {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}, {0x1F6E0, 0x1F6EA},
+	{0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773}, {0x1F780, 0x1F7D4},
+	{0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859},
+	{0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0xE0001, 0xE0001},
+	{0xE0020, 0xE007F},
+}
+
+// Condition have flag EastAsianWidth whether the current locale is CJK or not.
+type Condition struct {
+	EastAsianWidth bool
+}
+
+// NewCondition return new instance of Condition which is current locale.
+func NewCondition() *Condition {
+	return &Condition{EastAsianWidth}
+}
+
+// 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, emoji):
+		return 2
+	default:
+		return 1
+	}
+}
+
+// StringWidth return width as you can see
+func (c *Condition) StringWidth(s string) (width int) {
+	for _, r := range []rune(s) {
+		width += c.RuneWidth(r)
+	}
+	return width
+}
+
+// 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)
+}

vendor/github.com/mattn/go-runewidth/runewidth_posix.go 🔗

@@ -0,0 +1,77 @@
+// +build !windows,!js
+
+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_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)
+}

vendor/github.com/mattn/go-runewidth/runewidth_windows.go 🔗

@@ -0,0 +1,25 @@
+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
+}

vendor/github.com/nsf/termbox-go/LICENSE 🔗

@@ -0,0 +1,19 @@
+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.

vendor/github.com/nsf/termbox-go/README.md 🔗

@@ -0,0 +1,43 @@
+[![GoDoc](https://godoc.org/github.com/nsf/termbox-go?status.svg)](http://godoc.org/github.com/nsf/termbox-go)
+
+## 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.
+ - [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.
+
+### API reference
+[godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go)

vendor/github.com/nsf/termbox-go/api.go 🔗

@@ -0,0 +1,489 @@
+// +build !windows
+
+package termbox
+
+import "github.com/mattn/go-runewidth"
+import "fmt"
+import "os"
+import "os/signal"
+import "syscall"
+import "runtime"
+import "time"
+
+// 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
+
+	out, err = os.OpenFile("/dev/tty", syscall.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()
+}

vendor/github.com/nsf/termbox-go/api_common.go 🔗

@@ -0,0 +1,187 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/api_windows.go 🔗

@@ -0,0 +1,239 @@
+package termbox
+
+import (
+	"syscall"
+)
+
+// 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 = 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 = 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_cursor_info(out, &orig_cursor_info)
+	set_console_cursor_position(out, coord{})
+	set_console_screen_buffer_size(out, orig_size)
+	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 {
+		r := small_rect{
+			left:   0,
+			top:    diff.pos,
+			right:  term_size.x - 1,
+			bottom: diff.pos + diff.lines - 1,
+		}
+		write_console_output(out, diff.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
+}

vendor/github.com/nsf/termbox-go/collect_terminfo.py 🔗

@@ -0,0 +1,110 @@
+#!/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)
+

vendor/github.com/nsf/termbox-go/escwait.go 🔗

@@ -0,0 +1,11 @@
+// +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
+}

vendor/github.com/nsf/termbox-go/escwait_darwin.go 🔗

@@ -0,0 +1,9 @@
+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
+}

vendor/github.com/nsf/termbox-go/syscalls.go 🔗

@@ -0,0 +1,39 @@
+// +build ignore
+
+package termbox
+
+/*
+#include <termios.h>
+#include <sys/ioctl.h>
+*/
+import "C"
+
+type syscall_Termios C.struct_termios
+
+const (
+	syscall_IGNBRK = C.IGNBRK
+	syscall_BRKINT = C.BRKINT
+	syscall_PARMRK = C.PARMRK
+	syscall_ISTRIP = C.ISTRIP
+	syscall_INLCR  = C.INLCR
+	syscall_IGNCR  = C.IGNCR
+	syscall_ICRNL  = C.ICRNL
+	syscall_IXON   = C.IXON
+	syscall_OPOST  = C.OPOST
+	syscall_ECHO   = C.ECHO
+	syscall_ECHONL = C.ECHONL
+	syscall_ICANON = C.ICANON
+	syscall_ISIG   = C.ISIG
+	syscall_IEXTEN = C.IEXTEN
+	syscall_CSIZE  = C.CSIZE
+	syscall_PARENB = C.PARENB
+	syscall_CS8    = C.CS8
+	syscall_VMIN   = C.VMIN
+	syscall_VTIME  = C.VTIME
+
+	// on darwin change these to (on *bsd too?):
+	// C.TIOCGETA
+	// C.TIOCSETA
+	syscall_TCGETS = C.TCGETS
+	syscall_TCSETS = C.TCSETS
+)

vendor/github.com/nsf/termbox-go/syscalls_darwin.go 🔗

@@ -0,0 +1,41 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go 🔗

@@ -0,0 +1,40 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go 🔗

@@ -0,0 +1,39 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/syscalls_freebsd.go 🔗

@@ -0,0 +1,39 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/syscalls_linux.go 🔗

@@ -0,0 +1,33 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/syscalls_netbsd.go 🔗

@@ -0,0 +1,39 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/syscalls_openbsd.go 🔗

@@ -0,0 +1,39 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/syscalls_windows.go 🔗

@@ -0,0 +1,61 @@
+// 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
+)

vendor/github.com/nsf/termbox-go/termbox.go 🔗

@@ -0,0 +1,529 @@
+// +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
+}

vendor/github.com/nsf/termbox-go/termbox_common.go 🔗

@@ -0,0 +1,59 @@
+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
+}

vendor/github.com/nsf/termbox-go/termbox_windows.go 🔗

@@ -0,0 +1,915 @@
+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)))
+}
+
+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_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 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) {
+	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) {
+	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_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 {
+	err := get_console_screen_buffer_info(out, &tmp_info)
+	if err != nil {
+		panic(err)
+	}
+	return tmp_info.size
+}
+
+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 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)
+		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:
+			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
+			}
+		}
+	}
+}

vendor/github.com/nsf/termbox-go/terminfo.go 🔗

@@ -0,0 +1,232 @@
+// +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,
+}

vendor/github.com/nsf/termbox-go/terminfo_builtin.go 🔗

@@ -0,0 +1,64 @@
+// +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},
+}