mirror of
https://github.com/MichaelMure/git-bug.git
synced 2024-12-14 17:51:44 +03:00
vendor gocui
This commit is contained in:
parent
29bb7364c8
commit
bb9168f98a
20
Gopkg.lock
generated
20
Gopkg.lock
generated
@ -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
|
||||
|
1
vendor/github.com/jroimartin/gocui/.gitignore
generated
vendored
Normal file
1
vendor/github.com/jroimartin/gocui/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.swp
|
24
vendor/github.com/jroimartin/gocui/AUTHORS
generated
vendored
Normal file
24
vendor/github.com/jroimartin/gocui/AUTHORS
generated
vendored
Normal file
@ -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
|
23
vendor/github.com/jroimartin/gocui/LICENSE
generated
vendored
Normal file
23
vendor/github.com/jroimartin/gocui/LICENSE
generated
vendored
Normal file
@ -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.
|
91
vendor/github.com/jroimartin/gocui/README.md
generated
vendored
Normal file
91
vendor/github.com/jroimartin/gocui/README.md
generated
vendored
Normal file
@ -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)
|
32
vendor/github.com/jroimartin/gocui/attribute.go
generated
vendored
Normal file
32
vendor/github.com/jroimartin/gocui/attribute.go
generated
vendored
Normal file
@ -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)
|
||||
)
|
116
vendor/github.com/jroimartin/gocui/doc.go
generated
vendored
Normal file
116
vendor/github.com/jroimartin/gocui/doc.go
generated
vendored
Normal file
@ -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
|
341
vendor/github.com/jroimartin/gocui/edit.go
generated
vendored
Normal file
341
vendor/github.com/jroimartin/gocui/edit.go
generated
vendored
Normal file
@ -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
|
||||
}
|
168
vendor/github.com/jroimartin/gocui/escape.go
generated
vendored
Normal file
168
vendor/github.com/jroimartin/gocui/escape.go
generated
vendored
Normal file
@ -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
|
||||
}
|
646
vendor/github.com/jroimartin/gocui/gui.go
generated
vendored
Normal file
646
vendor/github.com/jroimartin/gocui/gui.go
generated
vendored
Normal file
@ -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
|
||||
}
|
141
vendor/github.com/jroimartin/gocui/keybinding.go
generated
vendored
Normal file
141
vendor/github.com/jroimartin/gocui/keybinding.go
generated
vendored
Normal file
@ -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
|
||||
}
|
474
vendor/github.com/jroimartin/gocui/view.go
generated
vendored
Normal file
474
vendor/github.com/jroimartin/gocui/view.go
generated
vendored
Normal file
@ -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
|
||||
}
|
8
vendor/github.com/mattn/go-runewidth/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/mattn/go-runewidth/.travis.yml
generated
vendored
Normal file
@ -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
|
21
vendor/github.com/mattn/go-runewidth/LICENSE
generated
vendored
Normal file
21
vendor/github.com/mattn/go-runewidth/LICENSE
generated
vendored
Normal file
@ -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.
|
27
vendor/github.com/mattn/go-runewidth/README.mkd
generated
vendored
Normal file
27
vendor/github.com/mattn/go-runewidth/README.mkd
generated
vendored
Normal file
@ -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
|
1223
vendor/github.com/mattn/go-runewidth/runewidth.go
generated
vendored
Normal file
1223
vendor/github.com/mattn/go-runewidth/runewidth.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
vendor/github.com/mattn/go-runewidth/runewidth_js.go
generated
vendored
Normal file
8
vendor/github.com/mattn/go-runewidth/runewidth_js.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// +build js
|
||||
|
||||
package runewidth
|
||||
|
||||
func IsEastAsian() bool {
|
||||
// TODO: Implement this for the web. Detect east asian in a compatible way, and return true.
|
||||
return false
|
||||
}
|
77
vendor/github.com/mattn/go-runewidth/runewidth_posix.go
generated
vendored
Normal file
77
vendor/github.com/mattn/go-runewidth/runewidth_posix.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
25
vendor/github.com/mattn/go-runewidth/runewidth_windows.go
generated
vendored
Normal file
25
vendor/github.com/mattn/go-runewidth/runewidth_windows.go
generated
vendored
Normal file
@ -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
|
||||
}
|
4
vendor/github.com/nsf/termbox-go/AUTHORS
generated
vendored
Normal file
4
vendor/github.com/nsf/termbox-go/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Please keep this file sorted.
|
||||
|
||||
Georg Reinke <guelfey@googlemail.com>
|
||||
nsf <no.smile.face@gmail.com>
|
19
vendor/github.com/nsf/termbox-go/LICENSE
generated
vendored
Normal file
19
vendor/github.com/nsf/termbox-go/LICENSE
generated
vendored
Normal file
@ -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.
|
43
vendor/github.com/nsf/termbox-go/README.md
generated
vendored
Normal file
43
vendor/github.com/nsf/termbox-go/README.md
generated
vendored
Normal file
@ -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)
|
489
vendor/github.com/nsf/termbox-go/api.go
generated
vendored
Normal file
489
vendor/github.com/nsf/termbox-go/api.go
generated
vendored
Normal file
@ -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()
|
||||
}
|
187
vendor/github.com/nsf/termbox-go/api_common.go
generated
vendored
Normal file
187
vendor/github.com/nsf/termbox-go/api_common.go
generated
vendored
Normal file
@ -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
|
||||
)
|
239
vendor/github.com/nsf/termbox-go/api_windows.go
generated
vendored
Normal file
239
vendor/github.com/nsf/termbox-go/api_windows.go
generated
vendored
Normal file
@ -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
|
||||
}
|
110
vendor/github.com/nsf/termbox-go/collect_terminfo.py
generated
vendored
Executable file
110
vendor/github.com/nsf/termbox-go/collect_terminfo.py
generated
vendored
Executable file
@ -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)
|
||||
|
11
vendor/github.com/nsf/termbox-go/escwait.go
generated
vendored
Normal file
11
vendor/github.com/nsf/termbox-go/escwait.go
generated
vendored
Normal file
@ -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
|
||||
}
|
9
vendor/github.com/nsf/termbox-go/escwait_darwin.go
generated
vendored
Normal file
9
vendor/github.com/nsf/termbox-go/escwait_darwin.go
generated
vendored
Normal file
@ -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
|
||||
}
|
39
vendor/github.com/nsf/termbox-go/syscalls.go
generated
vendored
Normal file
39
vendor/github.com/nsf/termbox-go/syscalls.go
generated
vendored
Normal file
@ -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
|
||||
)
|
41
vendor/github.com/nsf/termbox-go/syscalls_darwin.go
generated
vendored
Normal file
41
vendor/github.com/nsf/termbox-go/syscalls_darwin.go
generated
vendored
Normal file
@ -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
|
||||
)
|
40
vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
generated
vendored
Normal file
40
vendor/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
generated
vendored
Normal file
@ -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
|
||||
)
|
39
vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go
generated
vendored
Normal file
39
vendor/github.com/nsf/termbox-go/syscalls_dragonfly.go
generated
vendored
Normal file
@ -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
|
||||
)
|
39
vendor/github.com/nsf/termbox-go/syscalls_freebsd.go
generated
vendored
Normal file
39
vendor/github.com/nsf/termbox-go/syscalls_freebsd.go
generated
vendored
Normal file
@ -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
|
||||
)
|
33
vendor/github.com/nsf/termbox-go/syscalls_linux.go
generated
vendored
Normal file
33
vendor/github.com/nsf/termbox-go/syscalls_linux.go
generated
vendored
Normal file
@ -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
|
||||
)
|
39
vendor/github.com/nsf/termbox-go/syscalls_netbsd.go
generated
vendored
Normal file
39
vendor/github.com/nsf/termbox-go/syscalls_netbsd.go
generated
vendored
Normal file
@ -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
|
||||
)
|
39
vendor/github.com/nsf/termbox-go/syscalls_openbsd.go
generated
vendored
Normal file
39
vendor/github.com/nsf/termbox-go/syscalls_openbsd.go
generated
vendored
Normal file
@ -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
|
||||
)
|
61
vendor/github.com/nsf/termbox-go/syscalls_windows.go
generated
vendored
Normal file
61
vendor/github.com/nsf/termbox-go/syscalls_windows.go
generated
vendored
Normal file
@ -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
|
||||
)
|
529
vendor/github.com/nsf/termbox-go/termbox.go
generated
vendored
Normal file
529
vendor/github.com/nsf/termbox-go/termbox.go
generated
vendored
Normal file
@ -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
|
||||
}
|
59
vendor/github.com/nsf/termbox-go/termbox_common.go
generated
vendored
Normal file
59
vendor/github.com/nsf/termbox-go/termbox_common.go
generated
vendored
Normal file
@ -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
|
||||
}
|
915
vendor/github.com/nsf/termbox-go/termbox_windows.go
generated
vendored
Normal file
915
vendor/github.com/nsf/termbox-go/termbox_windows.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
232
vendor/github.com/nsf/termbox-go/terminfo.go
generated
vendored
Normal file
232
vendor/github.com/nsf/termbox-go/terminfo.go
generated
vendored
Normal file
@ -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,
|
||||
}
|
64
vendor/github.com/nsf/termbox-go/terminfo_builtin.go
generated
vendored
Normal file
64
vendor/github.com/nsf/termbox-go/terminfo_builtin.go
generated
vendored
Normal file
@ -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},
|
||||
}
|
Loading…
Reference in New Issue
Block a user