Add github.com/jroimartin/gocui

Add github.com/jroimartin/gocui. It will be used by the messenger app.

Change-Id: Ibca701ea528cc276c7eca1bd0ae045a6e35297f8
diff --git a/go/src/github.com/jroimartin/gocui/.gitignore b/go/src/github.com/jroimartin/gocui/.gitignore
new file mode 100644
index 0000000..1377554
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/.gitignore
@@ -0,0 +1 @@
+*.swp
diff --git a/go/src/github.com/jroimartin/gocui/AUTHORS b/go/src/github.com/jroimartin/gocui/AUTHORS
new file mode 100644
index 0000000..acf97f4
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/AUTHORS
@@ -0,0 +1,24 @@
+# This is the official list of gocui authors for copyright purposes.
+
+# Names should be added to this file as
+#	Name or Organization <email address> contribution
+#		Contribution
+# The email address is not required for organizations.
+
+Roi Martin <jroi.martin@gmail.com>
+	Main developer
+
+Ryan Sullivan <kayoticsully@gmail.com>
+	Toggleable view frames
+
+Matthieu Rakotojaona <matthieu.rakotojaona@gmail.com>
+	Wrapped views
+
+Harry Lawrence <hazbo@gmx.com>
+	Basic mouse support
+
+Danny Tylman <dtylman@gmail.com>
+	Masked views
+
+Frederik Deweerdt <frederik.deweerdt@gmail.com>
+	Colored fonts
diff --git a/go/src/github.com/jroimartin/gocui/LICENSE b/go/src/github.com/jroimartin/gocui/LICENSE
new file mode 100644
index 0000000..8cb2821
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2014 The gocui Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the gocui Authors nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/src/github.com/jroimartin/gocui/README.google b/go/src/github.com/jroimartin/gocui/README.google
new file mode 100644
index 0000000..a4a1ef2
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/README.google
@@ -0,0 +1,10 @@
+URL: https://github.com/jroimartin/gocui/archive/2dcda558bf18ec07c7065bf1eaf071b5305f7c0c.zip
+Version: 2dcda558bf18ec07c7065bf1eaf071b5305f7c0c
+License: New BSD
+License File: LICENSE
+
+Description:
+Minimalist Go package aimed at creating Console User Interfaces.
+
+Local Modifications:
+None.
diff --git a/go/src/github.com/jroimartin/gocui/README.md b/go/src/github.com/jroimartin/gocui/README.md
new file mode 100644
index 0000000..7662c11
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/README.md
@@ -0,0 +1,91 @@
+# GOCUI - Go Console User Interface
+
+[![GoDoc](https://godoc.org/github.com/jroimartin/gocui?status.svg)](https://godoc.org/github.com/jroimartin/gocui)
+
+Minimalist Go package aimed at creating Console User Interfaces.
+
+## Features
+
+* Minimalist API.
+* Views (the "windows" in the GUI) implement the interface io.ReadWriter.
+* Support for overlapping views.
+* The GUI can be modified at runtime (concurrent-safe).
+* Global and view-level keybindings.
+* Mouse support.
+* Colored text.
+* Customizable edition mode.
+
+## Installation
+
+Execute:
+
+```
+$ go get github.com/jroimartin/gocui
+```
+
+## Documentation
+
+Execute:
+
+```
+$ godoc github.com/jroimartin/gocui
+```
+
+Or visit [godoc.org](https://godoc.org/github.com/jroimartin/gocui) to read it
+online.
+
+## Example
+
+```go
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "Hello world!")
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+```
+
+## Screenshots
+
+_examples/demo.go:
+
+![_examples/demo.go](https://cloud.githubusercontent.com/assets/1223476/5992750/720b84f0-aa36-11e4-88ec-296fa3247b52.png)
+
+_examples/dynamic.go:
+
+![_examples/dynamic.go](https://cloud.githubusercontent.com/assets/1223476/5992751/76ad5cc2-aa36-11e4-8204-6a90269db827.png)
diff --git a/go/src/github.com/jroimartin/gocui/_examples/Mark.Twain-Tom.Sawyer.txt b/go/src/github.com/jroimartin/gocui/_examples/Mark.Twain-Tom.Sawyer.txt
new file mode 100644
index 0000000..f9f1b9c
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/Mark.Twain-Tom.Sawyer.txt
@@ -0,0 +1,420 @@
+The Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete
+by Mark Twain (Samuel Clemens)
+
+This eBook is for the use of anyone anywhere at no cost and with
+almost no restrictions whatsoever.  You may copy it, give it away or
+re-use it under the terms of the Project Gutenberg License included
+with this eBook or online at www.gutenberg.net
+
+
+Title: The Adventures of Tom Sawyer, Complete
+
+Author: Mark Twain (Samuel Clemens)
+
+Release Date: August 20, 2006 [EBook #74]
+[Last updated: May 3, 2011]
+
+Language: English
+
+
+*** START OF THIS PROJECT GUTENBERG EBOOK TOM SAWYER ***
+
+
+
+
+Produced by David Widger. The previous edition was updated by Jose
+Menendez.
+
+
+
+
+
+                   THE ADVENTURES OF TOM SAWYER
+                                BY
+                            MARK TWAIN
+                     (Samuel Langhorne Clemens)
+
+
+
+
+                           P R E F A C E
+
+MOST of the adventures recorded in this book really occurred; one or
+two were experiences of my own, the rest those of boys who were
+schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but
+not from an individual--he is a combination of the characteristics of
+three boys whom I knew, and therefore belongs to the composite order of
+architecture.
+
+The odd superstitions touched upon were all prevalent among children
+and slaves in the West at the period of this story--that is to say,
+thirty or forty years ago.
+
+Although my book is intended mainly for the entertainment of boys and
+girls, I hope it will not be shunned by men and women on that account,
+for part of my plan has been to try to pleasantly remind adults of what
+they once were themselves, and of how they felt and thought and talked,
+and what queer enterprises they sometimes engaged in.
+
+                                                            THE AUTHOR.
+
+HARTFORD, 1876.
+
+
+
+                          T O M   S A W Y E R
+
+
+
+CHAPTER I
+
+"TOM!"
+
+No answer.
+
+"TOM!"
+
+No answer.
+
+"What's gone with that boy,  I wonder? You TOM!"
+
+No answer.
+
+The old lady pulled her spectacles down and looked over them about the
+room; then she put them up and looked out under them. She seldom or
+never looked THROUGH them for so small a thing as a boy; they were her
+state pair, the pride of her heart, and were built for "style," not
+service--she could have seen through a pair of stove-lids just as well.
+She looked perplexed for a moment, and then said, not fiercely, but
+still loud enough for the furniture to hear:
+
+"Well, I lay if I get hold of you I'll--"
+
+She did not finish, for by this time she was bending down and punching
+under the bed with the broom, and so she needed breath to punctuate the
+punches with. She resurrected nothing but the cat.
+
+"I never did see the beat of that boy!"
+
+She went to the open door and stood in it and looked out among the
+tomato vines and "jimpson" weeds that constituted the garden. No Tom.
+So she lifted up her voice at an angle calculated for distance and
+shouted:
+
+"Y-o-u-u TOM!"
+
+There was a slight noise behind her and she turned just in time to
+seize a small boy by the slack of his roundabout and arrest his flight.
+
+"There! I might 'a' thought of that closet. What you been doing in
+there?"
+
+"Nothing."
+
+"Nothing! Look at your hands. And look at your mouth. What IS that
+truck?"
+
+"I don't know, aunt."
+
+"Well, I know. It's jam--that's what it is. Forty times I've said if
+you didn't let that jam alone I'd skin you. Hand me that switch."
+
+The switch hovered in the air--the peril was desperate--
+
+"My! Look behind you, aunt!"
+
+The old lady whirled round, and snatched her skirts out of danger. The
+lad fled on the instant, scrambled up the high board-fence, and
+disappeared over it.
+
+His aunt Polly stood surprised a moment, and then broke into a gentle
+laugh.
+
+"Hang the boy, can't I never learn anything? Ain't he played me tricks
+enough like that for me to be looking out for him by this time? But old
+fools is the biggest fools there is. Can't learn an old dog new tricks,
+as the saying is. But my goodness, he never plays them alike, two days,
+and how is a body to know what's coming? He 'pears to know just how
+long he can torment me before I get my dander up, and he knows if he
+can make out to put me off for a minute or make me laugh, it's all down
+again and I can't hit him a lick. I ain't doing my duty by that boy,
+and that's the Lord's truth, goodness knows. Spare the rod and spile
+the child, as the Good Book says. I'm a laying up sin and suffering for
+us both, I know. He's full of the Old Scratch, but laws-a-me! he's my
+own dead sister's boy, poor thing, and I ain't got the heart to lash
+him, somehow. Every time I let him off, my conscience does hurt me so,
+and every time I hit him my old heart most breaks. Well-a-well, man
+that is born of woman is of few days and full of trouble, as the
+Scripture says, and I reckon it's so. He'll play hookey this evening, *
+and [* Southwestern for "afternoon"] I'll just be obleeged to make him
+work, to-morrow, to punish him. It's mighty hard to make him work
+Saturdays, when all the boys is having holiday, but he hates work more
+than he hates anything else, and I've GOT to do some of my duty by him,
+or I'll be the ruination of the child."
+
+Tom did play hookey, and he had a very good time. He got back home
+barely in season to help Jim, the small colored boy, saw next-day's
+wood and split the kindlings before supper--at least he was there in
+time to tell his adventures to Jim while Jim did three-fourths of the
+work. Tom's younger brother (or rather half-brother) Sid was already
+through with his part of the work (picking up chips), for he was a
+quiet boy, and had no adventurous, troublesome ways.
+
+While Tom was eating his supper, and stealing sugar as opportunity
+offered, Aunt Polly asked him questions that were full of guile, and
+very deep--for she wanted to trap him into damaging revealments. Like
+many other simple-hearted souls, it was her pet vanity to believe she
+was endowed with a talent for dark and mysterious diplomacy, and she
+loved to contemplate her most transparent devices as marvels of low
+cunning. Said she:
+
+"Tom, it was middling warm in school, warn't it?"
+
+"Yes'm."
+
+"Powerful warm, warn't it?"
+
+"Yes'm."
+
+"Didn't you want to go in a-swimming, Tom?"
+
+A bit of a scare shot through Tom--a touch of uncomfortable suspicion.
+He searched Aunt Polly's face, but it told him nothing. So he said:
+
+"No'm--well, not very much."
+
+The old lady reached out her hand and felt Tom's shirt, and said:
+
+"But you ain't too warm now, though." And it flattered her to reflect
+that she had discovered that the shirt was dry without anybody knowing
+that that was what she had in her mind. But in spite of her, Tom knew
+where the wind lay, now. So he forestalled what might be the next move:
+
+"Some of us pumped on our heads--mine's damp yet. See?"
+
+Aunt Polly was vexed to think she had overlooked that bit of
+circumstantial evidence, and missed a trick. Then she had a new
+inspiration:
+
+"Tom, you didn't have to undo your shirt collar where I sewed it, to
+pump on your head, did you? Unbutton your jacket!"
+
+The trouble vanished out of Tom's face. He opened his jacket. His
+shirt collar was securely sewed.
+
+"Bother! Well, go 'long with you. I'd made sure you'd played hookey
+and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a
+singed cat, as the saying is--better'n you look. THIS time."
+
+She was half sorry her sagacity had miscarried, and half glad that Tom
+had stumbled into obedient conduct for once.
+
+But Sidney said:
+
+"Well, now, if I didn't think you sewed his collar with white thread,
+but it's black."
+
+"Why, I did sew it with white! Tom!"
+
+But Tom did not wait for the rest. As he went out at the door he said:
+
+"Siddy, I'll lick you for that."
+
+In a safe place Tom examined two large needles which were thrust into
+the lapels of his jacket, and had thread bound about them--one needle
+carried white thread and the other black. He said:
+
+"She'd never noticed if it hadn't been for Sid. Confound it! sometimes
+she sews it with white, and sometimes she sews it with black. I wish to
+geeminy she'd stick to one or t'other--I can't keep the run of 'em. But
+I bet you I'll lam Sid for that. I'll learn him!"
+
+He was not the Model Boy of the village. He knew the model boy very
+well though--and loathed him.
+
+Within two minutes, or even less, he had forgotten all his troubles.
+Not because his troubles were one whit less heavy and bitter to him
+than a man's are to a man, but because a new and powerful interest bore
+them down and drove them out of his mind for the time--just as men's
+misfortunes are forgotten in the excitement of new enterprises. This
+new interest was a valued novelty in whistling, which he had just
+acquired from a negro, and he was suffering to practise it undisturbed.
+It consisted in a peculiar bird-like turn, a sort of liquid warble,
+produced by touching the tongue to the roof of the mouth at short
+intervals in the midst of the music--the reader probably remembers how
+to do it, if he has ever been a boy. Diligence and attention soon gave
+him the knack of it, and he strode down the street with his mouth full
+of harmony and his soul full of gratitude. He felt much as an
+astronomer feels who has discovered a new planet--no doubt, as far as
+strong, deep, unalloyed pleasure is concerned, the advantage was with
+the boy, not the astronomer.
+
+The summer evenings were long. It was not dark, yet. Presently Tom
+checked his whistle. A stranger was before him--a boy a shade larger
+than himself. A new-comer of any age or either sex was an impressive
+curiosity in the poor little shabby village of St. Petersburg. This boy
+was well dressed, too--well dressed on a week-day. This was simply
+astounding. His cap was a dainty thing, his close-buttoned blue cloth
+roundabout was new and natty, and so were his pantaloons. He had shoes
+on--and it was only Friday. He even wore a necktie, a bright bit of
+ribbon. He had a citified air about him that ate into Tom's vitals. The
+more Tom stared at the splendid marvel, the higher he turned up his
+nose at his finery and the shabbier and shabbier his own outfit seemed
+to him to grow. Neither boy spoke. If one moved, the other moved--but
+only sidewise, in a circle; they kept face to face and eye to eye all
+the time. Finally Tom said:
+
+"I can lick you!"
+
+"I'd like to see you try it."
+
+"Well, I can do it."
+
+"No you can't, either."
+
+"Yes I can."
+
+"No you can't."
+
+"I can."
+
+"You can't."
+
+"Can!"
+
+"Can't!"
+
+An uncomfortable pause. Then Tom said:
+
+"What's your name?"
+
+"'Tisn't any of your business, maybe."
+
+"Well I 'low I'll MAKE it my business."
+
+"Well why don't you?"
+
+"If you say much, I will."
+
+"Much--much--MUCH. There now."
+
+"Oh, you think you're mighty smart, DON'T you? I could lick you with
+one hand tied behind me, if I wanted to."
+
+"Well why don't you DO it? You SAY you can do it."
+
+"Well I WILL, if you fool with me."
+
+"Oh yes--I've seen whole families in the same fix."
+
+"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!"
+
+"You can lump that hat if you don't like it. I dare you to knock it
+off--and anybody that'll take a dare will suck eggs."
+
+"You're a liar!"
+
+"You're another."
+
+"You're a fighting liar and dasn't take it up."
+
+"Aw--take a walk!"
+
+"Say--if you give me much more of your sass I'll take and bounce a
+rock off'n your head."
+
+"Oh, of COURSE you will."
+
+"Well I WILL."
+
+"Well why don't you DO it then? What do you keep SAYING you will for?
+Why don't you DO it? It's because you're afraid."
+
+"I AIN'T afraid."
+
+"You are."
+
+"I ain't."
+
+"You are."
+
+Another pause, and more eying and sidling around each other. Presently
+they were shoulder to shoulder. Tom said:
+
+"Get away from here!"
+
+"Go away yourself!"
+
+"I won't."
+
+"I won't either."
+
+So they stood, each with a foot placed at an angle as a brace, and
+both shoving with might and main, and glowering at each other with
+hate. But neither could get an advantage. After struggling till both
+were hot and flushed, each relaxed his strain with watchful caution,
+and Tom said:
+
+"You're a coward and a pup. I'll tell my big brother on you, and he
+can thrash you with his little finger, and I'll make him do it, too."
+
+"What do I care for your big brother? I've got a brother that's bigger
+than he is--and what's more, he can throw him over that fence, too."
+[Both brothers were imaginary.]
+
+"That's a lie."
+
+"YOUR saying so don't make it so."
+
+Tom drew a line in the dust with his big toe, and said:
+
+"I dare you to step over that, and I'll lick you till you can't stand
+up. Anybody that'll take a dare will steal sheep."
+
+The new boy stepped over promptly, and said:
+
+"Now you said you'd do it, now let's see you do it."
+
+"Don't you crowd me now; you better look out."
+
+"Well, you SAID you'd do it--why don't you do it?"
+
+"By jingo! for two cents I WILL do it."
+
+The new boy took two broad coppers out of his pocket and held them out
+with derision. Tom struck them to the ground. In an instant both boys
+were rolling and tumbling in the dirt, gripped together like cats; and
+for the space of a minute they tugged and tore at each other's hair and
+clothes, punched and scratched each other's nose, and covered
+themselves with dust and glory. Presently the confusion took form, and
+through the fog of battle Tom appeared, seated astride the new boy, and
+pounding him with his fists. "Holler 'nuff!" said he.
+
+The boy only struggled to free himself. He was crying--mainly from rage.
+
+"Holler 'nuff!"--and the pounding went on.
+
+At last the stranger got out a smothered "'Nuff!" and Tom let him up
+and said:
+
+"Now that'll learn you. Better look out who you're fooling with next
+time."
+
+The new boy went off brushing the dust from his clothes, sobbing,
+snuffling, and occasionally looking back and shaking his head and
+threatening what he would do to Tom the "next time he caught him out."
+To which Tom responded with jeers, and started off in high feather, and
+as soon as his back was turned the new boy snatched up a stone, threw
+it and hit him between the shoulders and then turned tail and ran like
+an antelope. Tom chased the traitor home, and thus found out where he
+lived. He then held a position at the gate for some time, daring the
+enemy to come outside, but the enemy only made faces at him through the
+window and declined. At last the enemy's mother appeared, and called
+Tom a bad, vicious, vulgar child, and ordered him away. So he went
+away; but he said he "'lowed" to "lay" for that boy.
+
+He got home pretty late that night, and when he climbed cautiously in
+at the window, he uncovered an ambuscade, in the person of his aunt;
+and when she saw the state his clothes were in her resolution to turn
+his Saturday holiday into captivity at hard labor became adamantine in
+its firmness.
diff --git a/go/src/github.com/jroimartin/gocui/_examples/colors.go b/go/src/github.com/jroimartin/gocui/_examples/colors.go
new file mode 100644
index 0000000..602ef20
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/colors.go
@@ -0,0 +1,49 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("colors", maxX/2-7, maxY/2-12, maxX/2+7, maxY/2+13); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		for i := 0; i <= 7; i++ {
+			for _, j := range []int{1, 4, 7} {
+				fmt.Fprintf(v, "Hello \033[3%d;%dmcolors!\033[0m\n", i, j)
+			}
+		}
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/demo.go b/go/src/github.com/jroimartin/gocui/_examples/demo.go
new file mode 100644
index 0000000..3786cca
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/demo.go
@@ -0,0 +1,207 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"strings"
+
+	"github.com/jroimartin/gocui"
+)
+
+func nextView(g *gocui.Gui, v *gocui.View) error {
+	if v == nil || v.Name() == "side" {
+		return g.SetCurrentView("main")
+	}
+	return g.SetCurrentView("side")
+}
+
+func cursorDown(g *gocui.Gui, v *gocui.View) error {
+	if v != nil {
+		cx, cy := v.Cursor()
+		if err := v.SetCursor(cx, cy+1); err != nil {
+			ox, oy := v.Origin()
+			if err := v.SetOrigin(ox, oy+1); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func cursorUp(g *gocui.Gui, v *gocui.View) error {
+	if v != nil {
+		ox, oy := v.Origin()
+		cx, cy := v.Cursor()
+		if err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {
+			if err := v.SetOrigin(ox, oy-1); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func getLine(g *gocui.Gui, v *gocui.View) error {
+	var l string
+	var err error
+
+	_, cy := v.Cursor()
+	if l, err = v.Line(cy); err != nil {
+		l = ""
+	}
+
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("msg", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, l)
+		if err := g.SetCurrentView("msg"); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func delMsg(g *gocui.Gui, v *gocui.View) error {
+	if err := g.DeleteView("msg"); err != nil {
+		return err
+	}
+	if err := g.SetCurrentView("side"); err != nil {
+		return err
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func keybindings(g *gocui.Gui) error {
+	if err := g.SetKeybinding("side", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("main", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("side", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("side", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("side", gocui.KeyEnter, gocui.ModNone, getLine); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("msg", gocui.KeyEnter, gocui.ModNone, delMsg); err != nil {
+		return err
+	}
+
+	if err := g.SetKeybinding("main", gocui.KeyCtrlS, gocui.ModNone, saveMain); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("main", gocui.KeyCtrlW, gocui.ModNone, saveVisualMain); err != nil {
+		return err
+	}
+	return nil
+}
+
+func saveMain(g *gocui.Gui, v *gocui.View) error {
+	f, err := ioutil.TempFile("", "gocui_demo_")
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	p := make([]byte, 5)
+	v.Rewind()
+	for {
+		n, err := v.Read(p)
+		if n > 0 {
+			if _, err := f.Write(p[:n]); err != nil {
+				return err
+			}
+		}
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func saveVisualMain(g *gocui.Gui, v *gocui.View) error {
+	f, err := ioutil.TempFile("", "gocui_demo_")
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	vb := v.ViewBuffer()
+	if _, err := io.Copy(f, strings.NewReader(vb)); err != nil {
+		return err
+	}
+	return nil
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("side", -1, -1, 30, maxY); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Highlight = true
+		fmt.Fprintln(v, "Item 1")
+		fmt.Fprintln(v, "Item 2")
+		fmt.Fprintln(v, "Item 3")
+		fmt.Fprint(v, "\rWill be")
+		fmt.Fprint(v, "deleted\rItem 4\nItem 5")
+	}
+	if v, err := g.SetView("main", 30, -1, maxX, maxY); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		b, err := ioutil.ReadFile("Mark.Twain-Tom.Sawyer.txt")
+		if err != nil {
+			panic(err)
+		}
+		fmt.Fprintf(v, "%s", b)
+		v.Editable = true
+		v.Wrap = true
+		if err := g.SetCurrentView("main"); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := keybindings(g); err != nil {
+		log.Panicln(err)
+	}
+	g.SelBgColor = gocui.ColorGreen
+	g.SelFgColor = gocui.ColorBlack
+	g.Cursor = true
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/dynamic.go b/go/src/github.com/jroimartin/gocui/_examples/dynamic.go
new file mode 100644
index 0000000..2d92665
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/dynamic.go
@@ -0,0 +1,202 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"strings"
+
+	"github.com/jroimartin/gocui"
+)
+
+const delta = 1
+
+var (
+	views   = []string{}
+	curView = -1
+	idxView = 0
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := initKeybindings(g); err != nil {
+		log.Panicln(err)
+	}
+	if err := newView(g); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, _ := g.Size()
+	v, err := g.SetView("legend", maxX-25, 0, maxX-1, 8)
+	if err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "KEYBINDINGS")
+		fmt.Fprintln(v, "Space: New View")
+		fmt.Fprintln(v, "Tab: Next View")
+		fmt.Fprintln(v, "← ↑ → ↓: Move View")
+		fmt.Fprintln(v, "Backspace: Delete View")
+		fmt.Fprintln(v, "t: Set view on top")
+		fmt.Fprintln(v, "^C: Exit")
+	}
+	return nil
+}
+
+func initKeybindings(g *gocui.Gui) error {
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeySpace, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return newView(g)
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeyBackspace2, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return delView(g)
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return nextView(g, true)
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeyArrowLeft, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return moveView(g, v, -delta, 0)
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeyArrowRight, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return moveView(g, v, delta, 0)
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeyArrowDown, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return moveView(g, v, 0, delta)
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", gocui.KeyArrowUp, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return moveView(g, v, 0, -delta)
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("", 't', gocui.ModNone, ontop); err != nil {
+		return err
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func newView(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	name := fmt.Sprintf("v%v", idxView)
+	v, err := g.SetView(name, maxX/2-5, maxY/2-5, maxX/2+5, maxY/2+5)
+	if err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Wrap = true
+		fmt.Fprintln(v, strings.Repeat(name+" ", 30))
+	}
+	if err := g.SetCurrentView(name); err != nil {
+		return err
+	}
+	v.BgColor = gocui.ColorRed
+
+	if curView >= 0 {
+		cv, err := g.View(views[curView])
+		if err != nil {
+			return err
+		}
+		cv.BgColor = g.BgColor
+	}
+
+	views = append(views, name)
+	curView = len(views) - 1
+	idxView += 1
+	return nil
+}
+
+func delView(g *gocui.Gui) error {
+	if len(views) <= 1 {
+		return nil
+	}
+
+	if err := g.DeleteView(views[curView]); err != nil {
+		return err
+	}
+	views = append(views[:curView], views[curView+1:]...)
+
+	return nextView(g, false)
+}
+
+func nextView(g *gocui.Gui, disableCurrent bool) error {
+	next := curView + 1
+	if next > len(views)-1 {
+		next = 0
+	}
+
+	nv, err := g.View(views[next])
+	if err != nil {
+		return err
+	}
+	if err := g.SetCurrentView(views[next]); err != nil {
+		return err
+	}
+	nv.BgColor = gocui.ColorRed
+
+	if disableCurrent && len(views) > 1 {
+		cv, err := g.View(views[curView])
+		if err != nil {
+			return err
+		}
+		cv.BgColor = g.BgColor
+	}
+
+	curView = next
+	return nil
+}
+
+func moveView(g *gocui.Gui, v *gocui.View, dx, dy int) error {
+	name := v.Name()
+	x0, y0, x1, y1, err := g.ViewPosition(name)
+	if err != nil {
+		return err
+	}
+	if _, err := g.SetView(name, x0+dx, y0+dy, x1+dx, y1+dy); err != nil {
+		return err
+	}
+	return nil
+}
+
+func ontop(g *gocui.Gui, v *gocui.View) error {
+	_, err := g.SetViewOnTop(views[curView])
+	return err
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/goroutine.go b/go/src/github.com/jroimartin/gocui/_examples/goroutine.go
new file mode 100644
index 0000000..c8dab36
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/goroutine.go
@@ -0,0 +1,98 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"sync"
+	"time"
+
+	"github.com/jroimartin/gocui"
+)
+
+const NumGoroutines = 10
+
+var (
+	done = make(chan bool)
+	wg   sync.WaitGroup
+
+	mu  sync.Mutex // protects ctr
+	ctr = 0
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := keybindings(g); err != nil {
+		log.Panicln(err)
+	}
+
+	for i := 0; i < NumGoroutines; i++ {
+		wg.Add(1)
+		go counter(g)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+
+	wg.Wait()
+}
+
+func layout(g *gocui.Gui) error {
+	if v, err := g.SetView("ctr", 2, 2, 12, 4); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "0")
+	}
+	return nil
+}
+
+func keybindings(g *gocui.Gui) error {
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		return err
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	for i := 0; i < NumGoroutines; i++ {
+		done <- true
+	}
+	return gocui.ErrQuit
+}
+
+func counter(g *gocui.Gui) {
+	defer wg.Done()
+
+	for {
+		select {
+		case <-done:
+			return
+		case <-time.After(500 * time.Millisecond):
+			mu.Lock()
+			n := ctr
+			ctr++
+			mu.Unlock()
+
+			g.Execute(func(g *gocui.Gui) error {
+				v, err := g.View("ctr")
+				if err != nil {
+					return err
+				}
+				v.Clear()
+				fmt.Fprintln(v, n)
+				return nil
+			})
+		}
+	}
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/hello.go b/go/src/github.com/jroimartin/gocui/_examples/hello.go
new file mode 100644
index 0000000..c02183e
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/hello.go
@@ -0,0 +1,45 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "Hello world!")
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/layout.go b/go/src/github.com/jroimartin/gocui/_examples/layout.go
new file mode 100644
index 0000000..50783bd
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/layout.go
@@ -0,0 +1,50 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if _, err := g.SetView("side", -1, -1, int(0.2*float32(maxX)), maxY-5); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("main", int(0.2*float32(maxX)), -1, maxX, maxY-5); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("cmdline", -1, maxY-5, maxX, maxY); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/mask.go b/go/src/github.com/jroimartin/gocui/_examples/mask.go
new file mode 100644
index 0000000..8ca8975
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/mask.go
@@ -0,0 +1,73 @@
+// Copyright 2015 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Fatalln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := initKeybindings(g); err != nil {
+		log.Fatalln(err)
+	}
+	g.Cursor = true
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Fatalln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+
+	if v, err := g.SetView("legend", maxX-23, 0, maxX-1, 3); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Keybindings"
+		fmt.Fprintln(v, "^a: Set mask")
+		fmt.Fprintln(v, "^c: Exit")
+	}
+
+	if v, err := g.SetView("input", 0, 0, maxX-24, maxY-1); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		if err := g.SetCurrentView("input"); err != nil {
+			return err
+		}
+		v.Editable = true
+		v.Wrap = true
+	}
+
+	return nil
+}
+
+func initKeybindings(g *gocui.Gui) error {
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			return gocui.ErrQuit
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("input", gocui.KeyCtrlA, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			v.Mask ^= '*'
+			return nil
+		}); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/mouse.go b/go/src/github.com/jroimartin/gocui/_examples/mouse.go
new file mode 100644
index 0000000..07f7359
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/mouse.go
@@ -0,0 +1,103 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := keybindings(g); err != nil {
+		log.Panicln(err)
+	}
+	g.SelBgColor = gocui.ColorGreen
+	g.SelFgColor = gocui.ColorBlack
+	g.Cursor = true
+	g.Mouse = true
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	if v, err := g.SetView("but1", 2, 2, 22, 7); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Highlight = true
+		fmt.Fprintln(v, "Button 1 - line 1")
+		fmt.Fprintln(v, "Button 1 - line 2")
+		fmt.Fprintln(v, "Button 1 - line 3")
+		fmt.Fprintln(v, "Button 1 - line 4")
+	}
+	if v, err := g.SetView("but2", 24, 2, 44, 4); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Highlight = true
+		fmt.Fprintln(v, "Button 2 - line 1")
+	}
+	return nil
+}
+
+func keybindings(g *gocui.Gui) error {
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		return err
+	}
+	for _, n := range []string{"but1", "but2"} {
+		if err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, showMsg); err != nil {
+			return err
+		}
+	}
+	if err := g.SetKeybinding("msg", gocui.MouseLeft, gocui.ModNone, delMsg); err != nil {
+		return err
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func showMsg(g *gocui.Gui, v *gocui.View) error {
+	var l string
+	var err error
+
+	if err := g.SetCurrentView(v.Name()); err != nil {
+		return err
+	}
+
+	_, cy := v.Cursor()
+	if l, err = v.Line(cy); err != nil {
+		l = ""
+	}
+
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("msg", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, l)
+	}
+	return nil
+}
+
+func delMsg(g *gocui.Gui, v *gocui.View) error {
+	if err := g.DeleteView("msg"); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/ontop.go b/go/src/github.com/jroimartin/gocui/_examples/ontop.go
new file mode 100644
index 0000000..e8e9621
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/ontop.go
@@ -0,0 +1,87 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := keybindings(g); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	if v, err := g.SetView("v1", 10, 2, 30, 6); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "View #1")
+	}
+	if v, err := g.SetView("v2", 20, 4, 40, 8); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "View #2")
+	}
+	if v, err := g.SetView("v3", 30, 6, 50, 10); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "View #3")
+	}
+
+	return nil
+}
+
+func keybindings(g *gocui.Gui) error {
+	err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {
+		return gocui.ErrQuit
+	})
+	if err != nil {
+		return err
+	}
+
+	err = g.SetKeybinding("", '1', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {
+		_, err := g.SetViewOnTop("v1")
+		return err
+	})
+	if err != nil {
+		return err
+	}
+
+	err = g.SetKeybinding("", '2', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {
+		_, err := g.SetViewOnTop("v2")
+		return err
+	})
+	if err != nil {
+		return err
+	}
+
+	err = g.SetKeybinding("", '3', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {
+		_, err := g.SetViewOnTop("v3")
+		return err
+	})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/overlap.go b/go/src/github.com/jroimartin/gocui/_examples/overlap.go
new file mode 100644
index 0000000..3ec364c
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/overlap.go
@@ -0,0 +1,73 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if _, err := g.SetView("v1", -1, -1, 10, 10); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v2", maxX-10, -1, maxX, 10); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v3", maxX/2-5, -1, maxX/2+5, 10); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v4", -1, maxY/2-5, 10, maxY/2+5); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v5", maxX-10, maxY/2-5, maxX, maxY/2+5); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v6", -1, maxY-10, 10, maxY); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v7", maxX-10, maxY-10, maxX, maxY); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v8", maxX/2-5, maxY-10, maxX/2+5, maxY); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	if _, err := g.SetView("v9", maxX/2-5, maxY/2-5, maxX/2+5, maxY/2+5); err != nil &&
+		err != gocui.ErrUnknownView {
+		return err
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/stdin.go b/go/src/github.com/jroimartin/gocui/_examples/stdin.go
new file mode 100644
index 0000000..c517d53
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/stdin.go
@@ -0,0 +1,107 @@
+// Copyright 2015 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"encoding/hex"
+	"fmt"
+	"io"
+	"log"
+	"os"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Fatalln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := initKeybindings(g); err != nil {
+		log.Fatalln(err)
+	}
+	g.Cursor = true
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Fatalln(err)
+	}
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, _ := g.Size()
+
+	if v, err := g.SetView("legend", maxX-23, 0, maxX-1, 5); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		fmt.Fprintln(v, "KEYBINDINGS")
+		fmt.Fprintln(v, "↑ ↓: Seek input")
+		fmt.Fprintln(v, "A: Enable autoscroll")
+		fmt.Fprintln(v, "^C: Exit")
+	}
+
+	if v, err := g.SetView("stdin", 0, 0, 80, 35); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		if err := g.SetCurrentView("stdin"); err != nil {
+			return err
+		}
+		dumper := hex.Dumper(v)
+		if _, err := io.Copy(dumper, os.Stdin); err != nil {
+			return err
+		}
+		v.Wrap = true
+	}
+
+	return nil
+}
+
+func initKeybindings(g *gocui.Gui) error {
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("stdin", 'a', gocui.ModNone, autoscroll); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("stdin", gocui.KeyArrowUp, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			scrollView(v, -1)
+			return nil
+		}); err != nil {
+		return err
+	}
+	if err := g.SetKeybinding("stdin", gocui.KeyArrowDown, gocui.ModNone,
+		func(g *gocui.Gui, v *gocui.View) error {
+			scrollView(v, 1)
+			return nil
+		}); err != nil {
+		return err
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func autoscroll(g *gocui.Gui, v *gocui.View) error {
+	v.Autoscroll = true
+	return nil
+}
+
+func scrollView(v *gocui.View, dy int) error {
+	if v != nil {
+		v.Autoscroll = false
+		ox, oy := v.Origin()
+		if err := v.SetOrigin(ox, oy+dy); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/title.go b/go/src/github.com/jroimartin/gocui/_examples/title.go
new file mode 100644
index 0000000..9864871
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/title.go
@@ -0,0 +1,161 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+
+	"github.com/jroimartin/gocui"
+)
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+
+	// Overlap (front)
+	if v, err := g.SetView("v1", 10, 2, 30, 6); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v2", 20, 4, 40, 8); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+
+	// Overlap (back)
+	if v, err := g.SetView("v3", 60, 4, 80, 8); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v4", 50, 2, 70, 6); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+
+	// Overlap (frame)
+	if v, err := g.SetView("v15", 90, 2, 110, 5); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v16", 100, 5, 120, 8); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v17", 140, 5, 160, 8); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v18", 130, 2, 150, 5); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+
+	// Long title
+	if v, err := g.SetView("v5", 10, 12, 30, 16); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Long long long long title"
+	}
+
+	// No title
+	if v, err := g.SetView("v6", 35, 12, 55, 16); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = ""
+	}
+	if _, err := g.SetView("v7", 60, 12, 80, 16); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+	}
+
+	// Small view
+	if v, err := g.SetView("v8", 85, 12, 88, 16); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+
+	// Screen borders
+	if v, err := g.SetView("v9", -10, 20, 10, 24); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v10", maxX-10, 20, maxX+10, 24); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+
+	// Out of screen
+	if v, err := g.SetView("v11", -21, 28, -1, 32); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v12", maxX, 28, maxX+20, 32); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v13", 10, -7, 30, -1); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+	if v, err := g.SetView("v14", 10, maxY, 30, maxY+6); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Title = "Regular title"
+	}
+
+	return nil
+}
diff --git a/go/src/github.com/jroimartin/gocui/_examples/wrap.go b/go/src/github.com/jroimartin/gocui/_examples/wrap.go
new file mode 100644
index 0000000..24f78ce
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/_examples/wrap.go
@@ -0,0 +1,49 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"strings"
+
+	"github.com/jroimartin/gocui"
+)
+
+func layout(g *gocui.Gui) error {
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("main", 1, 1, maxX-1, maxY-1); err != nil {
+		if err != gocui.ErrUnknownView {
+			return err
+		}
+		v.Wrap = true
+
+		line := strings.Repeat("This is a long line -- ", 10)
+		fmt.Fprintf(v, "%s\n\n", line)
+		fmt.Fprintln(v, "Short")
+	}
+	return nil
+}
+
+func quit(g *gocui.Gui, v *gocui.View) error {
+	return gocui.ErrQuit
+}
+
+func main() {
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		log.Panicln(err)
+	}
+	defer g.Close()
+
+	g.SetLayout(layout)
+	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
+		log.Panicln(err)
+	}
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		log.Panicln(err)
+	}
+}
diff --git a/go/src/github.com/jroimartin/gocui/attribute.go b/go/src/github.com/jroimartin/gocui/attribute.go
new file mode 100644
index 0000000..bad758a
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/attribute.go
@@ -0,0 +1,32 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "github.com/nsf/termbox-go"
+
+// Attribute represents a terminal attribute, like color, font style, etc. They
+// can be combined using bitwise OR (|). Note that it is not possible to
+// combine multiple color attributes.
+type Attribute termbox.Attribute
+
+// Color attributes.
+const (
+	ColorDefault Attribute = Attribute(termbox.ColorDefault)
+	ColorBlack             = Attribute(termbox.ColorBlack)
+	ColorRed               = Attribute(termbox.ColorRed)
+	ColorGreen             = Attribute(termbox.ColorGreen)
+	ColorYellow            = Attribute(termbox.ColorYellow)
+	ColorBlue              = Attribute(termbox.ColorBlue)
+	ColorMagenta           = Attribute(termbox.ColorMagenta)
+	ColorCyan              = Attribute(termbox.ColorCyan)
+	ColorWhite             = Attribute(termbox.ColorWhite)
+)
+
+// Text style attributes.
+const (
+	AttrBold      Attribute = Attribute(termbox.AttrBold)
+	AttrUnderline           = Attribute(termbox.AttrUnderline)
+	AttrReverse             = Attribute(termbox.AttrReverse)
+)
diff --git a/go/src/github.com/jroimartin/gocui/doc.go b/go/src/github.com/jroimartin/gocui/doc.go
new file mode 100644
index 0000000..796d725
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/doc.go
@@ -0,0 +1,116 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package gocui allows to create console user interfaces.
+
+Create a new GUI:
+
+	g := gocui.NewGui()
+	if err := g.Init(); err != nil {
+		// handle error
+	}
+	defer g.Close()
+
+	// Set layout and key bindings
+	// ...
+
+	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
+		// handle error
+	}
+
+Set the layout function:
+
+	g.SetLayout(fcn)
+
+On each iteration of the GUI's main loop, the "layout function" is executed.
+These layout functions can be used to set-up and update the application's main
+views, being possible to freely switch between them. Also, it is important to
+mention that a main loop iteration is executed on each reported event
+(key-press, mouse event, window resize, etc).
+
+GUIs are composed by Views, you can think of it as buffers. Views implement the
+io.ReadWriter interface, so you can just write to them if you want to modify
+their content. The same is valid for reading.
+
+Create and initialize a view with absolute coordinates:
+
+	if v, err := g.SetView("viewname", 2, 2, 22, 7); err != nil {
+		if err != gocui.ErrUnknownView {
+			// handle error
+		}
+		fmt.Fprintln(v, "This is a new view")
+		// ...
+	}
+
+Views can also be created using relative coordinates:
+
+	maxX, maxY := g.Size()
+	if v, err := g.SetView("viewname", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
+		// ...
+	}
+
+Configure keybindings:
+
+	if err := g.SetKeybinding("viewname", gocui.KeyEnter, gocui.ModNone, fcn); err != nil {
+		// handle error
+	}
+
+gocui implements full mouse support that can be enabled with:
+
+	g.Mouse = true
+
+Mouse events are handled like any other keybinding:
+
+	if err := g.SetKeybinding("viewname", gocui.MouseLeft, gocui.ModNone, fcn); err != nil {
+		// handle error
+	}
+
+IMPORTANT: Views can only be created, destroyed or updated in three ways: from
+layout funcions, from keybinding callbacks or via *Gui.Execute(). The reason
+for this is that it allows gocui to be conccurent-safe. So, if you want to
+update your GUI from a goroutine, you must use *Gui.Execute(). For example:
+
+	g.Execute(func(g *gocui.Gui) error {
+		v, err := g.View("viewname")
+		if err != nil {
+			// handle error
+		}
+		v.Clear()
+		fmt.Fprintln(v, "Writing from different goroutines")
+		return nil
+	})
+
+By default, gocui provides a basic edition mode. This mode can be extended
+and customized creating a new Editor and assigning it to *Gui.Editor:
+
+	type Editor interface {
+		Edit(v *View, key Key, ch rune, mod Modifier)
+	}
+
+DefaultEditor can be taken as example to create your own custom Editor:
+
+	var DefaultEditor Editor = EditorFunc(simpleEditor)
+
+	func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
+		switch {
+		case ch != 0 && mod == 0:
+			v.EditWrite(ch)
+		case key == KeySpace:
+			v.EditWrite(' ')
+		case key == KeyBackspace || key == KeyBackspace2:
+			v.EditDelete(true)
+		// ...
+		}
+	}
+
+Colored text:
+
+Views allow to add colored text using ANSI colors. For example:
+
+	fmt.Fprintln(v, "\x1b[0;31mHello world")
+
+For more information, see the examples in folder "_examples/".
+*/
+package gocui
diff --git a/go/src/github.com/jroimartin/gocui/edit.go b/go/src/github.com/jroimartin/gocui/edit.go
new file mode 100644
index 0000000..eb88819
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/edit.go
@@ -0,0 +1,228 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+const maxInt = int(^uint(0) >> 1)
+
+// Editor interface must be satisfied by gocui editors.
+type Editor interface {
+	Edit(v *View, key Key, ch rune, mod Modifier)
+}
+
+// The EditorFunc type is an adapter to allow the use of ordinary functions as
+// Editors. If f is a function with the appropriate signature, EditorFunc(f)
+// is an Editor object that calls f.
+type EditorFunc func(v *View, key Key, ch rune, mod Modifier)
+
+// Edit calls f(v, key, ch, mod)
+func (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) {
+	f(v, key, ch, mod)
+}
+
+// DefaultEditor is the default editor.
+var DefaultEditor Editor = EditorFunc(simpleEditor)
+
+// simpleEditor is used as the default gocui editor.
+func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
+	switch {
+	case ch != 0 && mod == 0:
+		v.EditWrite(ch)
+	case key == KeySpace:
+		v.EditWrite(' ')
+	case key == KeyBackspace || key == KeyBackspace2:
+		v.EditDelete(true)
+	case key == KeyDelete:
+		v.EditDelete(false)
+	case key == KeyInsert:
+		v.Overwrite = !v.Overwrite
+	case key == KeyEnter:
+		v.EditNewLine()
+	case key == KeyArrowDown:
+		v.MoveCursor(0, 1, false)
+	case key == KeyArrowUp:
+		v.MoveCursor(0, -1, false)
+	case key == KeyArrowLeft:
+		v.MoveCursor(-1, 0, false)
+	case key == KeyArrowRight:
+		v.MoveCursor(1, 0, false)
+	}
+}
+
+// EditWrite writes a rune at the cursor position.
+func (v *View) EditWrite(ch rune) {
+	v.writeRune(v.cx, v.cy, ch)
+	v.MoveCursor(1, 0, true)
+}
+
+// EditDelete deletes a rune at the cursor position. back determines the
+// direction.
+func (v *View) EditDelete(back bool) {
+	x, y := v.ox+v.cx, v.oy+v.cy
+	if y < 0 {
+		return
+	} else if y >= len(v.viewLines) {
+		v.MoveCursor(-1, 0, true)
+		return
+	}
+
+	maxX, _ := v.Size()
+	if back {
+		if x == 0 { // start of the line
+			if y < 1 {
+				return
+			}
+
+			var maxPrevWidth int
+			if v.Wrap {
+				maxPrevWidth = maxX
+			} else {
+				maxPrevWidth = maxInt
+			}
+
+			if v.viewLines[y].linesX == 0 { // regular line
+				v.mergeLines(v.cy - 1)
+				if len(v.viewLines[y-1].line) < maxPrevWidth {
+					v.MoveCursor(-1, 0, true)
+				}
+			} else { // wrapped line
+				v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
+				v.MoveCursor(-1, 0, true)
+			}
+		} else { // middle/end of the line
+			v.deleteRune(v.cx-1, v.cy)
+			v.MoveCursor(-1, 0, true)
+		}
+	} else {
+		if x == len(v.viewLines[y].line) { // end of the line
+			v.mergeLines(v.cy)
+		} else { // start/middle of the line
+			v.deleteRune(v.cx, v.cy)
+		}
+	}
+}
+
+// EditNewLine inserts a new line under the cursor.
+func (v *View) EditNewLine() {
+	v.breakLine(v.cx, v.cy)
+
+	y := v.oy + v.cy
+	if y >= len(v.viewLines) || (y >= 0 && y < len(v.viewLines) &&
+		!(v.Wrap && v.cx == 0 && v.viewLines[y].linesX > 0)) {
+		// new line at the end of the buffer or
+		// cursor is not at the beginning of a wrapped line
+		v.ox = 0
+		v.cx = 0
+		v.MoveCursor(0, 1, true)
+	}
+}
+
+// MoveCursor moves the cursor taking into account the width of the line/view,
+// displacing the origin if necessary.
+func (v *View) MoveCursor(dx, dy int, writeMode bool) {
+	maxX, maxY := v.Size()
+	cx, cy := v.cx+dx, v.cy+dy
+	x, y := v.ox+cx, v.oy+cy
+
+	var curLineWidth, prevLineWidth int
+	// get the width of the current line
+	if writeMode {
+		if v.Wrap {
+			curLineWidth = maxX - 1
+		} else {
+			curLineWidth = maxInt
+		}
+	} else {
+		if y >= 0 && y < len(v.viewLines) {
+			curLineWidth = len(v.viewLines[y].line)
+			if v.Wrap && curLineWidth >= maxX {
+				curLineWidth = maxX - 1
+			}
+		} else {
+			curLineWidth = 0
+		}
+	}
+	// get the width of the previous line
+	if y-1 >= 0 && y-1 < len(v.viewLines) {
+		prevLineWidth = len(v.viewLines[y-1].line)
+	} else {
+		prevLineWidth = 0
+	}
+
+	// adjust cursor's x position and view's x origin
+	if x > curLineWidth { // move to next line
+		if dx > 0 { // horizontal movement
+			if !v.Wrap {
+				v.ox = 0
+			}
+			v.cx = 0
+			cy++
+		} else { // vertical movement
+			if curLineWidth > 0 { // move cursor to the EOL
+				if v.Wrap {
+					v.cx = curLineWidth
+				} else {
+					ncx := curLineWidth - v.ox
+					if ncx < 0 {
+						v.ox += ncx
+						if v.ox < 0 {
+							v.ox = 0
+						}
+						v.cx = 0
+					} else {
+						v.cx = ncx
+					}
+				}
+			} else {
+				if !v.Wrap {
+					v.ox = 0
+				}
+				v.cx = 0
+			}
+		}
+	} else if cx < 0 {
+		if !v.Wrap && v.ox > 0 { // move origin to the left
+			v.ox--
+		} else { // move to previous line
+			if prevLineWidth > 0 {
+				if !v.Wrap { // set origin so the EOL is visible
+					nox := prevLineWidth - maxX + 1
+					if nox < 0 {
+						v.ox = 0
+					} else {
+						v.ox = nox
+					}
+				}
+				v.cx = prevLineWidth
+			} else {
+				if !v.Wrap {
+					v.ox = 0
+				}
+				v.cx = 0
+			}
+			cy--
+		}
+	} else { // stay on the same line
+		if v.Wrap {
+			v.cx = cx
+		} else {
+			if cx >= maxX {
+				v.ox++
+			} else {
+				v.cx = cx
+			}
+		}
+	}
+
+	// adjust cursor's y position and view's y origin
+	if cy >= maxY {
+		v.oy++
+	} else if cy < 0 {
+		if v.oy > 0 {
+			v.oy--
+		}
+	} else {
+		v.cy = cy
+	}
+}
diff --git a/go/src/github.com/jroimartin/gocui/escape.go b/go/src/github.com/jroimartin/gocui/escape.go
new file mode 100644
index 0000000..0fb64f3
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/escape.go
@@ -0,0 +1,171 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+	"errors"
+	"strconv"
+)
+
+type escapeInterpreter struct {
+	state                          escapeState
+	curch                          rune
+	csiParam                       []string
+	curFgColor, curBgColor         Attribute
+	defaultFgColor, defaultBgColor Attribute
+}
+
+type escapeState int
+
+const (
+	stateNone escapeState = iota
+	stateEscape
+	stateCSI
+	stateParams
+)
+
+var (
+	errNotCSI        = errors.New("Not a CSI escape sequence")
+	errCSINotANumber = errors.New("CSI escape sequence was expecting a number or a ;")
+	errCSIParseError = errors.New("CSI escape sequence parsing error")
+	errCSITooLong    = errors.New("CSI escape sequence is too long")
+)
+
+// runes in case of error will output the non-parsed runes as a string.
+func (ei *escapeInterpreter) runes() []rune {
+	switch ei.state {
+	case stateNone:
+		return []rune{0x1b}
+	case stateEscape:
+		return []rune{0x1b, ei.curch}
+	case stateCSI:
+		return []rune{0x1b, '[', ei.curch}
+	case stateParams:
+		ret := []rune{0x1b, '['}
+		for _, s := range ei.csiParam {
+			ret = append(ret, []rune(s)...)
+			ret = append(ret, ';')
+		}
+		return append(ret, ei.curch)
+	}
+	return nil
+}
+
+// newEscapeInterpreter returns an escapeInterpreter that will be able to parse
+// terminal escape sequences.
+func newEscapeInterpreter() *escapeInterpreter {
+	ei := &escapeInterpreter{
+		defaultFgColor: ColorWhite,
+		defaultBgColor: ColorBlack,
+		state:          stateNone,
+		curFgColor:     ColorWhite,
+		curBgColor:     ColorBlack,
+	}
+	return ei
+}
+
+// reset sets the escapeInterpreter in inital state.
+func (ei *escapeInterpreter) reset() {
+	ei.state = stateNone
+	ei.curFgColor = ei.defaultFgColor
+	ei.curBgColor = ei.defaultBgColor
+	ei.csiParam = nil
+}
+
+// paramToColor returns an attribute given a terminfo coloring.
+func paramToColor(p int) Attribute {
+	switch p {
+	case 0:
+		return ColorBlack
+	case 1:
+		return ColorRed
+	case 2:
+		return ColorGreen
+	case 3:
+		return ColorYellow
+	case 4:
+		return ColorBlue
+	case 5:
+		return ColorMagenta
+	case 6:
+		return ColorCyan
+	case 7:
+		return ColorWhite
+	}
+	return ColorDefault
+}
+
+// parseOne parses a rune. If isEscape is true, it means that the rune is part
+// of an escape sequence, and as such should not be printed verbatim. Otherwise,
+// it's not an escape sequence.
+func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) {
+	// Sanity checks to make sure we're not parsing something totally bogus.
+	if len(ei.csiParam) > 20 {
+		return false, errCSITooLong
+	}
+	if len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 {
+		return false, errCSITooLong
+	}
+	ei.curch = ch
+	switch ei.state {
+	case stateNone:
+		if ch == 0x1b {
+			ei.state = stateEscape
+			return true, nil
+		}
+		return false, nil
+	case stateEscape:
+		if ch == '[' {
+			ei.state = stateCSI
+			return true, nil
+		}
+		return false, errNotCSI
+	case stateCSI:
+		if ch >= '0' && ch <= '9' {
+			ei.state = stateParams
+			ei.csiParam = append(ei.csiParam, string(ch))
+			return true, nil
+		}
+		return false, errCSINotANumber
+	case stateParams:
+		switch {
+		case ch >= '0' && ch <= '9':
+			ei.csiParam[len(ei.csiParam)-1] += string(ch)
+			return true, nil
+		case ch == ';':
+			ei.csiParam = append(ei.csiParam, "")
+			return true, nil
+		case ch == 'm':
+			if len(ei.csiParam) < 1 {
+				return false, errCSIParseError
+			}
+			for _, param := range ei.csiParam {
+				p, err := strconv.Atoi(param)
+				if err != nil {
+					return false, errCSIParseError
+				}
+				switch {
+				case p >= 30 && p <= 37:
+					ei.curFgColor = paramToColor(p - 30)
+				case p >= 40 && p <= 47:
+					ei.curBgColor = paramToColor(p - 40)
+				case p == 1:
+					ei.curFgColor |= AttrBold
+				case p == 4:
+					ei.curFgColor |= AttrUnderline
+				case p == 7:
+					ei.curFgColor |= AttrReverse
+				case p == 0 || p == 39:
+					ei.curFgColor = ei.defaultFgColor
+					ei.curBgColor = ei.defaultBgColor
+				}
+			}
+			ei.state = stateNone
+			ei.csiParam = nil
+			return true, nil
+		}
+	}
+	return false, nil
+}
diff --git a/go/src/github.com/jroimartin/gocui/gui.go b/go/src/github.com/jroimartin/gocui/gui.go
new file mode 100644
index 0000000..d361afb
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/gui.go
@@ -0,0 +1,574 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+	"errors"
+
+	"github.com/nsf/termbox-go"
+)
+
+// Handler represents a handler that can be used to update or modify the GUI.
+type Handler func(*Gui) error
+
+// userEvent represents an event triggered by the user.
+type userEvent struct {
+	h Handler
+}
+
+var (
+	// ErrQuit is used to decide if the MainLoop finished successfully.
+	ErrQuit = errors.New("quit")
+
+	// ErrUnknownView allows to assert if a View must be initialized.
+	ErrUnknownView = errors.New("unknown view")
+)
+
+// Gui represents the whole User Interface, including the views, layouts
+// and keybindings.
+type Gui struct {
+	tbEvents    chan termbox.Event
+	userEvents  chan userEvent
+	views       []*View
+	currentView *View
+	layout      Handler
+	keybindings []*keybinding
+	maxX, maxY  int
+
+	// BgColor and FgColor allow to configure the background and foreground
+	// colors of the GUI.
+	BgColor, FgColor Attribute
+
+	// SelBgColor and SelFgColor are used to configure the background and
+	// foreground colors of the selected line, when it is highlighted.
+	SelBgColor, SelFgColor Attribute
+
+	// If Cursor is true then the cursor is enabled.
+	Cursor bool
+
+	// If Mouse is true then mouse events will be enabled.
+	Mouse bool
+
+	// Editor allows to define the editor that manages the edition mode,
+	// including keybindings or cursor behaviour. DefaultEditor is used by
+	// default.
+	Editor Editor
+}
+
+// NewGui returns a new Gui object.
+func NewGui() *Gui {
+	return &Gui{}
+}
+
+// Init initializes the library. This function must be called before
+// any other functions.
+func (g *Gui) Init() error {
+	if err := termbox.Init(); err != nil {
+		return err
+	}
+	g.tbEvents = make(chan termbox.Event, 20)
+	g.userEvents = make(chan userEvent, 20)
+	g.maxX, g.maxY = termbox.Size()
+	g.BgColor = ColorBlack
+	g.FgColor = ColorWhite
+	g.Editor = DefaultEditor
+	return nil
+}
+
+// Close finalizes the library. It should be called after a successful
+// initialization and when gocui is not needed anymore.
+func (g *Gui) Close() {
+	termbox.Close()
+}
+
+// Size returns the terminal's size.
+func (g *Gui) Size() (x, y int) {
+	return g.maxX, g.maxY
+}
+
+// SetRune writes a rune at the given point, relative to the top-left
+// corner of the terminal. It checks if the position is valid and applies
+// the gui's colors.
+func (g *Gui) SetRune(x, y int, ch rune) error {
+	if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+		return errors.New("invalid point")
+	}
+	termbox.SetCell(x, y, ch, termbox.Attribute(g.FgColor), termbox.Attribute(g.BgColor))
+	return nil
+}
+
+// Rune returns the rune contained in the cell at the given position.
+// It checks if the position is valid.
+func (g *Gui) Rune(x, y int) (rune, error) {
+	if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+		return ' ', errors.New("invalid point")
+	}
+	c := termbox.CellBuffer()[y*g.maxX+x]
+	return c.Ch, nil
+}
+
+// SetView creates a new view with its top-left corner at (x0, y0)
+// and the bottom-right one at (x1, y1). If a view with the same name
+// already exists, its dimensions are updated; otherwise, the error
+// ErrUnknownView is returned, which allows to assert if the View must
+// be initialized. It checks if the position is valid.
+func (g *Gui) SetView(name string, x0, y0, x1, y1 int) (*View, error) {
+	if x0 >= x1 || y0 >= y1 {
+		return nil, errors.New("invalid dimensions")
+	}
+	if name == "" {
+		return nil, errors.New("invalid name")
+	}
+
+	if v, err := g.View(name); err == nil {
+		v.x0 = x0
+		v.y0 = y0
+		v.x1 = x1
+		v.y1 = y1
+		v.tainted = true
+		return v, nil
+	}
+
+	v := newView(name, x0, y0, x1, y1)
+	v.BgColor, v.FgColor = g.BgColor, g.FgColor
+	v.SelBgColor, v.SelFgColor = g.SelBgColor, g.SelFgColor
+	g.views = append(g.views, v)
+	return v, ErrUnknownView
+}
+
+// SetViewOnTop sets the given view on top of the existing ones.
+func (g *Gui) SetViewOnTop(name string) (*View, error) {
+	for i, v := range g.views {
+		if v.name == name {
+			s := append(g.views[:i], g.views[i+1:]...)
+			g.views = append(s, v)
+			return v, nil
+		}
+	}
+	return nil, ErrUnknownView
+}
+
+// View returns a pointer to the view with the given name, or error
+// ErrUnknownView if a view with that name does not exist.
+func (g *Gui) View(name string) (*View, error) {
+	for _, v := range g.views {
+		if v.name == name {
+			return v, nil
+		}
+	}
+	return nil, ErrUnknownView
+}
+
+// ViewByPosition returns a pointer to a view matching the given position, or
+// error ErrUnknownView if a view in that position does not exist.
+func (g *Gui) ViewByPosition(x, y int) (*View, error) {
+	for _, v := range g.views {
+		if x > v.x0 && x < v.x1 && y > v.y0 && y < v.y1 {
+			return v, nil
+		}
+	}
+	return nil, ErrUnknownView
+}
+
+// ViewPosition returns the coordinates of the view with the given name, or
+// error ErrUnknownView if a view with that name does not exist.
+func (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) {
+	for _, v := range g.views {
+		if v.name == name {
+			return v.x0, v.y0, v.x1, v.y1, nil
+		}
+	}
+	return 0, 0, 0, 0, ErrUnknownView
+}
+
+// DeleteView deletes a view by name.
+func (g *Gui) DeleteView(name string) error {
+	for i, v := range g.views {
+		if v.name == name {
+			g.views = append(g.views[:i], g.views[i+1:]...)
+			return nil
+		}
+	}
+	return ErrUnknownView
+}
+
+// SetCurrentView gives the focus to a given view.
+func (g *Gui) SetCurrentView(name string) error {
+	for _, v := range g.views {
+		if v.name == name {
+			g.currentView = v
+			return nil
+		}
+	}
+	return ErrUnknownView
+}
+
+// CurrentView returns the currently focused view, or nil if no view
+// owns the focus.
+func (g *Gui) CurrentView() *View {
+	return g.currentView
+}
+
+// SetKeybinding creates a new keybinding. If viewname equals to ""
+// (empty string) then the keybinding will apply to all views. key must
+// be a rune or a Key.
+func (g *Gui) SetKeybinding(viewname string, key interface{}, mod Modifier, h KeybindingHandler) error {
+	var kb *keybinding
+
+	switch k := key.(type) {
+	case Key:
+		kb = newKeybinding(viewname, k, 0, mod, h)
+	case rune:
+		kb = newKeybinding(viewname, 0, k, mod, h)
+	default:
+		return errors.New("unknown type")
+	}
+	g.keybindings = append(g.keybindings, kb)
+	return nil
+}
+
+// Execute executes the given handler. This function can be called safely from
+// a goroutine in order to update the GUI. It is important to note that it
+// won't be executed immediately, instead it will be added to the user events
+// queue.
+func (g *Gui) Execute(h Handler) {
+	go func() { g.userEvents <- userEvent{h: h} }()
+}
+
+// SetLayout sets the current layout. A layout is a function that
+// will be called every time the gui is redrawn, it must contain
+// the base views and its initializations.
+func (g *Gui) SetLayout(layout Handler) {
+	g.layout = layout
+	g.currentView = nil
+	g.views = nil
+	go func() { g.tbEvents <- termbox.Event{Type: termbox.EventResize} }()
+}
+
+// MainLoop runs the main loop until an error is returned. A successful
+// finish should return ErrQuit.
+func (g *Gui) MainLoop() error {
+	go func() {
+		for {
+			g.tbEvents <- termbox.PollEvent()
+		}
+	}()
+
+	inputMode := termbox.InputAlt
+	if g.Mouse {
+		inputMode |= termbox.InputMouse
+	}
+	termbox.SetInputMode(inputMode)
+
+	if err := g.flush(); err != nil {
+		return err
+	}
+	for {
+		select {
+		case ev := <-g.tbEvents:
+			if err := g.handleEvent(&ev); err != nil {
+				return err
+			}
+		case ev := <-g.userEvents:
+			if err := ev.h(g); err != nil {
+				return err
+			}
+		}
+		if err := g.consumeevents(); err != nil {
+			return err
+		}
+		if err := g.flush(); err != nil {
+			return err
+		}
+	}
+}
+
+// consumeevents handles the remaining events in the events pool.
+func (g *Gui) consumeevents() error {
+	for {
+		select {
+		case ev := <-g.tbEvents:
+			if err := g.handleEvent(&ev); err != nil {
+				return err
+			}
+		case ev := <-g.userEvents:
+			if err := ev.h(g); err != nil {
+				return err
+			}
+		default:
+			return nil
+		}
+	}
+}
+
+// handleEvent handles an event, based on its type (key-press, error,
+// etc.)
+func (g *Gui) handleEvent(ev *termbox.Event) error {
+	switch ev.Type {
+	case termbox.EventKey, termbox.EventMouse:
+		return g.onKey(ev)
+	case termbox.EventError:
+		return ev.Err
+	default:
+		return nil
+	}
+}
+
+// flush updates the gui, re-drawing frames and buffers.
+func (g *Gui) flush() error {
+	if g.layout == nil {
+		return errors.New("Null layout")
+	}
+
+	termbox.Clear(termbox.Attribute(g.FgColor), termbox.Attribute(g.BgColor))
+
+	maxX, maxY := termbox.Size()
+	// if GUI's size has changed, we need to redraw all views
+	if maxX != g.maxX || maxY != g.maxY {
+		for _, v := range g.views {
+			v.tainted = true
+		}
+	}
+	g.maxX, g.maxY = maxX, maxY
+
+	if err := g.layout(g); err != nil {
+		return err
+	}
+	for _, v := range g.views {
+		if v.Frame {
+			if err := g.drawFrame(v); err != nil {
+				return err
+			}
+			if v.Title != "" {
+				if err := g.drawTitle(v); err != nil {
+					return err
+				}
+			}
+		}
+
+		if err := g.draw(v); err != nil {
+			return err
+		}
+	}
+	if err := g.drawIntersections(); err != nil {
+		return err
+	}
+	termbox.Flush()
+	return nil
+
+}
+
+// drawFrame draws the horizontal and vertical edges of a view.
+func (g *Gui) drawFrame(v *View) error {
+	for x := v.x0 + 1; x < v.x1 && x < g.maxX; x++ {
+		if x < 0 {
+			continue
+		}
+		if v.y0 > -1 && v.y0 < g.maxY {
+			if err := g.SetRune(x, v.y0, '─'); err != nil {
+				return err
+			}
+		}
+		if v.y1 > -1 && v.y1 < g.maxY {
+			if err := g.SetRune(x, v.y1, '─'); err != nil {
+				return err
+			}
+		}
+	}
+	for y := v.y0 + 1; y < v.y1 && y < g.maxY; y++ {
+		if y < 0 {
+			continue
+		}
+		if v.x0 > -1 && v.x0 < g.maxX {
+			if err := g.SetRune(v.x0, y, '│'); err != nil {
+				return err
+			}
+		}
+		if v.x1 > -1 && v.x1 < g.maxX {
+			if err := g.SetRune(v.x1, y, '│'); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// drawTitle draws the title of the view.
+func (g *Gui) drawTitle(v *View) error {
+	if v.y0 < 0 || v.y0 >= g.maxY {
+		return nil
+	}
+
+	for i, ch := range v.Title {
+		x := v.x0 + i + 2
+		if x < 0 {
+			continue
+		} else if x > v.x1-2 || x >= g.maxX {
+			break
+		}
+		if err := g.SetRune(x, v.y0, ch); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// draw manages the cursor and calls the draw function of a view.
+func (g *Gui) draw(v *View) error {
+	if g.Cursor {
+		if v := g.currentView; v != nil {
+			vMaxX, vMaxY := v.Size()
+			if v.cx < 0 {
+				v.cx = 0
+			} else if v.cx >= vMaxX {
+				v.cx = vMaxX - 1
+			}
+			if v.cy < 0 {
+				v.cy = 0
+			} else if v.cy >= vMaxY {
+				v.cy = vMaxY - 1
+			}
+
+			gMaxX, gMaxY := g.Size()
+			cx, cy := v.x0+v.cx+1, v.y0+v.cy+1
+			if cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY {
+				termbox.SetCursor(cx, cy)
+			} else {
+				termbox.HideCursor()
+			}
+		}
+	} else {
+		termbox.HideCursor()
+	}
+
+	v.clearRunes()
+	if err := v.draw(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// drawIntersections draws the corners of each view, based on the type
+// of the edges that converge at these points.
+func (g *Gui) drawIntersections() error {
+	for _, v := range g.views {
+		if ch, ok := g.intersectionRune(v.x0, v.y0); ok {
+			if err := g.SetRune(v.x0, v.y0, ch); err != nil {
+				return err
+			}
+		}
+		if ch, ok := g.intersectionRune(v.x0, v.y1); ok {
+			if err := g.SetRune(v.x0, v.y1, ch); err != nil {
+				return err
+			}
+		}
+		if ch, ok := g.intersectionRune(v.x1, v.y0); ok {
+			if err := g.SetRune(v.x1, v.y0, ch); err != nil {
+				return err
+			}
+		}
+		if ch, ok := g.intersectionRune(v.x1, v.y1); ok {
+			if err := g.SetRune(v.x1, v.y1, ch); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// intersectionRune returns the correct intersection rune at a given
+// point.
+func (g *Gui) intersectionRune(x, y int) (rune, bool) {
+	if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
+		return ' ', false
+	}
+
+	chTop, _ := g.Rune(x, y-1)
+	top := verticalRune(chTop)
+	chBottom, _ := g.Rune(x, y+1)
+	bottom := verticalRune(chBottom)
+	chLeft, _ := g.Rune(x-1, y)
+	left := horizontalRune(chLeft)
+	chRight, _ := g.Rune(x+1, y)
+	right := horizontalRune(chRight)
+
+	var ch rune
+	switch {
+	case !top && bottom && !left && right:
+		ch = '┌'
+	case !top && bottom && left && !right:
+		ch = '┐'
+	case top && !bottom && !left && right:
+		ch = '└'
+	case top && !bottom && left && !right:
+		ch = '┘'
+	case top && bottom && left && right:
+		ch = '┼'
+	case top && bottom && !left && right:
+		ch = '├'
+	case top && bottom && left && !right:
+		ch = '┤'
+	case !top && bottom && left && right:
+		ch = '┬'
+	case top && !bottom && left && right:
+		ch = '┴'
+	default:
+		return ' ', false
+	}
+	return ch, true
+}
+
+// verticalRune returns if the given character is a vertical rune.
+func verticalRune(ch rune) bool {
+	if ch == '│' || ch == '┼' || ch == '├' || ch == '┤' {
+		return true
+	}
+	return false
+}
+
+// verticalRune returns if the given character is a horizontal rune.
+func horizontalRune(ch rune) bool {
+	if ch == '─' || ch == '┼' || ch == '┬' || ch == '┴' {
+		return true
+	}
+	return false
+}
+
+// onKey manages key-press events. A keybinding handler is called when
+// a key-press or mouse event satisfies a configured keybinding. Furthermore,
+// currentView's internal buffer is modified if currentView.Editable is true.
+func (g *Gui) onKey(ev *termbox.Event) error {
+	var curView *View
+
+	switch ev.Type {
+	case termbox.EventKey:
+		if g.currentView != nil && g.currentView.Editable && g.Editor != nil {
+			g.Editor.Edit(g.currentView, Key(ev.Key), ev.Ch, Modifier(ev.Mod))
+		}
+		curView = g.currentView
+	case termbox.EventMouse:
+		mx, my := ev.MouseX, ev.MouseY
+		v, err := g.ViewByPosition(mx, my)
+		if err != nil {
+			break
+		}
+		if err := v.SetCursor(mx-v.x0-1, my-v.y0-1); err != nil {
+			return err
+		}
+		curView = v
+	}
+
+	for _, kb := range g.keybindings {
+		if kb.h == nil {
+			continue
+		}
+		if kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) && kb.matchView(curView) {
+			if err := kb.h(g, curView); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
diff --git a/go/src/github.com/jroimartin/gocui/keybinding.go b/go/src/github.com/jroimartin/gocui/keybinding.go
new file mode 100644
index 0000000..6151682
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/keybinding.go
@@ -0,0 +1,141 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import "github.com/nsf/termbox-go"
+
+type (
+	// Key represents special keys or keys combinations.
+	Key termbox.Key
+
+	// Modifier allows to define special keys combinations. They can be used
+	// in combination with Keys or Runes when a new keybinding is defined.
+	Modifier termbox.Modifier
+
+	// KeybindingHandler represents the handler linked to a specific
+	// keybindings. The handler is called when a key-press event satisfies a
+	// configured keybinding.
+	KeybindingHandler func(*Gui, *View) error
+)
+
+// Special keys.
+const (
+	KeyF1         Key = Key(termbox.KeyF1)
+	KeyF2             = Key(termbox.KeyF2)
+	KeyF3             = Key(termbox.KeyF3)
+	KeyF4             = Key(termbox.KeyF4)
+	KeyF5             = Key(termbox.KeyF5)
+	KeyF6             = Key(termbox.KeyF6)
+	KeyF7             = Key(termbox.KeyF7)
+	KeyF8             = Key(termbox.KeyF8)
+	KeyF9             = Key(termbox.KeyF9)
+	KeyF10            = Key(termbox.KeyF10)
+	KeyF11            = Key(termbox.KeyF11)
+	KeyF12            = Key(termbox.KeyF12)
+	KeyInsert         = Key(termbox.KeyInsert)
+	KeyDelete         = Key(termbox.KeyDelete)
+	KeyHome           = Key(termbox.KeyHome)
+	KeyEnd            = Key(termbox.KeyEnd)
+	KeyPgup           = Key(termbox.KeyPgup)
+	KeyPgdn           = Key(termbox.KeyPgdn)
+	KeyArrowUp        = Key(termbox.KeyArrowUp)
+	KeyArrowDown      = Key(termbox.KeyArrowDown)
+	KeyArrowLeft      = Key(termbox.KeyArrowLeft)
+	KeyArrowRight     = Key(termbox.KeyArrowRight)
+
+	MouseLeft   = Key(termbox.MouseLeft)
+	MouseMiddle = Key(termbox.MouseMiddle)
+	MouseRight  = Key(termbox.MouseRight)
+)
+
+// Keys combinations.
+const (
+	KeyCtrlTilde      Key = Key(termbox.KeyCtrlTilde)
+	KeyCtrl2              = Key(termbox.KeyCtrl2)
+	KeyCtrlSpace          = Key(termbox.KeyCtrlSpace)
+	KeyCtrlA              = Key(termbox.KeyCtrlA)
+	KeyCtrlB              = Key(termbox.KeyCtrlB)
+	KeyCtrlC              = Key(termbox.KeyCtrlC)
+	KeyCtrlD              = Key(termbox.KeyCtrlD)
+	KeyCtrlE              = Key(termbox.KeyCtrlE)
+	KeyCtrlF              = Key(termbox.KeyCtrlF)
+	KeyCtrlG              = Key(termbox.KeyCtrlG)
+	KeyBackspace          = Key(termbox.KeyBackspace)
+	KeyCtrlH              = Key(termbox.KeyCtrlH)
+	KeyTab                = Key(termbox.KeyTab)
+	KeyCtrlI              = Key(termbox.KeyCtrlI)
+	KeyCtrlJ              = Key(termbox.KeyCtrlJ)
+	KeyCtrlK              = Key(termbox.KeyCtrlK)
+	KeyCtrlL              = Key(termbox.KeyCtrlL)
+	KeyEnter              = Key(termbox.KeyEnter)
+	KeyCtrlM              = Key(termbox.KeyCtrlM)
+	KeyCtrlN              = Key(termbox.KeyCtrlN)
+	KeyCtrlO              = Key(termbox.KeyCtrlO)
+	KeyCtrlP              = Key(termbox.KeyCtrlP)
+	KeyCtrlQ              = Key(termbox.KeyCtrlQ)
+	KeyCtrlR              = Key(termbox.KeyCtrlR)
+	KeyCtrlS              = Key(termbox.KeyCtrlS)
+	KeyCtrlT              = Key(termbox.KeyCtrlT)
+	KeyCtrlU              = Key(termbox.KeyCtrlU)
+	KeyCtrlV              = Key(termbox.KeyCtrlV)
+	KeyCtrlW              = Key(termbox.KeyCtrlW)
+	KeyCtrlX              = Key(termbox.KeyCtrlX)
+	KeyCtrlY              = Key(termbox.KeyCtrlY)
+	KeyCtrlZ              = Key(termbox.KeyCtrlZ)
+	KeyEsc                = Key(termbox.KeyEsc)
+	KeyCtrlLsqBracket     = Key(termbox.KeyCtrlLsqBracket)
+	KeyCtrl3              = Key(termbox.KeyCtrl3)
+	KeyCtrl4              = Key(termbox.KeyCtrl4)
+	KeyCtrlBackslash      = Key(termbox.KeyCtrlBackslash)
+	KeyCtrl5              = Key(termbox.KeyCtrl5)
+	KeyCtrlRsqBracket     = Key(termbox.KeyCtrlRsqBracket)
+	KeyCtrl6              = Key(termbox.KeyCtrl6)
+	KeyCtrl7              = Key(termbox.KeyCtrl7)
+	KeyCtrlSlash          = Key(termbox.KeyCtrlSlash)
+	KeyCtrlUnderscore     = Key(termbox.KeyCtrlUnderscore)
+	KeySpace              = Key(termbox.KeySpace)
+	KeyBackspace2         = Key(termbox.KeyBackspace2)
+	KeyCtrl8              = Key(termbox.KeyCtrl8)
+)
+
+// Modifiers.
+const (
+	ModNone Modifier = Modifier(0)
+	ModAlt           = Modifier(termbox.ModAlt)
+)
+
+// Keybidings are used to link a given key-press event with a handler.
+type keybinding struct {
+	viewName string
+	key      Key
+	ch       rune
+	mod      Modifier
+	h        KeybindingHandler
+}
+
+// newKeybinding returns a new Keybinding object.
+func newKeybinding(viewname string, key Key, ch rune, mod Modifier, h KeybindingHandler) (kb *keybinding) {
+	kb = &keybinding{
+		viewName: viewname,
+		key:      key,
+		ch:       ch,
+		mod:      mod,
+		h:        h,
+	}
+	return kb
+}
+
+// matchKeypress returns if the keybinding matches the keypress.
+func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool {
+	return kb.key == key && kb.ch == ch && kb.mod == mod
+}
+
+// matchView returns if the keybinding matches the current view.
+func (kb *keybinding) matchView(v *View) bool {
+	if kb.viewName == "" {
+		return true
+	}
+	return v != nil && kb.viewName == v.name
+}
diff --git a/go/src/github.com/jroimartin/gocui/view.go b/go/src/github.com/jroimartin/gocui/view.go
new file mode 100644
index 0000000..910aecc
--- /dev/null
+++ b/go/src/github.com/jroimartin/gocui/view.go
@@ -0,0 +1,581 @@
+// Copyright 2014 The gocui Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gocui
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"strings"
+
+	"github.com/nsf/termbox-go"
+)
+
+// A View is a window. It maintains its own internal buffer and cursor
+// position.
+type View struct {
+	name           string
+	x0, y0, x1, y1 int
+	ox, oy         int
+	cx, cy         int
+	lines          [][]cell
+	readOffset     int
+	readCache      string
+
+	tainted   bool       // marks if the viewBuffer must be updated
+	viewLines []viewLine // internal representation of the view's buffer
+
+	ei *escapeInterpreter // used to decode ESC sequences on Write
+
+	// BgColor and FgColor allow to configure the background and foreground
+	// colors of the View.
+	BgColor, FgColor Attribute
+
+	// SelBgColor and SelFgColor are used to configure the background and
+	// foreground colors of the selected line, when it is highlighted.
+	SelBgColor, SelFgColor Attribute
+
+	// If Editable is true, keystrokes will be added to the view's internal
+	// buffer at the cursor position.
+	Editable bool
+
+	// Overwrite enables or disables the overwrite mode of the view.
+	Overwrite bool
+
+	// If Highlight is true, Sel{Bg,Fg}Colors will be used
+	// for the line under the cursor position.
+	Highlight bool
+
+	// If Frame is true, a border will be drawn around the view.
+	Frame bool
+
+	// If Wrap is true, the content that is written to this View is
+	// automatically wrapped when it is longer than its width. If true the
+	// view's x-origin will be ignored.
+	Wrap bool
+
+	// If Autoscroll is true, the View will automatically scroll down when the
+	// text overflows. If true the view's y-origin will be ignored.
+	Autoscroll bool
+
+	// If Frame is true, Title allows to configure a title for the view.
+	Title string
+
+	// If Mask is true, the View will display the mask instead of the real
+	// content
+	Mask rune
+}
+
+type viewLine struct {
+	linesX, linesY int // coordinates relative to v.lines
+	line           []cell
+}
+
+type cell struct {
+	chr              rune
+	bgColor, fgColor Attribute
+}
+
+type lineType []cell
+
+// String returns a string from a given cell slice.
+func (l lineType) String() string {
+	str := ""
+	for _, c := range l {
+		str += string(c.chr)
+	}
+	return str
+}
+
+// newView returns a new View object.
+func newView(name string, x0, y0, x1, y1 int) *View {
+	v := &View{
+		name:    name,
+		x0:      x0,
+		y0:      y0,
+		x1:      x1,
+		y1:      y1,
+		Frame:   true,
+		tainted: true,
+		ei:      newEscapeInterpreter(),
+	}
+	return v
+}
+
+// Size returns the number of visible columns and rows in the View.
+func (v *View) Size() (x, y int) {
+	return v.x1 - v.x0 - 1, v.y1 - v.y0 - 1
+}
+
+// Name returns the name of the view.
+func (v *View) Name() string {
+	return v.name
+}
+
+// setRune sets a rune at the given point relative to the view. It applies the
+// specified colors, taking into account if the cell must be highlighted. Also,
+// it checks if the position is valid.
+func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
+	maxX, maxY := v.Size()
+	if x < 0 || x >= maxX || y < 0 || y >= maxY {
+		return errors.New("invalid point")
+	}
+
+	var (
+		ry, rcy int
+		err     error
+	)
+	if v.Highlight {
+		_, ry, err = v.realPosition(x, y)
+		if err != nil {
+			return err
+		}
+		_, rcy, err = v.realPosition(v.cx, v.cy)
+		if err != nil {
+			return err
+		}
+	}
+
+	if v.Mask != 0 {
+		fgColor = v.FgColor
+		bgColor = v.BgColor
+		ch = v.Mask
+	} else if v.Highlight && ry == rcy {
+		fgColor = v.SelFgColor
+		bgColor = v.SelBgColor
+	}
+
+	termbox.SetCell(v.x0+x+1, v.y0+y+1, ch,
+		termbox.Attribute(fgColor), termbox.Attribute(bgColor))
+
+	return nil
+}
+
+// SetCursor sets the cursor position of the view at the given point,
+// relative to the view. It checks if the position is valid.
+func (v *View) SetCursor(x, y int) error {
+	maxX, maxY := v.Size()
+	if x < 0 || x >= maxX || y < 0 || y >= maxY {
+		return errors.New("invalid point")
+	}
+	v.cx = x
+	v.cy = y
+	return nil
+}
+
+// Cursor returns the cursor position of the view.
+func (v *View) Cursor() (x, y int) {
+	return v.cx, v.cy
+}
+
+// SetOrigin sets the origin position of the view's internal buffer,
+// so the buffer starts to be printed from this point, which means that
+// it is linked with the origin point of view. It can be used to
+// implement Horizontal and Vertical scrolling with just incrementing
+// or decrementing ox and oy.
+func (v *View) SetOrigin(x, y int) error {
+	if x < 0 || y < 0 {
+		return errors.New("invalid point")
+	}
+	v.ox = x
+	v.oy = y
+	return nil
+}
+
+// Origin returns the origin position of the view.
+func (v *View) Origin() (x, y int) {
+	return v.ox, v.oy
+}
+
+// Write appends a byte slice into the view's internal buffer. Because
+// View implements the io.Writer interface, it can be passed as parameter
+// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
+// be called to clear the view's buffer.
+func (v *View) Write(p []byte) (n int, err error) {
+	v.tainted = true
+
+	for _, ch := range bytes.Runes(p) {
+		switch ch {
+		case '\n':
+			v.lines = append(v.lines, nil)
+		case '\r':
+			nl := len(v.lines)
+			if nl > 0 {
+				v.lines[nl-1] = nil
+			} else {
+				v.lines = make([][]cell, 1)
+			}
+		default:
+			cells := v.parseInput(ch)
+			if cells == nil {
+				continue
+			}
+
+			nl := len(v.lines)
+			if nl > 0 {
+				v.lines[nl-1] = append(v.lines[nl-1], cells...)
+			} else {
+				v.lines = append(v.lines, cells)
+			}
+		}
+	}
+	return len(p), nil
+}
+
+// parseInput parses char by char the input written to the View. It returns nil
+// while processing ESC sequences. Otherwise, it returns a cell slice that
+// contains the processed data.
+func (v *View) parseInput(ch rune) []cell {
+	cells := []cell{}
+
+	// ei's default colors must be updated, because they could have been
+	// changed
+	v.ei.defaultFgColor = v.FgColor
+	v.ei.defaultBgColor = v.BgColor
+
+	isEscape, err := v.ei.parseOne(ch)
+	if err != nil {
+		for _, r := range v.ei.runes() {
+			c := cell{
+				fgColor: v.FgColor,
+				bgColor: v.BgColor,
+				chr:     r,
+			}
+			cells = append(cells, c)
+		}
+		v.ei.reset()
+	} else {
+		if isEscape {
+			return nil
+		} else {
+			c := cell{
+				fgColor: v.ei.curFgColor,
+				bgColor: v.ei.curBgColor,
+				chr:     ch,
+			}
+			cells = append(cells, c)
+		}
+	}
+
+	return cells
+}
+
+// Read reads data into p. It returns the number of bytes read into p.
+// At EOF, err will be io.EOF. Calling Read() after Rewind() makes the
+// cache to be refreshed with the contents of the view.
+func (v *View) Read(p []byte) (n int, err error) {
+	if v.readOffset == 0 {
+		v.readCache = v.Buffer()
+	}
+	if v.readOffset < len(v.readCache) {
+		n = copy(p, v.readCache[v.readOffset:])
+		v.readOffset += n
+	} else {
+		err = io.EOF
+	}
+	return
+}
+
+// Rewind sets the offset for the next Read to 0, which also refresh the
+// read cache.
+func (v *View) Rewind() {
+	v.readOffset = 0
+}
+
+// draw re-draws the view's contents.
+func (v *View) draw() error {
+	maxX, maxY := v.Size()
+
+	if v.Wrap {
+		if maxX == 0 {
+			return errors.New("X size of the view cannot be 0")
+		}
+		v.ox = 0
+	}
+	if v.tainted {
+		v.viewLines = nil
+		for i, line := range v.lines {
+			if v.Wrap {
+				if len(line) <= maxX {
+					vline := viewLine{linesX: 0, linesY: i, line: line}
+					v.viewLines = append(v.viewLines, vline)
+					continue
+				} else {
+					vline := viewLine{linesX: 0, linesY: i, line: line[:maxX]}
+					v.viewLines = append(v.viewLines, vline)
+				}
+				// Append remaining lines
+				for n := maxX; n < len(line); n += maxX {
+					if len(line[n:]) <= maxX {
+						vline := viewLine{linesX: n, linesY: i, line: line[n:]}
+						v.viewLines = append(v.viewLines, vline)
+					} else {
+						vline := viewLine{linesX: n, linesY: i, line: line[n : n+maxX]}
+						v.viewLines = append(v.viewLines, vline)
+					}
+				}
+			} else {
+				vline := viewLine{linesX: 0, linesY: i, line: line}
+				v.viewLines = append(v.viewLines, vline)
+			}
+		}
+		v.tainted = false
+	}
+
+	if v.Autoscroll && len(v.viewLines) > maxY {
+		v.oy = len(v.viewLines) - maxY
+	}
+	y := 0
+	for i, vline := range v.viewLines {
+		if i < v.oy {
+			continue
+		}
+		if y >= maxY {
+			break
+		}
+		x := 0
+		for j, c := range vline.line {
+			if j < v.ox {
+				continue
+			}
+			if x >= maxX {
+				break
+			}
+			if err := v.setRune(x, y, c.chr, c.fgColor, c.bgColor); err != nil {
+				return err
+			}
+			x++
+		}
+		y++
+	}
+	return nil
+}
+
+// realPosition returns the position in the internal buffer corresponding to the
+// point (x, y) of the view.
+func (v *View) realPosition(vx, vy int) (x, y int, err error) {
+	vx = v.ox + vx
+	vy = v.oy + vy
+
+	if vx < 0 || vy < 0 {
+		return 0, 0, errors.New("invalid point")
+	}
+
+	if len(v.viewLines) == 0 {
+		return vx, vy, nil
+	}
+
+	if vy < len(v.viewLines) {
+		vline := v.viewLines[vy]
+		x = vline.linesX + vx
+		y = vline.linesY
+	} else {
+		vline := v.viewLines[len(v.viewLines)-1]
+		x = vx
+		y = vline.linesY + vy - len(v.viewLines) + 1
+	}
+
+	return x, y, nil
+}
+
+// Clear empties the view's internal buffer.
+func (v *View) Clear() {
+	v.tainted = true
+
+	v.lines = nil
+	v.clearRunes()
+}
+
+// clearRunes erases all the cells in the view.
+func (v *View) clearRunes() {
+	maxX, maxY := v.Size()
+	for x := 0; x < maxX; x++ {
+		for y := 0; y < maxY; y++ {
+			termbox.SetCell(v.x0+x+1, v.y0+y+1, ' ',
+				termbox.Attribute(v.FgColor), termbox.Attribute(v.BgColor))
+		}
+	}
+}
+
+// writeRune writes a rune into the view's internal buffer, at the
+// position corresponding to the point (x, y). The length of the internal
+// buffer is increased if the point is out of bounds. Overwrite mode is
+// governed by the value of View.overwrite.
+func (v *View) writeRune(x, y int, ch rune) error {
+	v.tainted = true
+
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return err
+	}
+
+	if x < 0 || y < 0 {
+		return errors.New("invalid point")
+	}
+
+	if y >= len(v.lines) {
+		s := make([][]cell, y-len(v.lines)+1)
+		v.lines = append(v.lines, s...)
+	}
+
+	olen := len(v.lines[y])
+	if x >= len(v.lines[y]) {
+		s := make([]cell, x-len(v.lines[y])+1)
+		v.lines[y] = append(v.lines[y], s...)
+	}
+
+	c := cell{
+		fgColor: v.FgColor,
+		bgColor: v.BgColor,
+	}
+	if !v.Overwrite && x < olen {
+		c.chr = '\x00'
+		v.lines[y] = append(v.lines[y], c)
+		copy(v.lines[y][x+1:], v.lines[y][x:])
+	}
+	c.chr = ch
+	v.lines[y][x] = c
+	return nil
+}
+
+// deleteRune removes a rune from the view's internal buffer, at the
+// position corresponding to the point (x, y).
+func (v *View) deleteRune(x, y int) error {
+	v.tainted = true
+
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return err
+	}
+
+	if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
+		return errors.New("invalid point")
+	}
+	v.lines[y] = append(v.lines[y][:x], v.lines[y][x+1:]...)
+	return nil
+}
+
+// mergeLines merges the lines "y" and "y+1" if possible.
+func (v *View) mergeLines(y int) error {
+	v.tainted = true
+
+	_, y, err := v.realPosition(0, y)
+	if err != nil {
+		return err
+	}
+
+	if y < 0 || y >= len(v.lines) {
+		return errors.New("invalid point")
+	}
+
+	if y < len(v.lines)-1 { // otherwise we don't need to merge anything
+		v.lines[y] = append(v.lines[y], v.lines[y+1]...)
+		v.lines = append(v.lines[:y+1], v.lines[y+2:]...)
+	}
+	return nil
+}
+
+// breakLine breaks a line of the internal buffer at the position corresponding
+// to the point (x, y).
+func (v *View) breakLine(x, y int) error {
+	v.tainted = true
+
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return err
+	}
+
+	if y < 0 || y >= len(v.lines) {
+		return errors.New("invalid point")
+	}
+
+	var left, right []cell
+	if x < len(v.lines[y]) { // break line
+		left = make([]cell, len(v.lines[y][:x]))
+		copy(left, v.lines[y][:x])
+		right = make([]cell, len(v.lines[y][x:]))
+		copy(right, v.lines[y][x:])
+	} else { // new empty line
+		left = v.lines[y]
+	}
+
+	lines := make([][]cell, len(v.lines)+1)
+	lines[y] = left
+	lines[y+1] = right
+	copy(lines, v.lines[:y])
+	copy(lines[y+2:], v.lines[y+1:])
+	v.lines = lines
+	return nil
+}
+
+// Buffer returns a string with the contents of the view's internal
+// buffer.
+func (v *View) Buffer() string {
+	str := ""
+	for _, l := range v.lines {
+		str += lineType(l).String() + "\n"
+	}
+	return strings.Replace(str, "\x00", " ", -1)
+}
+
+// ViewBuffer returns a string with the contents of the view's buffer that is
+// shown to the user.
+func (v *View) ViewBuffer() string {
+	str := ""
+	for _, l := range v.viewLines {
+		str += lineType(l.line).String() + "\n"
+	}
+	return strings.Replace(str, "\x00", " ", -1)
+}
+
+// Line returns a string with the line of the view's internal buffer
+// at the position corresponding to the point (x, y).
+func (v *View) Line(y int) (string, error) {
+	_, y, err := v.realPosition(0, y)
+	if err != nil {
+		return "", err
+	}
+
+	if y < 0 || y >= len(v.lines) {
+		return "", errors.New("invalid point")
+	}
+
+	return lineType(v.lines[y]).String(), nil
+}
+
+// Word returns a string with the word of the view's internal buffer
+// at the position corresponding to the point (x, y).
+func (v *View) Word(x, y int) (string, error) {
+	x, y, err := v.realPosition(x, y)
+	if err != nil {
+		return "", err
+	}
+
+	if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
+		return "", errors.New("invalid point")
+	}
+
+	str := lineType(v.lines[y]).String()
+
+	nl := strings.LastIndexFunc(str[:x], indexFunc)
+	if nl == -1 {
+		nl = 0
+	} else {
+		nl = nl + 1
+	}
+	nr := strings.IndexFunc(str[x:], indexFunc)
+	if nr == -1 {
+		nr = len(str)
+	} else {
+		nr = nr + x
+	}
+	return string(str[nl:nr]), nil
+}
+
+// indexFunc allows to split lines by words taking into account spaces
+// and 0.
+func indexFunc(r rune) bool {
+	return r == ' ' || r == 0
+}