diff --git a/.travis.yml b/.travis.yml
index 11daadd41..ff3ff71f7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@ language: go
go:
- 1.4.2
before_install:
- - sudo add-apt-repository ppa:beineri/opt-qt541 -y
- sudo apt-get update -qq
- sudo apt-get install -yqq libgmp3-dev
install:
@@ -22,14 +21,12 @@ after_success:
- if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
env:
global:
- - PKG_CONFIG_PATH=/opt/qt54/lib/pkgconfig
- - LD_LIBRARY_PATH=/opt/qt54/lib
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
- on_success: change # options: [always|never|change] default: always
- on_failure: always # options: [always|never|change] default: always
- on_start: false # default: false
+ on_success: change
+ on_failure: always
+ on_start: false
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 0607990a8..c01655894 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -1,6 +1,6 @@
{
"ImportPath": "github.com/ethereum/go-ethereum",
- "GoVersion": "go1.4.2",
+ "GoVersion": "go1.4",
"Packages": [
"./..."
],
@@ -21,8 +21,12 @@
},
{
"ImportPath": "github.com/ethereum/ethash",
- "Comment": "v23.1-222-g173b8ff",
- "Rev": "173b8ff953610c13710061e83b95b50c73d7ea50"
+ "Comment": "v23.1-227-g8f6ccaa",
+ "Rev": "8f6ccaaef9b418553807a73a95cb5f49cd3ea39f"
+ },
+ {
+ "ImportPath": "github.com/gizak/termui",
+ "Rev": "bab8dce01c193d82bc04888a0a9a7814d505f532"
},
{
"ImportPath": "github.com/howeyc/fsnotify",
@@ -50,8 +54,13 @@
"Rev": "fdbe02a1b44e75977b2690062b83cf507d70c013"
},
{
- "ImportPath": "github.com/obscuren/qml",
- "Rev": "c288002b52e905973b131089a8a7c761d4a2c36a"
+ "ImportPath": "github.com/mattn/go-runewidth",
+ "Comment": "travisish-33-g5890272",
+ "Rev": "5890272cd41c5103531cd7b79e428d99c9e97f76"
+ },
+ {
+ "ImportPath": "github.com/nsf/termbox-go",
+ "Rev": "675ffd907b7401b8a709a5ef2249978af5616bb2"
},
{
"ImportPath": "github.com/peterh/liner",
@@ -65,6 +74,10 @@
"ImportPath": "github.com/rakyll/goini",
"Rev": "907cca0f578a5316fb864ec6992dc3d9730ec58c"
},
+ {
+ "ImportPath": "github.com/rcrowley/go-metrics",
+ "Rev": "a5cfc242a56ba7fa70b785f678d6214837bf93b9"
+ },
{
"ImportPath": "github.com/robertkrimen/otto",
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
@@ -117,14 +130,6 @@
{
"ImportPath": "gopkg.in/karalabe/cookiejar.v2/collections/prque",
"Rev": "0b2e270613f5d7ba262a5749b9e32270131497a2"
- },
- {
- "ImportPath": "gopkg.in/qml.v1/cdata",
- "Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
- },
- {
- "ImportPath": "gopkg.in/qml.v1/gl/glbase",
- "Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
}
]
}
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
index 73c5bf664..d0864da7f 100644
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
+++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
@@ -100,19 +100,29 @@ type Light struct {
func (l *Light) Verify(block pow.Block) bool {
// TODO: do ethash_quick_verify before getCache in order
// to prevent DOS attacks.
- var (
- blockNum = block.NumberU64()
- difficulty = block.Difficulty()
- cache = l.getCache(blockNum)
- dagSize = C.ethash_get_datasize(C.uint64_t(blockNum))
- )
- if l.test {
- dagSize = dagSizeForTesting
- }
+ blockNum := block.NumberU64()
if blockNum >= epochLength*2048 {
glog.V(logger.Debug).Infof("block number %d too high, limit is %d", epochLength*2048)
return false
}
+
+ difficulty := block.Difficulty()
+ /* Cannot happen if block header diff is validated prior to PoW, but can
+ happen if PoW is checked first due to parallel PoW checking.
+ We could check the minimum valid difficulty but for SoC we avoid (duplicating)
+ Ethereum protocol consensus rules here which are not in scope of Ethash
+ */
+ if difficulty.Cmp(common.Big0) == 0 {
+ glog.V(logger.Debug).Infof("invalid block difficulty")
+ return false
+ }
+
+ cache := l.getCache(blockNum)
+ dagSize := C.ethash_get_datasize(C.uint64_t(blockNum))
+
+ if l.test {
+ dagSize = dagSizeForTesting
+ }
// Recompute the hash using the cache.
hash := hashToH256(block.HashNoNonce())
ret := C.ethash_light_compute_internal(cache.ptr, dagSize, hash, C.uint64_t(block.Nonce()))
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go
index e6833e343..1e1de989d 100644
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go
+++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash_test.go
@@ -11,6 +11,7 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
)
func init() {
@@ -59,6 +60,14 @@ var validBlocks = []*testBlock{
},
}
+var invalidZeroDiffBlock = testBlock{
+ number: 61440000,
+ hashNoNonce: crypto.Sha3Hash([]byte("foo")),
+ difficulty: big.NewInt(0),
+ nonce: 0xcafebabec00000fe,
+ mixDigest: crypto.Sha3Hash([]byte("bar")),
+}
+
func TestEthashVerifyValid(t *testing.T) {
eth := New()
for i, block := range validBlocks {
@@ -68,6 +77,13 @@ func TestEthashVerifyValid(t *testing.T) {
}
}
+func TestEthashVerifyInvalid(t *testing.T) {
+ eth := New()
+ if eth.Verify(&invalidZeroDiffBlock) {
+ t.Errorf("should not validate - we just ensure it does not panic on this block")
+ }
+}
+
func TestEthashConcurrentVerify(t *testing.T) {
eth, err := NewForTesting()
if err != nil {
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c
index b28a59e43..338aa5ecd 100644
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c
+++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c
@@ -284,13 +284,13 @@ bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
)
{
ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
- return ethash_check_difficulty(&return_hash, difficulty);
+ return ethash_check_difficulty(&return_hash, boundary);
}
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h
index 4e2b695ac..26c395ad6 100644
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h
+++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h
@@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash)
memset(hash, 0, 32);
}
-// Returns if hash is less than or equal to difficulty
+// Returns if hash is less than or equal to boundary (2^256/difficulty)
static inline bool ethash_check_difficulty(
ethash_h256_t const* hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
)
{
- // Difficulty is big endian
+ // Boundary is big endian
for (int i = 0; i < 32; i++) {
- if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
+ if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
continue;
}
- return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
+ return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
}
return true;
}
+/**
+ * Difficulty quick check for POW preverification
+ *
+ * @param header_hash The hash of the header
+ * @param nonce The block's nonce
+ * @param mix_hash The mix digest hash
+ * @param boundary The boundary is defined as (2^256 / difficulty)
+ * @return true for succesful pre-verification and false otherwise
+ */
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
);
struct ethash_light {
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/.gitignore b/Godeps/_workspace/src/github.com/gizak/termui/.gitignore
new file mode 100644
index 000000000..daf913b1b
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/.travis.yml b/Godeps/_workspace/src/github.com/gizak/termui/.travis.yml
new file mode 100644
index 000000000..206e88740
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/.travis.yml
@@ -0,0 +1,6 @@
+language: go
+
+go:
+ - tip
+
+script: go test -v ./
\ No newline at end of file
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/LICENSE b/Godeps/_workspace/src/github.com/gizak/termui/LICENSE
new file mode 100644
index 000000000..311ccc74f
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Zack Guo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/README.md b/Godeps/_workspace/src/github.com/gizak/termui/README.md
new file mode 100644
index 000000000..b9bc3024d
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/README.md
@@ -0,0 +1,159 @@
+# termui [![Build Status](https://travis-ci.org/gizak/termui.svg?branch=master)](https://travis-ci.org/gizak/termui) [![Doc Status](https://godoc.org/github.com/gizak/termui?status.png)](https://godoc.org/github.com/gizak/termui)
+
+## Update 23/06/2015
+Pull requests and master branch are freezing, waiting for merging from `refactoring` branch.
+
+## Notice
+termui comes with ABSOLUTELY NO WARRANTY, and there is a breaking change coming up (see refactoring branch) which will change the `Bufferer` interface and many others. These changes reduce calculation overhead and introduce a new drawing buffer with better capacibilities. We will step into the next stage (call it beta) after merging these changes.
+
+## Introduction
+Go terminal dashboard. Inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go.
+
+Cross-platform, easy to compile, and fully-customizable.
+
+__Demo:__ (cast under osx 10.10; Terminal.app; Menlo Regular 12pt.)
+
+
+
+__Grid layout:__
+
+Expressive syntax, using [12 columns grid system](http://www.w3schools.com/bootstrap/bootstrap_grid_system.asp)
+```go
+ import ui "github.com/gizak/termui"
+ // init and create widgets...
+
+ // build
+ ui.Body.AddRows(
+ ui.NewRow(
+ ui.NewCol(6, 0, widget0),
+ ui.NewCol(6, 0, widget1)),
+ ui.NewRow(
+ ui.NewCol(3, 0, widget2),
+ ui.NewCol(3, 0, widget30, widget31, widget32),
+ ui.NewCol(6, 0, widget4)))
+
+ // calculate layout
+ ui.Body.Align()
+
+ ui.Render(ui.Body)
+```
+[demo code:](https://github.com/gizak/termui/blob/master/example/grid.go)
+
+
+
+## Installation
+
+ go get github.com/gizak/termui
+
+## Usage
+
+Each component's layout is a bit like HTML block (box model), which has border and padding.
+
+The `Border` property can be chosen to hide or display (with its border label), when it comes to display, the label takes 1 padding space (i.e. in css: `padding: 1;`, innerHeight and innerWidth therefore shrunk by 1).
+
+`````go
+ import ui "github.com/gizak/termui" // <- ui shortcut, optional
+
+ func main() {
+ err := ui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer ui.Close()
+
+ p := ui.NewPar(":PRESS q TO QUIT DEMO")
+ p.Height = 3
+ p.Width = 50
+ p.TextFgColor = ui.ColorWhite
+ p.Border.Label = "Text Box"
+ p.Border.FgColor = ui.ColorCyan
+
+ g := ui.NewGauge()
+ g.Percent = 50
+ g.Width = 50
+ g.Height = 3
+ g.Y = 11
+ g.Border.Label = "Gauge"
+ g.BarColor = ui.ColorRed
+ g.Border.FgColor = ui.ColorWhite
+ g.Border.LabelFgColor = ui.ColorCyan
+
+ ui.Render(p, g)
+
+ // event handler...
+ }
+`````
+
+Note that components can be overlapped (I'd rather call this a feature...), `Render(rs ...Renderer)` renders its args from left to right (i.e. each component's weight is arising from left to right).
+
+## Themes
+
+_All_ colors in _all_ components can be changed at _any_ time, while there provides some predefined color schemes:
+
+```go
+// for now there are only two themes: default and helloworld
+termui.UseTheme("helloworld")
+
+// create components...
+```
+The `default ` theme's settings depend on the user's terminal color scheme, which is saying if your terminal default font color is white and background is white, it will be like:
+
+
+
+The `helloworld` color scheme drops in some colors!
+
+
+
+## Widgets
+
+#### Par
+
+[demo code](https://github.com/gizak/termui/blob/master/example/par.go)
+
+
+
+#### List
+[demo code](https://github.com/gizak/termui/blob/master/example/list.go)
+
+
+
+#### Gauge
+[demo code](https://github.com/gizak/termui/blob/master/example/gauge.go)
+
+
+
+#### Line Chart
+[demo code](https://github.com/gizak/termui/blob/master/example/linechart.go)
+
+
+
+#### Bar Chart
+[demo code](https://github.com/gizak/termui/blob/master/example/barchart.go)
+
+
+
+#### Mult-Bar / Stacked-Bar Chart
+[demo code](https://github.com/gizak/termui/blob/master/example/mbarchart.go)
+
+
+
+#### Sparklines
+[demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go)
+
+
+
+
+## GoDoc
+
+[godoc](https://godoc.org/github.com/gizak/termui)
+
+## TODO
+
+- [x] Grid layout
+- [ ] Event system
+- [ ] Canvas widget
+- [ ] Refine APIs
+- [ ] Focusable widgets
+
+## License
+This library is under the [MIT License](http://opensource.org/licenses/MIT)
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/bar.go b/Godeps/_workspace/src/github.com/gizak/termui/bar.go
new file mode 100644
index 000000000..57bae0ae8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/bar.go
@@ -0,0 +1,135 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import "fmt"
+
+// BarChart creates multiple bars in a widget:
+/*
+ bc := termui.NewBarChart()
+ data := []int{3, 2, 5, 3, 9, 5}
+ bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
+ bc.Border.Label = "Bar Chart"
+ bc.Data = data
+ bc.Width = 26
+ bc.Height = 10
+ bc.DataLabels = bclabels
+ bc.TextColor = termui.ColorGreen
+ bc.BarColor = termui.ColorRed
+ bc.NumColor = termui.ColorYellow
+*/
+type BarChart struct {
+ Block
+ BarColor Attribute
+ TextColor Attribute
+ NumColor Attribute
+ Data []int
+ DataLabels []string
+ BarWidth int
+ BarGap int
+ labels [][]rune
+ dataNum [][]rune
+ numBar int
+ scale float64
+ max int
+}
+
+// NewBarChart returns a new *BarChart with current theme.
+func NewBarChart() *BarChart {
+ bc := &BarChart{Block: *NewBlock()}
+ bc.BarColor = theme.BarChartBar
+ bc.NumColor = theme.BarChartNum
+ bc.TextColor = theme.BarChartText
+ bc.BarGap = 1
+ bc.BarWidth = 3
+ return bc
+}
+
+func (bc *BarChart) layout() {
+ bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
+ bc.labels = make([][]rune, bc.numBar)
+ bc.dataNum = make([][]rune, len(bc.Data))
+
+ for i := 0; i < bc.numBar && i < len(bc.DataLabels) && i < len(bc.Data); i++ {
+ bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
+ n := bc.Data[i]
+ s := fmt.Sprint(n)
+ bc.dataNum[i] = trimStr2Runes(s, bc.BarWidth)
+ }
+
+ //bc.max = bc.Data[0] // what if Data is nil? Sometimes when bar graph is nill it produces panic with panic: runtime error: index out of range
+ // Asign a negative value to get maxvalue auto-populates
+ if bc.max == 0 {
+ bc.max = -1
+ }
+ for i := 0; i < len(bc.Data); i++ {
+ if bc.max < bc.Data[i] {
+ bc.max = bc.Data[i]
+ }
+ }
+ bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
+}
+
+func (bc *BarChart) SetMax(max int) {
+
+ if max > 0 {
+ bc.max = max
+ }
+}
+
+// Buffer implements Bufferer interface.
+func (bc *BarChart) Buffer() []Point {
+ ps := bc.Block.Buffer()
+ bc.layout()
+
+ for i := 0; i < bc.numBar && i < len(bc.Data) && i < len(bc.DataLabels); i++ {
+ h := int(float64(bc.Data[i]) / bc.scale)
+ oftX := i * (bc.BarWidth + bc.BarGap)
+ // plot bar
+ for j := 0; j < bc.BarWidth; j++ {
+ for k := 0; k < h; k++ {
+ p := Point{}
+ p.Ch = ' '
+ p.Bg = bc.BarColor
+ if bc.BarColor == ColorDefault { // when color is default, space char treated as transparent!
+ p.Bg |= AttrReverse
+ }
+ p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
+ p.Y = bc.innerY + bc.innerHeight - 2 - k
+ ps = append(ps, p)
+ }
+ }
+ // plot text
+ for j, k := 0, 0; j < len(bc.labels[i]); j++ {
+ w := charWidth(bc.labels[i][j])
+ p := Point{}
+ p.Ch = bc.labels[i][j]
+ p.Bg = bc.BgColor
+ p.Fg = bc.TextColor
+ p.Y = bc.innerY + bc.innerHeight - 1
+ p.X = bc.innerX + oftX + k
+ ps = append(ps, p)
+ k += w
+ }
+ // plot num
+ for j := 0; j < len(bc.dataNum[i]); j++ {
+ p := Point{}
+ p.Ch = bc.dataNum[i][j]
+ p.Fg = bc.NumColor
+ p.Bg = bc.BarColor
+ if bc.BarColor == ColorDefault { // the same as above
+ p.Bg |= AttrReverse
+ }
+ if h == 0 {
+ p.Bg = bc.BgColor
+ }
+ p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i]))/2 + j
+ p.Y = bc.innerY + bc.innerHeight - 2
+ ps = append(ps, p)
+ }
+ }
+
+ return bc.Block.chopOverflow(ps)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/block.go b/Godeps/_workspace/src/github.com/gizak/termui/block.go
new file mode 100644
index 000000000..953136596
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/block.go
@@ -0,0 +1,142 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+// Block is a base struct for all other upper level widgets,
+// consider it as css: display:block.
+// Normally you do not need to create it manually.
+type Block struct {
+ X int
+ Y int
+ Border labeledBorder
+ IsDisplay bool
+ HasBorder bool
+ BgColor Attribute
+ Width int
+ Height int
+ innerWidth int
+ innerHeight int
+ innerX int
+ innerY int
+ PaddingTop int
+ PaddingBottom int
+ PaddingLeft int
+ PaddingRight int
+}
+
+// NewBlock returns a *Block which inherits styles from current theme.
+func NewBlock() *Block {
+ d := Block{}
+ d.IsDisplay = true
+ d.HasBorder = theme.HasBorder
+ d.Border.BgColor = theme.BorderBg
+ d.Border.FgColor = theme.BorderFg
+ d.Border.LabelBgColor = theme.BorderLabelTextBg
+ d.Border.LabelFgColor = theme.BorderLabelTextFg
+ d.BgColor = theme.BlockBg
+ d.Width = 2
+ d.Height = 2
+ return &d
+}
+
+// compute box model
+func (d *Block) align() {
+ d.innerWidth = d.Width - d.PaddingLeft - d.PaddingRight
+ d.innerHeight = d.Height - d.PaddingTop - d.PaddingBottom
+ d.innerX = d.X + d.PaddingLeft
+ d.innerY = d.Y + d.PaddingTop
+
+ if d.HasBorder {
+ d.innerHeight -= 2
+ d.innerWidth -= 2
+ d.Border.X = d.X
+ d.Border.Y = d.Y
+ d.Border.Width = d.Width
+ d.Border.Height = d.Height
+ d.innerX++
+ d.innerY++
+ }
+
+ if d.innerHeight < 0 {
+ d.innerHeight = 0
+ }
+ if d.innerWidth < 0 {
+ d.innerWidth = 0
+ }
+
+}
+
+// InnerBounds returns the internal bounds of the block after aligning and
+// calculating the padding and border, if any.
+func (d *Block) InnerBounds() (x, y, width, height int) {
+ d.align()
+ return d.innerX, d.innerY, d.innerWidth, d.innerHeight
+}
+
+// Buffer implements Bufferer interface.
+// Draw background and border (if any).
+func (d *Block) Buffer() []Point {
+ d.align()
+
+ ps := []Point{}
+ if !d.IsDisplay {
+ return ps
+ }
+
+ if d.HasBorder {
+ ps = d.Border.Buffer()
+ }
+
+ for i := 0; i < d.innerWidth; i++ {
+ for j := 0; j < d.innerHeight; j++ {
+ p := Point{}
+ p.X = d.X + 1 + i
+ p.Y = d.Y + 1 + j
+ p.Ch = ' '
+ p.Bg = d.BgColor
+ ps = append(ps, p)
+ }
+ }
+ return ps
+}
+
+// GetHeight implements GridBufferer.
+// It returns current height of the block.
+func (d Block) GetHeight() int {
+ return d.Height
+}
+
+// SetX implements GridBufferer interface, which sets block's x position.
+func (d *Block) SetX(x int) {
+ d.X = x
+}
+
+// SetY implements GridBufferer interface, it sets y position for block.
+func (d *Block) SetY(y int) {
+ d.Y = y
+}
+
+// SetWidth implements GridBuffer interface, it sets block's width.
+func (d *Block) SetWidth(w int) {
+ d.Width = w
+}
+
+// chop the overflow parts
+func (d *Block) chopOverflow(ps []Point) []Point {
+ nps := make([]Point, 0, len(ps))
+ x := d.X
+ y := d.Y
+ w := d.Width
+ h := d.Height
+ for _, v := range ps {
+ if v.X >= x &&
+ v.X < x+w &&
+ v.Y >= y &&
+ v.Y < y+h {
+ nps = append(nps, v)
+ }
+ }
+ return nps
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/block_test.go b/Godeps/_workspace/src/github.com/gizak/termui/block_test.go
new file mode 100644
index 000000000..2de205b21
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/block_test.go
@@ -0,0 +1,46 @@
+package termui
+
+import "testing"
+
+func TestBlock_InnerBounds(t *testing.T) {
+ b := NewBlock()
+ b.X = 10
+ b.Y = 11
+ b.Width = 12
+ b.Height = 13
+
+ assert := func(name string, x, y, w, h int) {
+ t.Log(name)
+ cx, cy, cw, ch := b.InnerBounds()
+ if cx != x {
+ t.Errorf("expected x to be %d but got %d", x, cx)
+ }
+ if cy != y {
+ t.Errorf("expected y to be %d but got %d", y, cy)
+ }
+ if cw != w {
+ t.Errorf("expected width to be %d but got %d", w, cw)
+ }
+ if ch != h {
+ t.Errorf("expected height to be %d but got %d", h, ch)
+ }
+ }
+
+ b.HasBorder = false
+ assert("no border, no padding", 10, 11, 12, 13)
+
+ b.HasBorder = true
+ assert("border, no padding", 11, 12, 10, 11)
+
+ b.PaddingBottom = 2
+ assert("border, 2b padding", 11, 12, 10, 9)
+
+ b.PaddingTop = 3
+ assert("border, 2b 3t padding", 11, 15, 10, 6)
+
+ b.PaddingLeft = 4
+ assert("border, 2b 3t 4l padding", 15, 15, 6, 6)
+
+ b.PaddingRight = 5
+ assert("border, 2b 3t 4l 5r padding", 15, 15, 1, 6)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box.go b/Godeps/_workspace/src/github.com/gizak/termui/box.go
new file mode 100644
index 000000000..1dcfd8692
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/box.go
@@ -0,0 +1,117 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+type border struct {
+ X int
+ Y int
+ Width int
+ Height int
+ FgColor Attribute
+ BgColor Attribute
+}
+
+type hline struct {
+ X int
+ Y int
+ Length int
+ FgColor Attribute
+ BgColor Attribute
+}
+
+type vline struct {
+ X int
+ Y int
+ Length int
+ FgColor Attribute
+ BgColor Attribute
+}
+
+// Draw a horizontal line.
+func (l hline) Buffer() []Point {
+ pts := make([]Point, l.Length)
+ for i := 0; i < l.Length; i++ {
+ pts[i].X = l.X + i
+ pts[i].Y = l.Y
+ pts[i].Ch = HORIZONTAL_LINE
+ pts[i].Bg = l.BgColor
+ pts[i].Fg = l.FgColor
+ }
+ return pts
+}
+
+// Draw a vertical line.
+func (l vline) Buffer() []Point {
+ pts := make([]Point, l.Length)
+ for i := 0; i < l.Length; i++ {
+ pts[i].X = l.X
+ pts[i].Y = l.Y + i
+ pts[i].Ch = VERTICAL_LINE
+ pts[i].Bg = l.BgColor
+ pts[i].Fg = l.FgColor
+ }
+ return pts
+}
+
+// Draw a box border.
+func (b border) Buffer() []Point {
+ if b.Width < 2 || b.Height < 2 {
+ return nil
+ }
+ pts := make([]Point, 2*b.Width+2*b.Height-4)
+
+ pts[0].X = b.X
+ pts[0].Y = b.Y
+ pts[0].Fg = b.FgColor
+ pts[0].Bg = b.BgColor
+ pts[0].Ch = TOP_LEFT
+
+ pts[1].X = b.X + b.Width - 1
+ pts[1].Y = b.Y
+ pts[1].Fg = b.FgColor
+ pts[1].Bg = b.BgColor
+ pts[1].Ch = TOP_RIGHT
+
+ pts[2].X = b.X
+ pts[2].Y = b.Y + b.Height - 1
+ pts[2].Fg = b.FgColor
+ pts[2].Bg = b.BgColor
+ pts[2].Ch = BOTTOM_LEFT
+
+ pts[3].X = b.X + b.Width - 1
+ pts[3].Y = b.Y + b.Height - 1
+ pts[3].Fg = b.FgColor
+ pts[3].Bg = b.BgColor
+ pts[3].Ch = BOTTOM_RIGHT
+
+ copy(pts[4:], (hline{b.X + 1, b.Y, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
+ copy(pts[4+b.Width-2:], (hline{b.X + 1, b.Y + b.Height - 1, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
+ copy(pts[4+2*b.Width-4:], (vline{b.X, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
+ copy(pts[4+2*b.Width-4+b.Height-2:], (vline{b.X + b.Width - 1, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
+
+ return pts
+}
+
+type labeledBorder struct {
+ border
+ Label string
+ LabelFgColor Attribute
+ LabelBgColor Attribute
+}
+
+// Draw a box border with label.
+func (lb labeledBorder) Buffer() []Point {
+ ps := lb.border.Buffer()
+ maxTxtW := lb.Width - 2
+ rs := trimStr2Runes(lb.Label, maxTxtW)
+
+ for i, j, w := 0, 0, 0; i < len(rs); i++ {
+ w = charWidth(rs[i])
+ ps = append(ps, newPointWithAttrs(rs[i], lb.X+1+j, lb.Y, lb.LabelFgColor, lb.LabelBgColor))
+ j += w
+ }
+
+ return ps
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box_others.go b/Godeps/_workspace/src/github.com/gizak/termui/box_others.go
new file mode 100644
index 000000000..bcc3d7ded
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/box_others.go
@@ -0,0 +1,14 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build !windows
+
+package termui
+
+const TOP_RIGHT = '┐'
+const VERTICAL_LINE = '│'
+const HORIZONTAL_LINE = '─'
+const TOP_LEFT = '┌'
+const BOTTOM_RIGHT = '┘'
+const BOTTOM_LEFT = '└'
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go b/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go
new file mode 100644
index 000000000..dd39019fe
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/box_windows.go
@@ -0,0 +1,14 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build windows
+
+package termui
+
+const TOP_RIGHT = '+'
+const VERTICAL_LINE = '|'
+const HORIZONTAL_LINE = '-'
+const TOP_LEFT = '+'
+const BOTTOM_RIGHT = '+'
+const BOTTOM_LEFT = '+'
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/canvas.go b/Godeps/_workspace/src/github.com/gizak/termui/canvas.go
new file mode 100644
index 000000000..614635ee4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/canvas.go
@@ -0,0 +1,74 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+/*
+dots:
+ ,___,
+ |1 4|
+ |2 5|
+ |3 6|
+ |7 8|
+ `````
+*/
+
+var brailleBase = '\u2800'
+
+var brailleOftMap = [4][2]rune{
+ {'\u0001', '\u0008'},
+ {'\u0002', '\u0010'},
+ {'\u0004', '\u0020'},
+ {'\u0040', '\u0080'}}
+
+// Canvas contains drawing map: i,j -> rune
+type Canvas map[[2]int]rune
+
+// NewCanvas returns an empty Canvas
+func NewCanvas() Canvas {
+ return make(map[[2]int]rune)
+}
+
+func chOft(x, y int) rune {
+ return brailleOftMap[y%4][x%2]
+}
+
+func (c Canvas) rawCh(x, y int) rune {
+ if ch, ok := c[[2]int{x, y}]; ok {
+ return ch
+ }
+ return '\u0000' //brailleOffset
+}
+
+// return coordinate in terminal
+func chPos(x, y int) (int, int) {
+ return y / 4, x / 2
+}
+
+// Set sets a point (x,y) in the virtual coordinate
+func (c Canvas) Set(x, y int) {
+ i, j := chPos(x, y)
+ ch := c.rawCh(i, j)
+ ch |= chOft(x, y)
+ c[[2]int{i, j}] = ch
+}
+
+// Unset removes point (x,y)
+func (c Canvas) Unset(x, y int) {
+ i, j := chPos(x, y)
+ ch := c.rawCh(i, j)
+ ch &= ^chOft(x, y)
+ c[[2]int{i, j}] = ch
+}
+
+// Buffer returns un-styled points
+func (c Canvas) Buffer() []Point {
+ ps := make([]Point, len(c))
+ i := 0
+ for k, v := range c {
+ ps[i] = newPoint(v+brailleBase, k[0], k[1])
+ i++
+ }
+ return ps
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go b/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go
new file mode 100644
index 000000000..021949ced
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/canvas_test.go
@@ -0,0 +1,55 @@
+package termui
+
+import (
+ "testing"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+func TestCanvasSet(t *testing.T) {
+ c := NewCanvas()
+ c.Set(0, 0)
+ c.Set(0, 1)
+ c.Set(0, 2)
+ c.Set(0, 3)
+ c.Set(1, 3)
+ c.Set(2, 3)
+ c.Set(3, 3)
+ c.Set(4, 3)
+ c.Set(5, 3)
+ spew.Dump(c)
+}
+
+func TestCanvasUnset(t *testing.T) {
+ c := NewCanvas()
+ c.Set(0, 0)
+ c.Set(0, 1)
+ c.Set(0, 2)
+ c.Unset(0, 2)
+ spew.Dump(c)
+ c.Unset(0, 3)
+ spew.Dump(c)
+}
+
+func TestCanvasBuffer(t *testing.T) {
+ c := NewCanvas()
+ c.Set(0, 0)
+ c.Set(0, 1)
+ c.Set(0, 2)
+ c.Set(0, 3)
+ c.Set(1, 3)
+ c.Set(2, 3)
+ c.Set(3, 3)
+ c.Set(4, 3)
+ c.Set(5, 3)
+ c.Set(6, 3)
+ c.Set(7, 2)
+ c.Set(8, 1)
+ c.Set(9, 0)
+ bufs := c.Buffer()
+ rs := make([]rune, len(bufs))
+ for i, v := range bufs {
+ rs[i] = v.Ch
+ }
+ spew.Dump(string(rs))
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart.go b/Godeps/_workspace/src/github.com/gizak/termui/chart.go
new file mode 100644
index 000000000..d6fb8bc7d
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/chart.go
@@ -0,0 +1,336 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import (
+ "fmt"
+ "math"
+)
+
+// only 16 possible combinations, why bother
+var braillePatterns = map[[2]int]rune{
+ [2]int{0, 0}: '⣀',
+ [2]int{0, 1}: '⡠',
+ [2]int{0, 2}: '⡐',
+ [2]int{0, 3}: '⡈',
+
+ [2]int{1, 0}: '⢄',
+ [2]int{1, 1}: '⠤',
+ [2]int{1, 2}: '⠔',
+ [2]int{1, 3}: '⠌',
+
+ [2]int{2, 0}: '⢂',
+ [2]int{2, 1}: '⠢',
+ [2]int{2, 2}: '⠒',
+ [2]int{2, 3}: '⠊',
+
+ [2]int{3, 0}: '⢁',
+ [2]int{3, 1}: '⠡',
+ [2]int{3, 2}: '⠑',
+ [2]int{3, 3}: '⠉',
+}
+
+var lSingleBraille = [4]rune{'\u2840', '⠄', '⠂', '⠁'}
+var rSingleBraille = [4]rune{'\u2880', '⠠', '⠐', '⠈'}
+
+// LineChart has two modes: braille(default) and dot. Using braille gives 2x capicity as dot mode,
+// because one braille char can represent two data points.
+/*
+ lc := termui.NewLineChart()
+ lc.Border.Label = "braille-mode Line Chart"
+ lc.Data = [1.2, 1.3, 1.5, 1.7, 1.5, 1.6, 1.8, 2.0]
+ lc.Width = 50
+ lc.Height = 12
+ lc.AxesColor = termui.ColorWhite
+ lc.LineColor = termui.ColorGreen | termui.AttrBold
+ // termui.Render(lc)...
+*/
+type LineChart struct {
+ Block
+ Data []float64
+ DataLabels []string // if unset, the data indices will be used
+ Mode string // braille | dot
+ DotStyle rune
+ LineColor Attribute
+ scale float64 // data span per cell on y-axis
+ AxesColor Attribute
+ drawingX int
+ drawingY int
+ axisYHeight int
+ axisXWidth int
+ axisYLebelGap int
+ axisXLebelGap int
+ topValue float64
+ bottomValue float64
+ labelX [][]rune
+ labelY [][]rune
+ labelYSpace int
+ maxY float64
+ minY float64
+}
+
+// NewLineChart returns a new LineChart with current theme.
+func NewLineChart() *LineChart {
+ lc := &LineChart{Block: *NewBlock()}
+ lc.AxesColor = theme.LineChartAxes
+ lc.LineColor = theme.LineChartLine
+ lc.Mode = "braille"
+ lc.DotStyle = '•'
+ lc.axisXLebelGap = 2
+ lc.axisYLebelGap = 1
+ lc.bottomValue = math.Inf(1)
+ lc.topValue = math.Inf(-1)
+ return lc
+}
+
+// one cell contains two data points
+// so the capicity is 2x as dot-mode
+func (lc *LineChart) renderBraille() []Point {
+ ps := []Point{}
+
+ // return: b -> which cell should the point be in
+ // m -> in the cell, divided into 4 equal height levels, which subcell?
+ getPos := func(d float64) (b, m int) {
+ cnt4 := int((d-lc.bottomValue)/(lc.scale/4) + 0.5)
+ b = cnt4 / 4
+ m = cnt4 % 4
+ return
+ }
+ // plot points
+ for i := 0; 2*i+1 < len(lc.Data) && i < lc.axisXWidth; i++ {
+ b0, m0 := getPos(lc.Data[2*i])
+ b1, m1 := getPos(lc.Data[2*i+1])
+
+ if b0 == b1 {
+ p := Point{}
+ p.Ch = braillePatterns[[2]int{m0, m1}]
+ p.Bg = lc.BgColor
+ p.Fg = lc.LineColor
+ p.Y = lc.innerY + lc.innerHeight - 3 - b0
+ p.X = lc.innerX + lc.labelYSpace + 1 + i
+ ps = append(ps, p)
+ } else {
+ p0 := newPointWithAttrs(lSingleBraille[m0],
+ lc.innerX+lc.labelYSpace+1+i,
+ lc.innerY+lc.innerHeight-3-b0,
+ lc.LineColor,
+ lc.BgColor)
+ p1 := newPointWithAttrs(rSingleBraille[m1],
+ lc.innerX+lc.labelYSpace+1+i,
+ lc.innerY+lc.innerHeight-3-b1,
+ lc.LineColor,
+ lc.BgColor)
+ ps = append(ps, p0, p1)
+ }
+
+ }
+ return ps
+}
+
+func (lc *LineChart) renderDot() []Point {
+ ps := []Point{}
+ for i := 0; i < len(lc.Data) && i < lc.axisXWidth; i++ {
+ p := Point{}
+ p.Ch = lc.DotStyle
+ p.Fg = lc.LineColor
+ p.Bg = lc.BgColor
+ p.X = lc.innerX + lc.labelYSpace + 1 + i
+ p.Y = lc.innerY + lc.innerHeight - 3 - int((lc.Data[i]-lc.bottomValue)/lc.scale+0.5)
+ ps = append(ps, p)
+ }
+
+ return ps
+}
+
+func (lc *LineChart) calcLabelX() {
+ lc.labelX = [][]rune{}
+
+ for i, l := 0, 0; i < len(lc.DataLabels) && l < lc.axisXWidth; i++ {
+ if lc.Mode == "dot" {
+ if l >= len(lc.DataLabels) {
+ break
+ }
+
+ s := str2runes(lc.DataLabels[l])
+ w := strWidth(lc.DataLabels[l])
+ if l+w <= lc.axisXWidth {
+ lc.labelX = append(lc.labelX, s)
+ }
+ l += w + lc.axisXLebelGap
+ } else { // braille
+ if 2*l >= len(lc.DataLabels) {
+ break
+ }
+
+ s := str2runes(lc.DataLabels[2*l])
+ w := strWidth(lc.DataLabels[2*l])
+ if l+w <= lc.axisXWidth {
+ lc.labelX = append(lc.labelX, s)
+ }
+ l += w + lc.axisXLebelGap
+
+ }
+ }
+}
+
+func shortenFloatVal(x float64) string {
+ s := fmt.Sprintf("%.2f", x)
+ if len(s)-3 > 3 {
+ s = fmt.Sprintf("%.2e", x)
+ }
+
+ if x < 0 {
+ s = fmt.Sprintf("%.2f", x)
+ }
+ return s
+}
+
+func (lc *LineChart) calcLabelY() {
+ span := lc.topValue - lc.bottomValue
+ lc.scale = span / float64(lc.axisYHeight)
+
+ n := (1 + lc.axisYHeight) / (lc.axisYLebelGap + 1)
+ lc.labelY = make([][]rune, n)
+ maxLen := 0
+ for i := 0; i < n; i++ {
+ s := str2runes(shortenFloatVal(lc.bottomValue + float64(i)*span/float64(n)))
+ if len(s) > maxLen {
+ maxLen = len(s)
+ }
+ lc.labelY[i] = s
+ }
+
+ lc.labelYSpace = maxLen
+}
+
+func (lc *LineChart) calcLayout() {
+ // set datalabels if it is not provided
+ if lc.DataLabels == nil || len(lc.DataLabels) == 0 {
+ lc.DataLabels = make([]string, len(lc.Data))
+ for i := range lc.Data {
+ lc.DataLabels[i] = fmt.Sprint(i)
+ }
+ }
+
+ // lazy increase, to avoid y shaking frequently
+ // update bound Y when drawing is gonna overflow
+ lc.minY = lc.Data[0]
+ lc.maxY = lc.Data[0]
+
+ // valid visible range
+ vrange := lc.innerWidth
+ if lc.Mode == "braille" {
+ vrange = 2 * lc.innerWidth
+ }
+ if vrange > len(lc.Data) {
+ vrange = len(lc.Data)
+ }
+
+ for _, v := range lc.Data[:vrange] {
+ if v > lc.maxY {
+ lc.maxY = v
+ }
+ if v < lc.minY {
+ lc.minY = v
+ }
+ }
+
+ span := lc.maxY - lc.minY
+
+ if lc.minY < lc.bottomValue {
+ lc.bottomValue = lc.minY - 0.2*span
+ }
+
+ if lc.maxY > lc.topValue {
+ lc.topValue = lc.maxY + 0.2*span
+ }
+
+ lc.axisYHeight = lc.innerHeight - 2
+ lc.calcLabelY()
+
+ lc.axisXWidth = lc.innerWidth - 1 - lc.labelYSpace
+ lc.calcLabelX()
+
+ lc.drawingX = lc.innerX + 1 + lc.labelYSpace
+ lc.drawingY = lc.innerY
+}
+
+func (lc *LineChart) plotAxes() []Point {
+ origY := lc.innerY + lc.innerHeight - 2
+ origX := lc.innerX + lc.labelYSpace
+
+ ps := []Point{newPointWithAttrs(ORIGIN, origX, origY, lc.AxesColor, lc.BgColor)}
+
+ for x := origX + 1; x < origX+lc.axisXWidth; x++ {
+ p := Point{}
+ p.X = x
+ p.Y = origY
+ p.Bg = lc.BgColor
+ p.Fg = lc.AxesColor
+ p.Ch = HDASH
+ ps = append(ps, p)
+ }
+
+ for dy := 1; dy <= lc.axisYHeight; dy++ {
+ p := Point{}
+ p.X = origX
+ p.Y = origY - dy
+ p.Bg = lc.BgColor
+ p.Fg = lc.AxesColor
+ p.Ch = VDASH
+ ps = append(ps, p)
+ }
+
+ // x label
+ oft := 0
+ for _, rs := range lc.labelX {
+ if oft+len(rs) > lc.axisXWidth {
+ break
+ }
+ for j, r := range rs {
+ p := Point{}
+ p.Ch = r
+ p.Fg = lc.AxesColor
+ p.Bg = lc.BgColor
+ p.X = origX + oft + j
+ p.Y = lc.innerY + lc.innerHeight - 1
+ ps = append(ps, p)
+ }
+ oft += len(rs) + lc.axisXLebelGap
+ }
+
+ // y labels
+ for i, rs := range lc.labelY {
+ for j, r := range rs {
+ p := Point{}
+ p.Ch = r
+ p.Fg = lc.AxesColor
+ p.Bg = lc.BgColor
+ p.X = lc.innerX + j
+ p.Y = origY - i*(lc.axisYLebelGap+1)
+ ps = append(ps, p)
+ }
+ }
+
+ return ps
+}
+
+// Buffer implements Bufferer interface.
+func (lc *LineChart) Buffer() []Point {
+ ps := lc.Block.Buffer()
+ if lc.Data == nil || len(lc.Data) == 0 {
+ return ps
+ }
+ lc.calcLayout()
+ ps = append(ps, lc.plotAxes()...)
+
+ if lc.Mode == "dot" {
+ ps = append(ps, lc.renderDot()...)
+ } else {
+ ps = append(ps, lc.renderBraille()...)
+ }
+
+ return lc.Block.chopOverflow(ps)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go b/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go
new file mode 100644
index 000000000..8911873b6
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/chart_others.go
@@ -0,0 +1,11 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build !windows
+
+package termui
+
+const VDASH = '┊'
+const HDASH = '┈'
+const ORIGIN = '└'
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go b/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go
new file mode 100644
index 000000000..9f9a5e96c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/chart_windows.go
@@ -0,0 +1,11 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build windows
+
+package termui
+
+const VDASH = '|'
+const HDASH = '-'
+const ORIGIN = '+'
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/doc.go b/Godeps/_workspace/src/github.com/gizak/termui/doc.go
new file mode 100644
index 000000000..43f886f55
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/doc.go
@@ -0,0 +1,27 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+/*
+Package termui is a library designed for creating command line UI. For more info, goto http://github.com/gizak/termui
+
+A simplest example:
+ package main
+
+ import ui "github.com/gizak/termui"
+
+ func main() {
+ if err:=ui.Init(); err != nil {
+ panic(err)
+ }
+ defer ui.Close()
+
+ g := ui.NewGauge()
+ g.Percent = 50
+ g.Width = 50
+ g.Border.Label = "Gauge"
+
+ ui.Render(g)
+ }
+*/
+package termui
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/events.go b/Godeps/_workspace/src/github.com/gizak/termui/events.go
new file mode 100644
index 000000000..23a189b56
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/events.go
@@ -0,0 +1,219 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+//
+// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go)
+// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS)
+// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE)
+
+package termui
+
+import "github.com/nsf/termbox-go"
+
+/***********************************termbox-go**************************************/
+
+type (
+ EventType uint8
+ Modifier uint8
+ Key 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
+}
+
+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
+)
+
+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 = 0x01
+)
+
+// Event type. See Event.Type field.
+const (
+ EventKey EventType = iota
+ EventResize
+ EventMouse
+ EventError
+ EventInterrupt
+ EventRaw
+ EventNone
+)
+
+/**************************************end**************************************/
+
+// convert termbox.Event to termui.Event
+func uiEvt(e termbox.Event) Event {
+ event := Event{}
+ event.Type = EventType(e.Type)
+ event.Mod = Modifier(e.Mod)
+ event.Key = Key(e.Key)
+ event.Ch = e.Ch
+ event.Width = e.Width
+ event.Height = e.Height
+ event.Err = e.Err
+ event.MouseX = e.MouseX
+ event.MouseY = e.MouseY
+ event.N = e.N
+
+ return event
+}
+
+var evtChs = make([]chan Event, 0)
+
+// EventCh returns an output-only event channel.
+// This function can be called many times (multiplexer).
+func EventCh() <-chan Event {
+ out := make(chan Event)
+ evtChs = append(evtChs, out)
+ return out
+}
+
+// turn on event listener
+func evtListen() {
+ go func() {
+ for {
+ e := termbox.PollEvent()
+ // dispatch
+ for _, c := range evtChs {
+ go func(ch chan Event) {
+ ch <- uiEvt(e)
+ }(c)
+ }
+ }
+ }()
+}
+
+/*
+// EventHandlers is a handler sequence
+var EventHandlers []func(Event)
+
+var signalQuit = make(chan bool)
+
+// Quit sends quit signal to terminate termui
+func Quit() {
+ signalQuit <- true
+}
+
+// Wait listening to signalQuit, block operation.
+func Wait() {
+ <-signalQuit
+}
+
+// RegEvtHandler register function into TSEventHandler sequence.
+func RegEvtHandler(fn func(Event)) {
+ EventHandlers = append(EventHandlers, fn)
+}
+
+// EventLoop handles all events and
+// redirects every event to callbacks in EventHandlers
+func EventLoop() {
+ evt := make(chan termbox.Event)
+
+ go func() {
+ for {
+ evt <- termbox.PollEvent()
+ }
+ }()
+
+ for {
+ select {
+ case c := <-signalQuit:
+ defer func() { signalQuit <- c }()
+ return
+ case e := <-evt:
+ for _, fn := range EventHandlers {
+ fn(uiEvt(e))
+ }
+ }
+ }
+}
+*/
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/events_test.go b/Godeps/_workspace/src/github.com/gizak/termui/events_test.go
new file mode 100644
index 000000000..1137b1d26
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/events_test.go
@@ -0,0 +1,28 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+//
+// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go)
+// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS)
+// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE)
+
+package termui
+
+import (
+ "errors"
+ "testing"
+
+ termbox "github.com/nsf/termbox-go"
+ "github.com/stretchr/testify/assert"
+)
+
+type boxEvent termbox.Event
+
+func TestUiEvt(t *testing.T) {
+ err := errors.New("This is a mock error")
+ event := boxEvent{3, 5, 2, 'H', 200, 500, err, 50, 30, 2}
+ expetced := Event{3, 5, 2, 'H', 200, 500, err, 50, 30, 2}
+
+ // We need to do that ugly casting so that vet does not complain
+ assert.Equal(t, uiEvt(termbox.Event(event)), expetced)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go
new file mode 100644
index 000000000..83947f580
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.go
@@ -0,0 +1,35 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "github.com/gizak/termui"
+
+func main() {
+ err := termui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ termui.UseTheme("helloworld")
+
+ bc := termui.NewBarChart()
+ data := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
+ bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
+ bc.Border.Label = "Bar Chart"
+ bc.Data = data
+ bc.Width = 26
+ bc.Height = 10
+ bc.DataLabels = bclabels
+ bc.TextColor = termui.ColorGreen
+ bc.BarColor = termui.ColorRed
+ bc.NumColor = termui.ColorYellow
+
+ termui.Render(bc)
+
+ <-termui.EventCh()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png
new file mode 100644
index 000000000..a37912f7f
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/barchart.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif b/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif
new file mode 100644
index 000000000..8e1859c72
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.gif differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go b/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go
new file mode 100644
index 000000000..c14bb4413
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/dashboard.go
@@ -0,0 +1,148 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import ui "github.com/gizak/termui"
+import "math"
+
+import "time"
+
+func main() {
+ err := ui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer ui.Close()
+
+ p := ui.NewPar(":PRESS q TO QUIT DEMO")
+ p.Height = 3
+ p.Width = 50
+ p.TextFgColor = ui.ColorWhite
+ p.Border.Label = "Text Box"
+ p.Border.FgColor = ui.ColorCyan
+
+ strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
+ list := ui.NewList()
+ list.Items = strs
+ list.ItemFgColor = ui.ColorYellow
+ list.Border.Label = "List"
+ list.Height = 7
+ list.Width = 25
+ list.Y = 4
+
+ g := ui.NewGauge()
+ g.Percent = 50
+ g.Width = 50
+ g.Height = 3
+ g.Y = 11
+ g.Border.Label = "Gauge"
+ g.BarColor = ui.ColorRed
+ g.Border.FgColor = ui.ColorWhite
+ g.Border.LabelFgColor = ui.ColorCyan
+
+ spark := ui.Sparkline{}
+ spark.Height = 1
+ spark.Title = "srv 0:"
+ spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
+ spark.Data = spdata
+ spark.LineColor = ui.ColorCyan
+ spark.TitleColor = ui.ColorWhite
+
+ spark1 := ui.Sparkline{}
+ spark1.Height = 1
+ spark1.Title = "srv 1:"
+ spark1.Data = spdata
+ spark1.TitleColor = ui.ColorWhite
+ spark1.LineColor = ui.ColorRed
+
+ sp := ui.NewSparklines(spark, spark1)
+ sp.Width = 25
+ sp.Height = 7
+ sp.Border.Label = "Sparkline"
+ sp.Y = 4
+ sp.X = 25
+
+ sinps := (func() []float64 {
+ n := 220
+ ps := make([]float64, n)
+ for i := range ps {
+ ps[i] = 1 + math.Sin(float64(i)/5)
+ }
+ return ps
+ })()
+
+ lc := ui.NewLineChart()
+ lc.Border.Label = "dot-mode Line Chart"
+ lc.Data = sinps
+ lc.Width = 50
+ lc.Height = 11
+ lc.X = 0
+ lc.Y = 14
+ lc.AxesColor = ui.ColorWhite
+ lc.LineColor = ui.ColorRed | ui.AttrBold
+ lc.Mode = "dot"
+
+ bc := ui.NewBarChart()
+ bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
+ bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
+ bc.Border.Label = "Bar Chart"
+ bc.Width = 26
+ bc.Height = 10
+ bc.X = 51
+ bc.Y = 0
+ bc.DataLabels = bclabels
+ bc.BarColor = ui.ColorGreen
+ bc.NumColor = ui.ColorBlack
+
+ lc1 := ui.NewLineChart()
+ lc1.Border.Label = "braille-mode Line Chart"
+ lc1.Data = sinps
+ lc1.Width = 26
+ lc1.Height = 11
+ lc1.X = 51
+ lc1.Y = 14
+ lc1.AxesColor = ui.ColorWhite
+ lc1.LineColor = ui.ColorYellow | ui.AttrBold
+
+ p1 := ui.NewPar("Hey!\nI am a borderless block!")
+ p1.HasBorder = false
+ p1.Width = 26
+ p1.Height = 2
+ p1.TextFgColor = ui.ColorMagenta
+ p1.X = 52
+ p1.Y = 11
+
+ draw := func(t int) {
+ g.Percent = t % 101
+ list.Items = strs[t%9:]
+ sp.Lines[0].Data = spdata[:30+t%50]
+ sp.Lines[1].Data = spdata[:35+t%50]
+ lc.Data = sinps[t/2:]
+ lc1.Data = sinps[2*t:]
+ bc.Data = bcdata[t/2%10:]
+ ui.Render(p, list, g, sp, lc, bc, lc1, p1)
+ }
+
+ evt := ui.EventCh()
+
+ i := 0
+ for {
+ select {
+ case e := <-evt:
+ if e.Type == ui.EventKey && e.Ch == 'q' {
+ return
+ }
+ default:
+ draw(i)
+ i++
+ if i == 102 {
+ return
+ }
+ time.Sleep(time.Second / 2)
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go
new file mode 100644
index 000000000..b7033580f
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.go
@@ -0,0 +1,62 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "github.com/gizak/termui"
+
+func main() {
+ err := termui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ termui.UseTheme("helloworld")
+
+ g0 := termui.NewGauge()
+ g0.Percent = 40
+ g0.Width = 50
+ g0.Height = 3
+ g0.Border.Label = "Slim Gauge"
+ g0.BarColor = termui.ColorRed
+ g0.Border.FgColor = termui.ColorWhite
+ g0.Border.LabelFgColor = termui.ColorCyan
+
+ g2 := termui.NewGauge()
+ g2.Percent = 60
+ g2.Width = 50
+ g2.Height = 3
+ g2.PercentColor = termui.ColorBlue
+ g2.Y = 3
+ g2.Border.Label = "Slim Gauge"
+ g2.BarColor = termui.ColorYellow
+ g2.Border.FgColor = termui.ColorWhite
+
+ g1 := termui.NewGauge()
+ g1.Percent = 30
+ g1.Width = 50
+ g1.Height = 5
+ g1.Y = 6
+ g1.Border.Label = "Big Gauge"
+ g1.PercentColor = termui.ColorYellow
+ g1.BarColor = termui.ColorGreen
+ g1.Border.FgColor = termui.ColorWhite
+ g1.Border.LabelFgColor = termui.ColorMagenta
+
+ g3 := termui.NewGauge()
+ g3.Percent = 50
+ g3.Width = 50
+ g3.Height = 3
+ g3.Y = 11
+ g3.Border.Label = "Gauge with custom label"
+ g3.Label = "{{percent}}% (100MBs free)"
+ g3.LabelAlign = termui.AlignRight
+
+ termui.Render(g0, g1, g2, g3)
+
+ <-termui.EventCh()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png
new file mode 100644
index 000000000..5c20e6e8a
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/gauge.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif
new file mode 100644
index 000000000..7490043de
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.gif differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go
new file mode 100644
index 000000000..49121411f
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/grid.go
@@ -0,0 +1,134 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import ui "github.com/gizak/termui"
+import "math"
+import "time"
+
+func main() {
+ err := ui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer ui.Close()
+
+ sinps := (func() []float64 {
+ n := 400
+ ps := make([]float64, n)
+ for i := range ps {
+ ps[i] = 1 + math.Sin(float64(i)/5)
+ }
+ return ps
+ })()
+ sinpsint := (func() []int {
+ ps := make([]int, len(sinps))
+ for i, v := range sinps {
+ ps[i] = int(100*v + 10)
+ }
+ return ps
+ })()
+
+ ui.UseTheme("helloworld")
+
+ spark := ui.Sparkline{}
+ spark.Height = 8
+ spdata := sinpsint
+ spark.Data = spdata[:100]
+ spark.LineColor = ui.ColorCyan
+ spark.TitleColor = ui.ColorWhite
+
+ sp := ui.NewSparklines(spark)
+ sp.Height = 11
+ sp.Border.Label = "Sparkline"
+
+ lc := ui.NewLineChart()
+ lc.Border.Label = "braille-mode Line Chart"
+ lc.Data = sinps
+ lc.Height = 11
+ lc.AxesColor = ui.ColorWhite
+ lc.LineColor = ui.ColorYellow | ui.AttrBold
+
+ gs := make([]*ui.Gauge, 3)
+ for i := range gs {
+ gs[i] = ui.NewGauge()
+ gs[i].Height = 2
+ gs[i].HasBorder = false
+ gs[i].Percent = i * 10
+ gs[i].PaddingBottom = 1
+ gs[i].BarColor = ui.ColorRed
+ }
+
+ ls := ui.NewList()
+ ls.HasBorder = false
+ ls.Items = []string{
+ "[1] Downloading File 1",
+ "", // == \newline
+ "[2] Downloading File 2",
+ "",
+ "[3] Uploading File 3",
+ }
+ ls.Height = 5
+
+ par := ui.NewPar("<> This row has 3 columns\n<- Widgets can be stacked up like left side\n<- Stacked widgets are treated as a single widget")
+ par.Height = 5
+ par.Border.Label = "Demonstration"
+
+ // build layout
+ ui.Body.AddRows(
+ ui.NewRow(
+ ui.NewCol(6, 0, sp),
+ ui.NewCol(6, 0, lc)),
+ ui.NewRow(
+ ui.NewCol(3, 0, ls),
+ ui.NewCol(3, 0, gs[0], gs[1], gs[2]),
+ ui.NewCol(6, 0, par)))
+
+ // calculate layout
+ ui.Body.Align()
+
+ done := make(chan bool)
+ redraw := make(chan bool)
+
+ update := func() {
+ for i := 0; i < 103; i++ {
+ for _, g := range gs {
+ g.Percent = (g.Percent + 3) % 100
+ }
+
+ sp.Lines[0].Data = spdata[:100+i]
+ lc.Data = sinps[2*i:]
+
+ time.Sleep(time.Second / 2)
+ redraw <- true
+ }
+ done <- true
+ }
+
+ evt := ui.EventCh()
+
+ ui.Render(ui.Body)
+ go update()
+
+ for {
+ select {
+ case e := <-evt:
+ if e.Type == ui.EventKey && e.Ch == 'q' {
+ return
+ }
+ if e.Type == ui.EventResize {
+ ui.Body.Width = ui.TermWidth()
+ ui.Body.Align()
+ go func() { redraw <- true }()
+ }
+ case <-done:
+ return
+ case <-redraw:
+ ui.Render(ui.Body)
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go
new file mode 100644
index 000000000..1db543496
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.go
@@ -0,0 +1,68 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import (
+ "math"
+
+ "github.com/gizak/termui"
+)
+
+func main() {
+ err := termui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ termui.UseTheme("helloworld")
+
+ sinps := (func() []float64 {
+ n := 220
+ ps := make([]float64, n)
+ for i := range ps {
+ ps[i] = 1 + math.Sin(float64(i)/5)
+ }
+ return ps
+ })()
+
+ lc0 := termui.NewLineChart()
+ lc0.Border.Label = "braille-mode Line Chart"
+ lc0.Data = sinps
+ lc0.Width = 50
+ lc0.Height = 12
+ lc0.X = 0
+ lc0.Y = 0
+ lc0.AxesColor = termui.ColorWhite
+ lc0.LineColor = termui.ColorGreen | termui.AttrBold
+
+ lc1 := termui.NewLineChart()
+ lc1.Border.Label = "dot-mode Line Chart"
+ lc1.Mode = "dot"
+ lc1.Data = sinps
+ lc1.Width = 26
+ lc1.Height = 12
+ lc1.X = 51
+ lc1.DotStyle = '+'
+ lc1.AxesColor = termui.ColorWhite
+ lc1.LineColor = termui.ColorYellow | termui.AttrBold
+
+ lc2 := termui.NewLineChart()
+ lc2.Border.Label = "dot-mode Line Chart"
+ lc2.Mode = "dot"
+ lc2.Data = sinps[4:]
+ lc2.Width = 77
+ lc2.Height = 16
+ lc2.X = 0
+ lc2.Y = 12
+ lc2.AxesColor = termui.ColorWhite
+ lc2.LineColor = termui.ColorCyan | termui.AttrBold
+
+ termui.Render(lc0, lc1, lc2)
+
+ <-termui.EventCh()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png
new file mode 100644
index 000000000..655ef435f
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/linechart.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/list.go b/Godeps/_workspace/src/github.com/gizak/termui/example/list.go
new file mode 100644
index 000000000..d33a3616c
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/list.go
@@ -0,0 +1,41 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "github.com/gizak/termui"
+
+func main() {
+ err := termui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ termui.UseTheme("helloworld")
+
+ strs := []string{
+ "[0] github.com/gizak/termui",
+ "[1] 你好,世界",
+ "[2] こんにちは世界",
+ "[3] keyboard.go",
+ "[4] output.go",
+ "[5] random_out.go",
+ "[6] dashboard.go",
+ "[7] nsf/termbox-go"}
+
+ ls := termui.NewList()
+ ls.Items = strs
+ ls.ItemFgColor = termui.ColorYellow
+ ls.Border.Label = "List"
+ ls.Height = 7
+ ls.Width = 25
+ ls.Y = 0
+
+ termui.Render(ls)
+
+ <-termui.EventCh()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/list.png b/Godeps/_workspace/src/github.com/gizak/termui/example/list.png
new file mode 100644
index 000000000..8ca08c079
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/list.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go
new file mode 100644
index 000000000..a32a28e0a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.go
@@ -0,0 +1,50 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "github.com/gizak/termui"
+
+func main() {
+ err := termui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ termui.UseTheme("helloworld")
+
+ bc := termui.NewMBarChart()
+ math := []int{90, 85, 90, 80}
+ english := []int{70, 85, 75, 60}
+ science := []int{75, 60, 80, 85}
+ compsci := []int{100, 100, 100, 100}
+ bc.Data[0] = math
+ bc.Data[1] = english
+ bc.Data[2] = science
+ bc.Data[3] = compsci
+ studentsName := []string{"Ken", "Rob", "Dennis", "Linus"}
+ bc.Border.Label = "Student's Marks X-Axis=Name Y-Axis=Marks[Math,English,Science,ComputerScience] in %"
+ bc.Width = 100
+ bc.Height = 50
+ bc.Y = 10
+ bc.BarWidth = 10
+ bc.DataLabels = studentsName
+ bc.ShowScale = true //Show y_axis scale value (min and max)
+ bc.SetMax(400)
+
+ bc.TextColor = termui.ColorGreen //this is color for label (x-axis)
+ bc.BarColor[3] = termui.ColorGreen //BarColor for computerscience
+ bc.BarColor[1] = termui.ColorYellow //Bar Color for english
+ bc.NumColor[3] = termui.ColorRed // Num color for computerscience
+ bc.NumColor[1] = termui.ColorRed // num color for english
+
+ //Other colors are automatically populated, btw All the students seems do well in computerscience. :p
+
+ termui.Render(bc)
+
+ <-termui.EventCh()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png
new file mode 100644
index 000000000..9a4252616
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/mbarchart.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/par.go b/Godeps/_workspace/src/github.com/gizak/termui/example/par.go
new file mode 100644
index 000000000..ffbc60aa8
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/par.go
@@ -0,0 +1,48 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "github.com/gizak/termui"
+
+func main() {
+ err := termui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ termui.UseTheme("helloworld")
+
+ par0 := termui.NewPar("Borderless Text")
+ par0.Height = 1
+ par0.Width = 20
+ par0.Y = 1
+ par0.HasBorder = false
+
+ par1 := termui.NewPar("你好,世界。")
+ par1.Height = 3
+ par1.Width = 17
+ par1.X = 20
+ par1.Border.Label = "标签"
+
+ par2 := termui.NewPar("Simple text\nwith label. It can be multilined with \\n or break automatically")
+ par2.Height = 5
+ par2.Width = 37
+ par2.Y = 4
+ par2.Border.Label = "Multiline"
+ par2.Border.FgColor = termui.ColorYellow
+
+ par3 := termui.NewPar("Long text with label and it is auto trimmed.")
+ par3.Height = 3
+ par3.Width = 37
+ par3.Y = 9
+ par3.Border.Label = "Auto Trim"
+
+ termui.Render(par0, par1, par2, par3)
+
+ <-termui.EventCh()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/par.png b/Godeps/_workspace/src/github.com/gizak/termui/example/par.png
new file mode 100644
index 000000000..a85e64415
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/par.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go
new file mode 100644
index 000000000..f04baf570
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.go
@@ -0,0 +1,65 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "github.com/gizak/termui"
+
+func main() {
+ err := termui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer termui.Close()
+
+ termui.UseTheme("helloworld")
+
+ data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
+ spl0 := termui.NewSparkline()
+ spl0.Data = data[3:]
+ spl0.Title = "Sparkline 0"
+ spl0.LineColor = termui.ColorGreen
+
+ // single
+ spls0 := termui.NewSparklines(spl0)
+ spls0.Height = 2
+ spls0.Width = 20
+ spls0.HasBorder = false
+
+ spl1 := termui.NewSparkline()
+ spl1.Data = data
+ spl1.Title = "Sparkline 1"
+ spl1.LineColor = termui.ColorRed
+
+ spl2 := termui.NewSparkline()
+ spl2.Data = data[5:]
+ spl2.Title = "Sparkline 2"
+ spl2.LineColor = termui.ColorMagenta
+
+ // group
+ spls1 := termui.NewSparklines(spl0, spl1, spl2)
+ spls1.Height = 8
+ spls1.Width = 20
+ spls1.Y = 3
+ spls1.Border.Label = "Group Sparklines"
+
+ spl3 := termui.NewSparkline()
+ spl3.Data = data
+ spl3.Title = "Enlarged Sparkline"
+ spl3.Height = 8
+ spl3.LineColor = termui.ColorYellow
+
+ spls2 := termui.NewSparklines(spl3)
+ spls2.Height = 11
+ spls2.Width = 30
+ spls2.Border.FgColor = termui.ColorCyan
+ spls2.X = 21
+ spls2.Border.Label = "Tweeked Sparkline"
+
+ termui.Render(spls0, spls1, spls2)
+
+ <-termui.EventCh()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png
new file mode 100644
index 000000000..9dd7c82b1
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/sparklines.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/theme.go b/Godeps/_workspace/src/github.com/gizak/termui/example/theme.go
new file mode 100644
index 000000000..30c51a343
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/example/theme.go
@@ -0,0 +1,143 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import ui "github.com/gizak/termui"
+import "math"
+
+import "time"
+
+func main() {
+ err := ui.Init()
+ if err != nil {
+ panic(err)
+ }
+ defer ui.Close()
+
+ ui.UseTheme("helloworld")
+
+ p := ui.NewPar(":PRESS q TO QUIT DEMO")
+ p.Height = 3
+ p.Width = 50
+ p.Border.Label = "Text Box"
+
+ strs := []string{"[0] gizak/termui", "[1] editbox.go", "[2] iterrupt.go", "[3] keyboard.go", "[4] output.go", "[5] random_out.go", "[6] dashboard.go", "[7] nsf/termbox-go"}
+ list := ui.NewList()
+ list.Items = strs
+ list.Border.Label = "List"
+ list.Height = 7
+ list.Width = 25
+ list.Y = 4
+
+ g := ui.NewGauge()
+ g.Percent = 50
+ g.Width = 50
+ g.Height = 3
+ g.Y = 11
+ g.Border.Label = "Gauge"
+
+ spark := ui.NewSparkline()
+ spark.Title = "srv 0:"
+ spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
+ spark.Data = spdata
+
+ spark1 := ui.NewSparkline()
+ spark1.Title = "srv 1:"
+ spark1.Data = spdata
+
+ sp := ui.NewSparklines(spark, spark1)
+ sp.Width = 25
+ sp.Height = 7
+ sp.Border.Label = "Sparkline"
+ sp.Y = 4
+ sp.X = 25
+
+ lc := ui.NewLineChart()
+ sinps := (func() []float64 {
+ n := 100
+ ps := make([]float64, n)
+ for i := range ps {
+ ps[i] = 1 + math.Sin(float64(i)/4)
+ }
+ return ps
+ })()
+
+ lc.Border.Label = "Line Chart"
+ lc.Data = sinps
+ lc.Width = 50
+ lc.Height = 11
+ lc.X = 0
+ lc.Y = 14
+ lc.Mode = "dot"
+
+ bc := ui.NewBarChart()
+ bcdata := []int{3, 2, 5, 3, 9, 5, 3, 2, 5, 8, 3, 2, 4, 5, 3, 2, 5, 7, 5, 3, 2, 6, 7, 4, 6, 3, 6, 7, 8, 3, 6, 4, 5, 3, 2, 4, 6, 4, 8, 5, 9, 4, 3, 6, 5, 3, 6}
+ bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
+ bc.Border.Label = "Bar Chart"
+ bc.Width = 26
+ bc.Height = 10
+ bc.X = 51
+ bc.Y = 0
+ bc.DataLabels = bclabels
+
+ lc1 := ui.NewLineChart()
+ lc1.Border.Label = "Line Chart"
+ rndwalk := (func() []float64 {
+ n := 150
+ d := make([]float64, n)
+ for i := 1; i < n; i++ {
+ if i < 20 {
+ d[i] = d[i-1] + 0.01
+ }
+ if i > 20 {
+ d[i] = d[i-1] - 0.05
+ }
+ }
+ return d
+ })()
+ lc1.Data = rndwalk
+ lc1.Width = 26
+ lc1.Height = 11
+ lc1.X = 51
+ lc1.Y = 14
+
+ p1 := ui.NewPar("Hey!\nI am a borderless block!")
+ p1.HasBorder = false
+ p1.Width = 26
+ p1.Height = 2
+ p1.X = 52
+ p1.Y = 11
+
+ draw := func(t int) {
+ g.Percent = t % 101
+ list.Items = strs[t%9:]
+ sp.Lines[0].Data = spdata[t%10:]
+ sp.Lines[1].Data = spdata[t/2%10:]
+ lc.Data = sinps[t/2:]
+ lc1.Data = rndwalk[t:]
+ bc.Data = bcdata[t/2%10:]
+ ui.Render(p, list, g, sp, lc, bc, lc1, p1)
+ }
+
+ evt := ui.EventCh()
+ i := 0
+ for {
+ select {
+ case e := <-evt:
+ if e.Type == ui.EventKey && e.Ch == 'q' {
+ return
+ }
+ default:
+ draw(i)
+ i++
+ if i == 102 {
+ return
+ }
+ time.Sleep(time.Second / 2)
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png b/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png
new file mode 100644
index 000000000..23b574f96
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/themedefault.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png b/Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png
new file mode 100644
index 000000000..eaf4d9303
Binary files /dev/null and b/Godeps/_workspace/src/github.com/gizak/termui/example/themehelloworld.png differ
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/gauge.go b/Godeps/_workspace/src/github.com/gizak/termui/gauge.go
new file mode 100644
index 000000000..986f4f3dc
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/gauge.go
@@ -0,0 +1,113 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import (
+ "strconv"
+ "strings"
+)
+
+// Gauge is a progress bar like widget.
+// A simple example:
+/*
+ g := termui.NewGauge()
+ g.Percent = 40
+ g.Width = 50
+ g.Height = 3
+ g.Border.Label = "Slim Gauge"
+ g.BarColor = termui.ColorRed
+ g.PercentColor = termui.ColorBlue
+*/
+
+// Align is the position of the gauge's label.
+type Align int
+
+// All supported positions.
+const (
+ AlignLeft Align = iota
+ AlignCenter
+ AlignRight
+)
+
+type Gauge struct {
+ Block
+ Percent int
+ BarColor Attribute
+ PercentColor Attribute
+ Label string
+ LabelAlign Align
+}
+
+// NewGauge return a new gauge with current theme.
+func NewGauge() *Gauge {
+ g := &Gauge{
+ Block: *NewBlock(),
+ PercentColor: theme.GaugePercent,
+ BarColor: theme.GaugeBar,
+ Label: "{{percent}}%",
+ LabelAlign: AlignCenter,
+ }
+
+ g.Width = 12
+ g.Height = 5
+ return g
+}
+
+// Buffer implements Bufferer interface.
+func (g *Gauge) Buffer() []Point {
+ ps := g.Block.Buffer()
+
+ // plot bar
+ w := g.Percent * g.innerWidth / 100
+ for i := 0; i < g.innerHeight; i++ {
+ for j := 0; j < w; j++ {
+ p := Point{}
+ p.X = g.innerX + j
+ p.Y = g.innerY + i
+ p.Ch = ' '
+ p.Bg = g.BarColor
+ if p.Bg == ColorDefault {
+ p.Bg |= AttrReverse
+ }
+ ps = append(ps, p)
+ }
+ }
+
+ // plot percentage
+ s := strings.Replace(g.Label, "{{percent}}", strconv.Itoa(g.Percent), -1)
+ pry := g.innerY + g.innerHeight/2
+ rs := str2runes(s)
+ var pos int
+ switch g.LabelAlign {
+ case AlignLeft:
+ pos = 0
+
+ case AlignCenter:
+ pos = (g.innerWidth - strWidth(s)) / 2
+
+ case AlignRight:
+ pos = g.innerWidth - strWidth(s)
+ }
+
+ for i, v := range rs {
+ p := Point{}
+ p.X = 1 + pos + i
+ p.Y = pry
+ p.Ch = v
+ p.Fg = g.PercentColor
+ if w+g.innerX > pos+i {
+ p.Bg = g.BarColor
+ if p.Bg == ColorDefault {
+ p.Bg |= AttrReverse
+ }
+
+ } else {
+ p.Bg = g.Block.BgColor
+ }
+
+ ps = append(ps, p)
+ }
+ return g.Block.chopOverflow(ps)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/grid.go b/Godeps/_workspace/src/github.com/gizak/termui/grid.go
new file mode 100644
index 000000000..5f6e85e76
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/grid.go
@@ -0,0 +1,279 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+// GridBufferer introduces a Bufferer that can be manipulated by Grid.
+type GridBufferer interface {
+ Bufferer
+ GetHeight() int
+ SetWidth(int)
+ SetX(int)
+ SetY(int)
+}
+
+// Row builds a layout tree
+type Row struct {
+ Cols []*Row //children
+ Widget GridBufferer // root
+ X int
+ Y int
+ Width int
+ Height int
+ Span int
+ Offset int
+}
+
+// calculate and set the underlying layout tree's x, y, height and width.
+func (r *Row) calcLayout() {
+ r.assignWidth(r.Width)
+ r.Height = r.solveHeight()
+ r.assignX(r.X)
+ r.assignY(r.Y)
+}
+
+// tell if the node is leaf in the tree.
+func (r *Row) isLeaf() bool {
+ return r.Cols == nil || len(r.Cols) == 0
+}
+
+func (r *Row) isRenderableLeaf() bool {
+ return r.isLeaf() && r.Widget != nil
+}
+
+// assign widgets' (and their parent rows') width recursively.
+func (r *Row) assignWidth(w int) {
+ r.SetWidth(w)
+
+ accW := 0 // acc span and offset
+ calcW := make([]int, len(r.Cols)) // calculated width
+ calcOftX := make([]int, len(r.Cols)) // computated start position of x
+
+ for i, c := range r.Cols {
+ accW += c.Span + c.Offset
+ cw := int(float64(c.Span*r.Width) / 12.0)
+
+ if i >= 1 {
+ calcOftX[i] = calcOftX[i-1] +
+ calcW[i-1] +
+ int(float64(r.Cols[i-1].Offset*r.Width)/12.0)
+ }
+
+ // use up the space if it is the last col
+ if i == len(r.Cols)-1 && accW == 12 {
+ cw = r.Width - calcOftX[i]
+ }
+ calcW[i] = cw
+ r.Cols[i].assignWidth(cw)
+ }
+}
+
+// bottom up calc and set rows' (and their widgets') height,
+// return r's total height.
+func (r *Row) solveHeight() int {
+ if r.isRenderableLeaf() {
+ r.Height = r.Widget.GetHeight()
+ return r.Widget.GetHeight()
+ }
+
+ maxh := 0
+ if !r.isLeaf() {
+ for _, c := range r.Cols {
+ nh := c.solveHeight()
+ // when embed rows in Cols, row widgets stack up
+ if r.Widget != nil {
+ nh += r.Widget.GetHeight()
+ }
+ if nh > maxh {
+ maxh = nh
+ }
+ }
+ }
+
+ r.Height = maxh
+ return maxh
+}
+
+// recursively assign x position for r tree.
+func (r *Row) assignX(x int) {
+ r.SetX(x)
+
+ if !r.isLeaf() {
+ acc := 0
+ for i, c := range r.Cols {
+ if c.Offset != 0 {
+ acc += int(float64(c.Offset*r.Width) / 12.0)
+ }
+ r.Cols[i].assignX(x + acc)
+ acc += c.Width
+ }
+ }
+}
+
+// recursively assign y position to r.
+func (r *Row) assignY(y int) {
+ r.SetY(y)
+
+ if r.isLeaf() {
+ return
+ }
+
+ for i := range r.Cols {
+ acc := 0
+ if r.Widget != nil {
+ acc = r.Widget.GetHeight()
+ }
+ r.Cols[i].assignY(y + acc)
+ }
+
+}
+
+// GetHeight implements GridBufferer interface.
+func (r Row) GetHeight() int {
+ return r.Height
+}
+
+// SetX implements GridBufferer interface.
+func (r *Row) SetX(x int) {
+ r.X = x
+ if r.Widget != nil {
+ r.Widget.SetX(x)
+ }
+}
+
+// SetY implements GridBufferer interface.
+func (r *Row) SetY(y int) {
+ r.Y = y
+ if r.Widget != nil {
+ r.Widget.SetY(y)
+ }
+}
+
+// SetWidth implements GridBufferer interface.
+func (r *Row) SetWidth(w int) {
+ r.Width = w
+ if r.Widget != nil {
+ r.Widget.SetWidth(w)
+ }
+}
+
+// Buffer implements Bufferer interface,
+// recursively merge all widgets buffer
+func (r *Row) Buffer() []Point {
+ merged := []Point{}
+
+ if r.isRenderableLeaf() {
+ return r.Widget.Buffer()
+ }
+
+ // for those are not leaves but have a renderable widget
+ if r.Widget != nil {
+ merged = append(merged, r.Widget.Buffer()...)
+ }
+
+ // collect buffer from children
+ if !r.isLeaf() {
+ for _, c := range r.Cols {
+ merged = append(merged, c.Buffer()...)
+ }
+ }
+
+ return merged
+}
+
+// Grid implements 12 columns system.
+// A simple example:
+/*
+ import ui "github.com/gizak/termui"
+ // init and create widgets...
+
+ // build
+ ui.Body.AddRows(
+ ui.NewRow(
+ ui.NewCol(6, 0, widget0),
+ ui.NewCol(6, 0, widget1)),
+ ui.NewRow(
+ ui.NewCol(3, 0, widget2),
+ ui.NewCol(3, 0, widget30, widget31, widget32),
+ ui.NewCol(6, 0, widget4)))
+
+ // calculate layout
+ ui.Body.Align()
+
+ ui.Render(ui.Body)
+*/
+type Grid struct {
+ Rows []*Row
+ Width int
+ X int
+ Y int
+ BgColor Attribute
+}
+
+// NewGrid returns *Grid with given rows.
+func NewGrid(rows ...*Row) *Grid {
+ return &Grid{Rows: rows}
+}
+
+// AddRows appends given rows to Grid.
+func (g *Grid) AddRows(rs ...*Row) {
+ g.Rows = append(g.Rows, rs...)
+}
+
+// NewRow creates a new row out of given columns.
+func NewRow(cols ...*Row) *Row {
+ rs := &Row{Span: 12, Cols: cols}
+ return rs
+}
+
+// NewCol accepts: widgets are LayoutBufferer or widgets is A NewRow.
+// Note that if multiple widgets are provided, they will stack up in the col.
+func NewCol(span, offset int, widgets ...GridBufferer) *Row {
+ r := &Row{Span: span, Offset: offset}
+
+ if widgets != nil && len(widgets) == 1 {
+ wgt := widgets[0]
+ nw, isRow := wgt.(*Row)
+ if isRow {
+ r.Cols = nw.Cols
+ } else {
+ r.Widget = wgt
+ }
+ return r
+ }
+
+ r.Cols = []*Row{}
+ ir := r
+ for _, w := range widgets {
+ nr := &Row{Span: 12, Widget: w}
+ ir.Cols = []*Row{nr}
+ ir = nr
+ }
+
+ return r
+}
+
+// Align calculate each rows' layout.
+func (g *Grid) Align() {
+ h := 0
+ for _, r := range g.Rows {
+ r.SetWidth(g.Width)
+ r.SetX(g.X)
+ r.SetY(g.Y + h)
+ r.calcLayout()
+ h += r.GetHeight()
+ }
+}
+
+// Buffer implments Bufferer interface.
+func (g Grid) Buffer() []Point {
+ ps := []Point{}
+ for _, r := range g.Rows {
+ ps = append(ps, r.Buffer()...)
+ }
+ return ps
+}
+
+// Body corresponds to the entire terminal display region.
+var Body *Grid
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go b/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go
new file mode 100644
index 000000000..cdafb2052
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/grid_test.go
@@ -0,0 +1,98 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import (
+ "testing"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+var r *Row
+
+func TestRowWidth(t *testing.T) {
+ p0 := NewPar("p0")
+ p0.Height = 1
+ p1 := NewPar("p1")
+ p1.Height = 1
+ p2 := NewPar("p2")
+ p2.Height = 1
+ p3 := NewPar("p3")
+ p3.Height = 1
+
+ /* test against tree:
+
+ r
+ / \
+ 0:w 1
+ / \
+ 10:w 11
+ /
+ 110:w
+ /
+ 1100:w
+ */
+ /*
+ r = &row{
+ Span: 12,
+ Cols: []*row{
+ &row{Widget: p0, Span: 6},
+ &row{
+ Span: 6,
+ Cols: []*row{
+ &row{Widget: p1, Span: 6},
+ &row{
+ Span: 6,
+ Cols: []*row{
+ &row{
+ Span: 12,
+ Widget: p2,
+ Cols: []*row{
+ &row{Span: 12, Widget: p3}}}}}}}}}
+ */
+
+ r = NewRow(
+ NewCol(6, 0, p0),
+ NewCol(6, 0,
+ NewRow(
+ NewCol(6, 0, p1),
+ NewCol(6, 0, p2, p3))))
+
+ r.assignWidth(100)
+ if r.Width != 100 ||
+ (r.Cols[0].Width) != 50 ||
+ (r.Cols[1].Width) != 50 ||
+ (r.Cols[1].Cols[0].Width) != 25 ||
+ (r.Cols[1].Cols[1].Width) != 25 ||
+ (r.Cols[1].Cols[1].Cols[0].Width) != 25 ||
+ (r.Cols[1].Cols[1].Cols[0].Cols[0].Width) != 25 {
+ t.Error("assignWidth fails")
+ }
+}
+
+func TestRowHeight(t *testing.T) {
+ spew.Dump()
+
+ if (r.solveHeight()) != 2 ||
+ (r.Cols[1].Cols[1].Height) != 2 ||
+ (r.Cols[1].Cols[1].Cols[0].Height) != 2 ||
+ (r.Cols[1].Cols[0].Height) != 1 {
+ t.Error("solveHeight fails")
+ }
+}
+
+func TestAssignXY(t *testing.T) {
+ r.assignX(0)
+ r.assignY(0)
+ if (r.Cols[0].X) != 0 ||
+ (r.Cols[1].Cols[0].X) != 50 ||
+ (r.Cols[1].Cols[1].X) != 75 ||
+ (r.Cols[1].Cols[1].Cols[0].X) != 75 ||
+ (r.Cols[1].Cols[0].Y) != 0 ||
+ (r.Cols[1].Cols[1].Cols[0].Y) != 0 ||
+ (r.Cols[1].Cols[1].Cols[0].Cols[0].Y) != 1 {
+ t.Error("assignXY fails")
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/helper.go b/Godeps/_workspace/src/github.com/gizak/termui/helper.go
new file mode 100644
index 000000000..80d8a0278
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/helper.go
@@ -0,0 +1,66 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import tm "github.com/nsf/termbox-go"
+import rw "github.com/mattn/go-runewidth"
+
+/* ---------------Port from termbox-go --------------------- */
+
+// Attribute is printable cell's color and style.
+type Attribute uint16
+
+const (
+ ColorDefault Attribute = iota
+ ColorBlack
+ ColorRed
+ ColorGreen
+ ColorYellow
+ ColorBlue
+ ColorMagenta
+ ColorCyan
+ ColorWhite
+)
+
+const NumberofColors = 8 //Have a constant that defines number of colors
+const (
+ AttrBold Attribute = 1 << (iota + 9)
+ AttrUnderline
+ AttrReverse
+)
+
+var (
+ dot = "…"
+ dotw = rw.StringWidth(dot)
+)
+
+/* ----------------------- End ----------------------------- */
+
+func toTmAttr(x Attribute) tm.Attribute {
+ return tm.Attribute(x)
+}
+
+func str2runes(s string) []rune {
+ return []rune(s)
+}
+
+func trimStr2Runes(s string, w int) []rune {
+ if w <= 0 {
+ return []rune{}
+ }
+ sw := rw.StringWidth(s)
+ if sw > w {
+ return []rune(rw.Truncate(s, w, dot))
+ }
+ return str2runes(s) //[]rune(rw.Truncate(s, w, ""))
+}
+
+func strWidth(s string) int {
+ return rw.StringWidth(s)
+}
+
+func charWidth(ch rune) int {
+ return rw.RuneWidth(ch)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go b/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go
new file mode 100644
index 000000000..6d1a56130
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/helper_test.go
@@ -0,0 +1,58 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import (
+ "testing"
+
+ "github.com/davecgh/go-spew/spew"
+)
+
+func TestStr2Rune(t *testing.T) {
+ s := "你好,世界."
+ rs := str2runes(s)
+ if len(rs) != 6 {
+ t.Error()
+ }
+}
+
+func TestWidth(t *testing.T) {
+ s0 := "つのだ☆HIRO"
+ s1 := "11111111111"
+ spew.Dump(s0)
+ spew.Dump(s1)
+ // above not align for setting East Asian Ambiguous to wide!!
+
+ if strWidth(s0) != strWidth(s1) {
+ t.Error("str len failed")
+ }
+
+ len1 := []rune{'a', '2', '&', '「', 'オ', '。'} //will false: 'ᆵ', 'ᄚ', 'ᄒ'
+ for _, v := range len1 {
+ if charWidth(v) != 1 {
+ t.Error("len1 failed")
+ }
+ }
+
+ len2 := []rune{'漢', '字', '한', '자', '你', '好', 'だ', '。', '%', 's', 'E', 'ョ', '、', 'ヲ'}
+ for _, v := range len2 {
+ if charWidth(v) != 2 {
+ t.Error("len2 failed")
+ }
+ }
+}
+
+func TestTrim(t *testing.T) {
+ s := "つのだ☆HIRO"
+ if string(trimStr2Runes(s, 10)) != "つのだ☆HI"+dot {
+ t.Error("trim failed")
+ }
+ if string(trimStr2Runes(s, 11)) != "つのだ☆HIRO" {
+ t.Error("avoid tail trim failed")
+ }
+ if string(trimStr2Runes(s, 15)) != "つのだ☆HIRO" {
+ t.Error("avoid trim failed")
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/list.go b/Godeps/_workspace/src/github.com/gizak/termui/list.go
new file mode 100644
index 000000000..0640932f2
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/list.go
@@ -0,0 +1,104 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import "strings"
+
+// List displays []string as its items,
+// it has a Overflow option (default is "hidden"), when set to "hidden",
+// the item exceeding List's width is truncated, but when set to "wrap",
+// the overflowed text breaks into next line.
+/*
+ strs := []string{
+ "[0] github.com/gizak/termui",
+ "[1] editbox.go",
+ "[2] iterrupt.go",
+ "[3] keyboard.go",
+ "[4] output.go",
+ "[5] random_out.go",
+ "[6] dashboard.go",
+ "[7] nsf/termbox-go"}
+
+ ls := termui.NewList()
+ ls.Items = strs
+ ls.ItemFgColor = termui.ColorYellow
+ ls.Border.Label = "List"
+ ls.Height = 7
+ ls.Width = 25
+ ls.Y = 0
+*/
+type List struct {
+ Block
+ Items []string
+ Overflow string
+ ItemFgColor Attribute
+ ItemBgColor Attribute
+}
+
+// NewList returns a new *List with current theme.
+func NewList() *List {
+ l := &List{Block: *NewBlock()}
+ l.Overflow = "hidden"
+ l.ItemFgColor = theme.ListItemFg
+ l.ItemBgColor = theme.ListItemBg
+ return l
+}
+
+// Buffer implements Bufferer interface.
+func (l *List) Buffer() []Point {
+ ps := l.Block.Buffer()
+ switch l.Overflow {
+ case "wrap":
+ rs := str2runes(strings.Join(l.Items, "\n"))
+ i, j, k := 0, 0, 0
+ for i < l.innerHeight && k < len(rs) {
+ w := charWidth(rs[k])
+ if rs[k] == '\n' || j+w > l.innerWidth {
+ i++
+ j = 0
+ if rs[k] == '\n' {
+ k++
+ }
+ continue
+ }
+ pi := Point{}
+ pi.X = l.innerX + j
+ pi.Y = l.innerY + i
+
+ pi.Ch = rs[k]
+ pi.Bg = l.ItemBgColor
+ pi.Fg = l.ItemFgColor
+
+ ps = append(ps, pi)
+ k++
+ j++
+ }
+
+ case "hidden":
+ trimItems := l.Items
+ if len(trimItems) > l.innerHeight {
+ trimItems = trimItems[:l.innerHeight]
+ }
+ for i, v := range trimItems {
+ rs := trimStr2Runes(v, l.innerWidth)
+
+ j := 0
+ for _, vv := range rs {
+ w := charWidth(vv)
+ p := Point{}
+ p.X = l.innerX + j
+ p.Y = l.innerY + i
+
+ p.Ch = vv
+ p.Bg = l.ItemBgColor
+ p.Fg = l.ItemFgColor
+
+ ps = append(ps, p)
+ j += w
+ }
+ }
+ }
+ return l.Block.chopOverflow(ps)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/mbar.go b/Godeps/_workspace/src/github.com/gizak/termui/mbar.go
new file mode 100644
index 000000000..9d18c2cb4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/mbar.go
@@ -0,0 +1,233 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import (
+ "fmt"
+)
+
+// This is the implemetation of multi-colored or stacked bar graph. This is different from default barGraph which is implemented in bar.go
+// Multi-Colored-BarChart creates multiple bars in a widget:
+/*
+ bc := termui.NewMBarChart()
+ data := make([][]int, 2)
+ data[0] := []int{3, 2, 5, 7, 9, 4}
+ data[1] := []int{7, 8, 5, 3, 1, 6}
+ bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
+ bc.Border.Label = "Bar Chart"
+ bc.Data = data
+ bc.Width = 26
+ bc.Height = 10
+ bc.DataLabels = bclabels
+ bc.TextColor = termui.ColorGreen
+ bc.BarColor = termui.ColorRed
+ bc.NumColor = termui.ColorYellow
+*/
+type MBarChart struct {
+ Block
+ BarColor [NumberofColors]Attribute
+ TextColor Attribute
+ NumColor [NumberofColors]Attribute
+ Data [NumberofColors][]int
+ DataLabels []string
+ BarWidth int
+ BarGap int
+ labels [][]rune
+ dataNum [NumberofColors][][]rune
+ numBar int
+ scale float64
+ max int
+ minDataLen int
+ numStack int
+ ShowScale bool
+ maxScale []rune
+}
+
+// NewBarChart returns a new *BarChart with current theme.
+func NewMBarChart() *MBarChart {
+ bc := &MBarChart{Block: *NewBlock()}
+ bc.BarColor[0] = theme.MBarChartBar
+ bc.NumColor[0] = theme.MBarChartNum
+ bc.TextColor = theme.MBarChartText
+ bc.BarGap = 1
+ bc.BarWidth = 3
+ return bc
+}
+
+func (bc *MBarChart) layout() {
+ bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
+ bc.labels = make([][]rune, bc.numBar)
+ DataLen := 0
+ LabelLen := len(bc.DataLabels)
+ bc.minDataLen = 9999 //Set this to some very hight value so that we find the minimum one We want to know which array among data[][] has got the least length
+
+ // We need to know how many stack/data array data[0] , data[1] are there
+ for i := 0; i < len(bc.Data); i++ {
+ if bc.Data[i] == nil {
+ break
+ }
+ DataLen++
+ }
+ bc.numStack = DataLen
+
+ //We need to know what is the mimimum size of data array data[0] could have 10 elements data[1] could have only 5, so we plot only 5 bar graphs
+
+ for i := 0; i < DataLen; i++ {
+ if bc.minDataLen > len(bc.Data[i]) {
+ bc.minDataLen = len(bc.Data[i])
+ }
+ }
+
+ if LabelLen > bc.minDataLen {
+ LabelLen = bc.minDataLen
+ }
+
+ for i := 0; i < LabelLen && i < bc.numBar; i++ {
+ bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
+ }
+
+ for i := 0; i < bc.numStack; i++ {
+ bc.dataNum[i] = make([][]rune, len(bc.Data[i]))
+ //For each stack of bar calcualte the rune
+ for j := 0; j < LabelLen && i < bc.numBar; j++ {
+ n := bc.Data[i][j]
+ s := fmt.Sprint(n)
+ bc.dataNum[i][j] = trimStr2Runes(s, bc.BarWidth)
+ }
+ //If color is not defined by default then populate a color that is different from the prevous bar
+ if bc.BarColor[i] == ColorDefault && bc.NumColor[i] == ColorDefault {
+ if i == 0 {
+ bc.BarColor[i] = ColorBlack
+ } else {
+ bc.BarColor[i] = bc.BarColor[i-1] + 1
+ if bc.BarColor[i] > NumberofColors {
+ bc.BarColor[i] = ColorBlack
+ }
+ }
+ bc.NumColor[i] = (NumberofColors + 1) - bc.BarColor[i] //Make NumColor opposite of barColor for visibility
+ }
+ }
+
+ //If Max value is not set then we have to populate, this time the max value will be max(sum(d1[0],d2[0],d3[0]) .... sum(d1[n], d2[n], d3[n]))
+
+ if bc.max == 0 {
+ bc.max = -1
+ }
+ for i := 0; i < bc.minDataLen && i < LabelLen; i++ {
+ var dsum int
+ for j := 0; j < bc.numStack; j++ {
+ dsum += bc.Data[j][i]
+ }
+ if dsum > bc.max {
+ bc.max = dsum
+ }
+ }
+
+ //Finally Calculate max sale
+ if bc.ShowScale {
+ s := fmt.Sprintf("%d", bc.max)
+ bc.maxScale = trimStr2Runes(s, len(s))
+ bc.scale = float64(bc.max) / float64(bc.innerHeight-2)
+ } else {
+ bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
+ }
+
+}
+
+func (bc *MBarChart) SetMax(max int) {
+
+ if max > 0 {
+ bc.max = max
+ }
+}
+
+// Buffer implements Bufferer interface.
+func (bc *MBarChart) Buffer() []Point {
+ ps := bc.Block.Buffer()
+ bc.layout()
+ var oftX int
+
+ for i := 0; i < bc.numBar && i < bc.minDataLen && i < len(bc.DataLabels); i++ {
+ ph := 0 //Previous Height to stack up
+ oftX = i * (bc.BarWidth + bc.BarGap)
+ for i1 := 0; i1 < bc.numStack; i1++ {
+ h := int(float64(bc.Data[i1][i]) / bc.scale)
+ // plot bars
+ for j := 0; j < bc.BarWidth; j++ {
+ for k := 0; k < h; k++ {
+ p := Point{}
+ p.Ch = ' '
+ p.Bg = bc.BarColor[i1]
+ if bc.BarColor[i1] == ColorDefault { // when color is default, space char treated as transparent!
+ p.Bg |= AttrReverse
+ }
+ p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
+ p.Y = bc.innerY + bc.innerHeight - 2 - k - ph
+ ps = append(ps, p)
+ }
+ }
+ ph += h
+ }
+ // plot text
+ for j, k := 0, 0; j < len(bc.labels[i]); j++ {
+ w := charWidth(bc.labels[i][j])
+ p := Point{}
+ p.Ch = bc.labels[i][j]
+ p.Bg = bc.BgColor
+ p.Fg = bc.TextColor
+ p.Y = bc.innerY + bc.innerHeight - 1
+ p.X = bc.innerX + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k
+ ps = append(ps, p)
+ k += w
+ }
+ // plot num
+ ph = 0 //re-initialize previous height
+ for i1 := 0; i1 < bc.numStack; i1++ {
+ h := int(float64(bc.Data[i1][i]) / bc.scale)
+ for j := 0; j < len(bc.dataNum[i1][i]) && h > 0; j++ {
+ p := Point{}
+ p.Ch = bc.dataNum[i1][i][j]
+ p.Fg = bc.NumColor[i1]
+ p.Bg = bc.BarColor[i1]
+ if bc.BarColor[i1] == ColorDefault { // the same as above
+ p.Bg |= AttrReverse
+ }
+ if h == 0 {
+ p.Bg = bc.BgColor
+ }
+ p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j
+ p.Y = bc.innerY + bc.innerHeight - 2 - ph
+ ps = append(ps, p)
+ }
+ ph += h
+ }
+ }
+
+ if bc.ShowScale {
+ //Currently bar graph only supprts data range from 0 to MAX
+ //Plot 0
+ p := Point{}
+ p.Ch = '0'
+ p.Bg = bc.BgColor
+ p.Fg = bc.TextColor
+ p.Y = bc.innerY + bc.innerHeight - 2
+ p.X = bc.X
+ ps = append(ps, p)
+
+ //Plot the maximum sacle value
+ for i := 0; i < len(bc.maxScale); i++ {
+ p := Point{}
+ p.Ch = bc.maxScale[i]
+ p.Bg = bc.BgColor
+ p.Fg = bc.TextColor
+ p.Y = bc.innerY
+ p.X = bc.X + i
+ ps = append(ps, p)
+ }
+
+ }
+
+ return bc.Block.chopOverflow(ps)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/p.go b/Godeps/_workspace/src/github.com/gizak/termui/p.go
new file mode 100644
index 000000000..e327d7489
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/p.go
@@ -0,0 +1,71 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+// Par displays a paragraph.
+/*
+ par := termui.NewPar("Simple Text")
+ par.Height = 3
+ par.Width = 17
+ par.Border.Label = "Label"
+*/
+type Par struct {
+ Block
+ Text string
+ TextFgColor Attribute
+ TextBgColor Attribute
+}
+
+// NewPar returns a new *Par with given text as its content.
+func NewPar(s string) *Par {
+ return &Par{
+ Block: *NewBlock(),
+ Text: s,
+ TextFgColor: theme.ParTextFg,
+ TextBgColor: theme.ParTextBg}
+}
+
+// Buffer implements Bufferer interface.
+func (p *Par) Buffer() []Point {
+ ps := p.Block.Buffer()
+
+ rs := str2runes(p.Text)
+ i, j, k := 0, 0, 0
+ for i < p.innerHeight && k < len(rs) {
+ // the width of char is about to print
+ w := charWidth(rs[k])
+
+ if rs[k] == '\n' || j+w > p.innerWidth {
+ i++
+ j = 0 // set x = 0
+ if rs[k] == '\n' {
+ k++
+ }
+
+ if i >= p.innerHeight {
+ ps = append(ps, newPointWithAttrs('…',
+ p.innerX+p.innerWidth-1,
+ p.innerY+p.innerHeight-1,
+ p.TextFgColor, p.TextBgColor))
+ break
+ }
+
+ continue
+ }
+ pi := Point{}
+ pi.X = p.innerX + j
+ pi.Y = p.innerY + i
+
+ pi.Ch = rs[k]
+ pi.Bg = p.TextBgColor
+ pi.Fg = p.TextFgColor
+
+ ps = append(ps, pi)
+
+ k++
+ j += w
+ }
+ return p.Block.chopOverflow(ps)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/point.go b/Godeps/_workspace/src/github.com/gizak/termui/point.go
new file mode 100644
index 000000000..c381af9a4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/point.go
@@ -0,0 +1,28 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+// Point stands for a single cell in terminal.
+type Point struct {
+ Ch rune
+ Bg Attribute
+ Fg Attribute
+ X int
+ Y int
+}
+
+func newPoint(c rune, x, y int) (p Point) {
+ p.Ch = c
+ p.X = x
+ p.Y = y
+ return
+}
+
+func newPointWithAttrs(c rune, x, y int, fg, bg Attribute) Point {
+ p := newPoint(c, x, y)
+ p.Bg = bg
+ p.Fg = fg
+ return p
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/render.go b/Godeps/_workspace/src/github.com/gizak/termui/render.go
new file mode 100644
index 000000000..d697d0aea
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/render.go
@@ -0,0 +1,60 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import tm "github.com/nsf/termbox-go"
+
+// Bufferer should be implemented by all renderable components.
+type Bufferer interface {
+ Buffer() []Point
+}
+
+// Init initializes termui library. This function should be called before any others.
+// After initialization, the library must be finalized by 'Close' function.
+func Init() error {
+ Body = NewGrid()
+ Body.X = 0
+ Body.Y = 0
+ Body.BgColor = theme.BodyBg
+ defer func() {
+ w, _ := tm.Size()
+ Body.Width = w
+ evtListen()
+ }()
+ return tm.Init()
+}
+
+// Close finalizes termui library,
+// should be called after successful initialization when termui's functionality isn't required anymore.
+func Close() {
+ tm.Close()
+}
+
+// TermWidth returns the current terminal's width.
+func TermWidth() int {
+ tm.Sync()
+ w, _ := tm.Size()
+ return w
+}
+
+// TermHeight returns the current terminal's height.
+func TermHeight() int {
+ tm.Sync()
+ _, h := tm.Size()
+ return h
+}
+
+// Render renders all Bufferer in the given order from left to right,
+// right could overlap on left ones.
+func Render(rs ...Bufferer) {
+ tm.Clear(tm.ColorDefault, toTmAttr(theme.BodyBg))
+ for _, r := range rs {
+ buf := r.Buffer()
+ for _, v := range buf {
+ tm.SetCell(v.X, v.Y, v.Ch, toTmAttr(v.Fg), toTmAttr(v.Bg))
+ }
+ }
+ tm.Flush()
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go b/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go
new file mode 100644
index 000000000..c63a5857f
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/sparkline.go
@@ -0,0 +1,156 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+import "math"
+
+// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃
+/*
+ data := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1}
+ spl := termui.NewSparkline()
+ spl.Data = data
+ spl.Title = "Sparkline 0"
+ spl.LineColor = termui.ColorGreen
+*/
+type Sparkline struct {
+ Data []int
+ Height int
+ Title string
+ TitleColor Attribute
+ LineColor Attribute
+ displayHeight int
+ scale float32
+ max int
+}
+
+// Sparklines is a renderable widget which groups together the given sparklines.
+/*
+ spls := termui.NewSparklines(spl0,spl1,spl2) //...
+ spls.Height = 2
+ spls.Width = 20
+*/
+type Sparklines struct {
+ Block
+ Lines []Sparkline
+ displayLines int
+ displayWidth int
+}
+
+var sparks = []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
+
+// Add appends a given Sparkline to s *Sparklines.
+func (s *Sparklines) Add(sl Sparkline) {
+ s.Lines = append(s.Lines, sl)
+}
+
+// NewSparkline returns a unrenderable single sparkline that intended to be added into Sparklines.
+func NewSparkline() Sparkline {
+ return Sparkline{
+ Height: 1,
+ TitleColor: theme.SparklineTitle,
+ LineColor: theme.SparklineLine}
+}
+
+// NewSparklines return a new *Spaklines with given Sparkline(s), you can always add a new Sparkline later.
+func NewSparklines(ss ...Sparkline) *Sparklines {
+ s := &Sparklines{Block: *NewBlock(), Lines: ss}
+ return s
+}
+
+func (sl *Sparklines) update() {
+ for i, v := range sl.Lines {
+ if v.Title == "" {
+ sl.Lines[i].displayHeight = v.Height
+ } else {
+ sl.Lines[i].displayHeight = v.Height + 1
+ }
+ }
+ sl.displayWidth = sl.innerWidth
+
+ // get how many lines gotta display
+ h := 0
+ sl.displayLines = 0
+ for _, v := range sl.Lines {
+ if h+v.displayHeight <= sl.innerHeight {
+ sl.displayLines++
+ } else {
+ break
+ }
+ h += v.displayHeight
+ }
+
+ for i := 0; i < sl.displayLines; i++ {
+ data := sl.Lines[i].Data
+
+ max := math.MinInt32
+ for _, v := range data {
+ if max < v {
+ max = v
+ }
+ }
+ sl.Lines[i].max = max
+ sl.Lines[i].scale = float32(8*sl.Lines[i].Height) / float32(max)
+ }
+}
+
+// Buffer implements Bufferer interface.
+func (sl *Sparklines) Buffer() []Point {
+ ps := sl.Block.Buffer()
+ sl.update()
+
+ oftY := 0
+ for i := 0; i < sl.displayLines; i++ {
+ l := sl.Lines[i]
+ data := l.Data
+
+ if len(data) > sl.innerWidth {
+ data = data[len(data)-sl.innerWidth:]
+ }
+
+ if l.Title != "" {
+ rs := trimStr2Runes(l.Title, sl.innerWidth)
+ oftX := 0
+ for _, v := range rs {
+ w := charWidth(v)
+ p := Point{}
+ p.Ch = v
+ p.Fg = l.TitleColor
+ p.Bg = sl.BgColor
+ p.X = sl.innerX + oftX
+ p.Y = sl.innerY + oftY
+ ps = append(ps, p)
+ oftX += w
+ }
+ }
+
+ for j, v := range data {
+ h := int(float32(v)*l.scale + 0.5)
+ barCnt := h / 8
+ barMod := h % 8
+ for jj := 0; jj < barCnt; jj++ {
+ p := Point{}
+ p.X = sl.innerX + j
+ p.Y = sl.innerY + oftY + l.Height - jj
+ p.Ch = ' ' // => sparks[7]
+ p.Bg = l.LineColor
+ //p.Bg = sl.BgColor
+ ps = append(ps, p)
+ }
+ if barMod != 0 {
+ p := Point{}
+ p.X = sl.innerX + j
+ p.Y = sl.innerY + oftY + l.Height - barCnt
+ p.Ch = sparks[barMod-1]
+ p.Fg = l.LineColor
+ p.Bg = sl.BgColor
+ ps = append(ps, p)
+ }
+ }
+
+ oftY += l.displayHeight
+ }
+
+ return sl.Block.chopOverflow(ps)
+}
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/theme.go b/Godeps/_workspace/src/github.com/gizak/termui/theme.go
new file mode 100644
index 000000000..c8ad94756
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/gizak/termui/theme.go
@@ -0,0 +1,84 @@
+// Copyright 2015 Zack Guo . All rights reserved.
+// Use of this source code is governed by a MIT license that can
+// be found in the LICENSE file.
+
+package termui
+
+// A ColorScheme represents the current look-and-feel of the dashboard.
+type ColorScheme struct {
+ BodyBg Attribute
+ BlockBg Attribute
+ HasBorder bool
+ BorderFg Attribute
+ BorderBg Attribute
+ BorderLabelTextFg Attribute
+ BorderLabelTextBg Attribute
+ ParTextFg Attribute
+ ParTextBg Attribute
+ SparklineLine Attribute
+ SparklineTitle Attribute
+ GaugeBar Attribute
+ GaugePercent Attribute
+ LineChartLine Attribute
+ LineChartAxes Attribute
+ ListItemFg Attribute
+ ListItemBg Attribute
+ BarChartBar Attribute
+ BarChartText Attribute
+ BarChartNum Attribute
+ MBarChartBar Attribute
+ MBarChartText Attribute
+ MBarChartNum Attribute
+}
+
+// default color scheme depends on the user's terminal setting.
+var themeDefault = ColorScheme{HasBorder: true}
+
+var themeHelloWorld = ColorScheme{
+ BodyBg: ColorBlack,
+ BlockBg: ColorBlack,
+ HasBorder: true,
+ BorderFg: ColorWhite,
+ BorderBg: ColorBlack,
+ BorderLabelTextBg: ColorBlack,
+ BorderLabelTextFg: ColorGreen,
+ ParTextBg: ColorBlack,
+ ParTextFg: ColorWhite,
+ SparklineLine: ColorMagenta,
+ SparklineTitle: ColorWhite,
+ GaugeBar: ColorRed,
+ GaugePercent: ColorWhite,
+ LineChartLine: ColorYellow | AttrBold,
+ LineChartAxes: ColorWhite,
+ ListItemBg: ColorBlack,
+ ListItemFg: ColorYellow,
+ BarChartBar: ColorRed,
+ BarChartNum: ColorWhite,
+ BarChartText: ColorCyan,
+ MBarChartBar: ColorRed,
+ MBarChartNum: ColorWhite,
+ MBarChartText: ColorCyan,
+}
+
+var theme = themeDefault // global dep
+
+// Theme returns the currently used theme.
+func Theme() ColorScheme {
+ return theme
+}
+
+// SetTheme sets a new, custom theme.
+func SetTheme(newTheme ColorScheme) {
+ theme = newTheme
+}
+
+// UseTheme sets a predefined scheme. Currently available: "hello-world" and
+// "black-and-white".
+func UseTheme(th string) {
+ switch th {
+ case "helloworld":
+ theme = themeHelloWorld
+ default:
+ theme = themeDefault
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore
new file mode 100644
index 000000000..836562412
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/.gitignore
@@ -0,0 +1,23 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE
new file mode 100644
index 000000000..be2cc4dfb
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/LICENSE
@@ -0,0 +1,362 @@
+Mozilla Public License, version 2.0
+
+1. Definitions
+
+1.1. "Contributor"
+
+ means each individual or legal entity that creates, contributes to the
+ creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+
+ means the combination of the Contributions of others (if any) used by a
+ Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+
+ means Source Code Form to which the initial Contributor has attached the
+ notice in Exhibit A, the Executable Form of such Source Code Form, and
+ Modifications of such Source Code Form, in each case including portions
+ thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ a. that the initial Contributor has attached the notice described in
+ Exhibit B to the Covered Software; or
+
+ b. that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the terms of
+ a Secondary License.
+
+1.6. "Executable Form"
+
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+
+ means a work that combines Covered Software with other material, in a
+ separate file or files, that is not Covered Software.
+
+1.8. "License"
+
+ means this document.
+
+1.9. "Licensable"
+
+ means having the right to grant, to the maximum extent possible, whether
+ at the time of the initial grant or subsequently, any and all of the
+ rights conveyed by this License.
+
+1.10. "Modifications"
+
+ means any of the following:
+
+ a. any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered Software; or
+
+ b. any new file in Source Code Form that contains any Covered Software.
+
+1.11. "Patent Claims" of a Contributor
+
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the License,
+ by the making, using, selling, offering for sale, having made, import,
+ or transfer of either its Contributions or its Contributor Version.
+
+1.12. "Secondary License"
+
+ means either the GNU General Public License, Version 2.0, the GNU Lesser
+ General Public License, Version 2.1, the GNU Affero General Public
+ License, Version 3.0, or any later versions of those licenses.
+
+1.13. "Source Code Form"
+
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that controls, is
+ controlled by, or is under common control with You. For purposes of this
+ definition, "control" means (a) the power, direct or indirect, to cause
+ the direction or management of such entity, whether by contract or
+ otherwise, or (b) ownership of more than fifty percent (50%) of the
+ outstanding shares or beneficial ownership of such entity.
+
+
+2. License Grants and Conditions
+
+2.1. Grants
+
+ Each Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ a. under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+ b. under Patent Claims of such Contributor to make, use, sell, offer for
+ sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+ The licenses granted in Section 2.1 with respect to any Contribution
+ become effective for each Contribution on the date the Contributor first
+ distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+ The licenses granted in this Section 2 are the only rights granted under
+ this License. No additional rights or licenses will be implied from the
+ distribution or licensing of Covered Software under this License.
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
+ Contributor:
+
+ a. for any code that a Contributor has removed from Covered Software; or
+
+ b. for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+ c. under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+ This License does not grant any rights in the trademarks, service marks,
+ or logos of any Contributor (except as may be necessary to comply with
+ the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+ No Contributor makes additional grants as a result of Your choice to
+ distribute the Covered Software under a subsequent version of this
+ License (see Section 10.2) or under the terms of a Secondary License (if
+ permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+ Each Contributor represents that the Contributor believes its
+ Contributions are its original creation(s) or it has sufficient rights to
+ grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+ This License is not intended to limit any rights You have under
+ applicable copyright doctrines of fair use, fair dealing, or other
+ equivalents.
+
+2.7. Conditions
+
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+ Section 2.1.
+
+
+3. Responsibilities
+
+3.1. Distribution of Source Form
+
+ All distribution of Covered Software in Source Code Form, including any
+ Modifications that You create or to which You contribute, must be under
+ the terms of this License. You must inform recipients that the Source
+ Code Form of the Covered Software is governed by the terms of this
+ License, and how they can obtain a copy of this License. You may not
+ attempt to alter or restrict the recipients' rights in the Source Code
+ Form.
+
+3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+ a. such Covered Software must also be made available in Source Code Form,
+ as described in Section 3.1, and You must inform recipients of the
+ Executable Form how they can obtain a copy of such Source Code Form by
+ reasonable means in a timely manner, at a charge no more than the cost
+ of distribution to the recipient; and
+
+ b. You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter the
+ recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+ You may create and distribute a Larger Work under terms of Your choice,
+ provided that You also comply with the requirements of this License for
+ the Covered Software. If the Larger Work is a combination of Covered
+ Software with a work governed by one or more Secondary Licenses, and the
+ Covered Software is not Incompatible With Secondary Licenses, this
+ License permits You to additionally distribute such Covered Software
+ under the terms of such Secondary License(s), so that the recipient of
+ the Larger Work may, at their option, further distribute the Covered
+ Software under the terms of either this License or such Secondary
+ License(s).
+
+3.4. Notices
+
+ You may not remove or alter the substance of any license notices
+ (including copyright notices, patent notices, disclaimers of warranty, or
+ limitations of liability) contained within the Source Code Form of the
+ Covered Software, except that You may alter any license notices to the
+ extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+ You may choose to offer, and to charge a fee for, warranty, support,
+ indemnity or liability obligations to one or more recipients of Covered
+ Software. However, You may do so only on Your own behalf, and not on
+ behalf of any Contributor. You must make it absolutely clear that any
+ such warranty, support, indemnity, or liability obligation is offered by
+ You alone, and You hereby agree to indemnify every Contributor for any
+ liability incurred by such Contributor as a result of warranty, support,
+ indemnity or liability terms You offer. You may include additional
+ disclaimers of warranty and limitations of liability specific to any
+ jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+
+ If it is impossible for You to comply with any of the terms of this License
+ with respect to some or all of the Covered Software due to statute,
+ judicial order, or regulation then You must: (a) comply with the terms of
+ this License to the maximum extent possible; and (b) describe the
+ limitations and the code they affect. Such description must be placed in a
+ text file included with all distributions of the Covered Software under
+ this License. Except to the extent prohibited by statute or regulation,
+ such description must be sufficiently detailed for a recipient of ordinary
+ skill to be able to understand it.
+
+5. Termination
+
+5.1. The rights granted under this License will terminate automatically if You
+ fail to comply with any of its terms. However, if You become compliant,
+ then the rights granted under this License from a particular Contributor
+ are reinstated (a) provisionally, unless and until such Contributor
+ explicitly and finally terminates Your grants, and (b) on an ongoing
+ basis, if such Contributor fails to notify You of the non-compliance by
+ some reasonable means prior to 60 days after You have come back into
+ compliance. Moreover, Your grants from a particular Contributor are
+ reinstated on an ongoing basis if such Contributor notifies You of the
+ non-compliance by some reasonable means, this is the first time You have
+ received notice of non-compliance with this License from such
+ Contributor, and You become compliant prior to 30 days after Your receipt
+ of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+ infringement claim (excluding declaratory judgment actions,
+ counter-claims, and cross-claims) alleging that a Contributor Version
+ directly or indirectly infringes any patent, then the rights granted to
+ You by any and all Contributors for the Covered Software under Section
+ 2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
+ license agreements (excluding distributors and resellers) which have been
+ validly granted by You or Your distributors under this License prior to
+ termination shall survive termination.
+
+6. Disclaimer of Warranty
+
+ Covered Software is provided under this License on an "as is" basis,
+ without warranty of any kind, either expressed, implied, or statutory,
+ including, without limitation, warranties that the Covered Software is free
+ of defects, merchantable, fit for a particular purpose or non-infringing.
+ The entire risk as to the quality and performance of the Covered Software
+ is with You. Should any Covered Software prove defective in any respect,
+ You (not any Contributor) assume the cost of any necessary servicing,
+ repair, or correction. This disclaimer of warranty constitutes an essential
+ part of this License. No use of any Covered Software is authorized under
+ this License except under this disclaimer.
+
+7. Limitation of Liability
+
+ Under no circumstances and under no legal theory, whether tort (including
+ negligence), contract, or otherwise, shall any Contributor, or anyone who
+ distributes Covered Software as permitted above, be liable to You for any
+ direct, indirect, special, incidental, or consequential damages of any
+ character including, without limitation, damages for lost profits, loss of
+ goodwill, work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses, even if such party shall have been
+ informed of the possibility of such damages. This limitation of liability
+ shall not apply to liability for death or personal injury resulting from
+ such party's negligence to the extent applicable law prohibits such
+ limitation. Some jurisdictions do not allow the exclusion or limitation of
+ incidental or consequential damages, so this exclusion and limitation may
+ not apply to You.
+
+8. Litigation
+
+ Any litigation relating to this License may be brought only in the courts
+ of a jurisdiction where the defendant maintains its principal place of
+ business and such litigation shall be governed by laws of that
+ jurisdiction, without reference to its conflict-of-law provisions. Nothing
+ in this Section shall prevent a party's ability to bring cross-claims or
+ counter-claims.
+
+9. Miscellaneous
+
+ This License represents the complete agreement concerning the subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. Any law or regulation which provides that
+ the language of a contract shall be construed against the drafter shall not
+ be used to construe this License against a Contributor.
+
+
+10. Versions of the License
+
+10.1. New Versions
+
+ Mozilla Foundation is the license steward. Except as provided in Section
+ 10.3, no one other than the license steward has the right to modify or
+ publish new versions of this License. Each version will be given a
+ distinguishing version number.
+
+10.2. Effect of New Versions
+
+ You may distribute the Covered Software under the terms of the version
+ of the License under which You originally received the Covered Software,
+ or under the terms of any subsequent version published by the license
+ steward.
+
+10.3. Modified Versions
+
+ If you create software not governed by this License, and you want to
+ create a new license for such software, you may create and use a
+ modified version of this License if you rename the license and remove
+ any references to the name of the license steward (except to note that
+ such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+ Licenses If You choose to distribute Source Code Form that is
+ Incompatible With Secondary Licenses under the terms of this version of
+ the License, the notice described in Exhibit B of this License must be
+ attached.
+
+Exhibit A - Source Code Form License Notice
+
+ This Source Code Form is subject to the
+ terms of the Mozilla Public License, v.
+ 2.0. If a copy of the MPL was not
+ distributed with this file, You can
+ obtain one at
+ http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file,
+then You may include the notice in a location (such as a LICENSE file in a
+relevant directory) where a recipient would be likely to look for such a
+notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+
+ This Source Code Form is "Incompatible
+ With Secondary Licenses", as defined by
+ the Mozilla Public License, v. 2.0.
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md
new file mode 100644
index 000000000..33e58cfaf
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/README.md
@@ -0,0 +1,25 @@
+golang-lru
+==========
+
+This provides the `lru` package which implements a fixed-size
+thread safe LRU cache. It is based on the cache in Groupcache.
+
+Documentation
+=============
+
+Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru)
+
+Example
+=======
+
+Using the LRU is very simple:
+
+```go
+l, _ := New(128)
+for i := 0; i < 256; i++ {
+ l.Add(i, nil)
+}
+if l.Len() != 128 {
+ panic(fmt.Sprintf("bad len: %v", l.Len()))
+}
+```
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go
new file mode 100644
index 000000000..5f1e8a1af
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru.go
@@ -0,0 +1,175 @@
+// This package provides a simple LRU cache. It is based on the
+// LRU implementation in groupcache:
+// https://github.com/golang/groupcache/tree/master/lru
+package lru
+
+import (
+ "container/list"
+ "errors"
+ "sync"
+)
+
+// Cache is a thread-safe fixed size LRU cache.
+type Cache struct {
+ size int
+ evictList *list.List
+ items map[interface{}]*list.Element
+ lock sync.RWMutex
+ onEvicted func(key interface{}, value interface{})
+}
+
+// entry is used to hold a value in the evictList
+type entry struct {
+ key interface{}
+ value interface{}
+}
+
+// New creates an LRU of the given size
+func New(size int) (*Cache, error) {
+ return NewWithEvict(size, nil)
+}
+
+func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
+ if size <= 0 {
+ return nil, errors.New("Must provide a positive size")
+ }
+ c := &Cache{
+ size: size,
+ evictList: list.New(),
+ items: make(map[interface{}]*list.Element, size),
+ onEvicted: onEvicted,
+ }
+ return c, nil
+}
+
+// Purge is used to completely clear the cache
+func (c *Cache) Purge() {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if c.onEvicted != nil {
+ for k, v := range c.items {
+ c.onEvicted(k, v.Value.(*entry).value)
+ }
+ }
+
+ c.evictList = list.New()
+ c.items = make(map[interface{}]*list.Element, c.size)
+}
+
+// Add adds a value to the cache. Returns true if an eviction occured.
+func (c *Cache) Add(key, value interface{}) bool {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ // Check for existing item
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ ent.Value.(*entry).value = value
+ return false
+ }
+
+ // Add new item
+ ent := &entry{key, value}
+ entry := c.evictList.PushFront(ent)
+ c.items[key] = entry
+
+ evict := c.evictList.Len() > c.size
+ // Verify size not exceeded
+ if evict {
+ c.removeOldest()
+ }
+ return evict
+}
+
+// Get looks up a key's value from the cache.
+func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if ent, ok := c.items[key]; ok {
+ c.evictList.MoveToFront(ent)
+ return ent.Value.(*entry).value, true
+ }
+ return
+}
+
+// Check if a key is in the cache, without updating the recent-ness or deleting it for being stale.
+func (c *Cache) Contains(key interface{}) (ok bool) {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+
+ _, ok = c.items[key]
+ return ok
+}
+
+// Returns the key value (or undefined if not found) without updating the "recently used"-ness of the key.
+// (If you find yourself using this a lot, you might be using the wrong sort of data structure, but there are some use cases where it's handy.)
+func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+
+ if ent, ok := c.items[key]; ok {
+ return ent.Value.(*entry).value, true
+ }
+ return nil, ok
+}
+
+// Remove removes the provided key from the cache.
+func (c *Cache) Remove(key interface{}) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if ent, ok := c.items[key]; ok {
+ c.removeElement(ent)
+ }
+}
+
+// RemoveOldest removes the oldest item from the cache.
+func (c *Cache) RemoveOldest() {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ c.removeOldest()
+}
+
+// Keys returns a slice of the keys in the cache, from oldest to newest.
+func (c *Cache) Keys() []interface{} {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+
+ keys := make([]interface{}, len(c.items))
+ ent := c.evictList.Back()
+ i := 0
+ for ent != nil {
+ keys[i] = ent.Value.(*entry).key
+ ent = ent.Prev()
+ i++
+ }
+
+ return keys
+}
+
+// Len returns the number of items in the cache.
+func (c *Cache) Len() int {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.evictList.Len()
+}
+
+// removeOldest removes the oldest item from the cache.
+func (c *Cache) removeOldest() {
+ ent := c.evictList.Back()
+ if ent != nil {
+ c.removeElement(ent)
+ }
+}
+
+// removeElement is used to remove a given list element from the cache
+func (c *Cache) removeElement(e *list.Element) {
+ c.evictList.Remove(e)
+ kv := e.Value.(*entry)
+ delete(c.items, kv.key)
+ if c.onEvicted != nil {
+ c.onEvicted(kv.key, kv.value)
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go
new file mode 100644
index 000000000..b676cfd9d
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/hashicorp/golang-lru/lru_test.go
@@ -0,0 +1,127 @@
+package lru
+
+import "testing"
+
+func TestLRU(t *testing.T) {
+ evictCounter := 0
+ onEvicted := func(k interface{}, v interface{}) {
+ if k != v {
+ t.Fatalf("Evict values not equal (%v!=%v)", k, v)
+ }
+ evictCounter += 1
+ }
+ l, err := NewWithEvict(128, onEvicted)
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ for i := 0; i < 256; i++ {
+ l.Add(i, i)
+ }
+ if l.Len() != 128 {
+ t.Fatalf("bad len: %v", l.Len())
+ }
+
+ if evictCounter != 128 {
+ t.Fatalf("bad evict count: %v", evictCounter)
+ }
+
+ for i, k := range l.Keys() {
+ if v, ok := l.Get(k); !ok || v != k || v != i+128 {
+ t.Fatalf("bad key: %v", k)
+ }
+ }
+ for i := 0; i < 128; i++ {
+ _, ok := l.Get(i)
+ if ok {
+ t.Fatalf("should be evicted")
+ }
+ }
+ for i := 128; i < 256; i++ {
+ _, ok := l.Get(i)
+ if !ok {
+ t.Fatalf("should not be evicted")
+ }
+ }
+ for i := 128; i < 192; i++ {
+ l.Remove(i)
+ _, ok := l.Get(i)
+ if ok {
+ t.Fatalf("should be deleted")
+ }
+ }
+
+ l.Get(192) // expect 192 to be last key in l.Keys()
+
+ for i, k := range l.Keys() {
+ if (i < 63 && k != i+193) || (i == 63 && k != 192) {
+ t.Fatalf("out of order key: %v", k)
+ }
+ }
+
+ l.Purge()
+ if l.Len() != 0 {
+ t.Fatalf("bad len: %v", l.Len())
+ }
+ if _, ok := l.Get(200); ok {
+ t.Fatalf("should contain nothing")
+ }
+}
+
+// test that Add returns true/false if an eviction occured
+func TestLRUAdd(t *testing.T) {
+ evictCounter := 0
+ onEvicted := func(k interface{}, v interface{}) {
+ evictCounter += 1
+ }
+
+ l, err := NewWithEvict(1, onEvicted)
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ if l.Add(1, 1) == true || evictCounter != 0 {
+ t.Errorf("should not have an eviction")
+ }
+ if l.Add(2, 2) == false || evictCounter != 1 {
+ t.Errorf("should have an eviction")
+ }
+}
+
+// test that Contains doesn't update recent-ness
+func TestLRUContains(t *testing.T) {
+ l, err := New(2)
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ l.Add(1, 1)
+ l.Add(2, 2)
+ if !l.Contains(1) {
+ t.Errorf("1 should be contained")
+ }
+
+ l.Add(3, 3)
+ if l.Contains(1) {
+ t.Errorf("Contains should not have updated recent-ness of 1")
+ }
+}
+
+// test that Peek doesn't update recent-ness
+func TestLRUPeek(t *testing.T) {
+ l, err := New(2)
+ if err != nil {
+ t.Fatalf("err: %v", err)
+ }
+
+ l.Add(1, 1)
+ l.Add(2, 2)
+ if v, ok := l.Peek(1); !ok || v != 1 {
+ t.Errorf("1 should be set to 1: %v, %v", v, ok)
+ }
+
+ l.Add(3, 3)
+ if l.Contains(1) {
+ t.Errorf("should not have updated recent-ness of 1")
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/.gitignore b/Godeps/_workspace/src/github.com/howeyc/fsnotify/.gitignore
deleted file mode 100644
index e4706a9e9..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Setup a Global .gitignore for OS and editor generated files:
-# https://help.github.com/articles/ignoring-files
-# git config --global core.excludesfile ~/.gitignore_global
-
-.vagrant
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/AUTHORS b/Godeps/_workspace/src/github.com/howeyc/fsnotify/AUTHORS
deleted file mode 100644
index e52b72f83..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/AUTHORS
+++ /dev/null
@@ -1,28 +0,0 @@
-# Names should be added to this file as
-# Name or Organization
-# The email address is not required for organizations.
-
-# You can update this list using the following command:
-#
-# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
-
-# Please keep the list sorted.
-
-Adrien Bustany
-Caleb Spare
-Case Nelson
-Chris Howey
-Christoffer Buchholz
-Dave Cheney
-Francisco Souza
-John C Barstow
-Kelvin Fo
-Nathan Youngman
-Paul Hammond
-Pursuit92
-Rob Figueiredo
-Travis Cline
-Tudor Golubenco
-bronze1man
-debrando
-henrikedwards
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/CHANGELOG.md b/Godeps/_workspace/src/github.com/howeyc/fsnotify/CHANGELOG.md
deleted file mode 100644
index 761686aa9..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/CHANGELOG.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# Changelog
-
-## v0.9.0 / 2014-01-17
-
-* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
-* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
-* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
-
-## v0.8.12 / 2013-11-13
-
-* [API] Remove FD_SET and friends from Linux adapter
-
-## v0.8.11 / 2013-11-02
-
-* [Doc] Add Changelog [#72][] (thanks @nathany)
-* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond)
-
-## v0.8.10 / 2013-10-19
-
-* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
-* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
-* [Doc] specify OS-specific limits in README (thanks @debrando)
-
-## v0.8.9 / 2013-09-08
-
-* [Doc] Contributing (thanks @nathany)
-* [Doc] update package path in example code [#63][] (thanks @paulhammond)
-* [Doc] GoCI badge in README (Linux only) [#60][]
-* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
-
-## v0.8.8 / 2013-06-17
-
-* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
-
-## v0.8.7 / 2013-06-03
-
-* [API] Make syscall flags internal
-* [Fix] inotify: ignore event changes
-* [Fix] race in symlink test [#45][] (reported by @srid)
-* [Fix] tests on Windows
-* lower case error messages
-
-## v0.8.6 / 2013-05-23
-
-* kqueue: Use EVT_ONLY flag on Darwin
-* [Doc] Update README with full example
-
-## v0.8.5 / 2013-05-09
-
-* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
-
-## v0.8.4 / 2013-04-07
-
-* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
-
-## v0.8.3 / 2013-03-13
-
-* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
-* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
-
-## v0.8.2 / 2013-02-07
-
-* [Doc] add Authors
-* [Fix] fix data races for map access [#29][] (thanks @fsouza)
-
-## v0.8.1 / 2013-01-09
-
-* [Fix] Windows path separators
-* [Doc] BSD License
-
-## v0.8.0 / 2012-11-09
-
-* kqueue: directory watching improvements (thanks @vmirage)
-* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
-* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
-
-## v0.7.4 / 2012-10-09
-
-* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
-* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
-* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
-* [Fix] kqueue: modify after recreation of file
-
-## v0.7.3 / 2012-09-27
-
-* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
-* [Fix] kqueue: no longer get duplicate CREATE events
-
-## v0.7.2 / 2012-09-01
-
-* kqueue: events for created directories
-
-## v0.7.1 / 2012-07-14
-
-* [Fix] for renaming files
-
-## v0.7.0 / 2012-07-02
-
-* [Feature] FSNotify flags
-* [Fix] inotify: Added file name back to event path
-
-## v0.6.0 / 2012-06-06
-
-* kqueue: watch files after directory created (thanks @tmc)
-
-## v0.5.1 / 2012-05-22
-
-* [Fix] inotify: remove all watches before Close()
-
-## v0.5.0 / 2012-05-03
-
-* [API] kqueue: return errors during watch instead of sending over channel
-* kqueue: match symlink behavior on Linux
-* inotify: add `DELETE_SELF` (requested by @taralx)
-* [Fix] kqueue: handle EINTR (reported by @robfig)
-* [Doc] Godoc example [#1][] (thanks @davecheney)
-
-## v0.4.0 / 2012-03-30
-
-* Go 1 released: build with go tool
-* [Feature] Windows support using winfsnotify
-* Windows does not have attribute change notifications
-* Roll attribute notifications into IsModify
-
-## v0.3.0 / 2012-02-19
-
-* kqueue: add files when watch directory
-
-## v0.2.0 / 2011-12-30
-
-* update to latest Go weekly code
-
-## v0.1.0 / 2011-10-19
-
-* kqueue: add watch on file creation to match inotify
-* kqueue: create file event
-* inotify: ignore `IN_IGNORED` events
-* event String()
-* linux: common FileEvent functions
-* initial commit
-
-[#79]: https://github.com/howeyc/fsnotify/pull/79
-[#77]: https://github.com/howeyc/fsnotify/pull/77
-[#72]: https://github.com/howeyc/fsnotify/issues/72
-[#71]: https://github.com/howeyc/fsnotify/issues/71
-[#70]: https://github.com/howeyc/fsnotify/issues/70
-[#63]: https://github.com/howeyc/fsnotify/issues/63
-[#62]: https://github.com/howeyc/fsnotify/issues/62
-[#60]: https://github.com/howeyc/fsnotify/issues/60
-[#59]: https://github.com/howeyc/fsnotify/issues/59
-[#49]: https://github.com/howeyc/fsnotify/issues/49
-[#45]: https://github.com/howeyc/fsnotify/issues/45
-[#40]: https://github.com/howeyc/fsnotify/issues/40
-[#36]: https://github.com/howeyc/fsnotify/issues/36
-[#33]: https://github.com/howeyc/fsnotify/issues/33
-[#29]: https://github.com/howeyc/fsnotify/issues/29
-[#25]: https://github.com/howeyc/fsnotify/issues/25
-[#24]: https://github.com/howeyc/fsnotify/issues/24
-[#21]: https://github.com/howeyc/fsnotify/issues/21
-[#1]: https://github.com/howeyc/fsnotify/issues/1
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/CONTRIBUTING.md b/Godeps/_workspace/src/github.com/howeyc/fsnotify/CONTRIBUTING.md
deleted file mode 100644
index b2025d72c..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/CONTRIBUTING.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Contributing
-
-## Moving Notice
-
-There is a fork being actively developed with a new API in preparation for the Go Standard Library:
-[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify)
-
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/LICENSE b/Godeps/_workspace/src/github.com/howeyc/fsnotify/LICENSE
deleted file mode 100644
index f21e54080..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright (c) 2012 The Go Authors. All rights reserved.
-Copyright (c) 2012 fsnotify 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 Google Inc. 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.
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/README.md b/Godeps/_workspace/src/github.com/howeyc/fsnotify/README.md
deleted file mode 100644
index 4c7498d38..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/README.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# File system notifications for Go
-
-[![GoDoc](https://godoc.org/github.com/howeyc/fsnotify?status.png)](http://godoc.org/github.com/howeyc/fsnotify)
-
-Cross platform: Windows, Linux, BSD and OS X.
-
-## Moving Notice
-
-There is a fork being actively developed with a new API in preparation for the Go Standard Library:
-[github.com/go-fsnotify/fsnotify](https://github.com/go-fsnotify/fsnotify)
-
-## Example:
-
-```go
-package main
-
-import (
- "log"
-
- "github.com/howeyc/fsnotify"
-)
-
-func main() {
- watcher, err := fsnotify.NewWatcher()
- if err != nil {
- log.Fatal(err)
- }
-
- done := make(chan bool)
-
- // Process events
- go func() {
- for {
- select {
- case ev := <-watcher.Event:
- log.Println("event:", ev)
- case err := <-watcher.Error:
- log.Println("error:", err)
- }
- }
- }()
-
- err = watcher.Watch("testDir")
- if err != nil {
- log.Fatal(err)
- }
-
- <-done
-
- /* ... do stuff ... */
- watcher.Close()
-}
-```
-
-For each event:
-* Name
-* IsCreate()
-* IsDelete()
-* IsModify()
-* IsRename()
-
-## FAQ
-
-**When a file is moved to another directory is it still being watched?**
-
-No (it shouldn't be, unless you are watching where it was moved to).
-
-**When I watch a directory, are all subdirectories watched as well?**
-
-No, you must add watches for any directory you want to watch (a recursive watcher is in the works [#56][]).
-
-**Do I have to watch the Error and Event channels in a separate goroutine?**
-
-As of now, yes. Looking into making this single-thread friendly (see [#7][])
-
-**Why am I receiving multiple events for the same file on OS X?**
-
-Spotlight indexing on OS X can result in multiple events (see [#62][]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#54][]).
-
-**How many files can be watched at once?**
-
-There are OS-specific limits as to how many watches can be created:
-* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit,
-reaching this limit results in a "no space left on device" error.
-* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
-
-
-[#62]: https://github.com/howeyc/fsnotify/issues/62
-[#56]: https://github.com/howeyc/fsnotify/issues/56
-[#54]: https://github.com/howeyc/fsnotify/issues/54
-[#7]: https://github.com/howeyc/fsnotify/issues/7
-
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/example_test.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/example_test.go
deleted file mode 100644
index d3130e222..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/example_test.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2012 The Go 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 fsnotify_test
-
-import (
- "log"
-
- "github.com/howeyc/fsnotify"
-)
-
-func ExampleNewWatcher() {
- watcher, err := fsnotify.NewWatcher()
- if err != nil {
- log.Fatal(err)
- }
-
- go func() {
- for {
- select {
- case ev := <-watcher.Event:
- log.Println("event:", ev)
- case err := <-watcher.Error:
- log.Println("error:", err)
- }
- }
- }()
-
- err = watcher.Watch("/tmp/foo")
- if err != nil {
- log.Fatal(err)
- }
-}
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify.go
deleted file mode 100644
index 9a48d847d..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2012 The Go 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 fsnotify implements file system notification.
-package fsnotify
-
-import "fmt"
-
-const (
- FSN_CREATE = 1
- FSN_MODIFY = 2
- FSN_DELETE = 4
- FSN_RENAME = 8
-
- FSN_ALL = FSN_MODIFY | FSN_DELETE | FSN_RENAME | FSN_CREATE
-)
-
-// Purge events from interal chan to external chan if passes filter
-func (w *Watcher) purgeEvents() {
- for ev := range w.internalEvent {
- sendEvent := false
- w.fsnmut.Lock()
- fsnFlags := w.fsnFlags[ev.Name]
- w.fsnmut.Unlock()
-
- if (fsnFlags&FSN_CREATE == FSN_CREATE) && ev.IsCreate() {
- sendEvent = true
- }
-
- if (fsnFlags&FSN_MODIFY == FSN_MODIFY) && ev.IsModify() {
- sendEvent = true
- }
-
- if (fsnFlags&FSN_DELETE == FSN_DELETE) && ev.IsDelete() {
- sendEvent = true
- }
-
- if (fsnFlags&FSN_RENAME == FSN_RENAME) && ev.IsRename() {
- sendEvent = true
- }
-
- if sendEvent {
- w.Event <- ev
- }
-
- // If there's no file, then no more events for user
- // BSD must keep watch for internal use (watches DELETEs to keep track
- // what files exist for create events)
- if ev.IsDelete() {
- w.fsnmut.Lock()
- delete(w.fsnFlags, ev.Name)
- w.fsnmut.Unlock()
- }
- }
-
- close(w.Event)
-}
-
-// Watch a given file path
-func (w *Watcher) Watch(path string) error {
- return w.WatchFlags(path, FSN_ALL)
-}
-
-// Watch a given file path for a particular set of notifications (FSN_MODIFY etc.)
-func (w *Watcher) WatchFlags(path string, flags uint32) error {
- w.fsnmut.Lock()
- w.fsnFlags[path] = flags
- w.fsnmut.Unlock()
- return w.watch(path)
-}
-
-// Remove a watch on a file
-func (w *Watcher) RemoveWatch(path string) error {
- w.fsnmut.Lock()
- delete(w.fsnFlags, path)
- w.fsnmut.Unlock()
- return w.removeWatch(path)
-}
-
-// String formats the event e in the form
-// "filename: DELETE|MODIFY|..."
-func (e *FileEvent) String() string {
- var events string = ""
-
- if e.IsCreate() {
- events += "|" + "CREATE"
- }
-
- if e.IsDelete() {
- events += "|" + "DELETE"
- }
-
- if e.IsModify() {
- events += "|" + "MODIFY"
- }
-
- if e.IsRename() {
- events += "|" + "RENAME"
- }
-
- if e.IsAttrib() {
- events += "|" + "ATTRIB"
- }
-
- if len(events) > 0 {
- events = events[1:]
- }
-
- return fmt.Sprintf("%q: %s", e.Name, events)
-}
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_bsd.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_bsd.go
deleted file mode 100644
index e6ffd7e5b..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_bsd.go
+++ /dev/null
@@ -1,496 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build freebsd openbsd netbsd darwin
-
-package fsnotify
-
-import (
- "errors"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "sync"
- "syscall"
-)
-
-const (
- // Flags (from )
- sys_NOTE_DELETE = 0x0001 /* vnode was removed */
- sys_NOTE_WRITE = 0x0002 /* data contents changed */
- sys_NOTE_EXTEND = 0x0004 /* size increased */
- sys_NOTE_ATTRIB = 0x0008 /* attributes changed */
- sys_NOTE_LINK = 0x0010 /* link count changed */
- sys_NOTE_RENAME = 0x0020 /* vnode was renamed */
- sys_NOTE_REVOKE = 0x0040 /* vnode access was revoked */
-
- // Watch all events
- sys_NOTE_ALLEVENTS = sys_NOTE_DELETE | sys_NOTE_WRITE | sys_NOTE_ATTRIB | sys_NOTE_RENAME
-
- // Block for 100 ms on each call to kevent
- keventWaitTime = 100e6
-)
-
-type FileEvent struct {
- mask uint32 // Mask of events
- Name string // File name (optional)
- create bool // set by fsnotify package if found new file
-}
-
-// IsCreate reports whether the FileEvent was triggered by a creation
-func (e *FileEvent) IsCreate() bool { return e.create }
-
-// IsDelete reports whether the FileEvent was triggered by a delete
-func (e *FileEvent) IsDelete() bool { return (e.mask & sys_NOTE_DELETE) == sys_NOTE_DELETE }
-
-// IsModify reports whether the FileEvent was triggered by a file modification
-func (e *FileEvent) IsModify() bool {
- return ((e.mask&sys_NOTE_WRITE) == sys_NOTE_WRITE || (e.mask&sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB)
-}
-
-// IsRename reports whether the FileEvent was triggered by a change name
-func (e *FileEvent) IsRename() bool { return (e.mask & sys_NOTE_RENAME) == sys_NOTE_RENAME }
-
-// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata.
-func (e *FileEvent) IsAttrib() bool {
- return (e.mask & sys_NOTE_ATTRIB) == sys_NOTE_ATTRIB
-}
-
-type Watcher struct {
- mu sync.Mutex // Mutex for the Watcher itself.
- kq int // File descriptor (as returned by the kqueue() syscall)
- watches map[string]int // Map of watched file descriptors (key: path)
- wmut sync.Mutex // Protects access to watches.
- fsnFlags map[string]uint32 // Map of watched files to flags used for filter
- fsnmut sync.Mutex // Protects access to fsnFlags.
- enFlags map[string]uint32 // Map of watched files to evfilt note flags used in kqueue
- enmut sync.Mutex // Protects access to enFlags.
- paths map[int]string // Map of watched paths (key: watch descriptor)
- finfo map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor)
- pmut sync.Mutex // Protects access to paths and finfo.
- fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events)
- femut sync.Mutex // Protects access to fileExists.
- externalWatches map[string]bool // Map of watches added by user of the library.
- ewmut sync.Mutex // Protects access to externalWatches.
- Error chan error // Errors are sent on this channel
- internalEvent chan *FileEvent // Events are queued on this channel
- Event chan *FileEvent // Events are returned on this channel
- done chan bool // Channel for sending a "quit message" to the reader goroutine
- isClosed bool // Set to true when Close() is first called
-}
-
-// NewWatcher creates and returns a new kevent instance using kqueue(2)
-func NewWatcher() (*Watcher, error) {
- fd, errno := syscall.Kqueue()
- if fd == -1 {
- return nil, os.NewSyscallError("kqueue", errno)
- }
- w := &Watcher{
- kq: fd,
- watches: make(map[string]int),
- fsnFlags: make(map[string]uint32),
- enFlags: make(map[string]uint32),
- paths: make(map[int]string),
- finfo: make(map[int]os.FileInfo),
- fileExists: make(map[string]bool),
- externalWatches: make(map[string]bool),
- internalEvent: make(chan *FileEvent),
- Event: make(chan *FileEvent),
- Error: make(chan error),
- done: make(chan bool, 1),
- }
-
- go w.readEvents()
- go w.purgeEvents()
- return w, nil
-}
-
-// Close closes a kevent watcher instance
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the kevent instance
-func (w *Watcher) Close() error {
- w.mu.Lock()
- if w.isClosed {
- w.mu.Unlock()
- return nil
- }
- w.isClosed = true
- w.mu.Unlock()
-
- // Send "quit" message to the reader goroutine
- w.done <- true
- w.wmut.Lock()
- ws := w.watches
- w.wmut.Unlock()
- for path := range ws {
- w.removeWatch(path)
- }
-
- return nil
-}
-
-// AddWatch adds path to the watched file set.
-// The flags are interpreted as described in kevent(2).
-func (w *Watcher) addWatch(path string, flags uint32) error {
- w.mu.Lock()
- if w.isClosed {
- w.mu.Unlock()
- return errors.New("kevent instance already closed")
- }
- w.mu.Unlock()
-
- watchDir := false
-
- w.wmut.Lock()
- watchfd, found := w.watches[path]
- w.wmut.Unlock()
- if !found {
- fi, errstat := os.Lstat(path)
- if errstat != nil {
- return errstat
- }
-
- // don't watch socket
- if fi.Mode()&os.ModeSocket == os.ModeSocket {
- return nil
- }
-
- // Follow Symlinks
- // Unfortunately, Linux can add bogus symlinks to watch list without
- // issue, and Windows can't do symlinks period (AFAIK). To maintain
- // consistency, we will act like everything is fine. There will simply
- // be no file events for broken symlinks.
- // Hence the returns of nil on errors.
- if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
- path, err := filepath.EvalSymlinks(path)
- if err != nil {
- return nil
- }
-
- fi, errstat = os.Lstat(path)
- if errstat != nil {
- return nil
- }
- }
-
- fd, errno := syscall.Open(path, open_FLAGS, 0700)
- if fd == -1 {
- return errno
- }
- watchfd = fd
-
- w.wmut.Lock()
- w.watches[path] = watchfd
- w.wmut.Unlock()
-
- w.pmut.Lock()
- w.paths[watchfd] = path
- w.finfo[watchfd] = fi
- w.pmut.Unlock()
- }
- // Watch the directory if it has not been watched before.
- w.pmut.Lock()
- w.enmut.Lock()
- if w.finfo[watchfd].IsDir() &&
- (flags&sys_NOTE_WRITE) == sys_NOTE_WRITE &&
- (!found || (w.enFlags[path]&sys_NOTE_WRITE) != sys_NOTE_WRITE) {
- watchDir = true
- }
- w.enmut.Unlock()
- w.pmut.Unlock()
-
- w.enmut.Lock()
- w.enFlags[path] = flags
- w.enmut.Unlock()
-
- var kbuf [1]syscall.Kevent_t
- watchEntry := &kbuf[0]
- watchEntry.Fflags = flags
- syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_ADD|syscall.EV_CLEAR)
- entryFlags := watchEntry.Flags
- success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil)
- if success == -1 {
- return errno
- } else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
- return errors.New("kevent add error")
- }
-
- if watchDir {
- errdir := w.watchDirectoryFiles(path)
- if errdir != nil {
- return errdir
- }
- }
- return nil
-}
-
-// Watch adds path to the watched file set, watching all events.
-func (w *Watcher) watch(path string) error {
- w.ewmut.Lock()
- w.externalWatches[path] = true
- w.ewmut.Unlock()
- return w.addWatch(path, sys_NOTE_ALLEVENTS)
-}
-
-// RemoveWatch removes path from the watched file set.
-func (w *Watcher) removeWatch(path string) error {
- w.wmut.Lock()
- watchfd, ok := w.watches[path]
- w.wmut.Unlock()
- if !ok {
- return errors.New(fmt.Sprintf("can't remove non-existent kevent watch for: %s", path))
- }
- var kbuf [1]syscall.Kevent_t
- watchEntry := &kbuf[0]
- syscall.SetKevent(watchEntry, watchfd, syscall.EVFILT_VNODE, syscall.EV_DELETE)
- entryFlags := watchEntry.Flags
- success, errno := syscall.Kevent(w.kq, kbuf[:], nil, nil)
- if success == -1 {
- return os.NewSyscallError("kevent_rm_watch", errno)
- } else if (entryFlags & syscall.EV_ERROR) == syscall.EV_ERROR {
- return errors.New("kevent rm error")
- }
- syscall.Close(watchfd)
- w.wmut.Lock()
- delete(w.watches, path)
- w.wmut.Unlock()
- w.enmut.Lock()
- delete(w.enFlags, path)
- w.enmut.Unlock()
- w.pmut.Lock()
- delete(w.paths, watchfd)
- fInfo := w.finfo[watchfd]
- delete(w.finfo, watchfd)
- w.pmut.Unlock()
-
- // Find all watched paths that are in this directory that are not external.
- if fInfo.IsDir() {
- var pathsToRemove []string
- w.pmut.Lock()
- for _, wpath := range w.paths {
- wdir, _ := filepath.Split(wpath)
- if filepath.Clean(wdir) == filepath.Clean(path) {
- w.ewmut.Lock()
- if !w.externalWatches[wpath] {
- pathsToRemove = append(pathsToRemove, wpath)
- }
- w.ewmut.Unlock()
- }
- }
- w.pmut.Unlock()
- for _, p := range pathsToRemove {
- // Since these are internal, not much sense in propagating error
- // to the user, as that will just confuse them with an error about
- // a path they did not explicitly watch themselves.
- w.removeWatch(p)
- }
- }
-
- return nil
-}
-
-// readEvents reads from the kqueue file descriptor, converts the
-// received events into Event objects and sends them via the Event channel
-func (w *Watcher) readEvents() {
- var (
- eventbuf [10]syscall.Kevent_t // Event buffer
- events []syscall.Kevent_t // Received events
- twait *syscall.Timespec // Time to block waiting for events
- n int // Number of events returned from kevent
- errno error // Syscall errno
- )
- events = eventbuf[0:0]
- twait = new(syscall.Timespec)
- *twait = syscall.NsecToTimespec(keventWaitTime)
-
- for {
- // See if there is a message on the "done" channel
- var done bool
- select {
- case done = <-w.done:
- default:
- }
-
- // If "done" message is received
- if done {
- errno := syscall.Close(w.kq)
- if errno != nil {
- w.Error <- os.NewSyscallError("close", errno)
- }
- close(w.internalEvent)
- close(w.Error)
- return
- }
-
- // Get new events
- if len(events) == 0 {
- n, errno = syscall.Kevent(w.kq, nil, eventbuf[:], twait)
-
- // EINTR is okay, basically the syscall was interrupted before
- // timeout expired.
- if errno != nil && errno != syscall.EINTR {
- w.Error <- os.NewSyscallError("kevent", errno)
- continue
- }
-
- // Received some events
- if n > 0 {
- events = eventbuf[0:n]
- }
- }
-
- // Flush the events we received to the events channel
- for len(events) > 0 {
- fileEvent := new(FileEvent)
- watchEvent := &events[0]
- fileEvent.mask = uint32(watchEvent.Fflags)
- w.pmut.Lock()
- fileEvent.Name = w.paths[int(watchEvent.Ident)]
- fileInfo := w.finfo[int(watchEvent.Ident)]
- w.pmut.Unlock()
- if fileInfo != nil && fileInfo.IsDir() && !fileEvent.IsDelete() {
- // Double check to make sure the directory exist. This can happen when
- // we do a rm -fr on a recursively watched folders and we receive a
- // modification event first but the folder has been deleted and later
- // receive the delete event
- if _, err := os.Lstat(fileEvent.Name); os.IsNotExist(err) {
- // mark is as delete event
- fileEvent.mask |= sys_NOTE_DELETE
- }
- }
-
- if fileInfo != nil && fileInfo.IsDir() && fileEvent.IsModify() && !fileEvent.IsDelete() {
- w.sendDirectoryChangeEvents(fileEvent.Name)
- } else {
- // Send the event on the events channel
- w.internalEvent <- fileEvent
- }
-
- // Move to next event
- events = events[1:]
-
- if fileEvent.IsRename() {
- w.removeWatch(fileEvent.Name)
- w.femut.Lock()
- delete(w.fileExists, fileEvent.Name)
- w.femut.Unlock()
- }
- if fileEvent.IsDelete() {
- w.removeWatch(fileEvent.Name)
- w.femut.Lock()
- delete(w.fileExists, fileEvent.Name)
- w.femut.Unlock()
-
- // Look for a file that may have overwritten this
- // (ie mv f1 f2 will delete f2 then create f2)
- fileDir, _ := filepath.Split(fileEvent.Name)
- fileDir = filepath.Clean(fileDir)
- w.wmut.Lock()
- _, found := w.watches[fileDir]
- w.wmut.Unlock()
- if found {
- // make sure the directory exist before we watch for changes. When we
- // do a recursive watch and perform rm -fr, the parent directory might
- // have gone missing, ignore the missing directory and let the
- // upcoming delete event remove the watch form the parent folder
- if _, err := os.Lstat(fileDir); !os.IsNotExist(err) {
- w.sendDirectoryChangeEvents(fileDir)
- }
- }
- }
- }
- }
-}
-
-func (w *Watcher) watchDirectoryFiles(dirPath string) error {
- // Get all files
- files, err := ioutil.ReadDir(dirPath)
- if err != nil {
- return err
- }
-
- // Search for new files
- for _, fileInfo := range files {
- filePath := filepath.Join(dirPath, fileInfo.Name())
-
- // Inherit fsnFlags from parent directory
- w.fsnmut.Lock()
- if flags, found := w.fsnFlags[dirPath]; found {
- w.fsnFlags[filePath] = flags
- } else {
- w.fsnFlags[filePath] = FSN_ALL
- }
- w.fsnmut.Unlock()
-
- if fileInfo.IsDir() == false {
- // Watch file to mimic linux fsnotify
- e := w.addWatch(filePath, sys_NOTE_ALLEVENTS)
- if e != nil {
- return e
- }
- } else {
- // If the user is currently watching directory
- // we want to preserve the flags used
- w.enmut.Lock()
- currFlags, found := w.enFlags[filePath]
- w.enmut.Unlock()
- var newFlags uint32 = sys_NOTE_DELETE
- if found {
- newFlags |= currFlags
- }
-
- // Linux gives deletes if not explicitly watching
- e := w.addWatch(filePath, newFlags)
- if e != nil {
- return e
- }
- }
- w.femut.Lock()
- w.fileExists[filePath] = true
- w.femut.Unlock()
- }
-
- return nil
-}
-
-// sendDirectoryEvents searches the directory for newly created files
-// and sends them over the event channel. This functionality is to have
-// the BSD version of fsnotify match linux fsnotify which provides a
-// create event for files created in a watched directory.
-func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
- // Get all files
- files, err := ioutil.ReadDir(dirPath)
- if err != nil {
- w.Error <- err
- }
-
- // Search for new files
- for _, fileInfo := range files {
- filePath := filepath.Join(dirPath, fileInfo.Name())
- w.femut.Lock()
- _, doesExist := w.fileExists[filePath]
- w.femut.Unlock()
- if !doesExist {
- // Inherit fsnFlags from parent directory
- w.fsnmut.Lock()
- if flags, found := w.fsnFlags[dirPath]; found {
- w.fsnFlags[filePath] = flags
- } else {
- w.fsnFlags[filePath] = FSN_ALL
- }
- w.fsnmut.Unlock()
-
- // Send create event
- fileEvent := new(FileEvent)
- fileEvent.Name = filePath
- fileEvent.create = true
- w.internalEvent <- fileEvent
- }
- w.femut.Lock()
- w.fileExists[filePath] = true
- w.femut.Unlock()
- }
- w.watchDirectoryFiles(dirPath)
-}
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_linux.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_linux.go
deleted file mode 100644
index 80ade879f..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_linux.go
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build linux
-
-package fsnotify
-
-import (
- "errors"
- "fmt"
- "os"
- "strings"
- "sync"
- "syscall"
- "unsafe"
-)
-
-const (
- // Options for inotify_init() are not exported
- // sys_IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
- // sys_IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
-
- // Options for AddWatch
- sys_IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
- sys_IN_ONESHOT uint32 = syscall.IN_ONESHOT
- sys_IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
-
- // The "sys_IN_MASK_ADD" option is not exported, as AddWatch
- // adds it automatically, if there is already a watch for the given path
- // sys_IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
-
- // Events
- sys_IN_ACCESS uint32 = syscall.IN_ACCESS
- sys_IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
- sys_IN_ATTRIB uint32 = syscall.IN_ATTRIB
- sys_IN_CLOSE uint32 = syscall.IN_CLOSE
- sys_IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
- sys_IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
- sys_IN_CREATE uint32 = syscall.IN_CREATE
- sys_IN_DELETE uint32 = syscall.IN_DELETE
- sys_IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
- sys_IN_MODIFY uint32 = syscall.IN_MODIFY
- sys_IN_MOVE uint32 = syscall.IN_MOVE
- sys_IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
- sys_IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
- sys_IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
- sys_IN_OPEN uint32 = syscall.IN_OPEN
-
- sys_AGNOSTIC_EVENTS = sys_IN_MOVED_TO | sys_IN_MOVED_FROM | sys_IN_CREATE | sys_IN_ATTRIB | sys_IN_MODIFY | sys_IN_MOVE_SELF | sys_IN_DELETE | sys_IN_DELETE_SELF
-
- // Special events
- sys_IN_ISDIR uint32 = syscall.IN_ISDIR
- sys_IN_IGNORED uint32 = syscall.IN_IGNORED
- sys_IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
- sys_IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
-)
-
-type FileEvent struct {
- mask uint32 // Mask of events
- cookie uint32 // Unique cookie associating related events (for rename(2))
- Name string // File name (optional)
-}
-
-// IsCreate reports whether the FileEvent was triggered by a creation
-func (e *FileEvent) IsCreate() bool {
- return (e.mask&sys_IN_CREATE) == sys_IN_CREATE || (e.mask&sys_IN_MOVED_TO) == sys_IN_MOVED_TO
-}
-
-// IsDelete reports whether the FileEvent was triggered by a delete
-func (e *FileEvent) IsDelete() bool {
- return (e.mask&sys_IN_DELETE_SELF) == sys_IN_DELETE_SELF || (e.mask&sys_IN_DELETE) == sys_IN_DELETE
-}
-
-// IsModify reports whether the FileEvent was triggered by a file modification or attribute change
-func (e *FileEvent) IsModify() bool {
- return ((e.mask&sys_IN_MODIFY) == sys_IN_MODIFY || (e.mask&sys_IN_ATTRIB) == sys_IN_ATTRIB)
-}
-
-// IsRename reports whether the FileEvent was triggered by a change name
-func (e *FileEvent) IsRename() bool {
- return ((e.mask&sys_IN_MOVE_SELF) == sys_IN_MOVE_SELF || (e.mask&sys_IN_MOVED_FROM) == sys_IN_MOVED_FROM)
-}
-
-// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata.
-func (e *FileEvent) IsAttrib() bool {
- return (e.mask & sys_IN_ATTRIB) == sys_IN_ATTRIB
-}
-
-type watch struct {
- wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
- flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
-}
-
-type Watcher struct {
- mu sync.Mutex // Map access
- fd int // File descriptor (as returned by the inotify_init() syscall)
- watches map[string]*watch // Map of inotify watches (key: path)
- fsnFlags map[string]uint32 // Map of watched files to flags used for filter
- fsnmut sync.Mutex // Protects access to fsnFlags.
- paths map[int]string // Map of watched paths (key: watch descriptor)
- Error chan error // Errors are sent on this channel
- internalEvent chan *FileEvent // Events are queued on this channel
- Event chan *FileEvent // Events are returned on this channel
- done chan bool // Channel for sending a "quit message" to the reader goroutine
- isClosed bool // Set to true when Close() is first called
-}
-
-// NewWatcher creates and returns a new inotify instance using inotify_init(2)
-func NewWatcher() (*Watcher, error) {
- fd, errno := syscall.InotifyInit()
- if fd == -1 {
- return nil, os.NewSyscallError("inotify_init", errno)
- }
- w := &Watcher{
- fd: fd,
- watches: make(map[string]*watch),
- fsnFlags: make(map[string]uint32),
- paths: make(map[int]string),
- internalEvent: make(chan *FileEvent),
- Event: make(chan *FileEvent),
- Error: make(chan error),
- done: make(chan bool, 1),
- }
-
- go w.readEvents()
- go w.purgeEvents()
- return w, nil
-}
-
-// Close closes an inotify watcher instance
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the inotify instance
-func (w *Watcher) Close() error {
- if w.isClosed {
- return nil
- }
- w.isClosed = true
-
- // Remove all watches
- for path := range w.watches {
- w.RemoveWatch(path)
- }
-
- // Send "quit" message to the reader goroutine
- w.done <- true
-
- return nil
-}
-
-// AddWatch adds path to the watched file set.
-// The flags are interpreted as described in inotify_add_watch(2).
-func (w *Watcher) addWatch(path string, flags uint32) error {
- if w.isClosed {
- return errors.New("inotify instance already closed")
- }
-
- w.mu.Lock()
- watchEntry, found := w.watches[path]
- w.mu.Unlock()
- if found {
- watchEntry.flags |= flags
- flags |= syscall.IN_MASK_ADD
- }
- wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
- if wd == -1 {
- return errno
- }
-
- w.mu.Lock()
- w.watches[path] = &watch{wd: uint32(wd), flags: flags}
- w.paths[wd] = path
- w.mu.Unlock()
-
- return nil
-}
-
-// Watch adds path to the watched file set, watching all events.
-func (w *Watcher) watch(path string) error {
- return w.addWatch(path, sys_AGNOSTIC_EVENTS)
-}
-
-// RemoveWatch removes path from the watched file set.
-func (w *Watcher) removeWatch(path string) error {
- w.mu.Lock()
- defer w.mu.Unlock()
- watch, ok := w.watches[path]
- if !ok {
- return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
- }
- success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
- if success == -1 {
- return os.NewSyscallError("inotify_rm_watch", errno)
- }
- delete(w.watches, path)
- return nil
-}
-
-// readEvents reads from the inotify file descriptor, converts the
-// received events into Event objects and sends them via the Event channel
-func (w *Watcher) readEvents() {
- var (
- buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
- n int // Number of bytes read with read()
- errno error // Syscall errno
- )
-
- for {
- // See if there is a message on the "done" channel
- select {
- case <-w.done:
- syscall.Close(w.fd)
- close(w.internalEvent)
- close(w.Error)
- return
- default:
- }
-
- n, errno = syscall.Read(w.fd, buf[:])
-
- // If EOF is received
- if n == 0 {
- syscall.Close(w.fd)
- close(w.internalEvent)
- close(w.Error)
- return
- }
-
- if n < 0 {
- w.Error <- os.NewSyscallError("read", errno)
- continue
- }
- if n < syscall.SizeofInotifyEvent {
- w.Error <- errors.New("inotify: short read in readEvents()")
- continue
- }
-
- var offset uint32 = 0
- // We don't know how many events we just read into the buffer
- // While the offset points to at least one whole event...
- for offset <= uint32(n-syscall.SizeofInotifyEvent) {
- // Point "raw" to the event in the buffer
- raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
- event := new(FileEvent)
- event.mask = uint32(raw.Mask)
- event.cookie = uint32(raw.Cookie)
- nameLen := uint32(raw.Len)
- // If the event happened to the watched directory or the watched file, the kernel
- // doesn't append the filename to the event, but we would like to always fill the
- // the "Name" field with a valid filename. We retrieve the path of the watch from
- // the "paths" map.
- w.mu.Lock()
- event.Name = w.paths[int(raw.Wd)]
- w.mu.Unlock()
- watchedName := event.Name
- if nameLen > 0 {
- // Point "bytes" at the first byte of the filename
- bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
- // The filename is padded with NUL bytes. TrimRight() gets rid of those.
- event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
- }
-
- // Send the events that are not ignored on the events channel
- if !event.ignoreLinux() {
- // Setup FSNotify flags (inherit from directory watch)
- w.fsnmut.Lock()
- if _, fsnFound := w.fsnFlags[event.Name]; !fsnFound {
- if fsnFlags, watchFound := w.fsnFlags[watchedName]; watchFound {
- w.fsnFlags[event.Name] = fsnFlags
- } else {
- w.fsnFlags[event.Name] = FSN_ALL
- }
- }
- w.fsnmut.Unlock()
-
- w.internalEvent <- event
- }
-
- // Move to the next event in the buffer
- offset += syscall.SizeofInotifyEvent + nameLen
- }
- }
-}
-
-// Certain types of events can be "ignored" and not sent over the Event
-// channel. Such as events marked ignore by the kernel, or MODIFY events
-// against files that do not exist.
-func (e *FileEvent) ignoreLinux() bool {
- // Ignore anything the inotify API says to ignore
- if e.mask&sys_IN_IGNORED == sys_IN_IGNORED {
- return true
- }
-
- // If the event is not a DELETE or RENAME, the file must exist.
- // Otherwise the event is ignored.
- // *Note*: this was put in place because it was seen that a MODIFY
- // event was sent after the DELETE. This ignores that MODIFY and
- // assumes a DELETE will come or has come if the file doesn't exist.
- if !(e.IsDelete() || e.IsRename()) {
- _, statErr := os.Lstat(e.Name)
- return os.IsNotExist(statErr)
- }
- return false
-}
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_open_bsd.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_open_bsd.go
deleted file mode 100644
index 37ea998d0..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_open_bsd.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build freebsd openbsd netbsd
-
-package fsnotify
-
-import "syscall"
-
-const open_FLAGS = syscall.O_NONBLOCK | syscall.O_RDONLY
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_open_darwin.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_open_darwin.go
deleted file mode 100644
index d450318e6..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_open_darwin.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin
-
-package fsnotify
-
-import "syscall"
-
-const open_FLAGS = syscall.O_EVTONLY
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_symlink_test.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_symlink_test.go
deleted file mode 100644
index 39061f844..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_symlink_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build freebsd openbsd netbsd darwin linux
-
-package fsnotify
-
-import (
- "os"
- "path/filepath"
- "testing"
- "time"
-)
-
-func TestFsnotifyFakeSymlink(t *testing.T) {
- watcher := newWatcher(t)
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- var errorsReceived counter
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for errors := range watcher.Error {
- t.Logf("Received error: %s", errors)
- errorsReceived.increment()
- }
- }()
-
- // Count the CREATE events received
- var createEventsReceived, otherEventsReceived counter
- go func() {
- for ev := range watcher.Event {
- t.Logf("event received: %s", ev)
- if ev.IsCreate() {
- createEventsReceived.increment()
- } else {
- otherEventsReceived.increment()
- }
- }
- }()
-
- addWatch(t, watcher, testDir)
-
- if err := os.Symlink(filepath.Join(testDir, "zzz"), filepath.Join(testDir, "zzznew")); err != nil {
- t.Fatalf("Failed to create bogus symlink: %s", err)
- }
- t.Logf("Created bogus symlink")
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
-
- // Should not be error, just no events for broken links (watching nothing)
- if errorsReceived.value() > 0 {
- t.Fatal("fsnotify errors have been received.")
- }
- if otherEventsReceived.value() > 0 {
- t.Fatal("fsnotify other events received on the broken link")
- }
-
- // Except for 1 create event (for the link itself)
- if createEventsReceived.value() == 0 {
- t.Fatal("fsnotify create events were not received after 500 ms")
- }
- if createEventsReceived.value() > 1 {
- t.Fatal("fsnotify more create events received than expected")
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
-}
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_test.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_test.go
deleted file mode 100644
index 3f5a6487f..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_test.go
+++ /dev/null
@@ -1,1010 +0,0 @@
-// Copyright 2010 The Go 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 fsnotify
-
-import (
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "sync/atomic"
- "testing"
- "time"
-)
-
-// An atomic counter
-type counter struct {
- val int32
-}
-
-func (c *counter) increment() {
- atomic.AddInt32(&c.val, 1)
-}
-
-func (c *counter) value() int32 {
- return atomic.LoadInt32(&c.val)
-}
-
-func (c *counter) reset() {
- atomic.StoreInt32(&c.val, 0)
-}
-
-// tempMkdir makes a temporary directory
-func tempMkdir(t *testing.T) string {
- dir, err := ioutil.TempDir("", "fsnotify")
- if err != nil {
- t.Fatalf("failed to create test directory: %s", err)
- }
- return dir
-}
-
-// newWatcher initializes an fsnotify Watcher instance.
-func newWatcher(t *testing.T) *Watcher {
- watcher, err := NewWatcher()
- if err != nil {
- t.Fatalf("NewWatcher() failed: %s", err)
- }
- return watcher
-}
-
-// addWatch adds a watch for a directory
-func addWatch(t *testing.T, watcher *Watcher, dir string) {
- if err := watcher.Watch(dir); err != nil {
- t.Fatalf("watcher.Watch(%q) failed: %s", dir, err)
- }
-}
-
-func TestFsnotifyMultipleOperations(t *testing.T) {
- watcher := newWatcher(t)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- // Create directory that's not watched
- testDirToMoveFiles := tempMkdir(t)
- defer os.RemoveAll(testDirToMoveFiles)
-
- testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
- testFileRenamed := filepath.Join(testDirToMoveFiles, "TestFsnotifySeqRename.testfile")
-
- addWatch(t, watcher, testDir)
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var createReceived, modifyReceived, deleteReceived, renameReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
- t.Logf("event received: %s", event)
- if event.IsDelete() {
- deleteReceived.increment()
- }
- if event.IsModify() {
- modifyReceived.increment()
- }
- if event.IsCreate() {
- createReceived.increment()
- }
- if event.IsRename() {
- renameReceived.increment()
- }
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the fsnotify event queue
- var f *os.File
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
-
- time.Sleep(time.Millisecond)
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- if err := testRename(testFile, testFileRenamed); err != nil {
- t.Fatalf("rename failed: %s", err)
- }
-
- // Modify the file outside of the watched dir
- f, err = os.Open(testFileRenamed)
- if err != nil {
- t.Fatalf("open test renamed file failed: %s", err)
- }
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- // Recreate the file that was moved
- f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Close()
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- cReceived := createReceived.value()
- if cReceived != 2 {
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
- }
- mReceived := modifyReceived.value()
- if mReceived != 1 {
- t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
- }
- dReceived := deleteReceived.value()
- rReceived := renameReceived.value()
- if dReceived+rReceived != 1 {
- t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", rReceived+dReceived, 1)
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(2 * time.Second):
- t.Fatal("event stream was not closed after 2 seconds")
- }
-}
-
-func TestFsnotifyMultipleCreates(t *testing.T) {
- watcher := newWatcher(t)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
-
- addWatch(t, watcher, testDir)
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var createReceived, modifyReceived, deleteReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
- t.Logf("event received: %s", event)
- if event.IsDelete() {
- deleteReceived.increment()
- }
- if event.IsCreate() {
- createReceived.increment()
- }
- if event.IsModify() {
- modifyReceived.increment()
- }
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the fsnotify event queue
- var f *os.File
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
-
- time.Sleep(time.Millisecond)
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- os.Remove(testFile)
-
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- // Recreate the file
- f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Close()
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- // Modify
- f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
-
- time.Sleep(time.Millisecond)
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- // Modify
- f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
-
- time.Sleep(time.Millisecond)
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- cReceived := createReceived.value()
- if cReceived != 2 {
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
- }
- mReceived := modifyReceived.value()
- if mReceived < 3 {
- t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3)
- }
- dReceived := deleteReceived.value()
- if dReceived != 1 {
- t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1)
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(2 * time.Second):
- t.Fatal("event stream was not closed after 2 seconds")
- }
-}
-
-func TestFsnotifyDirOnly(t *testing.T) {
- watcher := newWatcher(t)
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- // Create a file before watching directory
- // This should NOT add any events to the fsnotify event queue
- testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
- {
- var f *os.File
- f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
- f.Close()
- }
-
- addWatch(t, watcher, testDir)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var createReceived, modifyReceived, deleteReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileAlreadyExists) {
- t.Logf("event received: %s", event)
- if event.IsDelete() {
- deleteReceived.increment()
- }
- if event.IsModify() {
- modifyReceived.increment()
- }
- if event.IsCreate() {
- createReceived.increment()
- }
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the fsnotify event queue
- var f *os.File
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
-
- time.Sleep(time.Millisecond)
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
-
- os.Remove(testFile)
- os.Remove(testFileAlreadyExists)
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- cReceived := createReceived.value()
- if cReceived != 1 {
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1)
- }
- mReceived := modifyReceived.value()
- if mReceived != 1 {
- t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
- }
- dReceived := deleteReceived.value()
- if dReceived != 2 {
- t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(2 * time.Second):
- t.Fatal("event stream was not closed after 2 seconds")
- }
-}
-
-func TestFsnotifyDeleteWatchedDir(t *testing.T) {
- watcher := newWatcher(t)
- defer watcher.Close()
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- // Create a file before watching directory
- testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
- {
- var f *os.File
- f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
- f.Close()
- }
-
- addWatch(t, watcher, testDir)
-
- // Add a watch for testFile
- addWatch(t, watcher, testFileAlreadyExists)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var deleteReceived counter
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFileAlreadyExists) {
- t.Logf("event received: %s", event)
- if event.IsDelete() {
- deleteReceived.increment()
- }
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- }()
-
- os.RemoveAll(testDir)
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- dReceived := deleteReceived.value()
- if dReceived < 2 {
- t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived)
- }
-}
-
-func TestFsnotifySubDir(t *testing.T) {
- watcher := newWatcher(t)
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
- testSubDir := filepath.Join(testDir, "sub")
- testSubDirFile := filepath.Join(testDir, "sub/TestFsnotifyFile1.testfile")
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var createReceived, deleteReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) {
- t.Logf("event received: %s", event)
- if event.IsCreate() {
- createReceived.increment()
- }
- if event.IsDelete() {
- deleteReceived.increment()
- }
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- addWatch(t, watcher, testDir)
-
- // Create sub-directory
- if err := os.Mkdir(testSubDir, 0777); err != nil {
- t.Fatalf("failed to create test sub-directory: %s", err)
- }
-
- // Create a file
- var f *os.File
- f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
- f.Close()
-
- // Create a file (Should not see this! we are not watching subdir)
- var fs *os.File
- fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- fs.Sync()
- fs.Close()
-
- time.Sleep(200 * time.Millisecond)
-
- // Make sure receive deletes for both file and sub-directory
- os.RemoveAll(testSubDir)
- os.Remove(testFile1)
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- cReceived := createReceived.value()
- if cReceived != 2 {
- t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
- }
- dReceived := deleteReceived.value()
- if dReceived != 2 {
- t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(2 * time.Second):
- t.Fatal("event stream was not closed after 2 seconds")
- }
-}
-
-func TestFsnotifyRename(t *testing.T) {
- watcher := newWatcher(t)
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- addWatch(t, watcher, testDir)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
- testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var renameReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
- if event.IsRename() {
- renameReceived.increment()
- }
- t.Logf("event received: %s", event)
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the fsnotify event queue
- var f *os.File
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
-
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- // Add a watch for testFile
- addWatch(t, watcher, testFile)
-
- if err := testRename(testFile, testFileRenamed); err != nil {
- t.Fatalf("rename failed: %s", err)
- }
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- if renameReceived.value() == 0 {
- t.Fatal("fsnotify rename events have not been received after 500 ms")
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(2 * time.Second):
- t.Fatal("event stream was not closed after 2 seconds")
- }
-
- os.Remove(testFileRenamed)
-}
-
-func TestFsnotifyRenameToCreate(t *testing.T) {
- watcher := newWatcher(t)
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- // Create directory to get file
- testDirFrom := tempMkdir(t)
- defer os.RemoveAll(testDirFrom)
-
- addWatch(t, watcher, testDir)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
- testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var createReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
- if event.IsCreate() {
- createReceived.increment()
- }
- t.Logf("event received: %s", event)
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the fsnotify event queue
- var f *os.File
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
- f.Close()
-
- if err := testRename(testFile, testFileRenamed); err != nil {
- t.Fatalf("rename failed: %s", err)
- }
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- if createReceived.value() == 0 {
- t.Fatal("fsnotify create events have not been received after 500 ms")
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(2 * time.Second):
- t.Fatal("event stream was not closed after 2 seconds")
- }
-
- os.Remove(testFileRenamed)
-}
-
-func TestFsnotifyRenameToOverwrite(t *testing.T) {
- switch runtime.GOOS {
- case "plan9", "windows":
- t.Skipf("skipping test on %q (os.Rename over existing file does not create event).", runtime.GOOS)
- }
-
- watcher := newWatcher(t)
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- // Create directory to get file
- testDirFrom := tempMkdir(t)
- defer os.RemoveAll(testDirFrom)
-
- testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
- testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
-
- // Create a file
- var fr *os.File
- fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- fr.Sync()
- fr.Close()
-
- addWatch(t, watcher, testDir)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- var eventReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testFileRenamed) {
- eventReceived.increment()
- t.Logf("event received: %s", event)
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the fsnotify event queue
- var f *os.File
- f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
- f.Close()
-
- if err := testRename(testFile, testFileRenamed); err != nil {
- t.Fatalf("rename failed: %s", err)
- }
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- time.Sleep(500 * time.Millisecond)
- if eventReceived.value() == 0 {
- t.Fatal("fsnotify events have not been received after 500 ms")
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(2 * time.Second):
- t.Fatal("event stream was not closed after 2 seconds")
- }
-
- os.Remove(testFileRenamed)
-}
-
-func TestRemovalOfWatch(t *testing.T) {
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- // Create a file before watching directory
- testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
- {
- var f *os.File
- f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
- f.Close()
- }
-
- watcher := newWatcher(t)
- defer watcher.Close()
-
- addWatch(t, watcher, testDir)
- if err := watcher.RemoveWatch(testDir); err != nil {
- t.Fatalf("Could not remove the watch: %v\n", err)
- }
-
- go func() {
- select {
- case ev := <-watcher.Event:
- t.Fatalf("We received event: %v\n", ev)
- case <-time.After(500 * time.Millisecond):
- t.Log("No event received, as expected.")
- }
- }()
-
- time.Sleep(200 * time.Millisecond)
- // Modify the file outside of the watched dir
- f, err := os.Open(testFileAlreadyExists)
- if err != nil {
- t.Fatalf("Open test file failed: %s", err)
- }
- f.WriteString("data")
- f.Sync()
- f.Close()
- if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
- t.Fatalf("chmod failed: %s", err)
- }
- time.Sleep(400 * time.Millisecond)
-}
-
-func TestFsnotifyAttrib(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("attributes don't work on Windows.")
- }
-
- watcher := newWatcher(t)
-
- // Create directory to watch
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- // Receive errors on the error channel on a separate goroutine
- go func() {
- for err := range watcher.Error {
- t.Fatalf("error received: %s", err)
- }
- }()
-
- testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
-
- // Receive events on the event channel on a separate goroutine
- eventstream := watcher.Event
- // The modifyReceived counter counts IsModify events that are not IsAttrib,
- // and the attribReceived counts IsAttrib events (which are also IsModify as
- // a consequence).
- var modifyReceived counter
- var attribReceived counter
- done := make(chan bool)
- go func() {
- for event := range eventstream {
- // Only count relevant events
- if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
- if event.IsModify() {
- modifyReceived.increment()
- }
- if event.IsAttrib() {
- attribReceived.increment()
- }
- t.Logf("event received: %s", event)
- } else {
- t.Logf("unexpected event received: %s", event)
- }
- }
- done <- true
- }()
-
- // Create a file
- // This should add at least one event to the fsnotify event queue
- var f *os.File
- f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
- if err != nil {
- t.Fatalf("creating test file failed: %s", err)
- }
- f.Sync()
-
- f.WriteString("data")
- f.Sync()
- f.Close()
-
- // Add a watch for testFile
- addWatch(t, watcher, testFile)
-
- if err := os.Chmod(testFile, 0700); err != nil {
- t.Fatalf("chmod failed: %s", err)
- }
-
- // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
- // Creating/writing a file changes also the mtime, so IsAttrib should be set to true here
- time.Sleep(500 * time.Millisecond)
- if modifyReceived.value() == 0 {
- t.Fatal("fsnotify modify events have not received after 500 ms")
- }
- if attribReceived.value() == 0 {
- t.Fatal("fsnotify attribute events have not received after 500 ms")
- }
-
- // Modifying the contents of the file does not set the attrib flag (although eg. the mtime
- // might have been modified).
- modifyReceived.reset()
- attribReceived.reset()
-
- f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
- if err != nil {
- t.Fatalf("reopening test file failed: %s", err)
- }
-
- f.WriteString("more data")
- f.Sync()
- f.Close()
-
- time.Sleep(500 * time.Millisecond)
-
- if modifyReceived.value() != 1 {
- t.Fatal("didn't receive a modify event after changing test file contents")
- }
-
- if attribReceived.value() != 0 {
- t.Fatal("did receive an unexpected attrib event after changing test file contents")
- }
-
- modifyReceived.reset()
- attribReceived.reset()
-
- // Doing a chmod on the file should trigger an event with the "attrib" flag set (the contents
- // of the file are not changed though)
- if err := os.Chmod(testFile, 0600); err != nil {
- t.Fatalf("chmod failed: %s", err)
- }
-
- time.Sleep(500 * time.Millisecond)
-
- if attribReceived.value() != 1 {
- t.Fatal("didn't receive an attribute change after 500ms")
- }
-
- // Try closing the fsnotify instance
- t.Log("calling Close()")
- watcher.Close()
- t.Log("waiting for the event channel to become closed...")
- select {
- case <-done:
- t.Log("event channel closed")
- case <-time.After(1e9):
- t.Fatal("event stream was not closed after 1 second")
- }
-
- os.Remove(testFile)
-}
-
-func TestFsnotifyClose(t *testing.T) {
- watcher := newWatcher(t)
- watcher.Close()
-
- var done int32
- go func() {
- watcher.Close()
- atomic.StoreInt32(&done, 1)
- }()
-
- time.Sleep(50e6) // 50 ms
- if atomic.LoadInt32(&done) == 0 {
- t.Fatal("double Close() test failed: second Close() call didn't return")
- }
-
- testDir := tempMkdir(t)
- defer os.RemoveAll(testDir)
-
- if err := watcher.Watch(testDir); err == nil {
- t.Fatal("expected error on Watch() after Close(), got nil")
- }
-}
-
-func testRename(file1, file2 string) error {
- switch runtime.GOOS {
- case "windows", "plan9":
- return os.Rename(file1, file2)
- default:
- cmd := exec.Command("mv", file1, file2)
- return cmd.Run()
- }
-}
diff --git a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_windows.go b/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_windows.go
deleted file mode 100644
index d88ae6340..000000000
--- a/Godeps/_workspace/src/github.com/howeyc/fsnotify/fsnotify_windows.go
+++ /dev/null
@@ -1,598 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows
-
-package fsnotify
-
-import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "runtime"
- "sync"
- "syscall"
- "unsafe"
-)
-
-const (
- // Options for AddWatch
- sys_FS_ONESHOT = 0x80000000
- sys_FS_ONLYDIR = 0x1000000
-
- // Events
- sys_FS_ACCESS = 0x1
- sys_FS_ALL_EVENTS = 0xfff
- sys_FS_ATTRIB = 0x4
- sys_FS_CLOSE = 0x18
- sys_FS_CREATE = 0x100
- sys_FS_DELETE = 0x200
- sys_FS_DELETE_SELF = 0x400
- sys_FS_MODIFY = 0x2
- sys_FS_MOVE = 0xc0
- sys_FS_MOVED_FROM = 0x40
- sys_FS_MOVED_TO = 0x80
- sys_FS_MOVE_SELF = 0x800
-
- // Special events
- sys_FS_IGNORED = 0x8000
- sys_FS_Q_OVERFLOW = 0x4000
-)
-
-const (
- // TODO(nj): Use syscall.ERROR_MORE_DATA from ztypes_windows in Go 1.3+
- sys_ERROR_MORE_DATA syscall.Errno = 234
-)
-
-// Event is the type of the notification messages
-// received on the watcher's Event channel.
-type FileEvent struct {
- mask uint32 // Mask of events
- cookie uint32 // Unique cookie associating related events (for rename)
- Name string // File name (optional)
-}
-
-// IsCreate reports whether the FileEvent was triggered by a creation
-func (e *FileEvent) IsCreate() bool { return (e.mask & sys_FS_CREATE) == sys_FS_CREATE }
-
-// IsDelete reports whether the FileEvent was triggered by a delete
-func (e *FileEvent) IsDelete() bool {
- return ((e.mask&sys_FS_DELETE) == sys_FS_DELETE || (e.mask&sys_FS_DELETE_SELF) == sys_FS_DELETE_SELF)
-}
-
-// IsModify reports whether the FileEvent was triggered by a file modification or attribute change
-func (e *FileEvent) IsModify() bool {
- return ((e.mask&sys_FS_MODIFY) == sys_FS_MODIFY || (e.mask&sys_FS_ATTRIB) == sys_FS_ATTRIB)
-}
-
-// IsRename reports whether the FileEvent was triggered by a change name
-func (e *FileEvent) IsRename() bool {
- return ((e.mask&sys_FS_MOVE) == sys_FS_MOVE || (e.mask&sys_FS_MOVE_SELF) == sys_FS_MOVE_SELF || (e.mask&sys_FS_MOVED_FROM) == sys_FS_MOVED_FROM || (e.mask&sys_FS_MOVED_TO) == sys_FS_MOVED_TO)
-}
-
-// IsAttrib reports whether the FileEvent was triggered by a change in the file metadata.
-func (e *FileEvent) IsAttrib() bool {
- return (e.mask & sys_FS_ATTRIB) == sys_FS_ATTRIB
-}
-
-const (
- opAddWatch = iota
- opRemoveWatch
-)
-
-const (
- provisional uint64 = 1 << (32 + iota)
-)
-
-type input struct {
- op int
- path string
- flags uint32
- reply chan error
-}
-
-type inode struct {
- handle syscall.Handle
- volume uint32
- index uint64
-}
-
-type watch struct {
- ov syscall.Overlapped
- ino *inode // i-number
- path string // Directory path
- mask uint64 // Directory itself is being watched with these notify flags
- names map[string]uint64 // Map of names being watched and their notify flags
- rename string // Remembers the old name while renaming a file
- buf [4096]byte
-}
-
-type indexMap map[uint64]*watch
-type watchMap map[uint32]indexMap
-
-// A Watcher waits for and receives event notifications
-// for a specific set of files and directories.
-type Watcher struct {
- mu sync.Mutex // Map access
- port syscall.Handle // Handle to completion port
- watches watchMap // Map of watches (key: i-number)
- fsnFlags map[string]uint32 // Map of watched files to flags used for filter
- fsnmut sync.Mutex // Protects access to fsnFlags.
- input chan *input // Inputs to the reader are sent on this channel
- internalEvent chan *FileEvent // Events are queued on this channel
- Event chan *FileEvent // Events are returned on this channel
- Error chan error // Errors are sent on this channel
- isClosed bool // Set to true when Close() is first called
- quit chan chan<- error
- cookie uint32
-}
-
-// NewWatcher creates and returns a Watcher.
-func NewWatcher() (*Watcher, error) {
- port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
- if e != nil {
- return nil, os.NewSyscallError("CreateIoCompletionPort", e)
- }
- w := &Watcher{
- port: port,
- watches: make(watchMap),
- fsnFlags: make(map[string]uint32),
- input: make(chan *input, 1),
- Event: make(chan *FileEvent, 50),
- internalEvent: make(chan *FileEvent),
- Error: make(chan error),
- quit: make(chan chan<- error, 1),
- }
- go w.readEvents()
- go w.purgeEvents()
- return w, nil
-}
-
-// Close closes a Watcher.
-// It sends a message to the reader goroutine to quit and removes all watches
-// associated with the watcher.
-func (w *Watcher) Close() error {
- if w.isClosed {
- return nil
- }
- w.isClosed = true
-
- // Send "quit" message to the reader goroutine
- ch := make(chan error)
- w.quit <- ch
- if err := w.wakeupReader(); err != nil {
- return err
- }
- return <-ch
-}
-
-// AddWatch adds path to the watched file set.
-func (w *Watcher) AddWatch(path string, flags uint32) error {
- if w.isClosed {
- return errors.New("watcher already closed")
- }
- in := &input{
- op: opAddWatch,
- path: filepath.Clean(path),
- flags: flags,
- reply: make(chan error),
- }
- w.input <- in
- if err := w.wakeupReader(); err != nil {
- return err
- }
- return <-in.reply
-}
-
-// Watch adds path to the watched file set, watching all events.
-func (w *Watcher) watch(path string) error {
- return w.AddWatch(path, sys_FS_ALL_EVENTS)
-}
-
-// RemoveWatch removes path from the watched file set.
-func (w *Watcher) removeWatch(path string) error {
- in := &input{
- op: opRemoveWatch,
- path: filepath.Clean(path),
- reply: make(chan error),
- }
- w.input <- in
- if err := w.wakeupReader(); err != nil {
- return err
- }
- return <-in.reply
-}
-
-func (w *Watcher) wakeupReader() error {
- e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
- if e != nil {
- return os.NewSyscallError("PostQueuedCompletionStatus", e)
- }
- return nil
-}
-
-func getDir(pathname string) (dir string, err error) {
- attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
- if e != nil {
- return "", os.NewSyscallError("GetFileAttributes", e)
- }
- if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
- dir = pathname
- } else {
- dir, _ = filepath.Split(pathname)
- dir = filepath.Clean(dir)
- }
- return
-}
-
-func getIno(path string) (ino *inode, err error) {
- h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
- syscall.FILE_LIST_DIRECTORY,
- syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
- nil, syscall.OPEN_EXISTING,
- syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
- if e != nil {
- return nil, os.NewSyscallError("CreateFile", e)
- }
- var fi syscall.ByHandleFileInformation
- if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
- syscall.CloseHandle(h)
- return nil, os.NewSyscallError("GetFileInformationByHandle", e)
- }
- ino = &inode{
- handle: h,
- volume: fi.VolumeSerialNumber,
- index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
- }
- return ino, nil
-}
-
-// Must run within the I/O thread.
-func (m watchMap) get(ino *inode) *watch {
- if i := m[ino.volume]; i != nil {
- return i[ino.index]
- }
- return nil
-}
-
-// Must run within the I/O thread.
-func (m watchMap) set(ino *inode, watch *watch) {
- i := m[ino.volume]
- if i == nil {
- i = make(indexMap)
- m[ino.volume] = i
- }
- i[ino.index] = watch
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) addWatch(pathname string, flags uint64) error {
- dir, err := getDir(pathname)
- if err != nil {
- return err
- }
- if flags&sys_FS_ONLYDIR != 0 && pathname != dir {
- return nil
- }
- ino, err := getIno(dir)
- if err != nil {
- return err
- }
- w.mu.Lock()
- watchEntry := w.watches.get(ino)
- w.mu.Unlock()
- if watchEntry == nil {
- if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
- syscall.CloseHandle(ino.handle)
- return os.NewSyscallError("CreateIoCompletionPort", e)
- }
- watchEntry = &watch{
- ino: ino,
- path: dir,
- names: make(map[string]uint64),
- }
- w.mu.Lock()
- w.watches.set(ino, watchEntry)
- w.mu.Unlock()
- flags |= provisional
- } else {
- syscall.CloseHandle(ino.handle)
- }
- if pathname == dir {
- watchEntry.mask |= flags
- } else {
- watchEntry.names[filepath.Base(pathname)] |= flags
- }
- if err = w.startRead(watchEntry); err != nil {
- return err
- }
- if pathname == dir {
- watchEntry.mask &= ^provisional
- } else {
- watchEntry.names[filepath.Base(pathname)] &= ^provisional
- }
- return nil
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) remWatch(pathname string) error {
- dir, err := getDir(pathname)
- if err != nil {
- return err
- }
- ino, err := getIno(dir)
- if err != nil {
- return err
- }
- w.mu.Lock()
- watch := w.watches.get(ino)
- w.mu.Unlock()
- if watch == nil {
- return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
- }
- if pathname == dir {
- w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED)
- watch.mask = 0
- } else {
- name := filepath.Base(pathname)
- w.sendEvent(watch.path+"\\"+name, watch.names[name]&sys_FS_IGNORED)
- delete(watch.names, name)
- }
- return w.startRead(watch)
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) deleteWatch(watch *watch) {
- for name, mask := range watch.names {
- if mask&provisional == 0 {
- w.sendEvent(watch.path+"\\"+name, mask&sys_FS_IGNORED)
- }
- delete(watch.names, name)
- }
- if watch.mask != 0 {
- if watch.mask&provisional == 0 {
- w.sendEvent(watch.path, watch.mask&sys_FS_IGNORED)
- }
- watch.mask = 0
- }
-}
-
-// Must run within the I/O thread.
-func (w *Watcher) startRead(watch *watch) error {
- if e := syscall.CancelIo(watch.ino.handle); e != nil {
- w.Error <- os.NewSyscallError("CancelIo", e)
- w.deleteWatch(watch)
- }
- mask := toWindowsFlags(watch.mask)
- for _, m := range watch.names {
- mask |= toWindowsFlags(m)
- }
- if mask == 0 {
- if e := syscall.CloseHandle(watch.ino.handle); e != nil {
- w.Error <- os.NewSyscallError("CloseHandle", e)
- }
- w.mu.Lock()
- delete(w.watches[watch.ino.volume], watch.ino.index)
- w.mu.Unlock()
- return nil
- }
- e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
- uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
- if e != nil {
- err := os.NewSyscallError("ReadDirectoryChanges", e)
- if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
- // Watched directory was probably removed
- if w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF) {
- if watch.mask&sys_FS_ONESHOT != 0 {
- watch.mask = 0
- }
- }
- err = nil
- }
- w.deleteWatch(watch)
- w.startRead(watch)
- return err
- }
- return nil
-}
-
-// readEvents reads from the I/O completion port, converts the
-// received events into Event objects and sends them via the Event channel.
-// Entry point to the I/O thread.
-func (w *Watcher) readEvents() {
- var (
- n, key uint32
- ov *syscall.Overlapped
- )
- runtime.LockOSThread()
-
- for {
- e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
- watch := (*watch)(unsafe.Pointer(ov))
-
- if watch == nil {
- select {
- case ch := <-w.quit:
- w.mu.Lock()
- var indexes []indexMap
- for _, index := range w.watches {
- indexes = append(indexes, index)
- }
- w.mu.Unlock()
- for _, index := range indexes {
- for _, watch := range index {
- w.deleteWatch(watch)
- w.startRead(watch)
- }
- }
- var err error
- if e := syscall.CloseHandle(w.port); e != nil {
- err = os.NewSyscallError("CloseHandle", e)
- }
- close(w.internalEvent)
- close(w.Error)
- ch <- err
- return
- case in := <-w.input:
- switch in.op {
- case opAddWatch:
- in.reply <- w.addWatch(in.path, uint64(in.flags))
- case opRemoveWatch:
- in.reply <- w.remWatch(in.path)
- }
- default:
- }
- continue
- }
-
- switch e {
- case sys_ERROR_MORE_DATA:
- if watch == nil {
- w.Error <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
- } else {
- // The i/o succeeded but the buffer is full.
- // In theory we should be building up a full packet.
- // In practice we can get away with just carrying on.
- n = uint32(unsafe.Sizeof(watch.buf))
- }
- case syscall.ERROR_ACCESS_DENIED:
- // Watched directory was probably removed
- w.sendEvent(watch.path, watch.mask&sys_FS_DELETE_SELF)
- w.deleteWatch(watch)
- w.startRead(watch)
- continue
- case syscall.ERROR_OPERATION_ABORTED:
- // CancelIo was called on this handle
- continue
- default:
- w.Error <- os.NewSyscallError("GetQueuedCompletionPort", e)
- continue
- case nil:
- }
-
- var offset uint32
- for {
- if n == 0 {
- w.internalEvent <- &FileEvent{mask: sys_FS_Q_OVERFLOW}
- w.Error <- errors.New("short read in readEvents()")
- break
- }
-
- // Point "raw" to the event in the buffer
- raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
- buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
- name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
- fullname := watch.path + "\\" + name
-
- var mask uint64
- switch raw.Action {
- case syscall.FILE_ACTION_REMOVED:
- mask = sys_FS_DELETE_SELF
- case syscall.FILE_ACTION_MODIFIED:
- mask = sys_FS_MODIFY
- case syscall.FILE_ACTION_RENAMED_OLD_NAME:
- watch.rename = name
- case syscall.FILE_ACTION_RENAMED_NEW_NAME:
- if watch.names[watch.rename] != 0 {
- watch.names[name] |= watch.names[watch.rename]
- delete(watch.names, watch.rename)
- mask = sys_FS_MOVE_SELF
- }
- }
-
- sendNameEvent := func() {
- if w.sendEvent(fullname, watch.names[name]&mask) {
- if watch.names[name]&sys_FS_ONESHOT != 0 {
- delete(watch.names, name)
- }
- }
- }
- if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
- sendNameEvent()
- }
- if raw.Action == syscall.FILE_ACTION_REMOVED {
- w.sendEvent(fullname, watch.names[name]&sys_FS_IGNORED)
- delete(watch.names, name)
- }
- if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
- if watch.mask&sys_FS_ONESHOT != 0 {
- watch.mask = 0
- }
- }
- if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
- fullname = watch.path + "\\" + watch.rename
- sendNameEvent()
- }
-
- // Move to the next event in the buffer
- if raw.NextEntryOffset == 0 {
- break
- }
- offset += raw.NextEntryOffset
-
- // Error!
- if offset >= n {
- w.Error <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
- break
- }
- }
-
- if err := w.startRead(watch); err != nil {
- w.Error <- err
- }
- }
-}
-
-func (w *Watcher) sendEvent(name string, mask uint64) bool {
- if mask == 0 {
- return false
- }
- event := &FileEvent{mask: uint32(mask), Name: name}
- if mask&sys_FS_MOVE != 0 {
- if mask&sys_FS_MOVED_FROM != 0 {
- w.cookie++
- }
- event.cookie = w.cookie
- }
- select {
- case ch := <-w.quit:
- w.quit <- ch
- case w.Event <- event:
- }
- return true
-}
-
-func toWindowsFlags(mask uint64) uint32 {
- var m uint32
- if mask&sys_FS_ACCESS != 0 {
- m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
- }
- if mask&sys_FS_MODIFY != 0 {
- m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
- }
- if mask&sys_FS_ATTRIB != 0 {
- m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
- }
- if mask&(sys_FS_MOVE|sys_FS_CREATE|sys_FS_DELETE) != 0 {
- m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
- }
- return m
-}
-
-func toFSnotifyFlags(action uint32) uint64 {
- switch action {
- case syscall.FILE_ACTION_ADDED:
- return sys_FS_CREATE
- case syscall.FILE_ACTION_REMOVED:
- return sys_FS_DELETE
- case syscall.FILE_ACTION_MODIFIED:
- return sys_FS_MODIFY
- case syscall.FILE_ACTION_RENAMED_OLD_NAME:
- return sys_FS_MOVED_FROM
- case syscall.FILE_ACTION_RENAMED_NEW_NAME:
- return sys_FS_MOVED_TO
- }
- return 0
-}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml b/Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml
new file mode 100644
index 000000000..ad584f4da
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+ - tip
+before_install:
+ - go get github.com/axw/gocov/gocov
+ - go get github.com/mattn/goveralls
+ - go get golang.org/x/tools/cmd/cover
+script:
+ - $HOME/gopath/bin/goveralls -repotoken lAKAWPzcGsD3A8yBX3BGGtRUdJ6CaGERL
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd b/Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd
new file mode 100644
index 000000000..4f0d583be
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/README.mkd
@@ -0,0 +1,25 @@
+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)
+
+Provides functions to get fixed width of the character or string.
+
+Usage
+-----
+
+```go
+runewidth.StringWidth("つのだ☆HIRO") == 12
+```
+
+
+Author
+------
+
+Yasuhiro Matsumoto
+
+License
+-------
+
+under the MIT License: http://mattn.mit-license.org/2013
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go
new file mode 100644
index 000000000..0b417db15
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth.go
@@ -0,0 +1,404 @@
+package runewidth
+
+var EastAsianWidth = IsEastAsian()
+var DefaultCondition = &Condition{EastAsianWidth}
+
+type interval struct {
+ first rune
+ last rune
+}
+
+var combining = []interval{
+ {0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489},
+ {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
+ {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603},
+ {0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670},
+ {0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
+ {0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
+ {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902},
+ {0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D},
+ {0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981},
+ {0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD},
+ {0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C},
+ {0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
+ {0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC},
+ {0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD},
+ {0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C},
+ {0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D},
+ {0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0},
+ {0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48},
+ {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC},
+ {0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
+ {0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D},
+ {0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6},
+ {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
+ {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
+ {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
+ {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E},
+ {0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97},
+ {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030},
+ {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039},
+ {0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F},
+ {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
+ {0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD},
+ {0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD},
+ {0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922},
+ {0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B},
+ {0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34},
+ {0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42},
+ {0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF},
+ {0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063},
+ {0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F},
+ {0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
+ {0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
+ {0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB},
+ {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
+ {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169},
+ {0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
+ {0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
+ {0xE0100, 0xE01EF},
+}
+
+type ctype int
+
+const (
+ narrow ctype = iota
+ ambiguous
+ wide
+ halfwidth
+ fullwidth
+ neutral
+)
+
+type intervalType struct {
+ first rune
+ last rune
+ ctype ctype
+}
+
+var ctypes = []intervalType{
+ {0x0020, 0x007E, narrow},
+ {0x00A1, 0x00A1, ambiguous},
+ {0x00A2, 0x00A3, narrow},
+ {0x00A4, 0x00A4, ambiguous},
+ {0x00A5, 0x00A6, narrow},
+ {0x00A7, 0x00A8, ambiguous},
+ {0x00AA, 0x00AA, ambiguous},
+ {0x00AC, 0x00AC, narrow},
+ {0x00AD, 0x00AE, ambiguous},
+ {0x00AF, 0x00AF, narrow},
+ {0x00B0, 0x00B4, ambiguous},
+ {0x00B6, 0x00BA, ambiguous},
+ {0x00BC, 0x00BF, ambiguous},
+ {0x00C6, 0x00C6, ambiguous},
+ {0x00D0, 0x00D0, ambiguous},
+ {0x00D7, 0x00D8, ambiguous},
+ {0x00DE, 0x00E1, ambiguous},
+ {0x00E6, 0x00E6, ambiguous},
+ {0x00E8, 0x00EA, ambiguous},
+ {0x00EC, 0x00ED, ambiguous},
+ {0x00F0, 0x00F0, ambiguous},
+ {0x00F2, 0x00F3, ambiguous},
+ {0x00F7, 0x00FA, ambiguous},
+ {0x00FC, 0x00FC, ambiguous},
+ {0x00FE, 0x00FE, ambiguous},
+ {0x0101, 0x0101, ambiguous},
+ {0x0111, 0x0111, ambiguous},
+ {0x0113, 0x0113, ambiguous},
+ {0x011B, 0x011B, ambiguous},
+ {0x0126, 0x0127, ambiguous},
+ {0x012B, 0x012B, ambiguous},
+ {0x0131, 0x0133, ambiguous},
+ {0x0138, 0x0138, ambiguous},
+ {0x013F, 0x0142, ambiguous},
+ {0x0144, 0x0144, ambiguous},
+ {0x0148, 0x014B, ambiguous},
+ {0x014D, 0x014D, ambiguous},
+ {0x0152, 0x0153, ambiguous},
+ {0x0166, 0x0167, ambiguous},
+ {0x016B, 0x016B, ambiguous},
+ {0x01CE, 0x01CE, ambiguous},
+ {0x01D0, 0x01D0, ambiguous},
+ {0x01D2, 0x01D2, ambiguous},
+ {0x01D4, 0x01D4, ambiguous},
+ {0x01D6, 0x01D6, ambiguous},
+ {0x01D8, 0x01D8, ambiguous},
+ {0x01DA, 0x01DA, ambiguous},
+ {0x01DC, 0x01DC, ambiguous},
+ {0x0251, 0x0251, ambiguous},
+ {0x0261, 0x0261, ambiguous},
+ {0x02C4, 0x02C4, ambiguous},
+ {0x02C7, 0x02C7, ambiguous},
+ {0x02C9, 0x02CB, ambiguous},
+ {0x02CD, 0x02CD, ambiguous},
+ {0x02D0, 0x02D0, ambiguous},
+ {0x02D8, 0x02DB, ambiguous},
+ {0x02DD, 0x02DD, ambiguous},
+ {0x02DF, 0x02DF, ambiguous},
+ {0x0300, 0x036F, ambiguous},
+ {0x0391, 0x03A2, ambiguous},
+ {0x03A3, 0x03A9, ambiguous},
+ {0x03B1, 0x03C1, ambiguous},
+ {0x03C3, 0x03C9, ambiguous},
+ {0x0401, 0x0401, ambiguous},
+ {0x0410, 0x044F, ambiguous},
+ {0x0451, 0x0451, ambiguous},
+ {0x1100, 0x115F, wide},
+ {0x2010, 0x2010, ambiguous},
+ {0x2013, 0x2016, ambiguous},
+ {0x2018, 0x2019, ambiguous},
+ {0x201C, 0x201D, ambiguous},
+ {0x2020, 0x2022, ambiguous},
+ {0x2024, 0x2027, ambiguous},
+ {0x2030, 0x2030, ambiguous},
+ {0x2032, 0x2033, ambiguous},
+ {0x2035, 0x2035, ambiguous},
+ {0x203B, 0x203B, ambiguous},
+ {0x203E, 0x203E, ambiguous},
+ {0x2074, 0x2074, ambiguous},
+ {0x207F, 0x207F, ambiguous},
+ {0x2081, 0x2084, ambiguous},
+ {0x20A9, 0x20A9, halfwidth},
+ {0x20AC, 0x20AC, ambiguous},
+ {0x2103, 0x2103, ambiguous},
+ {0x2105, 0x2105, ambiguous},
+ {0x2109, 0x2109, ambiguous},
+ {0x2113, 0x2113, ambiguous},
+ {0x2116, 0x2116, ambiguous},
+ {0x2121, 0x2122, ambiguous},
+ {0x2126, 0x2126, ambiguous},
+ {0x212B, 0x212B, ambiguous},
+ {0x2153, 0x2154, ambiguous},
+ {0x215B, 0x215E, ambiguous},
+ {0x2160, 0x216B, ambiguous},
+ {0x2170, 0x2179, ambiguous},
+ {0x2189, 0x218A, ambiguous},
+ {0x2190, 0x2199, ambiguous},
+ {0x21B8, 0x21B9, ambiguous},
+ {0x21D2, 0x21D2, ambiguous},
+ {0x21D4, 0x21D4, ambiguous},
+ {0x21E7, 0x21E7, ambiguous},
+ {0x2200, 0x2200, ambiguous},
+ {0x2202, 0x2203, ambiguous},
+ {0x2207, 0x2208, ambiguous},
+ {0x220B, 0x220B, ambiguous},
+ {0x220F, 0x220F, ambiguous},
+ {0x2211, 0x2211, ambiguous},
+ {0x2215, 0x2215, ambiguous},
+ {0x221A, 0x221A, ambiguous},
+ {0x221D, 0x2220, ambiguous},
+ {0x2223, 0x2223, ambiguous},
+ {0x2225, 0x2225, ambiguous},
+ {0x2227, 0x222C, ambiguous},
+ {0x222E, 0x222E, ambiguous},
+ {0x2234, 0x2237, ambiguous},
+ {0x223C, 0x223D, ambiguous},
+ {0x2248, 0x2248, ambiguous},
+ {0x224C, 0x224C, ambiguous},
+ {0x2252, 0x2252, ambiguous},
+ {0x2260, 0x2261, ambiguous},
+ {0x2264, 0x2267, ambiguous},
+ {0x226A, 0x226B, ambiguous},
+ {0x226E, 0x226F, ambiguous},
+ {0x2282, 0x2283, ambiguous},
+ {0x2286, 0x2287, ambiguous},
+ {0x2295, 0x2295, ambiguous},
+ {0x2299, 0x2299, ambiguous},
+ {0x22A5, 0x22A5, ambiguous},
+ {0x22BF, 0x22BF, ambiguous},
+ {0x2312, 0x2312, ambiguous},
+ {0x2329, 0x232A, wide},
+ {0x2460, 0x24E9, ambiguous},
+ {0x24EB, 0x254B, ambiguous},
+ {0x2550, 0x2573, ambiguous},
+ {0x2580, 0x258F, ambiguous},
+ {0x2592, 0x2595, ambiguous},
+ {0x25A0, 0x25A1, ambiguous},
+ {0x25A3, 0x25A9, ambiguous},
+ {0x25B2, 0x25B3, ambiguous},
+ {0x25B6, 0x25B7, ambiguous},
+ {0x25BC, 0x25BD, ambiguous},
+ {0x25C0, 0x25C1, ambiguous},
+ {0x25C6, 0x25C8, ambiguous},
+ {0x25CB, 0x25CB, ambiguous},
+ {0x25CE, 0x25D1, ambiguous},
+ {0x25E2, 0x25E5, ambiguous},
+ {0x25EF, 0x25EF, ambiguous},
+ {0x2605, 0x2606, ambiguous},
+ {0x2609, 0x2609, ambiguous},
+ {0x260E, 0x260F, ambiguous},
+ {0x2614, 0x2615, ambiguous},
+ {0x261C, 0x261C, ambiguous},
+ {0x261E, 0x261E, ambiguous},
+ {0x2640, 0x2640, ambiguous},
+ {0x2642, 0x2642, ambiguous},
+ {0x2660, 0x2661, ambiguous},
+ {0x2663, 0x2665, ambiguous},
+ {0x2667, 0x266A, ambiguous},
+ {0x266C, 0x266D, ambiguous},
+ {0x266F, 0x266F, ambiguous},
+ {0x269E, 0x269F, ambiguous},
+ {0x26BE, 0x26BF, ambiguous},
+ {0x26C4, 0x26CD, ambiguous},
+ {0x26CF, 0x26E1, ambiguous},
+ {0x26E3, 0x26E3, ambiguous},
+ {0x26E8, 0x26FF, ambiguous},
+ {0x273D, 0x273D, ambiguous},
+ {0x2757, 0x2757, ambiguous},
+ {0x2776, 0x277F, ambiguous},
+ {0x27E6, 0x27ED, narrow},
+ {0x2985, 0x2986, narrow},
+ {0x2B55, 0x2B59, ambiguous},
+ {0x2E80, 0x2E9A, wide},
+ {0x2E9B, 0x2EF4, wide},
+ {0x2F00, 0x2FD6, wide},
+ {0x2FF0, 0x2FFC, wide},
+ {0x3000, 0x3000, fullwidth},
+ {0x3001, 0x303E, wide},
+ {0x3041, 0x3097, wide},
+ {0x3099, 0x3100, wide},
+ {0x3105, 0x312E, wide},
+ {0x3131, 0x318F, wide},
+ {0x3190, 0x31BB, wide},
+ {0x31C0, 0x31E4, wide},
+ {0x31F0, 0x321F, wide},
+ {0x3220, 0x3247, wide},
+ {0x3248, 0x324F, ambiguous},
+ {0x3250, 0x32FF, wide},
+ {0x3300, 0x4DBF, wide},
+ {0x4E00, 0xA48D, wide},
+ {0xA490, 0xA4C7, wide},
+ {0xA960, 0xA97D, wide},
+ {0xAC00, 0xD7A4, wide},
+ {0xE000, 0xF8FF, ambiguous},
+ {0xF900, 0xFAFF, wide},
+ {0xFE00, 0xFE0F, ambiguous},
+ {0xFE10, 0xFE1A, wide},
+ {0xFE30, 0xFE53, wide},
+ {0xFE54, 0xFE67, wide},
+ {0xFE68, 0xFE6C, wide},
+ {0xFF01, 0xFF60, fullwidth},
+ {0xFF61, 0xFFBF, halfwidth},
+ {0xFFC2, 0xFFC8, halfwidth},
+ {0xFFCA, 0xFFD0, halfwidth},
+ {0xFFD2, 0xFFD8, halfwidth},
+ {0xFFDA, 0xFFDD, halfwidth},
+ {0xFFE0, 0xFFE7, fullwidth},
+ {0xFFE8, 0xFFEF, halfwidth},
+ {0xFFFD, 0xFFFE, ambiguous},
+ {0x1B000, 0x1B002, wide},
+ {0x1F100, 0x1F10A, ambiguous},
+ {0x1F110, 0x1F12D, ambiguous},
+ {0x1F130, 0x1F169, ambiguous},
+ {0x1F170, 0x1F19B, ambiguous},
+ {0x1F200, 0x1F203, wide},
+ {0x1F210, 0x1F23B, wide},
+ {0x1F240, 0x1F249, wide},
+ {0x1F250, 0x1F252, wide},
+ {0x20000, 0x2FFFE, wide},
+ {0x30000, 0x3FFFE, wide},
+ {0xE0100, 0xE01F0, ambiguous},
+ {0xF0000, 0xFFFFD, ambiguous},
+ {0x100000, 0x10FFFE, ambiguous},
+}
+
+type Condition struct {
+ EastAsianWidth bool
+}
+
+func NewCondition() *Condition {
+ return &Condition{EastAsianWidth}
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func (c *Condition) RuneWidth(r rune) int {
+ if r == 0 {
+ return 0
+ }
+ if r < 32 || (r >= 0x7f && r < 0xa0) {
+ return 1
+ }
+ for _, iv := range combining {
+ if iv.first <= r && r <= iv.last {
+ return 0
+ }
+ }
+
+ if c.EastAsianWidth && IsAmbiguousWidth(r) {
+ return 2
+ }
+
+ if r >= 0x1100 &&
+ (r <= 0x115f || r == 0x2329 || r == 0x232a ||
+ (r >= 0x2e80 && r <= 0xa4cf && r != 0x303f) ||
+ (r >= 0xac00 && r <= 0xd7a3) ||
+ (r >= 0xf900 && r <= 0xfaff) ||
+ (r >= 0xfe30 && r <= 0xfe6f) ||
+ (r >= 0xff00 && r <= 0xff60) ||
+ (r >= 0xffe0 && r <= 0xffe6) ||
+ (r >= 0x20000 && r <= 0x2fffd) ||
+ (r >= 0x30000 && r <= 0x3fffd)) {
+ return 2
+ }
+ return 1
+}
+
+func (c *Condition) StringWidth(s string) (width int) {
+ for _, r := range []rune(s) {
+ width += c.RuneWidth(r)
+ }
+ return width
+}
+
+func (c *Condition) Truncate(s string, w int, tail string) string {
+ r := []rune(s)
+ tw := StringWidth(tail)
+ w -= tw
+ width := 0
+ i := 0
+ for ; i < len(r); i++ {
+ cw := RuneWidth(r[i])
+ if width+cw > w {
+ break
+ }
+ width += cw
+ }
+ if i == len(r) {
+ return string(r[0:i])
+ }
+ return string(r[0:i]) + tail
+}
+
+// RuneWidth returns the number of cells in r.
+// See http://www.unicode.org/reports/tr11/
+func RuneWidth(r rune) int {
+ return DefaultCondition.RuneWidth(r)
+}
+
+func ct(r rune) ctype {
+ for _, iv := range ctypes {
+ if iv.first <= r && r <= iv.last {
+ return iv.ctype
+ }
+ }
+ return neutral
+}
+
+// IsAmbiguousWidth returns whether is ambiguous width or not.
+func IsAmbiguousWidth(r rune) bool {
+ return ct(r) == ambiguous
+}
+
+// IsAmbiguousWidth returns whether is ambiguous width or not.
+func IsNeutralWidth(r rune) bool {
+ return ct(r) == neutral
+}
+
+func StringWidth(s string) (width int) {
+ return DefaultCondition.StringWidth(s)
+}
+
+func Truncate(s string, w int, tail string) string {
+ return DefaultCondition.Truncate(s, w, tail)
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go
new file mode 100644
index 000000000..0ce32c5e7
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_js.go
@@ -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
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go
new file mode 100644
index 000000000..a4495909d
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_posix.go
@@ -0,0 +1,69 @@
+// +build !windows,!js
+
+package runewidth
+
+import (
+ "os"
+ "regexp"
+ "strings"
+)
+
+var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`)
+
+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
+ }
+
+ 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
+ }
+ }
+
+ mbc_max := 1
+ switch charset {
+ case "utf-8", "utf8":
+ mbc_max = 6
+ case "jis":
+ mbc_max = 8
+ case "eucjp":
+ mbc_max = 3
+ case "euckr", "euccn":
+ mbc_max = 2
+ case "sjis", "cp932", "cp51932", "cp936", "cp949", "cp950":
+ mbc_max = 2
+ case "big5":
+ mbc_max = 2
+ case "gbk", "gb2312":
+ mbc_max = 2
+ }
+
+ if mbc_max > 1 && (charset[0] != 'u' ||
+ strings.HasPrefix(locale, "ja") ||
+ strings.HasPrefix(locale, "ko") ||
+ strings.HasPrefix(locale, "zh")) {
+ return true
+ }
+ return false
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go
new file mode 100644
index 000000000..5cef3d6a4
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_test.go
@@ -0,0 +1,134 @@
+package runewidth
+
+import (
+ "testing"
+)
+
+var runewidthtests = []struct {
+ in rune
+ out int
+}{
+ {'世', 2},
+ {'界', 2},
+ {'セ', 1},
+ {'カ', 1},
+ {'イ', 1},
+ {'☆', 2}, // double width in ambiguous
+ {'\x00', 0},
+ {'\x01', 1},
+ {'\u0300', 0},
+}
+
+func TestRuneWidth(t *testing.T) {
+ c := NewCondition()
+ c.EastAsianWidth = true
+ for _, tt := range runewidthtests {
+ if out := c.RuneWidth(tt.in); out != tt.out {
+ t.Errorf("Width(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+var isambiguouswidthtests = []struct {
+ in rune
+ out bool
+}{
+ {'世', false},
+ {'■', true},
+ {'界', false},
+ {'○', true},
+ {'㈱', false},
+ {'①', true},
+ {'②', true},
+ {'③', true},
+ {'④', true},
+ {'⑤', true},
+ {'⑥', true},
+ {'⑦', true},
+ {'⑧', true},
+ {'⑨', true},
+ {'⑩', true},
+ {'⑪', true},
+ {'⑫', true},
+ {'⑬', true},
+ {'⑭', true},
+ {'⑮', true},
+ {'⑯', true},
+ {'⑰', true},
+ {'⑱', true},
+ {'⑲', true},
+ {'⑳', true},
+ {'☆', true},
+}
+
+func TestIsAmbiguousWidth(t *testing.T) {
+ for _, tt := range isambiguouswidthtests {
+ if out := IsAmbiguousWidth(tt.in); out != tt.out {
+ t.Errorf("IsAmbiguousWidth(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+var stringwidthtests = []struct {
+ in string
+ out int
+}{
+ {"■㈱の世界①", 12},
+ {"スター☆", 8},
+}
+
+func TestStringWidth(t *testing.T) {
+ c := NewCondition()
+ c.EastAsianWidth = true
+ for _, tt := range stringwidthtests {
+ if out := c.StringWidth(tt.in); out != tt.out {
+ t.Errorf("StringWidth(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+func TestStringWidthInvalid(t *testing.T) {
+ s := "こんにちわ\x00世界"
+ if out := StringWidth(s); out != 14 {
+ t.Errorf("StringWidth(%q) = %v, want %v", s, out, 14)
+ }
+}
+
+func TestTruncate(t *testing.T) {
+ s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお"
+ expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..."
+
+ if out := Truncate(s, 80, "..."); out != expected {
+ t.Errorf("Truncate(%q) = %v, want %v", s, out, expected)
+ }
+}
+
+func TestTruncateNoNeeded(t *testing.T) {
+ s := "あいうえおあい"
+ expected := "あいうえおあい"
+
+ if out := Truncate(s, 80, "..."); out != expected {
+ t.Errorf("Truncate(%q) = %v, want %v", s, out, expected)
+ }
+}
+
+var isneutralwidthtests = []struct {
+ in rune
+ out bool
+}{
+ {'→', false},
+ {'┊', false},
+ {'┈', false},
+ {'~', false},
+ {'└', false},
+ {'⣀', true},
+ {'⣀', true},
+}
+
+func TestIsNeutralWidth(t *testing.T) {
+ for _, tt := range isneutralwidthtests {
+ if out := IsNeutralWidth(tt.in); out != tt.out {
+ t.Errorf("IsNeutralWidth(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go
new file mode 100644
index 000000000..bdd84454b
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/mattn/go-runewidth/runewidth_windows.go
@@ -0,0 +1,24 @@
+package runewidth
+
+import (
+ "syscall"
+)
+
+var (
+ kernel32 = syscall.NewLazyDLL("kernel32")
+ procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP")
+)
+
+func IsEastAsian() bool {
+ r1, _, _ := procGetConsoleOutputCP.Call()
+ if r1 == 0 {
+ return false
+ }
+
+ switch int(r1) {
+ case 932, 51932, 936, 949, 950:
+ return true
+ }
+
+ return false
+}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/AUTHORS b/Godeps/_workspace/src/github.com/nsf/termbox-go/AUTHORS
new file mode 100644
index 000000000..fe26fb0fb
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/AUTHORS
@@ -0,0 +1,4 @@
+# Please keep this file sorted.
+
+Georg Reinke
+nsf
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/LICENSE b/Godeps/_workspace/src/github.com/nsf/termbox-go/LICENSE
new file mode 100644
index 000000000..d9bc068ce
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2012 termbox-go authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md
new file mode 100644
index 000000000..334d75102
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md
@@ -0,0 +1,21 @@
+## 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.
+ - [gomatrix](https://github.com/GeertJohan/gomatrix) connects to The Matrix and displays its data streams in your terminal.
+ - [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/michaeldv/mop) is stock market tracker for hackers.
+ - [termui](https://github.com/gizak/termui) is a terminal dashboard.
+
+### API reference
+[godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go
new file mode 100644
index 000000000..b08bca61a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go
@@ -0,0 +1,451 @@
+// +build !windows
+
+package termbox
+
+import "github.com/mattn/go-runewidth"
+import "fmt"
+import "os"
+import "os/signal"
+import "syscall"
+import "runtime"
+
+// 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.Oflag &^= syscall_OPOST
+ 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}
+ ok := extract_event(data, &event)
+ if !ok {
+ 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 {
+ var event Event
+
+ // try to extract event from input buffer, return on success
+ event.Type = EventKey
+ ok := extract_event(inbuf, &event)
+ if event.N != 0 {
+ copy(inbuf, inbuf[event.N:])
+ inbuf = inbuf[:len(inbuf)-event.N]
+ }
+ if ok {
+ 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
+ ok := extract_event(inbuf, &event)
+ if event.N != 0 {
+ copy(inbuf, inbuf[event.N:])
+ inbuf = inbuf[:len(inbuf)-event.N]
+ }
+ if ok {
+ 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
+ }
+ }
+ panic("unreachable")
+}
+
+// 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() (int, 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 click 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 {
+ 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:
+// 0x00 - 0x07: the 8 colors as in OutputNormal
+// 0x08 - 0x0f: Color* | AttrBold
+// 0x10 - 0xe7: 216 different colors
+// 0xe8 - 0xff: 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 dont need to provide an offset.
+//
+// 4. OutputGrayscale => [1..24]
+// This mode supports the 4th range of the 256 mode only.
+// But you dont need to provide an offset.
+//
+// In all modes, 0 represents the default color.
+//
+// `go run _demos/output.go` to see its impact on your terminal.
+//
+// If 'mode' is OutputCurrent, it returns the current output mode.
+//
+// Note that this may return a different OutputMode than the one requested,
+// as the requested mode may not be available on the target platform.
+func SetOutputMode(mode OutputMode) OutputMode {
+ if mode == OutputCurrent {
+ return output_mode
+ }
+
+ output_mode = mode
+ return output_mode
+}
+
+// Sync comes handy when something causes desync between termbox's understanding
+// of a terminal buffer and the reality. Such as a third party process. Sync
+// forces a complete resync between the termbox and a terminal, it may not be
+// visually pretty though.
+func Sync() error {
+ front_buffer.clear()
+ err := send_clear()
+ if err != nil {
+ return err
+ }
+
+ return Flush()
+}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go
new file mode 100644
index 000000000..c0069fb28
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_common.go
@@ -0,0 +1,183 @@
+// 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
+)
+
+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 = 0x01
+)
+
+// 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 attibutes.
+// For example windows console doesn't support AttrUnderline. And on some
+// terminals applying AttrBold to background may result in blinking text. Use
+// them with caution and test your code on various terminals.
+const (
+ AttrBold Attribute = 1 << (iota + 9)
+ AttrUnderline
+ AttrReverse
+)
+
+// Input mode. See SetInputMode function.
+const (
+ InputEsc InputMode = 1 << iota
+ InputAlt
+ InputMouse
+ InputCurrent InputMode = 0
+)
+
+// Output mode. See SetOutputMode function.
+const (
+ OutputCurrent OutputMode = iota
+ OutputNormal
+ Output256
+ Output216
+ OutputGrayscale
+)
+
+// Event type. See Event.Type field.
+const (
+ EventKey EventType = iota
+ EventResize
+ EventMouse
+ EventError
+ EventInterrupt
+ EventRaw
+ EventNone
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go
new file mode 100644
index 000000000..78d954b36
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go
@@ -0,0 +1,235 @@
+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)
+ <-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 click events.
+//
+// If 'mode' is InputCurrent, returns the current input mode. See also Input*
+// constants.
+func SetInputMode(mode InputMode) InputMode {
+ if mode == InputCurrent {
+ return input_mode
+ }
+ if mode&InputMouse != 0 {
+ err := set_console_mode(in, enable_window_input|enable_mouse_input|enable_extended_flags)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ err := set_console_mode(in, enable_window_input)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ input_mode = mode
+ return input_mode
+}
+
+// Sets the termbox output mode.
+//
+// Windows console does not support extra colour modes,
+// so this will always set and return OutputNormal.
+func SetOutputMode(mode OutputMode) OutputMode {
+ return OutputNormal
+}
+
+// Sync comes handy when something causes desync between termbox's understanding
+// of a terminal buffer and the reality. Such as a third party process. Sync
+// forces a complete resync between the termbox and a terminal, it may not be
+// visually pretty though. At the moment on Windows it does nothing.
+func Sync() error {
+ return nil
+}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/collect_terminfo.py b/Godeps/_workspace/src/github.com/nsf/termbox-go/collect_terminfo.py
new file mode 100644
index 000000000..5e50975e6
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/collect_terminfo.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+
+import sys, os, subprocess
+
+def escaped(s):
+ return repr(s)[1:-1]
+
+def tput(term, name):
+ try:
+ return subprocess.check_output(['tput', '-T%s' % term, name]).decode()
+ except subprocess.CalledProcessError as e:
+ return e.output.decode()
+
+
+def w(s):
+ if s == None:
+ return
+ sys.stdout.write(s)
+
+terminals = {
+ 'xterm' : 'xterm',
+ 'rxvt-256color' : 'rxvt_256color',
+ 'rxvt-unicode' : 'rxvt_unicode',
+ 'linux' : 'linux',
+ 'Eterm' : 'eterm',
+ 'screen' : 'screen'
+}
+
+keys = [
+ "F1", "kf1",
+ "F2", "kf2",
+ "F3", "kf3",
+ "F4", "kf4",
+ "F5", "kf5",
+ "F6", "kf6",
+ "F7", "kf7",
+ "F8", "kf8",
+ "F9", "kf9",
+ "F10", "kf10",
+ "F11", "kf11",
+ "F12", "kf12",
+ "INSERT", "kich1",
+ "DELETE", "kdch1",
+ "HOME", "khome",
+ "END", "kend",
+ "PGUP", "kpp",
+ "PGDN", "knp",
+ "KEY_UP", "kcuu1",
+ "KEY_DOWN", "kcud1",
+ "KEY_LEFT", "kcub1",
+ "KEY_RIGHT", "kcuf1"
+]
+
+funcs = [
+ "T_ENTER_CA", "smcup",
+ "T_EXIT_CA", "rmcup",
+ "T_SHOW_CURSOR", "cnorm",
+ "T_HIDE_CURSOR", "civis",
+ "T_CLEAR_SCREEN", "clear",
+ "T_SGR0", "sgr0",
+ "T_UNDERLINE", "smul",
+ "T_BOLD", "bold",
+ "T_BLINK", "blink",
+ "T_REVERSE", "rev",
+ "T_ENTER_KEYPAD", "smkx",
+ "T_EXIT_KEYPAD", "rmkx"
+]
+
+def iter_pairs(iterable):
+ iterable = iter(iterable)
+ while True:
+ yield (next(iterable), next(iterable))
+
+def do_term(term, nick):
+ w("// %s\n" % term)
+ w("var %s_keys = []string{\n\t" % nick)
+ for k, v in iter_pairs(keys):
+ w('"')
+ w(escaped(tput(term, v)))
+ w('",')
+ w("\n}\n")
+ w("var %s_funcs = []string{\n\t" % nick)
+ for k,v in iter_pairs(funcs):
+ w('"')
+ if v == "sgr":
+ w("\\033[3%d;4%dm")
+ elif v == "cup":
+ w("\\033[%d;%dH")
+ else:
+ w(escaped(tput(term, v)))
+ w('", ')
+ w("\n}\n\n")
+
+def do_terms(d):
+ w("var terms = []struct {\n")
+ w("\tname string\n")
+ w("\tkeys []string\n")
+ w("\tfuncs []string\n")
+ w("}{\n")
+ for k, v in d.items():
+ w('\t{"%s", %s_keys, %s_funcs},\n' % (k, v, v))
+ w("}\n\n")
+
+w("// +build !windows\n\npackage termbox\n\n")
+
+for k,v in terminals.items():
+ do_term(k, v)
+
+do_terms(terminals)
+
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls.go
new file mode 100644
index 000000000..4f52bb9af
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls.go
@@ -0,0 +1,39 @@
+// +build ignore
+
+package termbox
+
+/*
+#include
+#include
+*/
+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
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go
new file mode 100644
index 000000000..e03624ebc
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
new file mode 100644
index 000000000..11f25be79
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_amd64.go
@@ -0,0 +1,40 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint64
+ Oflag uint64
+ Cflag uint64
+ Lflag uint64
+ Cc [20]uint8
+ Pad_cgo_0 [4]byte
+ Ispeed uint64
+ Ospeed uint64
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x40487413
+ syscall_TCSETS = 0x80487414
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_freebsd.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_freebsd.go
new file mode 100644
index 000000000..e03624ebc
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_freebsd.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed uint32
+ Ospeed uint32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_linux.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_linux.go
new file mode 100644
index 000000000..b88960de6
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_linux.go
@@ -0,0 +1,33 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+import "syscall"
+
+type syscall_Termios syscall.Termios
+
+const (
+ syscall_IGNBRK = syscall.IGNBRK
+ syscall_BRKINT = syscall.BRKINT
+ syscall_PARMRK = syscall.PARMRK
+ syscall_ISTRIP = syscall.ISTRIP
+ syscall_INLCR = syscall.INLCR
+ syscall_IGNCR = syscall.IGNCR
+ syscall_ICRNL = syscall.ICRNL
+ syscall_IXON = syscall.IXON
+ syscall_OPOST = syscall.OPOST
+ syscall_ECHO = syscall.ECHO
+ syscall_ECHONL = syscall.ECHONL
+ syscall_ICANON = syscall.ICANON
+ syscall_ISIG = syscall.ISIG
+ syscall_IEXTEN = syscall.IEXTEN
+ syscall_CSIZE = syscall.CSIZE
+ syscall_PARENB = syscall.PARENB
+ syscall_CS8 = syscall.CS8
+ syscall_VMIN = syscall.VMIN
+ syscall_VTIME = syscall.VTIME
+
+ syscall_TCGETS = syscall.TCGETS
+ syscall_TCSETS = syscall.TCSETS
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_netbsd.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_netbsd.go
new file mode 100644
index 000000000..49a3355b9
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_netbsd.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_openbsd.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_openbsd.go
new file mode 100644
index 000000000..49a3355b9
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_openbsd.go
@@ -0,0 +1,39 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs syscalls.go
+
+package termbox
+
+type syscall_Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Cc [20]uint8
+ Ispeed int32
+ Ospeed int32
+}
+
+const (
+ syscall_IGNBRK = 0x1
+ syscall_BRKINT = 0x2
+ syscall_PARMRK = 0x8
+ syscall_ISTRIP = 0x20
+ syscall_INLCR = 0x40
+ syscall_IGNCR = 0x80
+ syscall_ICRNL = 0x100
+ syscall_IXON = 0x200
+ syscall_OPOST = 0x1
+ syscall_ECHO = 0x8
+ syscall_ECHONL = 0x10
+ syscall_ICANON = 0x100
+ syscall_ISIG = 0x80
+ syscall_IEXTEN = 0x400
+ syscall_CSIZE = 0x300
+ syscall_PARENB = 0x1000
+ syscall_CS8 = 0x300
+ syscall_VMIN = 0x10
+ syscall_VTIME = 0x11
+
+ syscall_TCGETS = 0x402c7413
+ syscall_TCSETS = 0x802c7414
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_windows.go
new file mode 100644
index 000000000..472d002a5
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_windows.go
@@ -0,0 +1,61 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -DUNICODE syscalls.go
+
+package termbox
+
+const (
+ foreground_blue = 0x1
+ foreground_green = 0x2
+ foreground_red = 0x4
+ foreground_intensity = 0x8
+ background_blue = 0x10
+ background_green = 0x20
+ background_red = 0x40
+ background_intensity = 0x80
+ std_input_handle = -0xa
+ std_output_handle = -0xb
+ key_event = 0x1
+ mouse_event = 0x2
+ window_buffer_size_event = 0x4
+ enable_window_input = 0x8
+ enable_mouse_input = 0x10
+ enable_extended_flags = 0x80
+
+ vk_f1 = 0x70
+ vk_f2 = 0x71
+ vk_f3 = 0x72
+ vk_f4 = 0x73
+ vk_f5 = 0x74
+ vk_f6 = 0x75
+ vk_f7 = 0x76
+ vk_f8 = 0x77
+ vk_f9 = 0x78
+ vk_f10 = 0x79
+ vk_f11 = 0x7a
+ vk_f12 = 0x7b
+ vk_insert = 0x2d
+ vk_delete = 0x2e
+ vk_home = 0x24
+ vk_end = 0x23
+ vk_pgup = 0x21
+ vk_pgdn = 0x22
+ vk_arrow_up = 0x26
+ vk_arrow_down = 0x28
+ vk_arrow_left = 0x25
+ vk_arrow_right = 0x27
+ vk_backspace = 0x8
+ vk_tab = 0x9
+ vk_enter = 0xd
+ vk_esc = 0x1b
+ vk_space = 0x20
+
+ left_alt_pressed = 0x2
+ left_ctrl_pressed = 0x8
+ right_alt_pressed = 0x1
+ right_ctrl_pressed = 0x4
+ shift_pressed = 0x10
+
+ generic_read = 0x80000000
+ generic_write = 0x40000000
+ console_textmode_buffer = 0x1
+)
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go
new file mode 100644
index 000000000..0aee8aca9
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go
@@ -0,0 +1,407 @@
+// +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
+}
+
+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)
+)
+
+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 > 24 {
+ fgcol = ColorDefault
+ }
+ if bgcol > 24 {
+ bgcol = ColorDefault
+ }
+ if fgcol != ColorDefault {
+ fgcol += 0xe8
+ }
+ if bgcol != ColorDefault {
+ bgcol += 0xe8
+ }
+ 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()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+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_escape_sequence(event *Event, buf []byte) (int, bool) {
+ bufstr := string(buf)
+ // mouse
+ if len(bufstr) >= 6 && strings.HasPrefix(bufstr, "\033[M") {
+ switch buf[3] & 3 {
+ case 0:
+ event.Key = MouseLeft
+ case 1:
+ event.Key = MouseMiddle
+ case 2:
+ event.Key = MouseRight
+ case 3:
+ return 6, false
+ }
+ event.Type = EventMouse // KeyEvent by default
+ // wheel up outputs MouseLeft
+ if buf[3] == 0x60 || buf[3] == 0x70 {
+ event.Key = MouseMiddle
+ }
+ // 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
+ }
+
+ for i, key := range keys {
+ if strings.HasPrefix(bufstr, key) {
+ event.Ch = 0
+ event.Key = Key(0xFFFF - i)
+ return len(key), true
+ }
+ }
+ return 0, true
+}
+
+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) bool {
+ if len(inbuf) == 0 {
+ event.N = 0
+ return false
+ }
+
+ if inbuf[0] == '\033' {
+ // possible escape sequence
+ n, ok := parse_escape_sequence(event, inbuf)
+ if n != 0 {
+ event.N = n
+ return ok
+ }
+
+ // 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 true
+ case input_mode&InputAlt != 0:
+ // if we're in alt mode, set Alt modifier to event and redo parsing
+ event.Mod = ModAlt
+ ok := extract_event(inbuf[1:], event)
+ if ok {
+ event.N++
+ } else {
+ event.N = 0
+ }
+ return ok
+ 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 true
+ }
+
+ // 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 true
+ }
+
+ return false
+}
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r, _, e := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), uintptr(cmd),
+ uintptr(arg))
+ val = int(r)
+ if e != 0 {
+ err = e
+ }
+ return
+}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_common.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_common.go
new file mode 100644
index 000000000..c3355cc25
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_common.go
@@ -0,0 +1,59 @@
+package termbox
+
+// private API, common OS agnostic part
+
+type cellbuf struct {
+ width int
+ height int
+ cells []Cell
+}
+
+func (this *cellbuf) init(width, height int) {
+ this.width = width
+ this.height = height
+ this.cells = make([]Cell, width*height)
+}
+
+func (this *cellbuf) resize(width, height int) {
+ if this.width == width && this.height == height {
+ return
+ }
+
+ oldw := this.width
+ oldh := this.height
+ oldcells := this.cells
+
+ this.init(width, height)
+ this.clear()
+
+ minw, minh := oldw, oldh
+
+ if width < minw {
+ minw = width
+ }
+ if height < minh {
+ minh = height
+ }
+
+ for i := 0; i < minh; i++ {
+ srco, dsto := i*oldw, i*width
+ src := oldcells[srco : srco+minw]
+ dst := this.cells[dsto : dsto+minw]
+ copy(dst, src)
+ }
+}
+
+func (this *cellbuf) clear() {
+ for i := range this.cells {
+ c := &this.cells[i]
+ c.Ch = ' '
+ c.Fg = foreground
+ c.Bg = background
+ }
+}
+
+const cursor_hidden = -1
+
+func is_cursor_hidden(x, y int) bool {
+ return x == cursor_hidden || y == cursor_hidden
+}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go
new file mode 100644
index 000000000..17d1bdc84
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go
@@ -0,0 +1,813 @@
+package termbox
+
+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
+ }
+)
+
+const (
+ mouse_lmb = 0x1
+ mouse_rmb = 0x2
+ mouse_mmb = 0x4 | 0x8 | 0x10
+)
+
+func (this coord) uintptr() uintptr {
+ return uintptr(*(*int32)(unsafe.Pointer(&this)))
+}
+
+var kernel32 = syscall.NewLazyDLL("kernel32.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")
+)
+
+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), nil
+}
+
+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), nil
+}
+
+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
+}
+
+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}
+)
+
+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_size(out syscall.Handle) coord {
+ err := get_console_screen_buffer_info(out, &tmp_info)
+ if err != nil {
+ panic(err)
+ }
+ return coord{
+ x: tmp_info.window.right - tmp_info.window.left + 1,
+ y: tmp_info.window.bottom - tmp_info.window.top + 1,
+ }
+}
+
+func update_size_maybe() {
+ size := get_term_size(out)
+ if size.x != term_size.x || size.y != term_size.y {
+ 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 cell_to_char_info(c Cell) (attr word, wc [2]wchar) {
+ attr = color_table_fg[c.Fg&0x0F] | color_table_bg[c.Bg&0x0F]
+ 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_state = dword(0)
+ 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))
+
+ // single or double click
+ switch mr.event_flags {
+ case 0:
+ cur_state := mr.button_state
+ switch {
+ case last_state&mouse_lmb == 0 && cur_state&mouse_lmb != 0:
+ last_button = MouseLeft
+ case last_state&mouse_rmb == 0 && cur_state&mouse_rmb != 0:
+ last_button = MouseRight
+ case last_state&mouse_mmb == 0 && cur_state&mouse_mmb != 0:
+ last_button = MouseMiddle
+ default:
+ last_state = cur_state
+ continue
+ }
+ last_state = cur_state
+ fallthrough
+ case 2:
+ input_comm <- Event{
+ Type: EventMouse,
+ Key: last_button,
+ MouseX: int(mr.mouse_pos.x),
+ MouseY: int(mr.mouse_pos.y),
+ }
+ }
+ }
+ }
+}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go
new file mode 100644
index 000000000..3569e3c0e
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo.go
@@ -0,0 +1,219 @@
+// +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
+)
+
+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
+ }
+ }
+ }
+
+ // 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
+ }
+
+ 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] + 2*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] = "\x1b[?1000h"
+ funcs[t_max_funcs-1] = "\x1b[?1000l"
+ return nil
+}
+
+func ti_read_string(rd *bytes.Reader, str_off, table int16) (string, error) {
+ var off int16
+
+ _, err := rd.Seek(int64(str_off), 0)
+ if err != nil {
+ return "", err
+ }
+ err = binary.Read(rd, binary.LittleEndian, &off)
+ if err != nil {
+ return "", err
+ }
+ _, err = rd.Seek(int64(table+off), 0)
+ if err != nil {
+ return "", err
+ }
+ var bs []byte
+ for {
+ b, err := rd.ReadByte()
+ if err != nil {
+ return "", err
+ }
+ if b == byte(0x00) {
+ break
+ }
+ bs = append(bs, b)
+ }
+ return string(bs), nil
+}
+
+// "Maps" the function constants from termbox.go to the number of the respective
+// string capability in the terminfo file. Taken from (ncurses) term.h.
+var ti_funcs = []int16{
+ 28, 40, 16, 13, 5, 39, 36, 27, 26, 34, 89, 88,
+}
+
+// Same as above for the special keys.
+var ti_keys = []int16{
+ 66, 68 /* apparently not a typo; 67 is F10 for whatever reason */, 69, 70,
+ 71, 72, 73, 74, 75, 67, 216, 217, 77, 59, 76, 164, 82, 81, 87, 61, 79, 83,
+}
diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go
new file mode 100644
index 000000000..6f927c852
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/terminfo_builtin.go
@@ -0,0 +1,64 @@
+// +build !windows
+
+package termbox
+
+// Eterm
+var eterm_keys = []string{
+ "\x1b[11~", "\x1b[12~", "\x1b[13~", "\x1b[14~", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[7~", "\x1b[8~", "\x1b[5~", "\x1b[6~", "\x1b[A", "\x1b[B", "\x1b[D", "\x1b[C",
+}
+var eterm_funcs = []string{
+ "\x1b7\x1b[?47h", "\x1b[2J\x1b[?47l\x1b8", "\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[2J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "", "", "", "",
+}
+
+// screen
+var screen_keys = []string{
+ "\x1bOP", "\x1bOQ", "\x1bOR", "\x1bOS", "\x1b[15~", "\x1b[17~", "\x1b[18~", "\x1b[19~", "\x1b[20~", "\x1b[21~", "\x1b[23~", "\x1b[24~", "\x1b[2~", "\x1b[3~", "\x1b[1~", "\x1b[4~", "\x1b[5~", "\x1b[6~", "\x1bOA", "\x1bOB", "\x1bOD", "\x1bOC",
+}
+var screen_funcs = []string{
+ "\x1b[?1049h", "\x1b[?1049l", "\x1b[34h\x1b[?25h", "\x1b[?25l", "\x1b[H\x1b[J", "\x1b[m\x0f", "\x1b[4m", "\x1b[1m", "\x1b[5m", "\x1b[7m", "\x1b[?1h\x1b=", "\x1b[?1l\x1b>", "\x1b[?1000h", "\x1b[?1000l",
+}
+
+// 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>", "\x1b[?1000h", "\x1b[?1000l",
+}
+
+// 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>", "\x1b[?1000h", "\x1b[?1000l",
+}
+
+// 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>", "\x1b[?1000h", "\x1b[?1000l",
+}
+
+var terms = []struct {
+ name string
+ keys []string
+ funcs []string
+}{
+ {"Eterm", eterm_keys, eterm_funcs},
+ {"screen", screen_keys, screen_funcs},
+ {"xterm", xterm_keys, xterm_funcs},
+ {"rxvt-unicode", rxvt_unicode_keys, rxvt_unicode_funcs},
+ {"linux", linux_keys, linux_funcs},
+ {"rxvt-256color", rxvt_256color_keys, rxvt_256color_funcs},
+}
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/.gitignore b/Godeps/_workspace/src/github.com/obscuren/qml/.gitignore
deleted file mode 100644
index e4b7f45b7..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-examples/qmlscene/qmlscene
-examples/snapweb/snapweb
-examples/particle/particle
-gl/gengl/gengl
-*.swp
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/LICENSE b/Godeps/_workspace/src/github.com/obscuren/qml/LICENSE
deleted file mode 100644
index 53320c352..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/LICENSE
+++ /dev/null
@@ -1,185 +0,0 @@
-This software is licensed under the LGPLv3, included below.
-
-As a special exception to the GNU Lesser General Public License version 3
-("LGPL3"), the copyright holders of this Library give you permission to
-convey to a third party a Combined Work that links statically or dynamically
-to this Library without providing any Minimal Corresponding Source or
-Minimal Application Code as set out in 4d or providing the installation
-information set out in section 4e, provided that you comply with the other
-provisions of LGPL3 and provided that you meet, for the Application the
-terms and conditions of the license(s) which apply to the Application.
-
-Except as stated in this special exception, the provisions of LGPL3 will
-continue to comply in full to this Library. If you modify this Library, you
-may apply this exception to your version of this Library, but you are not
-obliged to do so. If you do not wish to do so, delete this exception
-statement from your version. This exception does not (and cannot) modify any
-license terms which apply to the Application, with which you must still
-comply.
-
-
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
- This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
- 0. Additional Definitions.
-
- As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
- "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
- An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
- A "Combined Work" is a work produced by combining or linking an
-Application with the Library. The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
- The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
- The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
- 1. Exception to Section 3 of the GNU GPL.
-
- You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
- 2. Conveying Modified Versions.
-
- If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
- a) under this License, provided that you make a good faith effort to
- ensure that, in the event an Application does not supply the
- function or data, the facility still operates, and performs
- whatever part of its purpose remains meaningful, or
-
- b) under the GNU GPL, with none of the additional permissions of
- this License applicable to that copy.
-
- 3. Object Code Incorporating Material from Library Header Files.
-
- The object code form of an Application may incorporate material from
-a header file that is part of the Library. You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
- a) Give prominent notice with each copy of the object code that the
- Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the object code with a copy of the GNU GPL and this license
- document.
-
- 4. Combined Works.
-
- You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
- a) Give prominent notice with each copy of the Combined Work that
- the Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
- document.
-
- c) For a Combined Work that displays copyright notices during
- execution, include the copyright notice for the Library among
- these notices, as well as a reference directing the user to the
- copies of the GNU GPL and this license document.
-
- d) Do one of the following:
-
- 0) Convey the Minimal Corresponding Source under the terms of this
- License, and the Corresponding Application Code in a form
- suitable for, and under terms that permit, the user to
- recombine or relink the Application with a modified version of
- the Linked Version to produce a modified Combined Work, in the
- manner specified by section 6 of the GNU GPL for conveying
- Corresponding Source.
-
- 1) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (a) uses at run time
- a copy of the Library already present on the user's computer
- system, and (b) will operate properly with a modified version
- of the Library that is interface-compatible with the Linked
- Version.
-
- e) Provide Installation Information, but only if you would otherwise
- be required to provide such information under section 6 of the
- GNU GPL, and only to the extent that such information is
- necessary to install and execute a modified version of the
- Combined Work produced by recombining or relinking the
- Application with a modified version of the Linked Version. (If
- you use option 4d0, the Installation Information must accompany
- the Minimal Corresponding Source and Corresponding Application
- Code. If you use option 4d1, you must provide the Installation
- Information in the manner specified by section 6 of the GNU GPL
- for conveying Corresponding Source.)
-
- 5. Combined Libraries.
-
- You may place library facilities that are a work based on the
-Library side by side in a single library together with other library
-facilities that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
- a) Accompany the combined library with a copy of the same work based
- on the Library, uncombined with any other library facilities,
- conveyed under the terms of this License.
-
- b) Give prominent notice with the combined library that part of it
- is a work based on the Library, and explaining where to find the
- accompanying uncombined form of the same work.
-
- 6. Revised Versions of the GNU Lesser General Public License.
-
- The Free Software Foundation may publish revised and/or new versions
-of the GNU Lesser General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Library as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
- If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/README.md b/Godeps/_workspace/src/github.com/obscuren/qml/README.md
deleted file mode 100644
index e969c9e1d..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/README.md
+++ /dev/null
@@ -1,157 +0,0 @@
-# QML support for the Go language
-
-Documentation
--------------
-
-The introductory documentation as well as the detailed API documentation is
-available at [gopkg.in/qml.v1](http://godoc.org/gopkg.in/qml.v1).
-
-
-Blog posts
-----------
-
-Some relevant blog posts:
-
- * [Announcing qml v1 for Go](http://blog.labix.org/2014/08/13/announcing-qml-v1-for-go)
- * [Packing resources into Go qml binaries](http://blog.labix.org/2014/09/26/packing-resources-into-go-qml-binaries)
- * [Go qml contest results](http://blog.labix.org/2014/04/25/qml-contest-results)
- * [Arbitrary Qt extensions with Go qml](http://blog.labix.org/2014/03/21/arbitrary-qt-extensions-with-go-qml)
- * [The new Go qml OpenGL API](http://blog.labix.org/2014/08/29/the-new-go-qml-opengl-api)
- * [QML components with Go and OpenGL](http://blog.labix.org/2013/12/23/qml-components-with-go-and-opengl)
-
-
-Videos
-------
-
-These introductory videos demonstrate the use of Go QML:
-
- * [Initial demo and overview](http://youtu.be/FVQlMrPa7lI)
- * [Initial demo running on an Ubuntu Touch phone](http://youtu.be/HB-3o8Cysec)
- * [Spinning Gopher with Go + QML + OpenGL](http://youtu.be/qkH7_dtOyPk)
- * [SameGame QML tutorial in Go](http://youtu.be/z8noX48hiMI)
-
-
-Community
----------
-
-Please join the [mailing list](https://groups.google.com/forum/#!forum/go-qml) for
-following relevant development news and discussing project details.
-
-
-Installation
-------------
-
-To try the alpha release you'll need:
-
- * Go >= 1.2, for the C++ support of _go build_
- * Qt 5.0.X or 5.1.X with the development files
- * The Qt headers qmetaobject_p.h and qmetaobjectbuilder_p.h, for the dynamic meta object support
-
-See below for more details about getting these requirements installed in different environments and operating systems.
-
-After the requirements are satisfied, _go get_ should work as usual:
-
- go get gopkg.in/qml.v1
-
-
-Requirements on Ubuntu
-----------------------
-
-If you are using Ubuntu, the [Ubuntu SDK](http://developer.ubuntu.com/get-started/) will take care of the Qt dependencies:
-
- $ sudo add-apt-repository ppa:ubuntu-sdk-team/ppa
- $ sudo apt-get update
- $ sudo apt-get install qtdeclarative5-dev qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev qtdeclarative5-qtquick2-plugin
-
-and Go >= 1.2 may be installed using [godeb](http://blog.labix.org/2013/06/15/in-flight-deb-packages-of-go):
-
- $ # Pick the right one for your system: 386 or amd64
- $ ARCH=amd64
- $ wget -q https://godeb.s3.amazonaws.com/godeb-$ARCH.tar.gz
- $ tar xzvf godeb-$ARCH.tar.gz
- godeb
- $ sudo mv godeb /usr/local/bin
- $ godeb install
- $ go get gopkg.in/qml.v1
-
-
-Requirements on Ubuntu Touch
-----------------------------
-
-After following the [installation instructions](https://wiki.ubuntu.com/Touch/Install) for Ubuntu Touch,
-run the following commands to get a working build environment inside the device:
-
- $ adb shell
- # cd /tmp
- # wget https://github.com/go-qml/qml/raw/v1/cmd/ubuntu-touch/setup.sh
- # /bin/bash setup.sh
- # su - phablet
- $
-
-At the end of setup.sh, the phablet user will have GOPATH=$HOME in the environment,
-the qml package will be built, and the particle example will be built and run. For
-stopping it from the command line, run as the phablet user:
-
- $ ubuntu-app-stop gopkg.in.qml.particle-example
-
-for running it again:
-
- $ ubuntu-app-launch gopkg.in.qml.particle-example
-
-These commands depend on the following file, installed by setup.sh:
-
- ~/.local/share/applications/gopkg.in.qml.particle-example.desktop
-
-
-Requirements on Mac OS X
-------------------------
-
-On Mac OS X you'll need QT5. It's easiest to install with Homebrew, a
-third-party package management system for OS X.
-
-Installation instructions for Homebrew are here:
-
- http://brew.sh/
-
-Then, install the qt5 and pkg-config packages:
-
- $ brew install qt5 pkg-config
-
-Then, force brew to "link" qt5 (this makes it available under /usr/local):
-
- $ brew link --force qt5
-
-And finally, fetch and install go-qml:
-
- $ go get gopkg.in/qml.v1
-
-
-Requirements on Windows
------------------------
-
-On Windows you'll need the following:
-
- * [MinGW gcc](http://sourceforge.net/projects/mingw/files/latest/download) 4.8.1 (install mingw-get and install the gcc from within the setup GUI)
- * [Qt 5.1.1](http://download.qt-project.org/official_releases/qt/5.1/5.1.1/qt-windows-opensource-5.1.1-mingw48_opengl-x86-offline.exe) for MinGW 4.8
- * [Go >= 1.2](http://golang.org/doc/install)
-
-Then, assuming Qt was installed under `C:\Qt5.1.1\`, set up the following environment variables in the respective configuration:
-
- CPATH += C:\Qt5.1.1\5.1.1\mingw48_32\include
- LIBRARY_PATH += C:\Qt5.1.1\5.1.1\mingw48_32\lib
- PATH += C:\Qt5.1.1\5.1.1\mingw48_32\bin
-
-After reopening the shell for the environment changes to take effect, this should work:
-
- go get gopkg.in/qml.v1
-
-
-Requirements everywhere else
-----------------------------
-
-If your operating system does not offer these dependencies readily,
-you may still have success installing [Go >= 1.2](http://golang.org/doc/install)
-and [Qt 5.0.2](http://download.qt-project.org/archive/qt/5.0/5.0.2/)
-directly from the upstreams. Note that you'll likely have to adapt
-environment variables to reflect the custom installation path for
-these libraries. See the instructions above for examples.
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/all.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/all.cpp
deleted file mode 100644
index 965867b1b..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/all.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#include "cpp/capi.cpp"
-#include "cpp/govalue.cpp"
-#include "cpp/govaluetype.cpp"
-#include "cpp/idletimer.cpp"
-#include "cpp/connector.cpp"
-
-#include "cpp/moc_all.cpp"
-
-#ifdef _WIN32
-#include "cpp/mmemwin.cpp"
-#endif
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/bridge.go b/Godeps/_workspace/src/github.com/obscuren/qml/bridge.go
deleted file mode 100644
index 77b36a566..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/bridge.go
+++ /dev/null
@@ -1,681 +0,0 @@
-package qml
-
-// #cgo CPPFLAGS: -I./cpp
-// #cgo CXXFLAGS: -std=c++0x -pedantic-errors -Wall -fno-strict-aliasing
-// #cgo LDFLAGS: -lstdc++
-// #cgo pkg-config: Qt5Core Qt5Widgets Qt5Quick
-//
-// #include
-//
-// #include "cpp/capi.h"
-//
-import "C"
-
-import (
- "fmt"
- "os"
- "reflect"
- "runtime"
- "sync/atomic"
- "unsafe"
-
- "gopkg.in/qml.v1/cdata"
-)
-
-var (
- guiFunc = make(chan func())
- guiDone = make(chan struct{})
- guiLock = 0
- guiMainRef uintptr
- guiPaintRef uintptr
- guiIdleRun int32
-
- initialized int32
-)
-
-func init() {
- runtime.LockOSThread()
- guiMainRef = cdata.Ref()
-}
-
-// Run runs the main QML event loop, runs f, and then terminates the
-// event loop once f returns.
-//
-// Most functions from the qml package block until Run is called.
-//
-// The Run function must necessarily be called from the same goroutine as
-// the main function or the application may fail when running on Mac OS.
-func Run(f func() error) error {
- if cdata.Ref() != guiMainRef {
- panic("Run must be called on the initial goroutine so apps are portable to Mac OS")
- }
- if !atomic.CompareAndSwapInt32(&initialized, 0, 1) {
- panic("qml.Run called more than once")
- }
- C.newGuiApplication()
- C.idleTimerInit((*C.int32_t)(&guiIdleRun))
- done := make(chan error, 1)
- go func() {
- RunMain(func() {}) // Block until the event loop is running.
- done <- f()
- C.applicationExit()
- }()
- C.applicationExec()
- return <-done
-}
-
-// RunMain runs f in the main QML thread and waits for f to return.
-//
-// This is meant to be used by extensions that integrate directly with the
-// underlying QML logic.
-func RunMain(f func()) {
- ref := cdata.Ref()
- if ref == guiMainRef || ref == atomic.LoadUintptr(&guiPaintRef) {
- // Already within the GUI or render threads. Attempting to wait would deadlock.
- f()
- return
- }
-
- // Tell Qt we're waiting for the idle hook to be called.
- if atomic.AddInt32(&guiIdleRun, 1) == 1 {
- C.idleTimerStart()
- }
-
- // Send f to be executed by the idle hook in the main GUI thread.
- guiFunc <- f
-
- // Wait until f is done executing.
- <-guiDone
-}
-
-// Lock freezes all QML activity by blocking the main event loop.
-// Locking is necessary before updating shared data structures
-// without race conditions.
-//
-// It's safe to use qml functionality while holding a lock, as
-// long as the requests made do not depend on follow up QML
-// events to be processed before returning. If that happens, the
-// problem will be observed as the application freezing.
-//
-// The Lock function is reentrant. That means it may be called
-// multiple times, and QML activities will only be resumed after
-// Unlock is called a matching number of times.
-func Lock() {
- // TODO Better testing for this.
- RunMain(func() {
- guiLock++
- })
-}
-
-// Unlock releases the QML event loop. See Lock for details.
-func Unlock() {
- RunMain(func() {
- if guiLock == 0 {
- panic("qml.Unlock called without lock being held")
- }
- guiLock--
- })
-}
-
-// Flush synchronously flushes all pending QML activities.
-func Flush() {
- // TODO Better testing for this.
- RunMain(func() {
- C.applicationFlushAll()
- })
-}
-
-// Changed notifies all QML bindings that the given field value has changed.
-//
-// For example:
-//
-// qml.Changed(&value, &value.Field)
-//
-func Changed(value, fieldAddr interface{}) {
- valuev := reflect.ValueOf(value)
- fieldv := reflect.ValueOf(fieldAddr)
- for valuev.Kind() == reflect.Ptr {
- valuev = valuev.Elem()
- }
- if fieldv.Kind() != reflect.Ptr {
- panic("qml.Changed received non-address value as fieldAddr")
- }
- fieldv = fieldv.Elem()
- if fieldv.Type().Size() == 0 {
- panic("cannot report changes on zero-sized fields")
- }
- offset := fieldv.UnsafeAddr() - valuev.UnsafeAddr()
- if !(0 <= offset && offset < valuev.Type().Size()) {
- panic("provided field is not a member of the given value")
- }
-
- RunMain(func() {
- tinfo := typeInfo(value)
- for _, engine := range engines {
- fold := engine.values[value]
- for fold != nil {
- C.goValueActivate(fold.cvalue, tinfo, C.int(offset))
- fold = fold.next
- }
- // TODO typeNew might also be a linked list keyed by the gvalue.
- // This would prevent the iteration and the deferrals.
- for fold, _ = range typeNew {
- if fold.gvalue == value {
- // Activate these later so they don't get recursively moved
- // out of typeNew while the iteration is still happening.
- defer C.goValueActivate(fold.cvalue, tinfo, C.int(offset))
- }
- }
- }
- })
-}
-
-// hookIdleTimer is run once per iteration of the Qt event loop,
-// within the main GUI thread, but only if at least one goroutine
-// has atomically incremented guiIdleRun.
-//
-//export hookIdleTimer
-func hookIdleTimer() {
- var f func()
- for {
- select {
- case f = <-guiFunc:
- default:
- if guiLock > 0 {
- f = <-guiFunc
- } else {
- return
- }
- }
- f()
- guiDone <- struct{}{}
- atomic.AddInt32(&guiIdleRun, -1)
- }
-}
-
-type valueFold struct {
- engine *Engine
- gvalue interface{}
- cvalue unsafe.Pointer
- init reflect.Value
- prev *valueFold
- next *valueFold
- owner valueOwner
-}
-
-type valueOwner uint8
-
-const (
- cppOwner = 1 << iota
- jsOwner
-)
-
-// wrapGoValue creates a new GoValue object in C++ land wrapping
-// the Go value contained in the given interface.
-//
-// This must be run from the main GUI thread.
-func wrapGoValue(engine *Engine, gvalue interface{}, owner valueOwner) (cvalue unsafe.Pointer) {
- gvaluev := reflect.ValueOf(gvalue)
- gvaluek := gvaluev.Kind()
- if gvaluek == reflect.Struct && !hashable(gvalue) {
- name := gvaluev.Type().Name()
- if name != "" {
- name = " (" + name + ")"
- }
- panic("cannot hand an unhashable struct value" + name + " to QML logic; use its address instead")
- }
- if gvaluek == reflect.Ptr && gvaluev.Elem().Kind() == reflect.Ptr {
- panic("cannot hand pointer of pointer to QML logic; use a simple pointer instead")
- }
-
- painting := cdata.Ref() == atomic.LoadUintptr(&guiPaintRef)
-
- // Cannot reuse a jsOwner because the QML runtime may choose to destroy
- // the value _after_ we hand it a new reference to the same value.
- // See issue #68 for details.
- prev, ok := engine.values[gvalue]
- if ok && (prev.owner == cppOwner || painting) {
- return prev.cvalue
- }
-
- if painting {
- panic("cannot allocate new objects while painting")
- }
-
- parent := nilPtr
- if owner == cppOwner {
- parent = engine.addr
- }
- fold := &valueFold{
- engine: engine,
- gvalue: gvalue,
- owner: owner,
- }
- fold.cvalue = C.newGoValue(unsafe.Pointer(fold), typeInfo(gvalue), parent)
- if prev != nil {
- // Put new fold first so the single cppOwner, if any, is always the first entry.
- fold.next = prev
- prev.prev = fold
- }
- engine.values[gvalue] = fold
-
- //fmt.Printf("[DEBUG] value alive (wrapped): cvalue=%x gvalue=%x/%#v\n", fold.cvalue, addrOf(fold.gvalue), fold.gvalue)
- stats.valuesAlive(+1)
- C.engineSetContextForObject(engine.addr, fold.cvalue)
- switch owner {
- case cppOwner:
- C.engineSetOwnershipCPP(engine.addr, fold.cvalue)
- case jsOwner:
- C.engineSetOwnershipJS(engine.addr, fold.cvalue)
- }
- return fold.cvalue
-}
-
-func addrOf(gvalue interface{}) uintptr {
- return reflect.ValueOf(gvalue).Pointer()
-}
-
-// typeNew holds fold values that are created by registered types.
-// These values are special in two senses: first, they don't have a
-// reference to an engine before they are used in a context that can
-// set the reference; second, these values always hold a new cvalue,
-// because they are created as a side-effect of the registered type
-// being instantiated (it's too late to reuse an existent cvalue).
-//
-// For these reasons, typeNew holds the fold for these values until
-// their engine is known, and once it's known they may have to be
-// added to the linked list, since mulitple references for the same
-// gvalue may occur.
-var typeNew = make(map[*valueFold]bool)
-
-//export hookGoValueTypeNew
-func hookGoValueTypeNew(cvalue unsafe.Pointer, specp unsafe.Pointer) (foldp unsafe.Pointer) {
- // Initialization is postponed until the engine is available, so that
- // we can hand Init the qml.Object that represents the object.
- init := reflect.ValueOf((*TypeSpec)(specp).Init)
- fold := &valueFold{
- init: init,
- gvalue: reflect.New(init.Type().In(0).Elem()).Interface(),
- cvalue: cvalue,
- owner: jsOwner,
- }
- typeNew[fold] = true
- //fmt.Printf("[DEBUG] value alive (type-created): cvalue=%x gvalue=%x/%#v\n", fold.cvalue, addrOf(fold.gvalue), fold.gvalue)
- stats.valuesAlive(+1)
- return unsafe.Pointer(fold)
-}
-
-//export hookGoValueDestroyed
-func hookGoValueDestroyed(enginep unsafe.Pointer, foldp unsafe.Pointer) {
- fold := (*valueFold)(foldp)
- engine := fold.engine
- if engine == nil {
- before := len(typeNew)
- delete(typeNew, fold)
- if len(typeNew) == before {
- panic("destroying value without an associated engine; who created the value?")
- }
- } else if engines[engine.addr] == nil {
- // Must never do that. The engine holds memory references that C++ depends on.
- panic(fmt.Sprintf("engine %p was released from global list while its values were still alive", engine.addr))
- } else {
- switch {
- case fold.prev != nil:
- fold.prev.next = fold.next
- if fold.next != nil {
- fold.next.prev = fold.prev
- }
- case fold.next != nil:
- fold.next.prev = fold.prev
- if fold.prev != nil {
- fold.prev.next = fold.next
- } else {
- fold.engine.values[fold.gvalue] = fold.next
- }
- default:
- before := len(engine.values)
- delete(engine.values, fold.gvalue)
- if len(engine.values) == before {
- panic("destroying value that knows about the engine, but the engine doesn't know about the value; who cleared the engine?")
- }
- if engine.destroyed && len(engine.values) == 0 {
- delete(engines, engine.addr)
- }
- }
- }
- //fmt.Printf("[DEBUG] value destroyed: cvalue=%x gvalue=%x/%#v\n", fold.cvalue, addrOf(fold.gvalue), fold.gvalue)
- stats.valuesAlive(-1)
-}
-
-func deref(value reflect.Value) reflect.Value {
- for {
- switch value.Kind() {
- case reflect.Ptr, reflect.Interface:
- value = value.Elem()
- continue
- }
- return value
- }
- panic("cannot happen")
-}
-
-//export hookGoValueReadField
-func hookGoValueReadField(enginep, foldp unsafe.Pointer, reflectIndex, getIndex, setIndex C.int, resultdv *C.DataValue) {
- fold := ensureEngine(enginep, foldp)
-
- var field reflect.Value
- if getIndex >= 0 {
- field = reflect.ValueOf(fold.gvalue).Method(int(getIndex)).Call(nil)[0]
- } else {
- field = deref(reflect.ValueOf(fold.gvalue)).Field(int(reflectIndex))
- }
- field = deref(field)
-
- // Cannot compare Type directly as field may be invalid (nil).
- if field.Kind() == reflect.Slice && field.Type() == typeObjSlice {
- // TODO Handle getters that return []qml.Object.
- // TODO Handle other GoValue slices (!= []qml.Object).
- resultdv.dataType = C.DTListProperty
- *(*unsafe.Pointer)(unsafe.Pointer(&resultdv.data)) = C.newListProperty(foldp, C.intptr_t(reflectIndex), C.intptr_t(setIndex))
- return
- }
-
- fieldk := field.Kind()
- if fieldk == reflect.Slice || fieldk == reflect.Struct && field.Type() != typeRGBA {
- if field.CanAddr() {
- field = field.Addr()
- } else if !hashable(field.Interface()) {
- t := reflect.ValueOf(fold.gvalue).Type()
- for t.Kind() == reflect.Ptr {
- t = t.Elem()
- }
- panic(fmt.Sprintf("cannot access unaddressable and unhashable struct value on interface field %s.%s; value: %#v", t.Name(), t.Field(int(reflectIndex)).Name, field.Interface()))
- }
- }
- var gvalue interface{}
- if field.IsValid() {
- gvalue = field.Interface()
- }
-
- // TODO Strings are being passed in an unsafe manner here. There is a
- // small chance that the field is changed and the garbage collector is run
- // before C++ has a chance to look at the data. We can solve this problem
- // by queuing up values in a stack, and cleaning the stack when the
- // idle timer fires next.
- packDataValue(gvalue, resultdv, fold.engine, jsOwner)
-}
-
-//export hookGoValueWriteField
-func hookGoValueWriteField(enginep, foldp unsafe.Pointer, reflectIndex, setIndex C.int, assigndv *C.DataValue) {
- fold := ensureEngine(enginep, foldp)
- v := reflect.ValueOf(fold.gvalue)
- ve := v
- for ve.Type().Kind() == reflect.Ptr {
- ve = ve.Elem()
- }
- var field, setMethod reflect.Value
- if reflectIndex >= 0 {
- // It's a real field rather than a getter.
- field = ve.Field(int(reflectIndex))
- }
- if setIndex >= 0 {
- // It has a setter.
- setMethod = v.Method(int(setIndex))
- }
-
- assign := unpackDataValue(assigndv, fold.engine)
-
- // TODO Return false to the call site if it fails. That's how Qt seems to handle it internally.
- err := convertAndSet(field, reflect.ValueOf(assign), setMethod)
- if err != nil {
- panic(err.Error())
- }
-}
-
-func convertAndSet(to, from reflect.Value, setMethod reflect.Value) (err error) {
- var toType reflect.Type
- if setMethod.IsValid() {
- toType = setMethod.Type().In(0)
- } else {
- toType = to.Type()
- }
- fromType := from.Type()
- defer func() {
- // TODO This is catching more than it should. There are calls
- // to custom code below that should be isolated.
- if v := recover(); v != nil {
- err = fmt.Errorf("cannot use %s as a %s", fromType, toType)
- }
- }()
- if fromType == typeList && toType.Kind() == reflect.Slice {
- list := from.Interface().(*List)
- from = reflect.MakeSlice(toType, len(list.data), len(list.data))
- elemType := toType.Elem()
- for i, elem := range list.data {
- from.Index(i).Set(reflect.ValueOf(elem).Convert(elemType))
- }
- } else if fromType == typeMap && toType.Kind() == reflect.Map {
- qmap := from.Interface().(*Map)
- from = reflect.MakeMap(toType)
- elemType := toType.Elem()
- for i := 0; i < len(qmap.data); i += 2 {
- key := reflect.ValueOf(qmap.data[i])
- val := reflect.ValueOf(qmap.data[i+1])
- if val.Type() != elemType {
- val = val.Convert(elemType)
- }
- from.SetMapIndex(key, val)
- }
- } else if toType != fromType {
- from = from.Convert(toType)
- }
- if setMethod.IsValid() {
- setMethod.Call([]reflect.Value{from})
- } else {
- to.Set(from)
- }
- return nil
-}
-
-var (
- dataValueSize = uintptr(unsafe.Sizeof(C.DataValue{}))
- dataValueArray [C.MaxParams]C.DataValue
-)
-
-//export hookGoValueCallMethod
-func hookGoValueCallMethod(enginep, foldp unsafe.Pointer, reflectIndex C.int, args *C.DataValue) {
- fold := ensureEngine(enginep, foldp)
- v := reflect.ValueOf(fold.gvalue)
-
- // TODO Must assert that v is necessarily a pointer here, but we shouldn't have to manipulate
- // gvalue here for that. This should happen in a sensible place in the wrapping functions
- // that can still error out to the user in due time.
-
- method := v.Method(int(reflectIndex))
- methodt := method.Type()
- methodName := v.Type().Method(int(reflectIndex)).Name
-
- // TODO Ensure methods with more parameters than this are not registered.
- var params [C.MaxParams]reflect.Value
- var err error
-
- numIn := methodt.NumIn()
- for i := 0; i < numIn; i++ {
- paramdv := (*C.DataValue)(unsafe.Pointer(uintptr(unsafe.Pointer(args)) + (uintptr(i)+1)*dataValueSize))
- param := reflect.ValueOf(unpackDataValue(paramdv, fold.engine))
- if argt := methodt.In(i); param.Type() != argt {
- param, err = convertParam(methodName, i, param, argt)
- if err != nil {
- panic(err.Error())
- }
- }
- params[i] = param
- }
-
- result := method.Call(params[:numIn])
-
- if len(result) == 1 {
- packDataValue(result[0].Interface(), args, fold.engine, jsOwner)
- } else if len(result) > 1 {
- if len(result) > len(dataValueArray) {
- panic("function has too many results")
- }
- for i, v := range result {
- packDataValue(v.Interface(), &dataValueArray[i], fold.engine, jsOwner)
- }
- args.dataType = C.DTVariantList
- *(*unsafe.Pointer)(unsafe.Pointer(&args.data)) = C.newVariantList(&dataValueArray[0], C.int(len(result)))
- }
-}
-
-func convertParam(methodName string, index int, param reflect.Value, argt reflect.Type) (reflect.Value, error) {
- out := reflect.New(argt).Elem()
- err := convertAndSet(out, param, reflect.Value{})
- if err != nil {
- err = fmt.Errorf("cannot convert parameter %d of method %s from %s to %s; provided value: %#v",
- index, methodName, param.Type(), argt, param.Interface())
- return reflect.Value{}, err
- }
- return out, nil
-}
-
-func printPaintPanic() {
- if v := recover(); v != nil {
- buf := make([]byte, 8192)
- runtime.Stack(buf, false)
- fmt.Fprintf(os.Stderr, "panic while painting: %s\n\n%s", v, buf)
- }
-}
-
-//export hookGoValuePaint
-func hookGoValuePaint(enginep, foldp unsafe.Pointer, reflectIndex C.intptr_t) {
- // Besides a convenience this is a workaround for http://golang.org/issue/8588
- defer printPaintPanic()
- defer atomic.StoreUintptr(&guiPaintRef, 0)
-
- // The main GUI thread is mutex-locked while paint methods are called,
- // so no two paintings should be happening at the same time.
- atomic.StoreUintptr(&guiPaintRef, cdata.Ref())
-
- fold := ensureEngine(enginep, foldp)
- if fold.init.IsValid() {
- return
- }
-
- painter := &Painter{engine: fold.engine, obj: &Common{fold.cvalue, fold.engine}}
- v := reflect.ValueOf(fold.gvalue)
- method := v.Method(int(reflectIndex))
- method.Call([]reflect.Value{reflect.ValueOf(painter)})
-}
-
-func ensureEngine(enginep, foldp unsafe.Pointer) *valueFold {
- fold := (*valueFold)(foldp)
- if fold.engine != nil {
- if fold.init.IsValid() {
- initGoType(fold)
- }
- return fold
- }
-
- if enginep == nilPtr {
- panic("accessing value without an engine pointer; who created the value?")
- }
- engine := engines[enginep]
- if engine == nil {
- panic("unknown engine pointer; who created the engine?")
- }
- fold.engine = engine
- prev := engine.values[fold.gvalue]
- if prev != nil {
- for prev.next != nil {
- prev = prev.next
- }
- prev.next = fold
- fold.prev = prev
- } else {
- engine.values[fold.gvalue] = fold
- }
- before := len(typeNew)
- delete(typeNew, fold)
- if len(typeNew) == before {
- panic("value had no engine, but was not created by a registered type; who created the value?")
- }
- initGoType(fold)
- return fold
-}
-
-func initGoType(fold *valueFold) {
- if cdata.Ref() == atomic.LoadUintptr(&guiPaintRef) {
- go RunMain(func() { _initGoType(fold, true) })
- } else {
- _initGoType(fold, false)
- }
-}
-
-func _initGoType(fold *valueFold, schedulePaint bool) {
- if !fold.init.IsValid() {
- return
- }
- // TODO Would be good to preserve identity on the Go side. See unpackDataValue as well.
- obj := &Common{engine: fold.engine, addr: fold.cvalue}
- fold.init.Call([]reflect.Value{reflect.ValueOf(fold.gvalue), reflect.ValueOf(obj)})
- fold.init = reflect.Value{}
- if schedulePaint {
- obj.Call("update")
- }
-}
-
-//export hookPanic
-func hookPanic(message *C.char) {
- defer C.free(unsafe.Pointer(message))
- panic(C.GoString(message))
-}
-
-func listSlice(fold *valueFold, reflectIndex C.intptr_t) *[]Object {
- field := deref(reflect.ValueOf(fold.gvalue)).Field(int(reflectIndex))
- return field.Addr().Interface().(*[]Object)
-}
-
-//export hookListPropertyAt
-func hookListPropertyAt(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t, index C.int) (objp unsafe.Pointer) {
- fold := (*valueFold)(foldp)
- slice := listSlice(fold, reflectIndex)
- return (*slice)[int(index)].Common().addr
-}
-
-//export hookListPropertyCount
-func hookListPropertyCount(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t) C.int {
- fold := (*valueFold)(foldp)
- slice := listSlice(fold, reflectIndex)
- return C.int(len(*slice))
-}
-
-//export hookListPropertyAppend
-func hookListPropertyAppend(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t, objp unsafe.Pointer) {
- fold := (*valueFold)(foldp)
- slice := listSlice(fold, reflectIndex)
- var objdv C.DataValue
- objdv.dataType = C.DTObject
- *(*unsafe.Pointer)(unsafe.Pointer(&objdv.data)) = objp
- newslice := append(*slice, unpackDataValue(&objdv, fold.engine).(Object))
- if setIndex >= 0 {
- reflect.ValueOf(fold.gvalue).Method(int(setIndex)).Call([]reflect.Value{reflect.ValueOf(newslice)})
- } else {
- *slice = newslice
- }
-}
-
-//export hookListPropertyClear
-func hookListPropertyClear(foldp unsafe.Pointer, reflectIndex, setIndex C.intptr_t) {
- fold := (*valueFold)(foldp)
- slice := listSlice(fold, reflectIndex)
- newslice := (*slice)[0:0]
- if setIndex >= 0 {
- reflect.ValueOf(fold.gvalue).Method(int(setIndex)).Call([]reflect.Value{reflect.ValueOf(newslice)})
- } else {
- for i := range *slice {
- (*slice)[i] = nil
- }
- *slice = newslice
- }
-}
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata.go b/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata.go
deleted file mode 100644
index 6f13b810f..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata.go
+++ /dev/null
@@ -1,6 +0,0 @@
-// Package cdata supports the implementation of the qml package.
-package cdata
-
-func Ref() uintptr
-
-func Addrs() (uintptr, uintptr)
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata12.c b/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata12.c
deleted file mode 100644
index 2e60abfa2..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata12.c
+++ /dev/null
@@ -1,18 +0,0 @@
-// +build !go1.4
-
-#include "runtime.h"
-
-void ·Ref(uintptr ref) {
- ref = (uintptr)g->m;
- FLUSH(&ref);
-}
-
-void runtime·main(void);
-void main·main(void);
-
-void ·Addrs(uintptr rmain, uintptr mmain) {
- rmain = (uintptr)runtime·main;
- mmain = (uintptr)main·main;
- FLUSH(&rmain);
- FLUSH(&mmain);
-}
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_386.s b/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_386.s
deleted file mode 100644
index 7dae9b961..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_386.s
+++ /dev/null
@@ -1,17 +0,0 @@
-// +build go1.4
-
-#include "textflag.h"
-
-TEXT ·Ref(SB),NOSPLIT,$4-4
- CALL runtime·acquirem(SB)
- MOVL 0(SP), AX
- MOVL AX, ret+0(FP)
- CALL runtime·releasem(SB)
- RET
-
-TEXT ·Addrs(SB),NOSPLIT,$0-8
- MOVL $runtime·main(SB), AX
- MOVL AX, ret+0(FP)
- MOVL $runtime·main_main(SB), AX
- MOVL AX, ret+8(FP)
- RET
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_amd64.s b/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_amd64.s
deleted file mode 100644
index 83cc22c9c..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_amd64.s
+++ /dev/null
@@ -1,17 +0,0 @@
-// +build go1.4
-
-#include "textflag.h"
-
-TEXT ·Ref(SB),NOSPLIT,$8-8
- CALL runtime·acquirem(SB)
- MOVQ 0(SP), AX
- MOVQ AX, ret+0(FP)
- CALL runtime·releasem(SB)
- RET
-
-TEXT ·Addrs(SB),NOSPLIT,$0-16
- MOVQ $runtime·main(SB), AX
- MOVQ AX, ret+0(FP)
- MOVQ $runtime·main_main(SB), AX
- MOVQ AX, ret+8(FP)
- RET
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_arm.s b/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_arm.s
deleted file mode 100644
index c66bbafbf..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata14_arm.s
+++ /dev/null
@@ -1,18 +0,0 @@
-// +build go1.4
-
-#include "textflag.h"
-
-TEXT ·Ref(SB),NOSPLIT,$4-4
- BL runtime·acquirem(SB)
- MOVW 4(R13), R0
- MOVW R0, ret+0(FP)
- MOVW R0, 4(R13)
- BL runtime·releasem(SB)
- RET
-
-TEXT ·Addrs(SB),NOSPLIT,$0-8
- MOVW $runtime·main(SB), R0
- MOVW R0, ret+0(FP)
- MOVW $runtime·main_main(SB), R0
- MOVW R0, ret+4(FP)
- RET
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata_test.go b/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata_test.go
deleted file mode 100644
index e7c3f33c5..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cdata/cdata_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package cdata
-
-import (
- "runtime"
- "sync"
- "testing"
-)
-
-type refPair struct {
- ref1, ref2 uintptr
-}
-
-func TestRef(t *testing.T) {
- const N = 10
- runtime.LockOSThread()
- exit := sync.WaitGroup{}
- exit.Add(1)
- defer exit.Done()
- wg := sync.WaitGroup{}
- wg.Add(N)
- ch := make(chan refPair)
- for i := 0; i < N; i++ {
- go func() {
- runtime.LockOSThread()
- wg.Done()
- ch <- refPair{Ref(), Ref()}
- exit.Wait()
- }()
- }
- wg.Wait()
- refs := make(map[uintptr]bool)
- for i := 0; i < N; i++ {
- pair := <-ch
- if pair.ref1 != pair.ref2 {
- t.Fatalf("found inconsistent ref: %d != %d", pair.ref1, pair.ref2)
- }
- if refs[pair.ref1] {
- t.Fatalf("found duplicated ref: %d", pair.ref1)
- }
- refs[pair.ref1] = true
- }
-}
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cmd/genqrc/main.go b/Godeps/_workspace/src/github.com/obscuren/qml/cmd/genqrc/main.go
deleted file mode 100644
index a601d8126..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cmd/genqrc/main.go
+++ /dev/null
@@ -1,218 +0,0 @@
-
-// XXX: The documentation is duplicated here and in the the doc variable
-// below. Update both at the same time.
-
-// Command genqrc packs resource files into the Go binary.
-//
-// Usage: genqrc [options] [ ...]
-//
-// The genqrc tool packs all resource files under the provided subdirectories into
-// a single qrc.go file that may be built into the generated binary. Bundled files
-// may then be loaded by Go or QML code under the URL "qrc:///some/path", where
-// "some/path" matches the original path for the resource file locally.
-//
-// For example, the following will load a .qml file from the resource pack, and
-// that file may in turn reference other content (code, images, etc) in the pack:
-//
-// component, err := engine.LoadFile("qrc://path/to/file.qml")
-//
-// Starting with Go 1.4, this tool may be conveniently run by the "go generate"
-// subcommand by adding a line similar to the following one to any existent .go
-// file in the project (assuming the subdirectories ./code/ and ./images/ exist):
-//
-// //go:generate genqrc code images
-//
-// Then, just run "go generate" to update the qrc.go file.
-//
-// During development, the generated qrc.go can repack the filesystem content at
-// runtime to avoid the process of regenerating the qrc.go file and rebuilding the
-// application to test every minor change made. Runtime repacking is enabled by
-// setting the QRC_REPACK environment variable to 1:
-//
-// export QRC_REPACK=1
-//
-// This does not update the static content in the qrc.go file, though, so after
-// the changes are performed, genqrc must be run again to update the content that
-// will ship with built binaries.
-package main
-
-import (
- "flag"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "text/template"
-
- "gopkg.in/qml.v1"
-)
-
-const doc = `
-Usage: genqrc [options] [ ...]
-
-The genqrc tool packs all resource files under the provided subdirectories into
-a single qrc.go file that may be built into the generated binary. Bundled files
-may then be loaded by Go or QML code under the URL "qrc:///some/path", where
-"some/path" matches the original path for the resource file locally.
-
-For example, the following will load a .qml file from the resource pack, and
-that file may in turn reference other content (code, images, etc) in the pack:
-
- component, err := engine.LoadFile("qrc://path/to/file.qml")
-
-Starting with Go 1.4, this tool may be conveniently run by the "go generate"
-subcommand by adding a line similar to the following one to any existent .go
-file in the project (assuming the subdirectories ./code/ and ./images/ exist):
-
- //go:generate genqrc code images
-
-Then, just run "go generate" to update the qrc.go file.
-
-During development, the generated qrc.go can repack the filesystem content at
-runtime to avoid the process of regenerating the qrc.go file and rebuilding the
-application to test every minor change made. Runtime repacking is enabled by
-setting the QRC_REPACK environment variable to 1:
-
- export QRC_REPACK=1
-
-This does not update the static content in the qrc.go file, though, so after
-the changes are performed, genqrc must be run again to update the content that
-will ship with built binaries.
-`
-
-// XXX: The documentation is duplicated here and in the the package comment
-// above. Update both at the same time.
-
-var packageName = flag.String("package", "main", "package name that qrc.go will be under (not needed for go generate)")
-
-func main() {
- flag.Usage = func() {
- fmt.Fprintf(os.Stderr, "%s", doc)
- flag.PrintDefaults()
- }
- flag.Parse()
- if err := run(); err != nil {
- fmt.Fprintf(os.Stderr, "error: %v\n", err)
- os.Exit(1)
- }
-}
-
-func run() error {
- subdirs := flag.Args()
- if len(subdirs) == 0 {
- return fmt.Errorf("must provide at least one subdirectory path")
- }
-
- var rp qml.ResourcesPacker
-
- for _, subdir := range flag.Args() {
- err := filepath.Walk(subdir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- data, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- rp.Add(filepath.ToSlash(path), data)
- return nil
- })
- if err != nil {
- return err
- }
- }
-
- resdata := rp.Pack().Bytes()
-
- f, err := os.Create("qrc.go")
- if err != nil {
- return err
- }
- defer f.Close()
-
- data := templateData{
- PackageName: *packageName,
- SubDirs: subdirs,
- ResourcesData: resdata,
- }
-
- // $GOPACKAGE is set automatically by go generate.
- if pkgname := os.Getenv("GOPACKAGE"); pkgname != "" {
- data.PackageName = pkgname
- }
-
- return tmpl.Execute(f, data)
-}
-
-type templateData struct {
- PackageName string
- SubDirs []string
- ResourcesData []byte
-}
-
-func buildTemplate(name, content string) *template.Template {
- return template.Must(template.New(name).Parse(content))
-}
-
-var tmpl = buildTemplate("qrc.go", `package {{.PackageName}}
-
-// This file is automatically generated by gopkg.in/qml.v1/cmd/genqrc
-
-import (
- "io/ioutil"
- "os"
- "path/filepath"
-
- "gopkg.in/qml.v1"
-)
-
-func init() {
- var r *qml.Resources
- var err error
- if os.Getenv("QRC_REPACK") == "1" {
- err = qrcRepackResources()
- if err != nil {
- panic("cannot repack qrc resources: " + err.Error())
- }
- r, err = qml.ParseResources(qrcResourcesRepacked)
- } else {
- r, err = qml.ParseResourcesString(qrcResourcesData)
- }
- if err != nil {
- panic("cannot parse bundled resources data: " + err.Error())
- }
- qml.LoadResources(r)
-}
-
-func qrcRepackResources() error {
- subdirs := {{printf "%#v" .SubDirs}}
- var rp qml.ResourcesPacker
- for _, subdir := range subdirs {
- err := filepath.Walk(subdir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if info.IsDir() {
- return nil
- }
- data, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- rp.Add(filepath.ToSlash(path), data)
- return nil
- })
- if err != nil {
- return err
- }
- }
- qrcResourcesRepacked = rp.Pack().Bytes()
- return nil
-}
-
-var qrcResourcesRepacked []byte
-var qrcResourcesData = {{printf "%q" .ResourcesData}}
-`)
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cmd/ubuntu-touch/particle.desktop b/Godeps/_workspace/src/github.com/obscuren/qml/cmd/ubuntu-touch/particle.desktop
deleted file mode 100644
index 76a62cb50..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cmd/ubuntu-touch/particle.desktop
+++ /dev/null
@@ -1,15 +0,0 @@
-[Desktop Entry]
-Encoding=UTF-8
-Version=1.0
-Type=Application
-Terminal=false
-Path=/home/phablet/src/gopkg.in/qml.v0/examples/particle/
-Exec=./particle
-Icon=properties
-Name=Particle Example
-X-Ubuntu-Touch=true
-X-Ubuntu-StageHint=SideStage
-
-# Copy this file to:
-#
-# ~phablet/.local/share/applications/gopkg.in.qml.particle-example.desktop
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cmd/ubuntu-touch/setup.sh b/Godeps/_workspace/src/github.com/obscuren/qml/cmd/ubuntu-touch/setup.sh
deleted file mode 100644
index 1d0454110..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cmd/ubuntu-touch/setup.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$USER" != "root" ]; then
- echo 'This script must be run as root.'
- exit 1
-fi
-
-echo 'Remounting root as read-write ------------------------------------------------'
-
-mount -o remount,rw /
-
-echo 'Installing Go and dependencies -----------------------------------------------'
-
-apt-get update
-apt-get install -y \
- golang-go g++ git pkg-config ubuntu-app-launch\
- qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev
-apt-get clean
-
-echo 'Setting up environment for phablet user --------------------------------------'
-
-echo 'export GOPATH=$HOME' >> ~phablet/.bash_profile
-
-echo 'Fetching the qml package -----------------------------------------------------'
-
-su -l phablet -c 'go get gopkg.in/qml.v0'
-
-echo 'Installing the .desktop file for the particle example ------------------------'
-
-APP_ID='gopkg.in.qml.particle-example'
-cp ~phablet/src/gopkg.in/qml.v*/cmd/ubuntu-touch/particle.desktop ~phablet/.local/share/applications/$APP_ID.desktop
-
-echo 'Building and launching particle example --------------------------------------'
-
-su -l phablet -c 'cd $HOME/src/gopkg.in/qml.v0/examples/particle; go build'
-
-echo 'Launching particle example ---------------------------------------------------'
-
-su -l phablet -c "ubuntu-app-launch $APP_ID"
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp
deleted file mode 100644
index 024e5ec9c..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.cpp
+++ /dev/null
@@ -1,884 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include "govalue.h"
-#include "govaluetype.h"
-#include "connector.h"
-#include "capi.h"
-
-static char *local_strdup(const char *str)
-{
- char *strcopy = 0;
- if (str) {
- size_t len = strlen(str) + 1;
- strcopy = (char *)malloc(len);
- memcpy(strcopy, str, len);
- }
- return strcopy;
-}
-
-error *errorf(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- QString str = QString().vsprintf(format, ap);
- va_end(ap);
- QByteArray ba = str.toUtf8();
- return local_strdup(ba.constData());
-}
-
-void panicf(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- QString str = QString().vsprintf(format, ap);
- va_end(ap);
- QByteArray ba = str.toUtf8();
- hookPanic(local_strdup(ba.constData()));
-}
-
-void newGuiApplication()
-{
- static char empty[1] = {0};
- static char *argv[] = {empty, 0};
- static int argc = 1;
- new QApplication(argc, argv);
-
- // The event loop should never die.
- qApp->setQuitOnLastWindowClosed(false);
-}
-
-void applicationExec()
-{
- qApp->exec();
-}
-
-void applicationExit()
-{
- qApp->exit(0);
-}
-
-void applicationFlushAll()
-{
- qApp->processEvents();
-}
-
-void *currentThread()
-{
- return QThread::currentThread();
-}
-
-void *appThread()
-{
- return QCoreApplication::instance()->thread();
-}
-
-QQmlEngine_ *newEngine(QObject_ *parent)
-{
- return new QQmlEngine(reinterpret_cast(parent));
-}
-
-QQmlContext_ *engineRootContext(QQmlEngine_ *engine)
-{
- return reinterpret_cast(engine)->rootContext();
-}
-
-void engineSetContextForObject(QQmlEngine_ *engine, QObject_ *object)
-{
- QQmlEngine *qengine = reinterpret_cast(engine);
- QObject *qobject = reinterpret_cast(object);
-
- QQmlEngine::setContextForObject(qobject, qengine->rootContext());
-}
-
-void engineSetOwnershipCPP(QQmlEngine_ *engine, QObject_ *object)
-{
- QQmlEngine *qengine = reinterpret_cast(engine);
- QObject *qobject = reinterpret_cast(object);
-
- qengine->setObjectOwnership(qobject, QQmlEngine::CppOwnership);
-}
-
-void engineSetOwnershipJS(QQmlEngine_ *engine, QObject_ *object)
-{
- QQmlEngine *qengine = reinterpret_cast(engine);
- QObject *qobject = reinterpret_cast(object);
-
- qengine->setObjectOwnership(qobject, QQmlEngine::JavaScriptOwnership);
-}
-
-QQmlComponent_ *newComponent(QQmlEngine_ *engine, QObject_ *parent)
-{
- QQmlEngine *qengine = reinterpret_cast(engine);
- //QObject *qparent = reinterpret_cast(parent);
- QQmlComponent *qcomponent = new QQmlComponent(qengine);
- // Qt 5.2.0 returns NULL on qmlEngine(qcomponent) without this.
- QQmlEngine::setContextForObject(qcomponent, qengine->rootContext());
- return qcomponent;
-}
-
-class GoImageProvider : public QQuickImageProvider {
-
- // TODO Destroy this when engine is destroyed.
-
- public:
-
- GoImageProvider(void *imageFunc) : QQuickImageProvider(QQmlImageProviderBase::Image), imageFunc(imageFunc) {};
-
- virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize)
- {
- QByteArray ba = id.toUtf8();
- int width = 0, height = 0;
- if (requestedSize.isValid()) {
- width = requestedSize.width();
- height = requestedSize.height();
- }
- QImage *ptr = reinterpret_cast(hookRequestImage(imageFunc, (char*)ba.constData(), ba.size(), width, height));
- QImage image = *ptr;
- delete ptr;
-
- *size = image.size();
- if (requestedSize.isValid() && requestedSize != *size) {
- image = image.scaled(requestedSize, Qt::KeepAspectRatio);
- }
- return image;
- };
-
- private:
-
- void *imageFunc;
-};
-
-void engineAddImageProvider(QQmlEngine_ *engine, QString_ *providerId, void *imageFunc)
-{
- QQmlEngine *qengine = reinterpret_cast(engine);
- QString *qproviderId = reinterpret_cast(providerId);
-
- qengine->addImageProvider(*qproviderId, new GoImageProvider(imageFunc));
-}
-
-void componentLoadURL(QQmlComponent_ *component, const char *url, int urlLen)
-{
- QByteArray qurl(url, urlLen);
- QString qsurl = QString::fromUtf8(qurl);
- reinterpret_cast(component)->loadUrl(qsurl);
-}
-
-void componentSetData(QQmlComponent_ *component, const char *data, int dataLen, const char *url, int urlLen)
-{
- QByteArray qdata(data, dataLen);
- QByteArray qurl(url, urlLen);
- QString qsurl = QString::fromUtf8(qurl);
- reinterpret_cast(component)->setData(qdata, qsurl);
-}
-
-char *componentErrorString(QQmlComponent_ *component)
-{
- QQmlComponent *qcomponent = reinterpret_cast(component);
- if (qcomponent->isReady()) {
- return NULL;
- }
- if (qcomponent->isError()) {
- QByteArray ba = qcomponent->errorString().toUtf8();
- return local_strdup(ba.constData());
- }
- return local_strdup("component is not ready (why!?)");
-}
-
-QObject_ *componentCreate(QQmlComponent_ *component, QQmlContext_ *context)
-{
- QQmlComponent *qcomponent = reinterpret_cast(component);
- QQmlContext *qcontext = reinterpret_cast(context);
-
- if (!qcontext) {
- qcontext = qmlContext(qcomponent);
- }
- return qcomponent->create(qcontext);
-}
-
-QQuickWindow_ *componentCreateWindow(QQmlComponent_ *component, QQmlContext_ *context)
-{
- QQmlComponent *qcomponent = reinterpret_cast(component);
- QQmlContext *qcontext = reinterpret_cast(context);
-
- if (!qcontext) {
- qcontext = qmlContext(qcomponent);
- }
- QObject *obj = qcomponent->create(qcontext);
- if (!objectIsWindow(obj)) {
- QQuickView *view = new QQuickView(qmlEngine(qcomponent), 0);
- view->setContent(qcomponent->url(), qcomponent, obj);
- view->setResizeMode(QQuickView::SizeRootObjectToView);
- obj = view;
- }
- return obj;
-}
-
-// Workaround for bug https://bugs.launchpad.net/bugs/1179716
-struct DoShowWindow : public QQuickWindow {
- void show() {
- QQuickWindow::show();
- QResizeEvent resize(size(), size());
- resizeEvent(&resize);
- }
-};
-
-void windowShow(QQuickWindow_ *win)
-{
- reinterpret_cast(win)->show();
-}
-
-void windowHide(QQuickWindow_ *win)
-{
- reinterpret_cast(win)->hide();
-}
-
-uintptr_t windowPlatformId(QQuickWindow_ *win)
-{
- return reinterpret_cast(win)->winId();
-}
-
-void windowConnectHidden(QQuickWindow_ *win)
-{
- QQuickWindow *qwin = reinterpret_cast(win);
- QObject::connect(qwin, &QWindow::visibleChanged, [=](bool visible){
- if (!visible) {
- hookWindowHidden(win);
- }
- });
-}
-
-QObject_ *windowRootObject(QQuickWindow_ *win)
-{
- if (objectIsView(win)) {
- return reinterpret_cast(win)->rootObject();
- }
- return win;
-}
-
-QImage_ *windowGrabWindow(QQuickWindow_ *win)
-{
- QQuickWindow *qwin = reinterpret_cast(win);
- QImage *image = new QImage;
- *image = qwin->grabWindow().convertToFormat(QImage::Format_ARGB32_Premultiplied);
- return image;
-}
-
-QImage_ *newImage(int width, int height)
-{
- return new QImage(width, height, QImage::Format_ARGB32_Premultiplied);
-}
-
-void delImage(QImage_ *image)
-{
- delete reinterpret_cast(image);
-}
-
-void imageSize(QImage_ *image, int *width, int *height)
-{
- QImage *qimage = reinterpret_cast(image);
- *width = qimage->width();
- *height = qimage->height();
-}
-
-unsigned char *imageBits(QImage_ *image)
-{
- QImage *qimage = reinterpret_cast(image);
- return qimage->bits();
-}
-
-const unsigned char *imageConstBits(QImage_ *image)
-{
- QImage *qimage = reinterpret_cast(image);
- return qimage->constBits();
-}
-
-void contextSetObject(QQmlContext_ *context, QObject_ *value)
-{
- QQmlContext *qcontext = reinterpret_cast(context);
- QObject *qvalue = reinterpret_cast(value);
-
- // Give qvalue an engine reference if it doesn't yet have one.
- if (!qmlEngine(qvalue)) {
- QQmlEngine::setContextForObject(qvalue, qcontext->engine()->rootContext());
- }
-
- qcontext->setContextObject(qvalue);
-}
-
-void contextSetProperty(QQmlContext_ *context, QString_ *name, DataValue *value)
-{
- const QString *qname = reinterpret_cast(name);
- QQmlContext *qcontext = reinterpret_cast(context);
-
- QVariant var;
- unpackDataValue(value, &var);
-
- // Give qvalue an engine reference if it doesn't yet have one .
- QObject *obj = var.value();
- if (obj && !qmlEngine(obj)) {
- QQmlEngine::setContextForObject(obj, qcontext);
- }
-
- qcontext->setContextProperty(*qname, var);
-}
-
-void contextGetProperty(QQmlContext_ *context, QString_ *name, DataValue *result)
-{
- QQmlContext *qcontext = reinterpret_cast(context);
- const QString *qname = reinterpret_cast(name);
-
- QVariant var = qcontext->contextProperty(*qname);
- packDataValue(&var, result);
-}
-
-QQmlContext_ *contextSpawn(QQmlContext_ *context)
-{
- QQmlContext *qcontext = reinterpret_cast(context);
- return new QQmlContext(qcontext);
-}
-
-void delObject(QObject_ *object)
-{
- delete reinterpret_cast(object);
-}
-
-void delObjectLater(QObject_ *object)
-{
- reinterpret_cast(object)->deleteLater();
-}
-
-const char *objectTypeName(QObject_ *object)
-{
- return reinterpret_cast(object)->metaObject()->className();
-}
-
-int objectGetProperty(QObject_ *object, const char *name, DataValue *result)
-{
- QObject *qobject = reinterpret_cast(object);
-
- QVariant var = qobject->property(name);
- packDataValue(&var, result);
-
- if (!var.isValid() && qobject->metaObject()->indexOfProperty(name) == -1) {
- // TODO May have to check the dynamic property names too.
- return 0;
- }
- return 1;
-}
-
-error *objectSetProperty(QObject_ *object, const char *name, DataValue *value)
-{
- QObject *qobject = reinterpret_cast(object);
- QVariant var;
- unpackDataValue(value, &var);
-
- // Give qvalue an engine reference if it doesn't yet have one.
- QObject *obj = var.value();
- if (obj && !qmlEngine(obj)) {
- QQmlContext *context = qmlContext(qobject);
- if (context) {
- QQmlEngine::setContextForObject(obj, context);
- }
- }
-
- // Check that the types are compatible. There's probably more to be done here.
- const QMetaObject *metaObject = qobject->metaObject();
- int propIndex = metaObject->indexOfProperty(name);
- if (propIndex == -1) {
- return errorf("cannot set non-existent property \"%s\" on type %s", name, qobject->metaObject()->className());
- }
-
- QMetaProperty prop = metaObject->property(propIndex);
- int propType = prop.userType();
- void *valueArg;
- if (propType == QMetaType::QVariant) {
- valueArg = (void *)&var;
- } else {
- int varType = var.userType();
- QVariant saved = var;
- if (propType != varType && !var.convert(propType)) {
- if (varType == QMetaType::QObjectStar) {
- return errorf("cannot set property \"%s\" with type %s to value of %s*",
- name, QMetaType::typeName(propType), saved.value()->metaObject()->className());
- } else {
- return errorf("cannot set property \"%s\" with type %s to value of %s",
- name, QMetaType::typeName(propType), QMetaType::typeName(varType));
- }
- }
- valueArg = (void *)var.constData();
- }
-
- int status = -1;
- int flags = 0;
- void *args[] = {valueArg, 0, &status, &flags};
- QMetaObject::metacall(qobject, QMetaObject::WriteProperty, propIndex, args);
- return 0;
-}
-
-error *objectInvoke(QObject_ *object, const char *method, int methodLen, DataValue *resultdv, DataValue *paramsdv, int paramsLen)
-{
- QObject *qobject = reinterpret_cast(object);
-
- QVariant result;
- QVariant param[MaxParams];
- QGenericArgument arg[MaxParams];
- for (int i = 0; i < paramsLen; i++) {
- unpackDataValue(¶msdv[i], ¶m[i]);
- arg[i] = Q_ARG(QVariant, param[i]);
- }
- if (paramsLen > 10) {
- panicf("fix the parameter dispatching");
- }
-
- const QMetaObject *metaObject = qobject->metaObject();
- // Walk backwards so descendants have priority.
- for (int i = metaObject->methodCount()-1; i >= 0; i--) {
- QMetaMethod metaMethod = metaObject->method(i);
- QMetaMethod::MethodType methodType = metaMethod.methodType();
- if (methodType == QMetaMethod::Method || methodType == QMetaMethod::Slot) {
- QByteArray name = metaMethod.name();
- if (name.length() == methodLen && qstrncmp(name.constData(), method, methodLen) == 0) {
- if (metaMethod.parameterCount() < paramsLen) {
- // TODO Might continue looking to see if a different signal has the same name and enough arguments.
- return errorf("method \"%s\" has too few parameters for provided arguments", method);
- }
-
- bool ok;
- if (metaMethod.returnType() == QMetaType::Void) {
- ok = metaMethod.invoke(qobject, Qt::DirectConnection,
- arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]);
- } else {
- ok = metaMethod.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(QVariant, result),
- arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]);
- }
- if (!ok) {
- return errorf("invalid parameters to method \"%s\"", method);
- }
-
- packDataValue(&result, resultdv);
- return 0;
- }
- }
- }
-
- return errorf("object does not expose a method \"%s\"", method);
-}
-
-void objectFindChild(QObject_ *object, QString_ *name, DataValue *resultdv)
-{
- QObject *qobject = reinterpret_cast(object);
- QString *qname = reinterpret_cast(name);
-
- QVariant var;
- QObject *result = qobject->findChild(*qname);
- if (result) {
- var.setValue(result);
- }
- packDataValue(&var, resultdv);
-}
-
-void objectSetParent(QObject_ *object, QObject_ *parent)
-{
- QObject *qobject = reinterpret_cast(object);
- QObject *qparent = reinterpret_cast(parent);
-
- qobject->setParent(qparent);
-}
-
-error *objectConnect(QObject_ *object, const char *signal, int signalLen, QQmlEngine_ *engine, void *func, int argsLen)
-{
- QObject *qobject = reinterpret_cast(object);
- QQmlEngine *qengine = reinterpret_cast(engine);
- QByteArray qsignal(signal, signalLen);
-
- const QMetaObject *meta = qobject->metaObject();
- // Walk backwards so descendants have priority.
- for (int i = meta->methodCount()-1; i >= 0; i--) {
- QMetaMethod method = meta->method(i);
- if (method.methodType() == QMetaMethod::Signal) {
- QByteArray name = method.name();
- if (name.length() == signalLen && qstrncmp(name.constData(), signal, signalLen) == 0) {
- if (method.parameterCount() < argsLen) {
- // TODO Might continue looking to see if a different signal has the same name and enough arguments.
- return errorf("signal \"%s\" has too few parameters for provided function", name.constData());
- }
- Connector *connector = new Connector(qobject, method, qengine, func, argsLen);
- const QMetaObject *connmeta = connector->metaObject();
- QObject::connect(qobject, method, connector, connmeta->method(connmeta->methodOffset()));
- return 0;
- }
- }
- }
- // Cannot use constData here as the byte array is not null-terminated.
- return errorf("object does not expose a \"%s\" signal", qsignal.data());
-}
-
-QQmlContext_ *objectContext(QObject_ *object)
-{
- return qmlContext(static_cast(object));
-}
-
-int objectIsComponent(QObject_ *object)
-{
- QObject *qobject = static_cast(object);
- return dynamic_cast(qobject) ? 1 : 0;
-}
-
-int objectIsWindow(QObject_ *object)
-{
- QObject *qobject = static_cast(object);
- return dynamic_cast(qobject) ? 1 : 0;
-}
-
-int objectIsView(QObject_ *object)
-{
- QObject *qobject = static_cast(object);
- return dynamic_cast(qobject) ? 1 : 0;
-}
-
-error *objectGoAddr(QObject_ *object, GoAddr **addr)
-{
- QObject *qobject = static_cast(object);
- GoValue *goValue = dynamic_cast(qobject);
- if (goValue) {
- *addr = goValue->addr;
- return 0;
- }
- GoPaintedValue *goPaintedValue = dynamic_cast(qobject);
- if (goPaintedValue) {
- *addr = goPaintedValue->addr;
- return 0;
- }
- return errorf("QML object is not backed by a Go value");
-}
-
-QString_ *newString(const char *data, int len)
-{
- // This will copy data only once.
- QByteArray ba = QByteArray::fromRawData(data, len);
- return new QString(ba);
-}
-
-void delString(QString_ *s)
-{
- delete reinterpret_cast(s);
-}
-
-GoValue_ *newGoValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject_ *parent)
-{
- QObject *qparent = reinterpret_cast(parent);
- if (typeInfo->paint) {
- return new GoPaintedValue(addr, typeInfo, qparent);
- }
- return new GoValue(addr, typeInfo, qparent);
-}
-
-void goValueActivate(GoValue_ *value, GoTypeInfo *typeInfo, int addrOffset)
-{
- GoMemberInfo *fieldInfo = typeInfo->fields;
- for (int i = 0; i < typeInfo->fieldsLen; i++) {
- if (fieldInfo->addrOffset == addrOffset) {
- if (typeInfo->paint) {
- static_cast(value)->activate(fieldInfo->metaIndex);
- } else {
- static_cast(value)->activate(fieldInfo->metaIndex);
- }
- return;
- }
- fieldInfo++;
- }
-
- // TODO Return an error; probably an unexported field.
-}
-
-void unpackDataValue(DataValue *value, QVariant_ *var)
-{
- QVariant *qvar = reinterpret_cast(var);
- switch (value->dataType) {
- case DTString:
- *qvar = QString::fromUtf8(*(char **)value->data, value->len);
- break;
- case DTBool:
- *qvar = bool(*(char *)(value->data) != 0);
- break;
- case DTInt64:
- *qvar = *(qint64*)(value->data);
- break;
- case DTInt32:
- *qvar = *(qint32*)(value->data);
- break;
- case DTUint64:
- *qvar = *(quint64*)(value->data);
- break;
- case DTUint32:
- *qvar = *(quint32*)(value->data);
- break;
- case DTFloat64:
- *qvar = *(double*)(value->data);
- break;
- case DTFloat32:
- *qvar = *(float*)(value->data);
- break;
- case DTColor:
- *qvar = QColor::fromRgba(*(QRgb*)(value->data));
- break;
- case DTVariantList:
- *qvar = **(QVariantList**)(value->data);
- delete *(QVariantList**)(value->data);
- break;
- case DTObject:
- qvar->setValue(*(QObject**)(value->data));
- break;
- case DTInvalid:
- // null would be more natural, but an invalid variant means
- // it has proper semantics when dealing with non-qml qt code.
- //qvar->setValue(QJSValue(QJSValue::NullValue));
- qvar->clear();
- break;
- default:
- panicf("unknown data type: %d", value->dataType);
- break;
- }
-}
-
-void packDataValue(QVariant_ *var, DataValue *value)
-{
- QVariant *qvar = reinterpret_cast(var);
-
- // Some assumptions are made below regarding the size of types.
- // There's apparently no better way to handle this since that's
- // how the types with well defined sizes (qint64) are mapped to
- // meta-types (QMetaType::LongLong).
- switch ((int)qvar->type()) {
- case QVariant::Invalid:
- value->dataType = DTInvalid;
- break;
- case QMetaType::QUrl:
- *qvar = qvar->value().toString();
- // fallthrough
- case QMetaType::QString:
- {
- value->dataType = DTString;
- QByteArray ba = qvar->toByteArray();
- *(char**)(value->data) = local_strdup(ba.constData());
- value->len = ba.size();
- break;
- }
- case QMetaType::Bool:
- value->dataType = DTBool;
- *(qint8*)(value->data) = (qint8)qvar->toInt();
- break;
- case QMetaType::LongLong:
- // Some of these entries will have to be fixed when handling platforms
- // where sizeof(long long) != 8 or sizeof(int) != 4.
- value->dataType = DTInt64;
- *(qint64*)(value->data) = qvar->toLongLong();
- break;
- case QMetaType::ULongLong:
- value->dataType = DTUint64;
- *(quint64*)(value->data) = qvar->toLongLong();
- break;
- case QMetaType::Int:
- value->dataType = DTInt32;
- *(qint32*)(value->data) = qvar->toInt();
- break;
- case QMetaType::UInt:
- value->dataType = DTUint32;
- *(quint32*)(value->data) = qvar->toUInt();
- break;
- case QMetaType::VoidStar:
- value->dataType = DTUintptr;
- *(uintptr_t*)(value->data) = (uintptr_t)qvar->value();
- break;
- case QMetaType::Double:
- value->dataType = DTFloat64;
- *(double*)(value->data) = qvar->toDouble();
- break;
- case QMetaType::Float:
- value->dataType = DTFloat32;
- *(float*)(value->data) = qvar->toFloat();
- break;
- case QMetaType::QColor:
- value->dataType = DTColor;
- *(unsigned int*)(value->data) = qvar->value().rgba();
- break;
- case QMetaType::QVariantList:
- {
- QVariantList varlist = qvar->toList();
- int len = varlist.size();
- DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len);
- for (int i = 0; i < len; i++) {
- packDataValue((void*)&varlist.at(i), &dvlist[i]);
- }
- value->dataType = DTValueList;
- value->len = len;
- *(DataValue**)(value->data) = dvlist;
- }
- break;
- case QMetaType::QVariantMap:
- {
- QVariantMap varmap = qvar->toMap();
- int len = varmap.size() * 2;
- DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len);
- QMapIterator it(varmap);
- for (int i = 0; i < len; i += 2) {
- if (!it.hasNext()) {
- panicf("QVariantMap mutated during iteration");
- }
- it.next();
- QVariant key = it.key();
- QVariant val = it.value();
- packDataValue((void*)&key, &dvlist[i]);
- packDataValue((void*)&val, &dvlist[i+1]);
- }
- value->dataType = DTValueMap;
- value->len = len;
- *(DataValue**)(value->data) = dvlist;
- }
- break;
- case QMetaType::User:
- {
- static const int qjstype = QVariant::fromValue(QJSValue()).userType();
- if (qvar->userType() == qjstype) {
- auto var = qvar->value().toVariant();
- packDataValue(&var, value);
- }
- }
- break;
- default:
- if (qvar->type() == (int)QMetaType::QObjectStar || qvar->canConvert()) {
- QObject *qobject = qvar->value();
- GoValue *goValue = dynamic_cast(qobject);
- if (goValue) {
- value->dataType = DTGoAddr;
- *(void **)(value->data) = goValue->addr;
- break;
- }
- GoPaintedValue *goPaintedValue = dynamic_cast(qobject);
- if (goPaintedValue) {
- value->dataType = DTGoAddr;
- *(void **)(value->data) = goPaintedValue->addr;
- break;
- }
- value->dataType = DTObject;
- *(void **)(value->data) = qobject;
- break;
- }
- {
- QQmlListReference ref = qvar->value();
- if (ref.isValid() && ref.canCount() && ref.canAt()) {
- int len = ref.count();
- DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len);
- QVariant elem;
- for (int i = 0; i < len; i++) {
- elem.setValue(ref.at(i));
- packDataValue(&elem, &dvlist[i]);
- }
- value->dataType = DTValueList;
- value->len = len;
- *(DataValue**)(value->data) = dvlist;
- break;
- }
- }
- if (qstrncmp(qvar->typeName(), "QQmlListProperty<", 17) == 0) {
- QQmlListProperty *list = reinterpret_cast*>(qvar->data());
- if (list->count && list->at) {
- int len = list->count(list);
- DataValue *dvlist = (DataValue *) malloc(sizeof(DataValue) * len);
- QVariant elem;
- for (int i = 0; i < len; i++) {
- elem.setValue(list->at(list, i));
- packDataValue(&elem, &dvlist[i]);
- }
- value->dataType = DTValueList;
- value->len = len;
- *(DataValue**)(value->data) = dvlist;
- break;
- }
- }
- panicf("unsupported variant type: %d (%s)", qvar->type(), qvar->typeName());
- break;
- }
-}
-
-QVariantList_ *newVariantList(DataValue *list, int len)
-{
- QVariantList *vlist = new QVariantList();
- vlist->reserve(len);
- for (int i = 0; i < len; i++) {
- QVariant var;
- unpackDataValue(&list[i], &var);
- vlist->append(var);
- }
- return vlist;
-}
-
-QObject *listPropertyAt(QQmlListProperty *list, int i)
-{
- return reinterpret_cast(hookListPropertyAt(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, i));
-}
-
-int listPropertyCount(QQmlListProperty *list)
-{
- return hookListPropertyCount(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2);
-}
-
-void listPropertyAppend(QQmlListProperty *list, QObject *obj)
-{
- hookListPropertyAppend(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2, obj);
-}
-
-void listPropertyClear(QQmlListProperty *list)
-{
- hookListPropertyClear(list->data, (intptr_t)list->dummy1, (intptr_t)list->dummy2);
-}
-
-QQmlListProperty_ *newListProperty(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex)
-{
- QQmlListProperty *list = new QQmlListProperty();
- list->data = addr;
- list->dummy1 = (void*)reflectIndex;
- list->dummy2 = (void*)setIndex;
- list->at = listPropertyAt;
- list->count = listPropertyCount;
- list->append = listPropertyAppend;
- list->clear = listPropertyClear;
- return list;
-}
-
-void internalLogHandler(QtMsgType severity, const QMessageLogContext &context, const QString &text)
-{
- if (context.file == NULL) return;
-
- QByteArray textba = text.toUtf8();
- LogMessage message = {severity, textba.constData(), textba.size(), context.file, (int)strlen(context.file), context.line};
- hookLogHandler(&message);
-}
-
-void installLogHandler()
-{
- qInstallMessageHandler(internalLogHandler);
-}
-
-
-extern bool qRegisterResourceData(int version, const unsigned char *tree, const unsigned char *name, const unsigned char *data);
-extern bool qUnregisterResourceData(int version, const unsigned char *tree, const unsigned char *name, const unsigned char *data);
-
-void registerResourceData(int version, char *tree, char *name, char *data)
-{
- qRegisterResourceData(version, (unsigned char*)tree, (unsigned char*)name, (unsigned char*)data);
-}
-
-void unregisterResourceData(int version, char *tree, char *name, char *data)
-{
- qUnregisterResourceData(version, (unsigned char*)tree, (unsigned char*)name, (unsigned char*)data);
-}
-
-// vim:ts=4:sw=4:et:ft=cpp
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.h
deleted file mode 100644
index 25218637d..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/capi.h
+++ /dev/null
@@ -1,211 +0,0 @@
-#ifndef CAPI_H
-#define CAPI_H
-
-#include
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// It's surprising that MaximumParamCount is privately defined within qmetaobject.cpp.
-// Must fix the objectInvoke function if this is changed.
-// This is Qt's MaximuParamCount - 1, as it does not take the result value in account.
-enum { MaxParams = 10 };
-
-typedef void QApplication_;
-typedef void QMetaObject_;
-typedef void QObject_;
-typedef void QVariant_;
-typedef void QVariantList_;
-typedef void QString_;
-typedef void QQmlEngine_;
-typedef void QQmlContext_;
-typedef void QQmlComponent_;
-typedef void QQmlListProperty_;
-typedef void QQuickWindow_;
-typedef void QQuickView_;
-typedef void QMessageLogContext_;
-typedef void QImage_;
-typedef void GoValue_;
-typedef void GoAddr;
-typedef void GoTypeSpec_;
-
-typedef char error;
-error *errorf(const char *format, ...);
-void panicf(const char *format, ...);
-
-typedef enum {
- DTUnknown = 0, // Has an unsupported type.
- DTInvalid = 1, // Does not exist or similar.
-
- DTString = 10,
- DTBool = 11,
- DTInt64 = 12,
- DTInt32 = 13,
- DTUint64 = 14,
- DTUint32 = 15,
- DTUintptr = 16,
- DTFloat64 = 17,
- DTFloat32 = 18,
- DTColor = 19,
-
- DTGoAddr = 100,
- DTObject = 101,
- DTValueMap = 102,
- DTValueList = 103,
- DTVariantList = 104,
- DTListProperty = 105,
-
- // Used in type information, not in an actual data value.
- DTAny = 201, // Can hold any of the above types.
- DTMethod = 202
-} DataType;
-
-typedef struct {
- DataType dataType;
- char data[8];
- int len;
-} DataValue;
-
-typedef struct {
- char *memberName; // points to memberNames
- DataType memberType;
- int reflectIndex;
- int reflectGetIndex;
- int reflectSetIndex;
- int metaIndex;
- int addrOffset;
- char *methodSignature;
- char *resultSignature;
- int numIn;
- int numOut;
-} GoMemberInfo;
-
-typedef struct {
- char *typeName;
- GoMemberInfo *fields;
- GoMemberInfo *methods;
- GoMemberInfo *members; // fields + methods
- GoMemberInfo *paint; // in methods too
- int fieldsLen;
- int methodsLen;
- int membersLen;
- char *memberNames;
-
- QMetaObject_ *metaObject;
-} GoTypeInfo;
-
-typedef struct {
- int severity;
- const char *text;
- int textLen;
- const char *file;
- int fileLen;
- int line;
-} LogMessage;
-
-void newGuiApplication();
-void applicationExec();
-void applicationExit();
-void applicationFlushAll();
-
-void idleTimerInit(int32_t *guiIdleRun);
-void idleTimerStart();
-
-void *currentThread();
-void *appThread();
-
-QQmlEngine_ *newEngine(QObject_ *parent);
-QQmlContext_ *engineRootContext(QQmlEngine_ *engine);
-void engineSetOwnershipCPP(QQmlEngine_ *engine, QObject_ *object);
-void engineSetOwnershipJS(QQmlEngine_ *engine, QObject_ *object);
-void engineSetContextForObject(QQmlEngine_ *engine, QObject_ *object);
-void engineAddImageProvider(QQmlEngine_ *engine, QString_ *providerId, void *imageFunc);
-
-void contextGetProperty(QQmlContext_ *context, QString_ *name, DataValue *value);
-void contextSetProperty(QQmlContext_ *context, QString_ *name, DataValue *value);
-void contextSetObject(QQmlContext_ *context, QObject_ *value);
-QQmlContext_ *contextSpawn(QQmlContext_ *context);
-
-void delObject(QObject_ *object);
-void delObjectLater(QObject_ *object);
-const char *objectTypeName(QObject_ *object);
-int objectGetProperty(QObject_ *object, const char *name, DataValue *result);
-error *objectSetProperty(QObject_ *object, const char *name, DataValue *value);
-void objectSetParent(QObject_ *object, QObject_ *parent);
-error *objectInvoke(QObject_ *object, const char *method, int methodLen, DataValue *result, DataValue *params, int paramsLen);
-void objectFindChild(QObject_ *object, QString_ *name, DataValue *result);
-QQmlContext_ *objectContext(QObject_ *object);
-int objectIsComponent(QObject_ *object);
-int objectIsWindow(QObject_ *object);
-int objectIsView(QObject_ *object);
-error *objectConnect(QObject_ *object, const char *signal, int signalLen, QQmlEngine_ *engine, void *func, int argsLen);
-error *objectGoAddr(QObject_ *object, GoAddr **addr);
-
-QQmlComponent_ *newComponent(QQmlEngine_ *engine, QObject_ *parent);
-void componentLoadURL(QQmlComponent_ *component, const char *url, int urlLen);
-void componentSetData(QQmlComponent_ *component, const char *data, int dataLen, const char *url, int urlLen);
-char *componentErrorString(QQmlComponent_ *component);
-QObject_ *componentCreate(QQmlComponent_ *component, QQmlContext_ *context);
-QQuickWindow_ *componentCreateWindow(QQmlComponent_ *component, QQmlContext_ *context);
-
-void windowShow(QQuickWindow_ *win);
-void windowHide(QQuickWindow_ *win);
-uintptr_t windowPlatformId(QQuickWindow_ *win);
-void windowConnectHidden(QQuickWindow_ *win);
-QObject_ *windowRootObject(QQuickWindow_ *win);
-QImage_ *windowGrabWindow(QQuickWindow_ *win);
-
-QImage_ *newImage(int width, int height);
-void delImage(QImage_ *image);
-void imageSize(QImage_ *image, int *width, int *height);
-unsigned char *imageBits(QImage_ *image);
-const unsigned char *imageConstBits(QImage_ *image);
-
-QString_ *newString(const char *data, int len);
-void delString(QString_ *s);
-
-GoValue_ *newGoValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject_ *parent);
-void goValueActivate(GoValue_ *value, GoTypeInfo *typeInfo, int addrOffset);
-
-void packDataValue(QVariant_ *var, DataValue *result);
-void unpackDataValue(DataValue *value, QVariant_ *result);
-
-QVariantList_ *newVariantList(DataValue *list, int len);
-
-QQmlListProperty_ *newListProperty(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex);
-
-int registerType(char *location, int major, int minor, char *name, GoTypeInfo *typeInfo, GoTypeSpec_ *spec);
-int registerSingleton(char *location, int major, int minor, char *name, GoTypeInfo *typeInfo, GoTypeSpec_ *spec);
-
-void installLogHandler();
-
-void hookIdleTimer();
-void hookLogHandler(LogMessage *message);
-void hookGoValueReadField(QQmlEngine_ *engine, GoAddr *addr, int memberIndex, int getIndex, int setIndex, DataValue *result);
-void hookGoValueWriteField(QQmlEngine_ *engine, GoAddr *addr, int memberIndex, int setIndex, DataValue *assign);
-void hookGoValueCallMethod(QQmlEngine_ *engine, GoAddr *addr, int memberIndex, DataValue *result);
-void hookGoValueDestroyed(QQmlEngine_ *engine, GoAddr *addr);
-void hookGoValuePaint(QQmlEngine_ *engine, GoAddr *addr, intptr_t reflextIndex);
-QImage_ *hookRequestImage(void *imageFunc, char *id, int idLen, int width, int height);
-GoAddr *hookGoValueTypeNew(GoValue_ *value, GoTypeSpec_ *spec);
-void hookWindowHidden(QObject_ *addr);
-void hookSignalCall(QQmlEngine_ *engine, void *func, DataValue *params);
-void hookSignalDisconnect(void *func);
-void hookPanic(char *message);
-int hookListPropertyCount(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex);
-QObject_ *hookListPropertyAt(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex, int i);
-void hookListPropertyAppend(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex, QObject_ *obj);
-void hookListPropertyClear(GoAddr *addr, intptr_t reflectIndex, intptr_t setIndex);
-
-void registerResourceData(int version, char *tree, char *name, char *data);
-void unregisterResourceData(int version, char *tree, char *name, char *data);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // CAPI_H
-
-// vim:ts=4:et
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/connector.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/connector.cpp
deleted file mode 100644
index 6005bfc62..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/connector.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#include
-
-#include "connector.h"
-#include "capi.h"
-
-Connector::~Connector()
-{
- hookSignalDisconnect(func);
-}
-
-void Connector::invoke()
-{
- panicf("should never get called");
-}
-
-int Connector::qt_metacall(QMetaObject::Call c, int idx, void **a)
-{
- if (c == QMetaObject::InvokeMetaMethod && idx == metaObject()->methodOffset()) {
- DataValue args[MaxParams];
- QObject *plain = NULL;
- for (int i = 0; i < argsLen; i++) {
- int paramType = method.parameterType(i);
- if (paramType == 0 && a[1 + i] != NULL) {
- const char *typeName = method.parameterTypes()[i].constData();
- void *addr = a[1 + i];
- if (typeName[strlen(typeName)-1] == '*') {
- addr = *(void **)addr;
- }
- plain = new PlainObject(typeName, addr, plain);
- QVariant var = QVariant::fromValue((QObject *)plain);
- packDataValue(&var, &args[i]);
- } else {
- QVariant var(method.parameterType(i), a[1 + i]);
- packDataValue(&var, &args[i]);
- }
- }
- hookSignalCall(engine, func, args);
- if (plain != NULL) {
- delete plain;
- }
- return -1;
- }
- return standard_qt_metacall(c, idx, a);
-}
-
-// vim:ts=4:sw=4:et
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/connector.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/connector.h
deleted file mode 100644
index 82954927b..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/connector.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef CONNECTOR_H
-#define CONNECTOR_H
-
-#include
-
-#include
-
-class Connector : public QObject
-{
- Q_OBJECT
-
- public:
-
- Connector(QObject *sender, QMetaMethod method, QQmlEngine *engine, void *func, int argsLen)
- : QObject(sender), engine(engine), method(method), func(func), argsLen(argsLen) {};
-
- virtual ~Connector();
-
- // MOC HACK: s/Connector::qt_metacall/Connector::standard_qt_metacall/
- int standard_qt_metacall(QMetaObject::Call c, int idx, void **a);
-
- public slots:
-
- void invoke();
-
- private:
-
- QQmlEngine *engine;
- QMetaMethod method;
- void *func;
- int argsLen;
-};
-
-class PlainObject : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(QString plainType READ getPlainType)
- Q_PROPERTY(void *plainAddr READ getPlainAddr)
-
- QString plainType;
- void *plainAddr;
-
- public:
-
- PlainObject(QObject *parent = 0)
- : QObject(parent) {};
-
- PlainObject(const char *plainType, void *plainAddr, QObject *parent = 0)
- : QObject(parent), plainType(plainType), plainAddr(plainAddr) {};
-
- QString getPlainType() { return plainType; };
- void *getPlainAddr() { return plainAddr; };
-};
-
-#endif // CONNECTOR_H
-
-// vim:ts=4:sw=4:et
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govalue.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govalue.cpp
deleted file mode 100644
index 5cf58a62d..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govalue.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-#include
-
-#include
-#include
-
-#include
-#include
-#include
-
-#include "govalue.h"
-#include "capi.h"
-
-class GoValueMetaObject : public QAbstractDynamicMetaObject
-{
-public:
- GoValueMetaObject(QObject* value, GoAddr *addr, GoTypeInfo *typeInfo);
-
- void activatePropIndex(int propIndex);
-
-protected:
- int metaCall(QMetaObject::Call c, int id, void **a);
-
-private:
- QObject *value;
- GoAddr *addr;
- GoTypeInfo *typeInfo;
-};
-
-GoValueMetaObject::GoValueMetaObject(QObject *value, GoAddr *addr, GoTypeInfo *typeInfo)
- : value(value), addr(addr), typeInfo(typeInfo)
-{
- //d->parent = static_cast(priv->metaObject);
- *static_cast(this) = *metaObjectFor(typeInfo);
-
- QObjectPrivate *objPriv = QObjectPrivate::get(value);
- objPriv->metaObject = this;
-}
-
-int GoValueMetaObject::metaCall(QMetaObject::Call c, int idx, void **a)
-{
- //qWarning() << "GoValueMetaObject::metaCall" << c << idx;
- switch (c) {
- case QMetaObject::ReadProperty:
- case QMetaObject::WriteProperty:
- {
- // TODO Cache propertyOffset, methodOffset (and maybe qmlEngine)
- int propOffset = propertyOffset();
- if (idx < propOffset) {
- return value->qt_metacall(c, idx, a);
- }
- GoMemberInfo *memberInfo = typeInfo->fields;
- for (int i = 0; i < typeInfo->fieldsLen; i++) {
- if (memberInfo->metaIndex == idx) {
- if (c == QMetaObject::ReadProperty) {
- DataValue result;
- hookGoValueReadField(qmlEngine(value), addr, memberInfo->reflectIndex, memberInfo->reflectGetIndex, memberInfo->reflectSetIndex, &result);
- if (memberInfo->memberType == DTListProperty) {
- if (result.dataType != DTListProperty) {
- panicf("reading DTListProperty field returned non-DTListProperty result");
- }
- QQmlListProperty *in = *reinterpret_cast **>(result.data);
- QQmlListProperty *out = reinterpret_cast *>(a[0]);
- *out = *in;
- // TODO Could provide a single variable in the stack to ReadField instead.
- delete in;
- } else {
- QVariant *out = reinterpret_cast(a[0]);
- unpackDataValue(&result, out);
- }
- } else {
- DataValue assign;
- QVariant *in = reinterpret_cast(a[0]);
- packDataValue(in, &assign);
- hookGoValueWriteField(qmlEngine(value), addr, memberInfo->reflectIndex, memberInfo->reflectSetIndex, &assign);
- activate(value, methodOffset() + (idx - propOffset), 0);
- }
- return -1;
- }
- memberInfo++;
- }
- QMetaProperty prop = property(idx);
- qWarning() << "Property" << prop.name() << "not found!?";
- break;
- }
- case QMetaObject::InvokeMetaMethod:
- {
- if (idx < methodOffset()) {
- return value->qt_metacall(c, idx, a);
- }
- GoMemberInfo *memberInfo = typeInfo->methods;
- for (int i = 0; i < typeInfo->methodsLen; i++) {
- if (memberInfo->metaIndex == idx) {
- // args[0] is the result if any.
- DataValue args[1 + MaxParams];
- for (int i = 1; i < memberInfo->numIn+1; i++) {
- packDataValue(reinterpret_cast(a[i]), &args[i]);
- }
- hookGoValueCallMethod(qmlEngine(value), addr, memberInfo->reflectIndex, args);
- if (memberInfo->numOut > 0) {
- unpackDataValue(&args[0], reinterpret_cast(a[0]));
- }
- return -1;
- }
- memberInfo++;
- }
- QMetaMethod m = method(idx);
- qWarning() << "Method" << m.name() << "not found!?";
- break;
- }
- default:
- break; // Unhandled.
- }
- return -1;
-}
-
-void GoValueMetaObject::activatePropIndex(int propIndex)
-{
- // Properties are added first, so the first fieldLen methods are in
- // fact the signals of the respective properties.
- int relativeIndex = propIndex - propertyOffset();
- activate(value, methodOffset() + relativeIndex, 0);
-}
-
-GoValue::GoValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject *parent)
- : addr(addr), typeInfo(typeInfo)
-{
- valueMeta = new GoValueMetaObject(this, addr, typeInfo);
- setParent(parent);
-}
-
-GoValue::~GoValue()
-{
- hookGoValueDestroyed(qmlEngine(this), addr);
-}
-
-void GoValue::activate(int propIndex)
-{
- valueMeta->activatePropIndex(propIndex);
-}
-
-GoPaintedValue::GoPaintedValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject *parent)
- : addr(addr), typeInfo(typeInfo)
-{
- valueMeta = new GoValueMetaObject(this, addr, typeInfo);
- setParent(parent);
-
- QQuickItem::setFlag(QQuickItem::ItemHasContents, true);
- QQuickPaintedItem::setRenderTarget(QQuickPaintedItem::FramebufferObject);
-}
-
-GoPaintedValue::~GoPaintedValue()
-{
- hookGoValueDestroyed(qmlEngine(this), addr);
-}
-
-void GoPaintedValue::activate(int propIndex)
-{
- valueMeta->activatePropIndex(propIndex);
-}
-
-void GoPaintedValue::paint(QPainter *painter)
-{
- painter->beginNativePainting();
- hookGoValuePaint(qmlEngine(this), addr, typeInfo->paint->reflectIndex);
- painter->endNativePainting();
-}
-
-QMetaObject *metaObjectFor(GoTypeInfo *typeInfo)
-{
- if (typeInfo->metaObject) {
- return reinterpret_cast(typeInfo->metaObject);
- }
-
- QMetaObjectBuilder mob;
- if (typeInfo->paint) {
- mob.setSuperClass(&QQuickPaintedItem::staticMetaObject);
- } else {
- mob.setSuperClass(&QObject::staticMetaObject);
- }
- mob.setClassName(typeInfo->typeName);
- mob.setFlags(QMetaObjectBuilder::DynamicMetaObject);
-
- GoMemberInfo *memberInfo;
-
- memberInfo = typeInfo->fields;
- int relativePropIndex = mob.propertyCount();
- for (int i = 0; i < typeInfo->fieldsLen; i++) {
- mob.addSignal("__" + QByteArray::number(relativePropIndex) + "()");
- const char *typeName = "QVariant";
- if (memberInfo->memberType == DTListProperty) {
- typeName = "QQmlListProperty";
- }
- QMetaPropertyBuilder propb = mob.addProperty(memberInfo->memberName, typeName, relativePropIndex);
- propb.setWritable(true);
- memberInfo->metaIndex = relativePropIndex;
- memberInfo++;
- relativePropIndex++;
- }
-
- memberInfo = typeInfo->methods;
- int relativeMethodIndex = mob.methodCount();
- for (int i = 0; i < typeInfo->methodsLen; i++) {
- if (*memberInfo->resultSignature) {
- mob.addMethod(memberInfo->methodSignature, memberInfo->resultSignature);
- } else {
- mob.addMethod(memberInfo->methodSignature);
- }
- memberInfo->metaIndex = relativeMethodIndex;
- memberInfo++;
- relativeMethodIndex++;
- }
-
- // TODO Support default properties.
- //mob.addClassInfo("DefaultProperty", "objects");
-
- QMetaObject *mo = mob.toMetaObject();
-
- // Turn the relative indexes into absolute indexes.
- memberInfo = typeInfo->fields;
- int propOffset = mo->propertyOffset();
- for (int i = 0; i < typeInfo->fieldsLen; i++) {
- memberInfo->metaIndex += propOffset;
- memberInfo++;
- }
- memberInfo = typeInfo->methods;
- int methodOffset = mo->methodOffset();
- for (int i = 0; i < typeInfo->methodsLen; i++) {
- memberInfo->metaIndex += methodOffset;
- memberInfo++;
- }
-
- typeInfo->metaObject = mo;
- return mo;
-}
-
-// vim:ts=4:sw=4:et:ft=cpp
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govalue.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govalue.h
deleted file mode 100644
index aa6ddd10c..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govalue.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef GOVALUE_H
-#define GOVALUE_H
-
-// Unfortunatley we need access to private bits, because the
-// whole dynamic meta-object concept is sadly being hidden
-// away, and without it this package wouldn't exist.
-#include
-
-#include
-#include
-
-#include "capi.h"
-
-class GoValueMetaObject;
-
-QMetaObject *metaObjectFor(GoTypeInfo *typeInfo);
-
-class GoValue : public QObject
-{
- Q_OBJECT
-
-public:
- GoAddr *addr;
- GoTypeInfo *typeInfo;
-
- GoValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject *parent);
- virtual ~GoValue();
-
- void activate(int propIndex);
-
-private:
- GoValueMetaObject *valueMeta;
-};
-
-class GoPaintedValue : public QQuickPaintedItem
-{
- Q_OBJECT
-
-public:
- GoAddr *addr;
- GoTypeInfo *typeInfo;
-
- GoPaintedValue(GoAddr *addr, GoTypeInfo *typeInfo, QObject *parent);
- virtual ~GoPaintedValue();
-
- void activate(int propIndex);
-
- virtual void paint(QPainter *painter);
-
-private:
- GoValueMetaObject *valueMeta;
-};
-
-#endif // GOVALUE_H
-
-// vim:ts=4:sw=4:et:ft=cpp
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govaluetype.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govaluetype.cpp
deleted file mode 100644
index 925045390..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govaluetype.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-#include "govaluetype.h"
-
-#define DEFINE_GOVALUETYPE(N) \
- template<> QMetaObject GoValueType::staticMetaObject = QMetaObject(); \
- template<> GoTypeInfo *GoValueType::typeInfo = 0; \
- template<> GoTypeSpec_ *GoValueType::typeSpec = 0;
-
-#define DEFINE_GOPAINTEDVALUETYPE(N) \
- template<> QMetaObject GoPaintedValueType::staticMetaObject = QMetaObject(); \
- template<> GoTypeInfo *GoPaintedValueType::typeInfo = 0; \
- template<> GoTypeSpec_ *GoPaintedValueType::typeSpec = 0;
-
-DEFINE_GOVALUETYPE(1)
-DEFINE_GOVALUETYPE(2)
-DEFINE_GOVALUETYPE(3)
-DEFINE_GOVALUETYPE(4)
-DEFINE_GOVALUETYPE(5)
-DEFINE_GOVALUETYPE(6)
-DEFINE_GOVALUETYPE(7)
-DEFINE_GOVALUETYPE(8)
-DEFINE_GOVALUETYPE(9)
-DEFINE_GOVALUETYPE(10)
-DEFINE_GOVALUETYPE(11)
-DEFINE_GOVALUETYPE(12)
-DEFINE_GOVALUETYPE(13)
-DEFINE_GOVALUETYPE(14)
-DEFINE_GOVALUETYPE(15)
-DEFINE_GOVALUETYPE(16)
-DEFINE_GOVALUETYPE(17)
-DEFINE_GOVALUETYPE(18)
-DEFINE_GOVALUETYPE(19)
-DEFINE_GOVALUETYPE(20)
-DEFINE_GOVALUETYPE(21)
-DEFINE_GOVALUETYPE(22)
-DEFINE_GOVALUETYPE(23)
-DEFINE_GOVALUETYPE(24)
-DEFINE_GOVALUETYPE(25)
-DEFINE_GOVALUETYPE(26)
-DEFINE_GOVALUETYPE(27)
-DEFINE_GOVALUETYPE(28)
-DEFINE_GOVALUETYPE(29)
-DEFINE_GOVALUETYPE(30)
-
-DEFINE_GOPAINTEDVALUETYPE(1)
-DEFINE_GOPAINTEDVALUETYPE(2)
-DEFINE_GOPAINTEDVALUETYPE(3)
-DEFINE_GOPAINTEDVALUETYPE(4)
-DEFINE_GOPAINTEDVALUETYPE(5)
-DEFINE_GOPAINTEDVALUETYPE(6)
-DEFINE_GOPAINTEDVALUETYPE(7)
-DEFINE_GOPAINTEDVALUETYPE(8)
-DEFINE_GOPAINTEDVALUETYPE(9)
-DEFINE_GOPAINTEDVALUETYPE(10)
-DEFINE_GOPAINTEDVALUETYPE(11)
-DEFINE_GOPAINTEDVALUETYPE(12)
-DEFINE_GOPAINTEDVALUETYPE(13)
-DEFINE_GOPAINTEDVALUETYPE(14)
-DEFINE_GOPAINTEDVALUETYPE(15)
-DEFINE_GOPAINTEDVALUETYPE(16)
-DEFINE_GOPAINTEDVALUETYPE(17)
-DEFINE_GOPAINTEDVALUETYPE(18)
-DEFINE_GOPAINTEDVALUETYPE(19)
-DEFINE_GOPAINTEDVALUETYPE(20)
-DEFINE_GOPAINTEDVALUETYPE(21)
-DEFINE_GOPAINTEDVALUETYPE(22)
-DEFINE_GOPAINTEDVALUETYPE(23)
-DEFINE_GOPAINTEDVALUETYPE(24)
-DEFINE_GOPAINTEDVALUETYPE(25)
-DEFINE_GOPAINTEDVALUETYPE(26)
-DEFINE_GOPAINTEDVALUETYPE(27)
-DEFINE_GOPAINTEDVALUETYPE(28)
-DEFINE_GOPAINTEDVALUETYPE(29)
-DEFINE_GOPAINTEDVALUETYPE(30)
-
-static int goValueTypeN = 0;
-static int goPaintedValueTypeN = 0;
-
-template
-int registerSingletonN(char *location, int major, int minor, char *name, GoTypeInfo *info, GoTypeSpec_ *spec) {
- GoValueType::init(info, spec);
- return qmlRegisterSingletonType< GoValueType >(location, major, minor, name, [](QQmlEngine *qmlEngine, QJSEngine *jsEngine) -> QObject* {
- QObject *singleton = new GoValueType();
- QQmlEngine::setContextForObject(singleton, qmlEngine->rootContext());
- return singleton;
- });
-}
-
-template
-int registerPaintedSingletonN(char *location, int major, int minor, char *name, GoTypeInfo *info, GoTypeSpec_ *spec) {
- GoPaintedValueType::init(info, spec);
- return qmlRegisterSingletonType< GoPaintedValueType >(location, major, minor, name, [](QQmlEngine *qmlEngine, QJSEngine *jsEngine) -> QObject* {
- QObject *singleton = new GoPaintedValueType();
- QQmlEngine::setContextForObject(singleton, qmlEngine->rootContext());
- return singleton;
- });
-}
-
-#define GOVALUETYPE_CASE_SINGLETON(N) \
- case N: return registerSingletonN(location, major, minor, name, info, spec);
-#define GOPAINTEDVALUETYPE_CASE_SINGLETON(N) \
- case N: return registerPaintedSingletonN(location, major, minor, name, info, spec);
-
-int registerSingleton(char *location, int major, int minor, char *name, GoTypeInfo *info, GoTypeSpec_ *spec)
-{
- if (!info->paint) {
- switch (++goValueTypeN) {
- GOVALUETYPE_CASE_SINGLETON(1)
- GOVALUETYPE_CASE_SINGLETON(2)
- GOVALUETYPE_CASE_SINGLETON(3)
- GOVALUETYPE_CASE_SINGLETON(4)
- GOVALUETYPE_CASE_SINGLETON(5)
- GOVALUETYPE_CASE_SINGLETON(6)
- GOVALUETYPE_CASE_SINGLETON(7)
- GOVALUETYPE_CASE_SINGLETON(8)
- GOVALUETYPE_CASE_SINGLETON(9)
- GOVALUETYPE_CASE_SINGLETON(10)
- GOVALUETYPE_CASE_SINGLETON(11)
- GOVALUETYPE_CASE_SINGLETON(12)
- GOVALUETYPE_CASE_SINGLETON(13)
- GOVALUETYPE_CASE_SINGLETON(14)
- GOVALUETYPE_CASE_SINGLETON(15)
- GOVALUETYPE_CASE_SINGLETON(16)
- GOVALUETYPE_CASE_SINGLETON(17)
- GOVALUETYPE_CASE_SINGLETON(18)
- GOVALUETYPE_CASE_SINGLETON(19)
- GOVALUETYPE_CASE_SINGLETON(20)
- GOVALUETYPE_CASE_SINGLETON(21)
- GOVALUETYPE_CASE_SINGLETON(22)
- GOVALUETYPE_CASE_SINGLETON(23)
- GOVALUETYPE_CASE_SINGLETON(24)
- GOVALUETYPE_CASE_SINGLETON(25)
- GOVALUETYPE_CASE_SINGLETON(26)
- GOVALUETYPE_CASE_SINGLETON(27)
- GOVALUETYPE_CASE_SINGLETON(28)
- GOVALUETYPE_CASE_SINGLETON(29)
- GOVALUETYPE_CASE_SINGLETON(30)
- }
- } else {
- switch (++goPaintedValueTypeN) {
- GOPAINTEDVALUETYPE_CASE_SINGLETON(1)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(2)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(3)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(4)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(5)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(6)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(7)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(8)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(9)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(10)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(11)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(12)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(13)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(14)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(15)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(16)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(17)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(18)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(19)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(20)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(21)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(22)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(23)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(24)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(25)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(26)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(27)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(28)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(29)
- GOPAINTEDVALUETYPE_CASE_SINGLETON(30)
- }
- }
- panicf("too many registered types; please contact the Go QML developers");
- return 0;
-}
-
-#define GOVALUETYPE_CASE(N) \
- case N: GoValueType::init(info, spec); return qmlRegisterType< GoValueType >(location, major, minor, name);
-#define GOPAINTEDVALUETYPE_CASE(N) \
- case N: GoPaintedValueType::init(info, spec); return qmlRegisterType< GoPaintedValueType >(location, major, minor, name);
-
-int registerType(char *location, int major, int minor, char *name, GoTypeInfo *info, GoTypeSpec_ *spec)
-{
- if (!info->paint) {
- switch (++goValueTypeN) {
- GOVALUETYPE_CASE(1)
- GOVALUETYPE_CASE(2)
- GOVALUETYPE_CASE(3)
- GOVALUETYPE_CASE(4)
- GOVALUETYPE_CASE(5)
- GOVALUETYPE_CASE(6)
- GOVALUETYPE_CASE(7)
- GOVALUETYPE_CASE(8)
- GOVALUETYPE_CASE(9)
- GOVALUETYPE_CASE(10)
- GOVALUETYPE_CASE(11)
- GOVALUETYPE_CASE(12)
- GOVALUETYPE_CASE(13)
- GOVALUETYPE_CASE(14)
- GOVALUETYPE_CASE(15)
- GOVALUETYPE_CASE(16)
- GOVALUETYPE_CASE(17)
- GOVALUETYPE_CASE(18)
- GOVALUETYPE_CASE(19)
- GOVALUETYPE_CASE(20)
- GOVALUETYPE_CASE(21)
- GOVALUETYPE_CASE(22)
- GOVALUETYPE_CASE(23)
- GOVALUETYPE_CASE(24)
- GOVALUETYPE_CASE(25)
- GOVALUETYPE_CASE(26)
- GOVALUETYPE_CASE(27)
- GOVALUETYPE_CASE(28)
- GOVALUETYPE_CASE(29)
- GOVALUETYPE_CASE(30)
- }
- } else {
- switch (++goPaintedValueTypeN) {
- GOPAINTEDVALUETYPE_CASE(1)
- GOPAINTEDVALUETYPE_CASE(2)
- GOPAINTEDVALUETYPE_CASE(3)
- GOPAINTEDVALUETYPE_CASE(4)
- GOPAINTEDVALUETYPE_CASE(5)
- GOPAINTEDVALUETYPE_CASE(6)
- GOPAINTEDVALUETYPE_CASE(7)
- GOPAINTEDVALUETYPE_CASE(8)
- GOPAINTEDVALUETYPE_CASE(9)
- GOPAINTEDVALUETYPE_CASE(10)
- GOPAINTEDVALUETYPE_CASE(11)
- GOPAINTEDVALUETYPE_CASE(12)
- GOPAINTEDVALUETYPE_CASE(13)
- GOPAINTEDVALUETYPE_CASE(14)
- GOPAINTEDVALUETYPE_CASE(15)
- GOPAINTEDVALUETYPE_CASE(16)
- GOPAINTEDVALUETYPE_CASE(17)
- GOPAINTEDVALUETYPE_CASE(18)
- GOPAINTEDVALUETYPE_CASE(19)
- GOPAINTEDVALUETYPE_CASE(20)
- GOPAINTEDVALUETYPE_CASE(21)
- GOPAINTEDVALUETYPE_CASE(22)
- GOPAINTEDVALUETYPE_CASE(23)
- GOPAINTEDVALUETYPE_CASE(24)
- GOPAINTEDVALUETYPE_CASE(25)
- GOPAINTEDVALUETYPE_CASE(26)
- GOPAINTEDVALUETYPE_CASE(27)
- GOPAINTEDVALUETYPE_CASE(28)
- GOPAINTEDVALUETYPE_CASE(29)
- GOPAINTEDVALUETYPE_CASE(30)
- }
- }
- panicf("too many registered types; please contact the Go QML developers");
- return 0;
-}
-
-// vim:sw=4:st=4:et:ft=cpp
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govaluetype.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govaluetype.h
deleted file mode 100644
index 6007d394c..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/govaluetype.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef GOVALUETYPE_H
-#define GOVALUETYPE_H
-
-#include "govalue.h"
-
-template
-class GoValueType : public GoValue
-{
-public:
-
- GoValueType()
- : GoValue(hookGoValueTypeNew(this, typeSpec), typeInfo, 0) {};
-
- static void init(GoTypeInfo *info, GoTypeSpec_ *spec)
- {
- typeInfo = info;
- typeSpec = spec;
- static_cast(staticMetaObject) = *metaObjectFor(typeInfo);
- };
-
- static GoTypeSpec_ *typeSpec;
- static GoTypeInfo *typeInfo;
- static QMetaObject staticMetaObject;
-};
-
-template
-class GoPaintedValueType : public GoPaintedValue
-{
-public:
-
- GoPaintedValueType()
- : GoPaintedValue(hookGoValueTypeNew(this, typeSpec), typeInfo, 0) {};
-
- static void init(GoTypeInfo *info, GoTypeSpec_ *spec)
- {
- typeInfo = info;
- typeSpec = spec;
- static_cast(staticMetaObject) = *metaObjectFor(typeInfo);
- };
-
- static GoTypeSpec_ *typeSpec;
- static GoTypeInfo *typeInfo;
- static QMetaObject staticMetaObject;
-};
-
-#endif // GOVALUETYPE_H
-
-// vim:ts=4:sw=4:et
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/idletimer.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/idletimer.cpp
deleted file mode 100644
index 3bd097508..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/idletimer.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include
-#include
-#include
-#include
-
-#include "capi.h"
-
-class IdleTimer : public QObject
-{
- Q_OBJECT
-
- public:
-
- static IdleTimer *singleton() {
- static IdleTimer singleton;
- return &singleton;
- }
-
- void init(int32_t *guiIdleRun)
- {
- this->guiIdleRun = guiIdleRun;
- }
-
- Q_INVOKABLE void start()
- {
- timer.start(0, this);
- }
-
- protected:
-
- void timerEvent(QTimerEvent *event)
- {
- __sync_synchronize();
- if (*guiIdleRun > 0) {
- hookIdleTimer();
- } else {
- timer.stop();
- }
- }
-
- private:
-
- int32_t *guiIdleRun;
-
- QBasicTimer timer;
-};
-
-void idleTimerInit(int32_t *guiIdleRun)
-{
- IdleTimer::singleton()->init(guiIdleRun);
-}
-
-void idleTimerStart()
-{
- QMetaObject::invokeMethod(IdleTimer::singleton(), "start", Qt::QueuedConnection);
-}
-
-// vim:ts=4:sw=4:et:ft=cpp
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/mmemwin.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/mmemwin.cpp
deleted file mode 100644
index 7aa3bff2b..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/mmemwin.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include
-
-#define protREAD 1
-#define protWRITE 2
-#define protEXEC 4
-
-extern "C" {
-
-int mprotect(void *addr, size_t len, int prot)
-{
- DWORD wprot = 0;
- if (prot & protWRITE) {
- wprot = PAGE_READWRITE;
- } else if (prot & protREAD) {
- wprot = PAGE_READONLY;
- }
- if (prot & protEXEC) {
- wprot <<= 4;
- }
- DWORD oldwprot;
- if (!VirtualProtect(addr, len, wprot, &oldwprot)) {
- return -1;
- }
- return 0;
-}
-
-} // extern "C"
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_all.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_all.cpp
deleted file mode 100644
index cff097058..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_all.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// This file is automatically generated by cpp/update-moc.sh
-#include "cpp/moc_connector.cpp"
-#include "cpp/moc_govalue.cpp"
-#include "cpp/moc_idletimer.cpp"
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_connector.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_connector.cpp
deleted file mode 100644
index 2de2d827a..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_connector.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-/****************************************************************************
-** Meta object code from reading C++ file 'connector.h'
-**
-** Created by: The Qt Meta Object Compiler version 67 (Qt 5.2.1)
-**
-** WARNING! All changes made in this file will be lost!
-*****************************************************************************/
-
-#include "connector.h"
-#include
-#include
-#if !defined(Q_MOC_OUTPUT_REVISION)
-#error "The header file 'connector.h' doesn't include ."
-#elif Q_MOC_OUTPUT_REVISION != 67
-#error "This file was generated using the moc from 5.2.1. It"
-#error "cannot be used with the include files from this version of Qt."
-#error "(The moc has changed too much.)"
-#endif
-
-QT_BEGIN_MOC_NAMESPACE
-struct qt_meta_stringdata_Connector_t {
- QByteArrayData data[3];
- char stringdata[19];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- offsetof(qt_meta_stringdata_Connector_t, stringdata) + ofs \
- - idx * sizeof(QByteArrayData) \
- )
-static const qt_meta_stringdata_Connector_t qt_meta_stringdata_Connector = {
- {
-QT_MOC_LITERAL(0, 0, 9),
-QT_MOC_LITERAL(1, 10, 6),
-QT_MOC_LITERAL(2, 17, 0)
- },
- "Connector\0invoke\0\0"
-};
-#undef QT_MOC_LITERAL
-
-static const uint qt_meta_data_Connector[] = {
-
- // content:
- 7, // revision
- 0, // classname
- 0, 0, // classinfo
- 1, 14, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
- 0, 0, // constructors
- 0, // flags
- 0, // signalCount
-
- // slots: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x0a,
-
- // slots: parameters
- QMetaType::Void,
-
- 0 // eod
-};
-
-void Connector::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
-{
- if (_c == QMetaObject::InvokeMetaMethod) {
- Connector *_t = static_cast(_o);
- switch (_id) {
- case 0: _t->invoke(); break;
- default: ;
- }
- }
- Q_UNUSED(_a);
-}
-
-const QMetaObject Connector::staticMetaObject = {
- { &QObject::staticMetaObject, qt_meta_stringdata_Connector.data,
- qt_meta_data_Connector, qt_static_metacall, 0, 0}
-};
-
-
-const QMetaObject *Connector::metaObject() const
-{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
-}
-
-void *Connector::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_Connector.stringdata))
- return static_cast(const_cast< Connector*>(this));
- return QObject::qt_metacast(_clname);
-}
-
-int Connector::standard_qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QObject::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- if (_c == QMetaObject::InvokeMetaMethod) {
- if (_id < 1)
- qt_static_metacall(this, _c, _id, _a);
- _id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
- }
- return _id;
-}
-struct qt_meta_stringdata_PlainObject_t {
- QByteArrayData data[3];
- char stringdata[33];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- offsetof(qt_meta_stringdata_PlainObject_t, stringdata) + ofs \
- - idx * sizeof(QByteArrayData) \
- )
-static const qt_meta_stringdata_PlainObject_t qt_meta_stringdata_PlainObject = {
- {
-QT_MOC_LITERAL(0, 0, 11),
-QT_MOC_LITERAL(1, 12, 9),
-QT_MOC_LITERAL(2, 22, 9)
- },
- "PlainObject\0plainType\0plainAddr\0"
-};
-#undef QT_MOC_LITERAL
-
-static const uint qt_meta_data_PlainObject[] = {
-
- // content:
- 7, // revision
- 0, // classname
- 0, 0, // classinfo
- 0, 0, // methods
- 2, 14, // properties
- 0, 0, // enums/sets
- 0, 0, // constructors
- 0, // flags
- 0, // signalCount
-
- // properties: name, type, flags
- 1, QMetaType::QString, 0x00095001,
- 2, QMetaType::VoidStar, 0x00095001,
-
- 0 // eod
-};
-
-void PlainObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
-{
- Q_UNUSED(_o);
- Q_UNUSED(_id);
- Q_UNUSED(_c);
- Q_UNUSED(_a);
-}
-
-const QMetaObject PlainObject::staticMetaObject = {
- { &QObject::staticMetaObject, qt_meta_stringdata_PlainObject.data,
- qt_meta_data_PlainObject, qt_static_metacall, 0, 0}
-};
-
-
-const QMetaObject *PlainObject::metaObject() const
-{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
-}
-
-void *PlainObject::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_PlainObject.stringdata))
- return static_cast(const_cast< PlainObject*>(this));
- return QObject::qt_metacast(_clname);
-}
-
-int PlainObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QObject::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
-
-#ifndef QT_NO_PROPERTIES
- if (_c == QMetaObject::ReadProperty) {
- void *_v = _a[0];
- switch (_id) {
- case 0: *reinterpret_cast< QString*>(_v) = getPlainType(); break;
- case 1: *reinterpret_cast< void**>(_v) = getPlainAddr(); break;
- }
- _id -= 2;
- } else if (_c == QMetaObject::WriteProperty) {
- _id -= 2;
- } else if (_c == QMetaObject::ResetProperty) {
- _id -= 2;
- } else if (_c == QMetaObject::QueryPropertyDesignable) {
- _id -= 2;
- } else if (_c == QMetaObject::QueryPropertyScriptable) {
- _id -= 2;
- } else if (_c == QMetaObject::QueryPropertyStored) {
- _id -= 2;
- } else if (_c == QMetaObject::QueryPropertyEditable) {
- _id -= 2;
- } else if (_c == QMetaObject::QueryPropertyUser) {
- _id -= 2;
- } else if (_c == QMetaObject::RegisterPropertyMetaType) {
- if (_id < 2)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 2;
- }
-#endif // QT_NO_PROPERTIES
- return _id;
-}
-QT_END_MOC_NAMESPACE
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_govalue.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_govalue.cpp
deleted file mode 100644
index e41f86042..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_govalue.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/****************************************************************************
-** Meta object code from reading C++ file 'govalue.h'
-**
-** Created by: The Qt Meta Object Compiler version 67 (Qt 5.2.1)
-**
-** WARNING! All changes made in this file will be lost!
-*****************************************************************************/
-
-#include "govalue.h"
-#include
-#include
-#if !defined(Q_MOC_OUTPUT_REVISION)
-#error "The header file 'govalue.h' doesn't include ."
-#elif Q_MOC_OUTPUT_REVISION != 67
-#error "This file was generated using the moc from 5.2.1. It"
-#error "cannot be used with the include files from this version of Qt."
-#error "(The moc has changed too much.)"
-#endif
-
-QT_BEGIN_MOC_NAMESPACE
-struct qt_meta_stringdata_GoValue_t {
- QByteArrayData data[1];
- char stringdata[9];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- offsetof(qt_meta_stringdata_GoValue_t, stringdata) + ofs \
- - idx * sizeof(QByteArrayData) \
- )
-static const qt_meta_stringdata_GoValue_t qt_meta_stringdata_GoValue = {
- {
-QT_MOC_LITERAL(0, 0, 7)
- },
- "GoValue\0"
-};
-#undef QT_MOC_LITERAL
-
-static const uint qt_meta_data_GoValue[] = {
-
- // content:
- 7, // revision
- 0, // classname
- 0, 0, // classinfo
- 0, 0, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
- 0, 0, // constructors
- 0, // flags
- 0, // signalCount
-
- 0 // eod
-};
-
-void GoValue::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
-{
- Q_UNUSED(_o);
- Q_UNUSED(_id);
- Q_UNUSED(_c);
- Q_UNUSED(_a);
-}
-
-const QMetaObject GoValue::staticMetaObject = {
- { &QObject::staticMetaObject, qt_meta_stringdata_GoValue.data,
- qt_meta_data_GoValue, qt_static_metacall, 0, 0}
-};
-
-
-const QMetaObject *GoValue::metaObject() const
-{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
-}
-
-void *GoValue::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_GoValue.stringdata))
- return static_cast(const_cast< GoValue*>(this));
- return QObject::qt_metacast(_clname);
-}
-
-int GoValue::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QObject::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- return _id;
-}
-struct qt_meta_stringdata_GoPaintedValue_t {
- QByteArrayData data[1];
- char stringdata[16];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- offsetof(qt_meta_stringdata_GoPaintedValue_t, stringdata) + ofs \
- - idx * sizeof(QByteArrayData) \
- )
-static const qt_meta_stringdata_GoPaintedValue_t qt_meta_stringdata_GoPaintedValue = {
- {
-QT_MOC_LITERAL(0, 0, 14)
- },
- "GoPaintedValue\0"
-};
-#undef QT_MOC_LITERAL
-
-static const uint qt_meta_data_GoPaintedValue[] = {
-
- // content:
- 7, // revision
- 0, // classname
- 0, 0, // classinfo
- 0, 0, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
- 0, 0, // constructors
- 0, // flags
- 0, // signalCount
-
- 0 // eod
-};
-
-void GoPaintedValue::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
-{
- Q_UNUSED(_o);
- Q_UNUSED(_id);
- Q_UNUSED(_c);
- Q_UNUSED(_a);
-}
-
-const QMetaObject GoPaintedValue::staticMetaObject = {
- { &QQuickPaintedItem::staticMetaObject, qt_meta_stringdata_GoPaintedValue.data,
- qt_meta_data_GoPaintedValue, qt_static_metacall, 0, 0}
-};
-
-
-const QMetaObject *GoPaintedValue::metaObject() const
-{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
-}
-
-void *GoPaintedValue::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_GoPaintedValue.stringdata))
- return static_cast(const_cast< GoPaintedValue*>(this));
- return QQuickPaintedItem::qt_metacast(_clname);
-}
-
-int GoPaintedValue::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QQuickPaintedItem::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- return _id;
-}
-QT_END_MOC_NAMESPACE
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_idletimer.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_idletimer.cpp
deleted file mode 100644
index 98dda16e3..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/moc_idletimer.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-** Meta object code from reading C++ file 'idletimer.cpp'
-**
-** Created by: The Qt Meta Object Compiler version 67 (Qt 5.2.1)
-**
-** WARNING! All changes made in this file will be lost!
-*****************************************************************************/
-
-#include
-#include
-#if !defined(Q_MOC_OUTPUT_REVISION)
-#error "The header file 'idletimer.cpp' doesn't include ."
-#elif Q_MOC_OUTPUT_REVISION != 67
-#error "This file was generated using the moc from 5.2.1. It"
-#error "cannot be used with the include files from this version of Qt."
-#error "(The moc has changed too much.)"
-#endif
-
-QT_BEGIN_MOC_NAMESPACE
-struct qt_meta_stringdata_IdleTimer_t {
- QByteArrayData data[3];
- char stringdata[18];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- offsetof(qt_meta_stringdata_IdleTimer_t, stringdata) + ofs \
- - idx * sizeof(QByteArrayData) \
- )
-static const qt_meta_stringdata_IdleTimer_t qt_meta_stringdata_IdleTimer = {
- {
-QT_MOC_LITERAL(0, 0, 9),
-QT_MOC_LITERAL(1, 10, 5),
-QT_MOC_LITERAL(2, 16, 0)
- },
- "IdleTimer\0start\0\0"
-};
-#undef QT_MOC_LITERAL
-
-static const uint qt_meta_data_IdleTimer[] = {
-
- // content:
- 7, // revision
- 0, // classname
- 0, 0, // classinfo
- 1, 14, // methods
- 0, 0, // properties
- 0, 0, // enums/sets
- 0, 0, // constructors
- 0, // flags
- 0, // signalCount
-
- // methods: name, argc, parameters, tag, flags
- 1, 0, 19, 2, 0x02,
-
- // methods: parameters
- QMetaType::Void,
-
- 0 // eod
-};
-
-void IdleTimer::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
-{
- if (_c == QMetaObject::InvokeMetaMethod) {
- IdleTimer *_t = static_cast(_o);
- switch (_id) {
- case 0: _t->start(); break;
- default: ;
- }
- }
- Q_UNUSED(_a);
-}
-
-const QMetaObject IdleTimer::staticMetaObject = {
- { &QObject::staticMetaObject, qt_meta_stringdata_IdleTimer.data,
- qt_meta_data_IdleTimer, qt_static_metacall, 0, 0}
-};
-
-
-const QMetaObject *IdleTimer::metaObject() const
-{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
-}
-
-void *IdleTimer::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_IdleTimer.stringdata))
- return static_cast(const_cast< IdleTimer*>(this));
- return QObject::qt_metacast(_clname);
-}
-
-int IdleTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QObject::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- if (_c == QMetaObject::InvokeMetaMethod) {
- if (_id < 1)
- qt_static_metacall(this, _c, _id, _a);
- _id -= 1;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
- }
- return _id;
-}
-QT_END_MOC_NAMESPACE
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qmetaobject_p.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qmetaobject_p.h
deleted file mode 100644
index af506e54f..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qmetaobject_p.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "private/qtheader.h"
-#include QT_PRIVATE_HEADER(QtCore,qmetaobject_p.h)
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qmetaobjectbuilder_p.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qmetaobjectbuilder_p.h
deleted file mode 100644
index 47cd9b77f..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qmetaobjectbuilder_p.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "private/qtheader.h"
-#include QT_PRIVATE_HEADER(QtCore,qmetaobjectbuilder_p.h)
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qobject_p.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qobject_p.h
deleted file mode 100644
index 75c7f84b4..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qobject_p.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "private/qtheader.h"
-#include QT_PRIVATE_HEADER(QtCore,qobject_p.h)
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qtheader.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qtheader.h
deleted file mode 100644
index efa8b87c4..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/private/qtheader.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef QTPRIVATE_H
-#define QTPRIVATE_H
-
-#include
-
-#define QT_MAJOR_ (QT_VERSION>>16)
-#define QT_MINOR_ (QT_VERSION>>8&0xFF)
-#define QT_MICRO_ (QT_VERSION&0xFF)
-
-#if QT_MAJOR_ == 5
-#define QT_MAJOR 5
-#else
-#error Unupported Qt major version. Please report.
-#endif
-
-#if QT_MINOR_ == 0
-#define QT_MINOR 0
-#elif QT_MINOR_ == 1
-#define QT_MINOR 1
-#elif QT_MINOR_ == 2
-#define QT_MINOR 2
-#elif QT_MINOR_ == 3
-#define QT_MINOR 3
-#elif QT_MINOR_ == 4
-#define QT_MINOR 4
-#elif QT_MINOR_ == 5
-#define QT_MINOR 5
-#elif QT_MINOR_ == 6
-#define QT_MINOR 6
-#elif QT_MINOR_ == 7
-#define QT_MINOR 7
-#elif QT_MINOR_ == 8
-#define QT_MINOR 8
-#elif QT_MINOR_ == 9
-#define QT_MINOR 9
-#elif QT_MINOR_ == 10
-#define QT_MINOR 10
-#else
-#error Unupported Qt minor version. Please report.
-#endif
-
-#if QT_MICRO_ == 0
-#define QT_MICRO 0
-#elif QT_MICRO_ == 1
-#define QT_MICRO 1
-#elif QT_MICRO_ == 2
-#define QT_MICRO 2
-#elif QT_MICRO_ == 3
-#define QT_MICRO 3
-#elif QT_MICRO_ == 4
-#define QT_MICRO 4
-#elif QT_MICRO_ == 5
-#define QT_MICRO 5
-#elif QT_MICRO_ == 6
-#define QT_MICRO 6
-#elif QT_MICRO_ == 7
-#define QT_MICRO 7
-#elif QT_MICRO_ == 8
-#define QT_MICRO 8
-#elif QT_MICRO_ == 9
-#define QT_MICRO 9
-#elif QT_MICRO_ == 10
-#define QT_MICRO 10
-#else
-#error Unupported Qt micro version. Please report.
-#endif
-
-#define QT_PRIVATE_HEADER(dir,file)
-
-#endif // QTPRIVATE_H
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/update-moc.sh b/Godeps/_workspace/src/github.com/obscuren/qml/cpp/update-moc.sh
deleted file mode 100644
index 135840f45..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpp/update-moc.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-set -e
-cd `dirname $0`
-
-subdir=`basename $PWD`
-
-export QT_SELECT=5
-
-ALL=moc_all.cpp
-
-echo "// This file is automatically generated by cpp/update-moc.sh" > $ALL
-
-for file in `grep -l Q_''OBJECT *`; do
- mocfile=`echo $file | awk -F. '{print("moc_"$1".cpp")}'`
- mochack=`sed -n 's,^ *// MOC HACK: \(.*\),\1,p' $file`
- moc $file | sed "$mochack" > $mocfile
- echo "#include \"$subdir/$mocfile\"" >> $ALL
-done
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.cpp
deleted file mode 100644
index e0b25699f..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include
-
-#include "cpptest.h"
-#include "testtype.h"
-
-TestType_ *newTestType()
-{
- return new TestType();
-}
-
-int plainTestTypeN(PlainTestType_ *plain)
-{
- return static_cast(plain)->n;
-}
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.go b/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.go
deleted file mode 100644
index 4ba24bce0..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// Package cpptest is an internal test helper.
-package cpptest
-
-// #cgo CXXFLAGS: -std=c++0x -Wall -fno-strict-aliasing -I..
-// #cgo LDFLAGS: -lstdc++
-//
-// #cgo pkg-config: Qt5Core
-//
-// #include "cpptest.h"
-//
-import "C"
-
-import (
- "unsafe"
-
- "gopkg.in/qml.v1"
-)
-
-func NewTestType(engine *qml.Engine) qml.Object {
- var obj qml.Object
- qml.RunMain(func() {
- addr := C.newTestType()
- obj = qml.CommonOf(addr, engine)
- })
- return obj
-}
-
-func PlainTestTypeN(obj qml.Object) int {
- return int(C.plainTestTypeN(unsafe.Pointer(obj.Property("plainAddr").(uintptr))))
-}
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.h
deleted file mode 100644
index e06a8af3f..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/cpptest.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef UONEAUTH_H
-#define UONEAUTH_H
-
-#include
-#include
-#include
-
-typedef void TestType_;
-typedef void PlainTestType_;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-TestType_ *newTestType();
-
-int plainTestTypeN(PlainTestType_ *plain);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // UONEAUTH_H
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/moc_testtype.cpp b/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/moc_testtype.cpp
deleted file mode 100644
index f958d1b8c..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/moc_testtype.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/****************************************************************************
-** Meta object code from reading C++ file 'testtype.h'
-**
-** Created by: The Qt Meta Object Compiler version 67 (Qt 5.2.1)
-**
-** WARNING! All changes made in this file will be lost!
-*****************************************************************************/
-
-#include "testtype.h"
-#include
-#include
-#if !defined(Q_MOC_OUTPUT_REVISION)
-#error "The header file 'testtype.h' doesn't include ."
-#elif Q_MOC_OUTPUT_REVISION != 67
-#error "This file was generated using the moc from 5.2.1. It"
-#error "cannot be used with the include files from this version of Qt."
-#error "(The moc has changed too much.)"
-#endif
-
-QT_BEGIN_MOC_NAMESPACE
-struct qt_meta_stringdata_TestType_t {
- QByteArrayData data[10];
- char stringdata[119];
-};
-#define QT_MOC_LITERAL(idx, ofs, len) \
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- offsetof(qt_meta_stringdata_TestType_t, stringdata) + ofs \
- - idx * sizeof(QByteArrayData) \
- )
-static const qt_meta_stringdata_TestType_t qt_meta_stringdata_TestType = {
- {
-QT_MOC_LITERAL(0, 0, 8),
-QT_MOC_LITERAL(1, 9, 15),
-QT_MOC_LITERAL(2, 25, 0),
-QT_MOC_LITERAL(3, 26, 13),
-QT_MOC_LITERAL(4, 40, 5),
-QT_MOC_LITERAL(5, 46, 15),
-QT_MOC_LITERAL(6, 62, 15),
-QT_MOC_LITERAL(7, 78, 20),
-QT_MOC_LITERAL(8, 99, 9),
-QT_MOC_LITERAL(9, 109, 8)
- },
- "TestType\0plainEmittedCpy\0\0PlainTestType\0"
- "plain\0plainEmittedRef\0plainEmittedPtr\0"
- "const PlainTestType*\0emitPlain\0voidAddr\0"
-};
-#undef QT_MOC_LITERAL
-
-static const uint qt_meta_data_TestType[] = {
-
- // content:
- 7, // revision
- 0, // classname
- 0, 0, // classinfo
- 4, 14, // methods
- 1, 44, // properties
- 0, 0, // enums/sets
- 0, 0, // constructors
- 0, // flags
- 3, // signalCount
-
- // signals: name, argc, parameters, tag, flags
- 1, 1, 34, 2, 0x06,
- 5, 1, 37, 2, 0x06,
- 6, 1, 40, 2, 0x06,
-
- // methods: name, argc, parameters, tag, flags
- 8, 0, 43, 2, 0x02,
-
- // signals: parameters
- QMetaType::Void, 0x80000000 | 3, 4,
- QMetaType::Void, 0x80000000 | 3, 4,
- QMetaType::Void, 0x80000000 | 7, 4,
-
- // methods: parameters
- QMetaType::Void,
-
- // properties: name, type, flags
- 9, QMetaType::VoidStar, 0x00095001,
-
- 0 // eod
-};
-
-void TestType::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
-{
- if (_c == QMetaObject::InvokeMetaMethod) {
- TestType *_t = static_cast(_o);
- switch (_id) {
- case 0: _t->plainEmittedCpy((*reinterpret_cast< const PlainTestType(*)>(_a[1]))); break;
- case 1: _t->plainEmittedRef((*reinterpret_cast< const PlainTestType(*)>(_a[1]))); break;
- case 2: _t->plainEmittedPtr((*reinterpret_cast< const PlainTestType*(*)>(_a[1]))); break;
- case 3: _t->emitPlain(); break;
- default: ;
- }
- } else if (_c == QMetaObject::IndexOfMethod) {
- int *result = reinterpret_cast(_a[0]);
- void **func = reinterpret_cast(_a[1]);
- {
- typedef void (TestType::*_t)(const PlainTestType );
- if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestType::plainEmittedCpy)) {
- *result = 0;
- }
- }
- {
- typedef void (TestType::*_t)(const PlainTestType & );
- if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestType::plainEmittedRef)) {
- *result = 1;
- }
- }
- {
- typedef void (TestType::*_t)(const PlainTestType * );
- if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestType::plainEmittedPtr)) {
- *result = 2;
- }
- }
- }
-}
-
-const QMetaObject TestType::staticMetaObject = {
- { &QObject::staticMetaObject, qt_meta_stringdata_TestType.data,
- qt_meta_data_TestType, qt_static_metacall, 0, 0}
-};
-
-
-const QMetaObject *TestType::metaObject() const
-{
- return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
-}
-
-void *TestType::qt_metacast(const char *_clname)
-{
- if (!_clname) return 0;
- if (!strcmp(_clname, qt_meta_stringdata_TestType.stringdata))
- return static_cast(const_cast< TestType*>(this));
- return QObject::qt_metacast(_clname);
-}
-
-int TestType::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
-{
- _id = QObject::qt_metacall(_c, _id, _a);
- if (_id < 0)
- return _id;
- if (_c == QMetaObject::InvokeMetaMethod) {
- if (_id < 4)
- qt_static_metacall(this, _c, _id, _a);
- _id -= 4;
- } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
- if (_id < 4)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 4;
- }
-#ifndef QT_NO_PROPERTIES
- else if (_c == QMetaObject::ReadProperty) {
- void *_v = _a[0];
- switch (_id) {
- case 0: *reinterpret_cast< void**>(_v) = getVoidAddr(); break;
- }
- _id -= 1;
- } else if (_c == QMetaObject::WriteProperty) {
- _id -= 1;
- } else if (_c == QMetaObject::ResetProperty) {
- _id -= 1;
- } else if (_c == QMetaObject::QueryPropertyDesignable) {
- _id -= 1;
- } else if (_c == QMetaObject::QueryPropertyScriptable) {
- _id -= 1;
- } else if (_c == QMetaObject::QueryPropertyStored) {
- _id -= 1;
- } else if (_c == QMetaObject::QueryPropertyEditable) {
- _id -= 1;
- } else if (_c == QMetaObject::QueryPropertyUser) {
- _id -= 1;
- } else if (_c == QMetaObject::RegisterPropertyMetaType) {
- if (_id < 1)
- *reinterpret_cast(_a[0]) = -1;
- _id -= 1;
- }
-#endif // QT_NO_PROPERTIES
- return _id;
-}
-
-// SIGNAL 0
-void TestType::plainEmittedCpy(const PlainTestType _t1)
-{
- void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) };
- QMetaObject::activate(this, &staticMetaObject, 0, _a);
-}
-
-// SIGNAL 1
-void TestType::plainEmittedRef(const PlainTestType & _t1)
-{
- void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) };
- QMetaObject::activate(this, &staticMetaObject, 1, _a);
-}
-
-// SIGNAL 2
-void TestType::plainEmittedPtr(const PlainTestType * _t1)
-{
- void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) };
- QMetaObject::activate(this, &staticMetaObject, 2, _a);
-}
-QT_END_MOC_NAMESPACE
diff --git a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/testtype.h b/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/testtype.h
deleted file mode 100644
index 4d281b98f..000000000
--- a/Godeps/_workspace/src/github.com/obscuren/qml/cpptest/testtype.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef TESTTYPE_H
-#define TESTTYPE_H
-
-#include