Full Code of jroimartin/gocui for AI

master 0e75b37a4ce7 cached
33 files
105.6 KB
34.1k tokens
289 symbols
1 requests
Download .txt
Repository: jroimartin/gocui
Branch: master
Commit: 0e75b37a4ce7
Files: 33
Total size: 105.6 KB

Directory structure:
gitextract_k_yugcw4/

├── .gitignore
├── AUTHORS
├── LICENSE
├── README.md
├── _examples/
│   ├── Mark.Twain-Tom.Sawyer.txt
│   ├── active.go
│   ├── bufs.go
│   ├── colors.go
│   ├── colors256.go
│   ├── demo.go
│   ├── dynamic.go
│   ├── flow_layout.go
│   ├── goroutine.go
│   ├── hello.go
│   ├── layout.go
│   ├── mask.go
│   ├── mouse.go
│   ├── ontop.go
│   ├── overlap.go
│   ├── size.go
│   ├── stdin.go
│   ├── title.go
│   ├── widgets.go
│   └── wrap.go
├── attribute.go
├── doc.go
├── edit.go
├── escape.go
├── go.mod
├── go.sum
├── gui.go
├── keybinding.go
└── view.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.swp


================================================
FILE: AUTHORS
================================================
# 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

Henri Koski <henri.t.koski@gmail.com>
	Custom current view color

Dustin Willis Webber <dustin.webber@gmail.com>
	256-colors output mode support


================================================
FILE: LICENSE
================================================
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.


================================================
FILE: README.md
================================================
# GOCUI - Go Console User Interface

[![Go Reference](https://pkg.go.dev/badge/github.com/jroimartin/gocui.svg)](https://pkg.go.dev/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.
* Easy to build reusable widgets, complex layouts...

## Installation

Execute:

```sh
go get github.com/jroimartin/gocui
```

## Documentation

Execute:

```sh
go doc github.com/jroimartin/gocui
```

Or visit [pkg.go.dev](https://pkg.go.dev/github.com/jroimartin/gocui) to read
it online.

## Example

```go
package main

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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

![r2cui](https://cloud.githubusercontent.com/assets/1223476/19418932/63645052-93ce-11e6-867c-da5e97e37237.png)

![_examples/demo.go](https://cloud.githubusercontent.com/assets/1223476/5992750/720b84f0-aa36-11e4-88ec-296fa3247b52.png)

![_examples/dynamic.go](https://cloud.githubusercontent.com/assets/1223476/5992751/76ad5cc2-aa36-11e4-8204-6a90269db827.png)


================================================
FILE: _examples/Mark.Twain-Tom.Sawyer.txt
================================================
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.


================================================
FILE: _examples/active.go
================================================
// 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"
)

var (
	viewArr = []string{"v1", "v2", "v3", "v4"}
	active  = 0
)

func setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) {
	if _, err := g.SetCurrentView(name); err != nil {
		return nil, err
	}
	return g.SetViewOnTop(name)
}

func nextView(g *gocui.Gui, v *gocui.View) error {
	nextIndex := (active + 1) % len(viewArr)
	name := viewArr[nextIndex]

	out, err := g.View("v2")
	if err != nil {
		return err
	}
	fmt.Fprintln(out, "Going from view "+v.Name()+" to "+name)

	if _, err := setCurrentViewOnTop(g, name); err != nil {
		return err
	}

	if nextIndex == 0 || nextIndex == 3 {
		g.Cursor = true
	} else {
		g.Cursor = false
	}

	active = nextIndex
	return nil
}

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("v1", 0, 0, maxX/2-1, maxY/2-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "v1 (editable)"
		v.Editable = true
		v.Wrap = true

		if _, err = setCurrentViewOnTop(g, "v1"); err != nil {
			return err
		}
	}

	if v, err := g.SetView("v2", maxX/2-1, 0, maxX-1, maxY/2-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "v2"
		v.Wrap = true
		v.Autoscroll = true
	}
	if v, err := g.SetView("v3", 0, maxY/2-1, maxX/2-1, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "v3"
		v.Wrap = true
		v.Autoscroll = true
		fmt.Fprint(v, "Press TAB to change current view")
	}
	if v, err := g.SetView("v4", maxX/2, maxY/2, maxX-1, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Title = "v4 (editable)"
		v.Editable = true
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit
}

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Highlight = true
	g.Cursor = true
	g.SelFgColor = gocui.ColorGreen

	g.SetManagerFunc(layout)

	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, nextView); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}


================================================
FILE: _examples/bufs.go
================================================
// 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.

// WARNING: tricky code just for testing purposes, do not use as reference.

package main

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

var vbuf, buf string

func quit(g *gocui.Gui, v *gocui.View) error {
	vbuf = v.ViewBuffer()
	buf = v.Buffer()
	return gocui.ErrQuit
}

func overwrite(g *gocui.Gui, v *gocui.View) error {
	v.Overwrite = !v.Overwrite
	return nil
}

func layout(g *gocui.Gui) error {
	_, maxY := g.Size()
	if v, err := g.SetView("main", 0, 0, 20, maxY-1); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Editable = true
		v.Wrap = true
		if _, err := g.SetCurrentView("main"); err != nil {
			return err
		}
	}
	return nil
}

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}

	g.Cursor = true
	g.Mouse = true

	g.SetManagerFunc(layout)

	if err := g.SetKeybinding("main", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("main", gocui.KeyCtrlI, gocui.ModNone, overwrite); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}

	g.Close()

	fmt.Printf("VBUF:\n%s\n", vbuf)
	fmt.Printf("BUF:\n%s\n", buf)
}


================================================
FILE: _examples/colors.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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
}


================================================
FILE: _examples/colors256.go
================================================
// 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, err := gocui.NewGui(gocui.Output256)

	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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", -1, -1, maxX, maxY); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}

		// 256-colors escape codes
		for i := 0; i < 256; i++ {
			str := fmt.Sprintf("\x1b[48;5;%dm\x1b[30m%3d\x1b[0m ", i, i)
			str += fmt.Sprintf("\x1b[38;5;%dm%3d\x1b[0m ", i, i)

			if (i+1)%10 == 0 {
				str += "\n"
			}

			fmt.Fprint(v, str)
		}

		fmt.Fprint(v, "\n\n")

		// 8-colors escape codes
		ctr := 0
		for i := 0; i <= 7; i++ {
			for _, j := range []int{1, 4, 7} {
				str := fmt.Sprintf("\x1b[3%d;%dm%d:%d\x1b[0m ", i, j, i, j)
				if (ctr+1)%20 == 0 {
					str += "\n"
				}

				fmt.Fprint(v, str)

				ctr++
			}
		}
	}
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit
}


================================================
FILE: _examples/demo.go
================================================
// 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" {
		_, err := g.SetCurrentView("main")
		return err
	}
	_, err := g.SetCurrentView("side")
	return err
}

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
		v.SelBgColor = gocui.ColorGreen
		v.SelFgColor = gocui.ColorBlack
		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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Cursor = true

	g.SetManagerFunc(layout)

	if err := keybindings(g); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}


================================================
FILE: _examples/dynamic.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Highlight = true
	g.SelFgColor = gocui.ColorRed

	g.SetManagerFunc(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("help", maxX-25, 0, maxX-1, 9)
	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, "b: Set view on bottom")
		fmt.Fprintln(v, "^C: Exit")
	}
	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("", 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,
		func(g *gocui.Gui, v *gocui.View) error {
			_, err := g.SetViewOnTop(views[curView])
			return err
		}); err != nil {
		return err
	}
	if err := g.SetKeybinding("", 'b', gocui.ModNone,
		func(g *gocui.Gui, v *gocui.View) error {
			_, err := g.SetViewOnBottom(views[curView])
			return err
		}); err != nil {
		return err
	}
	return nil
}

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
	}

	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
	}

	if _, err := g.SetCurrentView(views[next]); err != nil {
		return err
	}

	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
}


================================================
FILE: _examples/flow_layout.go
================================================
// 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"
)

type Label struct {
	name string
	w, h int
	body string
}

func NewLabel(name string, body string) *Label {
	lines := strings.Split(body, "\n")

	w := 0
	for _, l := range lines {
		if len(l) > w {
			w = len(l)
		}
	}
	h := len(lines) + 1
	w = w + 1

	return &Label{name: name, w: w, h: h, body: body}
}

func (w *Label) Layout(g *gocui.Gui) error {
	v, err := g.SetView(w.name, 0, 0, w.w, w.h)
	if err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		fmt.Fprint(v, w.body)
	}
	return nil
}

func flowLayout(g *gocui.Gui) error {
	views := g.Views()
	x := 0
	for _, v := range views {
		w, h := v.Size()
		_, err := g.SetView(v.Name(), x, 0, x+w+1, h+1)
		if err != nil && err != gocui.ErrUnknownView {
			return err
		}
		x += w + 2
	}
	return nil
}

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	l1 := NewLabel("l1", "This")
	l2 := NewLabel("l2", "is")
	l3 := NewLabel("l3", "a")
	l4 := NewLabel("l4", "flow\nlayout")
	l5 := NewLabel("l5", "!")
	fl := gocui.ManagerFunc(flowLayout)
	g.SetManager(l1, l2, l3, l4, l5, fl)

	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
}


================================================
FILE: _examples/goroutine.go
================================================
// 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 struct{})
	wg   sync.WaitGroup

	mu  sync.Mutex // protects ctr
	ctr = 0
)

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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 {
	close(done)
	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.Update(func(g *gocui.Gui) error {
				v, err := g.View("ctr")
				if err != nil {
					return err
				}
				v.Clear()
				fmt.Fprintln(v, n)
				return nil
			})
		}
	}
}


================================================
FILE: _examples/hello.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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
}


================================================
FILE: _examples/layout.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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)
	}
}


================================================
FILE: _examples/mask.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Fatalln(err)
	}
	defer g.Close()

	g.Cursor = true

	g.SetManagerFunc(layout)

	if err := initKeybindings(g); err != nil {
		log.Fatalln(err)
	}

	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("help", 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
}


================================================
FILE: _examples/mouse.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Cursor = true
	g.Mouse = true

	g.SetManagerFunc(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("but1", 2, 2, 22, 7); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		v.Highlight = true
		v.SelBgColor = gocui.ColorGreen
		v.SelFgColor = gocui.ColorBlack
		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
		v.SelBgColor = gocui.ColorGreen
		v.SelFgColor = gocui.ColorBlack
		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
}


================================================
FILE: _examples/ontop.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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
}


================================================
FILE: _examples/overlap.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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)
	}
}


================================================
FILE: _examples/size.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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()
	v, err := g.SetView("size", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2)
	if err != nil && err != gocui.ErrUnknownView {
		return err
	}
	v.Clear()
	fmt.Fprintf(v, "%d, %d", maxX, maxY)
	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit
}


================================================
FILE: _examples/stdin.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Fatalln(err)
	}
	defer g.Close()

	g.Cursor = true

	g.SetManagerFunc(layout)

	if err := initKeybindings(g); err != nil {
		log.Fatalln(err)
	}

	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("help", 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
}


================================================
FILE: _examples/title.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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
}


================================================
FILE: _examples/widgets.go
================================================
// 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 (
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/jroimartin/gocui"
)

const delta = 0.2

type HelpWidget struct {
	name string
	x, y int
	w, h int
	body string
}

func NewHelpWidget(name string, x, y int, body string) *HelpWidget {
	lines := strings.Split(body, "\n")

	w := 0
	for _, l := range lines {
		if len(l) > w {
			w = len(l)
		}
	}
	h := len(lines) + 1
	w = w + 1

	return &HelpWidget{name: name, x: x, y: y, w: w, h: h, body: body}
}

func (w *HelpWidget) Layout(g *gocui.Gui) error {
	v, err := g.SetView(w.name, w.x, w.y, w.x+w.w, w.y+w.h)
	if err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		fmt.Fprint(v, w.body)
	}
	return nil
}

type StatusbarWidget struct {
	name string
	x, y int
	w    int
	val  float64
}

func NewStatusbarWidget(name string, x, y, w int) *StatusbarWidget {
	return &StatusbarWidget{name: name, x: x, y: y, w: w}
}

func (w *StatusbarWidget) SetVal(val float64) error {
	if val < 0 || val > 1 {
		return errors.New("invalid value")
	}
	w.val = val
	return nil
}

func (w *StatusbarWidget) Val() float64 {
	return w.val
}

func (w *StatusbarWidget) Layout(g *gocui.Gui) error {
	v, err := g.SetView(w.name, w.x, w.y, w.x+w.w, w.y+2)
	if err != nil && err != gocui.ErrUnknownView {
		return err
	}
	v.Clear()

	rep := int(w.val * float64(w.w-1))
	fmt.Fprint(v, strings.Repeat("▒", rep))
	return nil
}

type ButtonWidget struct {
	name    string
	x, y    int
	w       int
	label   string
	handler func(g *gocui.Gui, v *gocui.View) error
}

func NewButtonWidget(name string, x, y int, label string, handler func(g *gocui.Gui, v *gocui.View) error) *ButtonWidget {
	return &ButtonWidget{name: name, x: x, y: y, w: len(label) + 1, label: label, handler: handler}
}

func (w *ButtonWidget) Layout(g *gocui.Gui) error {
	v, err := g.SetView(w.name, w.x, w.y, w.x+w.w, w.y+2)
	if err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		if _, err := g.SetCurrentView(w.name); err != nil {
			return err
		}
		if err := g.SetKeybinding(w.name, gocui.KeyEnter, gocui.ModNone, w.handler); err != nil {
			return err
		}
		fmt.Fprint(v, w.label)
	}
	return nil
}

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Highlight = true
	g.SelFgColor = gocui.ColorRed

	help := NewHelpWidget("help", 1, 1, helpText)
	status := NewStatusbarWidget("status", 1, 7, 50)
	butdown := NewButtonWidget("butdown", 52, 7, "DOWN", statusDown(status))
	butup := NewButtonWidget("butup", 58, 7, "UP", statusUp(status))
	g.SetManager(help, status, butdown, butup)

	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone, toggleButton); 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 toggleButton(g *gocui.Gui, v *gocui.View) error {
	nextview := "butdown"
	if v != nil && v.Name() == "butdown" {
		nextview = "butup"
	}
	_, err := g.SetCurrentView(nextview)
	return err
}

func statusUp(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error {
	return func(g *gocui.Gui, v *gocui.View) error {
		return statusSet(status, delta)
	}
}

func statusDown(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error {
	return func(g *gocui.Gui, v *gocui.View) error {
		return statusSet(status, -delta)
	}
}

func statusSet(sw *StatusbarWidget, inc float64) error {
	val := sw.Val() + inc
	if val < 0 || val > 1 {
		return nil
	}
	return sw.SetVal(val)
}

const helpText = `KEYBINDINGS
Tab: Move between buttons
Enter: Push button
^C: Exit`


================================================
FILE: _examples/wrap.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(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)
	}
}


================================================
FILE: attribute.go
================================================
// 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)
)


================================================
FILE: doc.go
================================================
// 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, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		// handle error
	}
	defer g.Close()

	// Set GUI managers and key bindings
	// ...

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		// handle error
	}

Set GUI managers:

	g.SetManager(mgr1, mgr2)

Managers are in charge of GUI's layout and can be used to build widgets. On
each iteration of the GUI's main loop, the Layout function of each configured
manager is executed. Managers are used to set-up and update the application's
main views, being possible to freely change them during execution. 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
the Layout function within managers, from keybinding callbacks or via
*Gui.Update(). The reason for this is that it allows gocui to be
concurrent-safe. So, if you want to update your GUI from a goroutine, you must
use *Gui.Update(). For example:

	g.Update(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 *View.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


================================================
FILE: edit.go
================================================
// Copyright 2014 The gocui Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gocui

import "errors"

const maxInt = int(^uint(0) >> 1)

// Editor interface must be satisfied by gocui editors.
type Editor interface {
	Edit(v *View, key Key, ch rune, mod Modifier)
}

// The EditorFunc type is an adapter to allow the use of ordinary functions as
// Editors. If f is a function with the appropriate signature, EditorFunc(f)
// is an Editor object that calls f.
type EditorFunc func(v *View, key Key, ch rune, mod Modifier)

// Edit calls f(v, key, ch, mod)
func (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) {
	f(v, key, ch, mod)
}

// DefaultEditor is the default editor.
var DefaultEditor Editor = EditorFunc(simpleEditor)

// simpleEditor is used as the default gocui editor.
func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
	switch {
	case ch != 0 && mod == 0:
		v.EditWrite(ch)
	case key == KeySpace:
		v.EditWrite(' ')
	case key == KeyBackspace || key == KeyBackspace2:
		v.EditDelete(true)
	case key == KeyDelete:
		v.EditDelete(false)
	case key == KeyInsert:
		v.Overwrite = !v.Overwrite
	case key == KeyEnter:
		v.EditNewLine()
	case key == KeyArrowDown:
		v.MoveCursor(0, 1, false)
	case key == KeyArrowUp:
		v.MoveCursor(0, -1, false)
	case key == KeyArrowLeft:
		v.MoveCursor(-1, 0, false)
	case key == KeyArrowRight:
		v.MoveCursor(1, 0, false)
	}
}

// EditWrite writes a rune at the cursor position.
func (v *View) EditWrite(ch rune) {
	v.writeRune(v.cx, v.cy, ch)
	v.MoveCursor(1, 0, true)
}

// EditDelete deletes a rune at the cursor position. back determines the
// direction.
func (v *View) EditDelete(back bool) {
	x, y := v.ox+v.cx, v.oy+v.cy
	if y < 0 {
		return
	} else if y >= len(v.viewLines) {
		v.MoveCursor(-1, 0, true)
		return
	}

	maxX, _ := v.Size()
	if back {
		if x == 0 { // start of the line
			if y < 1 {
				return
			}

			var maxPrevWidth int
			if v.Wrap {
				maxPrevWidth = maxX
			} else {
				maxPrevWidth = maxInt
			}

			if v.viewLines[y].linesX == 0 { // regular line
				v.mergeLines(v.cy - 1)
				if len(v.viewLines[y-1].line) < maxPrevWidth {
					v.MoveCursor(-1, 0, true)
				}
			} else { // wrapped line
				v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
				v.MoveCursor(-1, 0, true)
			}
		} else { // middle/end of the line
			v.deleteRune(v.cx-1, v.cy)
			v.MoveCursor(-1, 0, true)
		}
	} else {
		if x == len(v.viewLines[y].line) { // end of the line
			v.mergeLines(v.cy)
		} else { // start/middle of the line
			v.deleteRune(v.cx, v.cy)
		}
	}
}

// EditNewLine inserts a new line under the cursor.
func (v *View) EditNewLine() {
	v.breakLine(v.cx, v.cy)
	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
			cy++
			if writeMode || v.oy+cy < len(v.viewLines) {
				if !v.Wrap {
					v.ox = 0
				}
				v.cx = 0
			}
		} 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 writeMode || v.oy+cy < len(v.viewLines) {
					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 += cx
			v.cx = 0
		} else { // move to previous line
			cy--
			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
			}
		}
	} else { // stay on the same line
		if v.Wrap {
			v.cx = cx
		} else {
			if cx >= maxX {
				v.ox += cx - maxX + 1
				v.cx = maxX
			} else {
				v.cx = cx
			}
		}
	}

	// adjust cursor's y position and view's y origin
	if cy < 0 {
		if v.oy > 0 {
			v.oy--
		}
	} else if writeMode || v.oy+cy < len(v.viewLines) {
		if cy >= maxY {
			v.oy++
		} else {
			v.cy = cy
		}
	}
}

// writeRune writes a rune into the view's internal buffer, at the
// position corresponding to the point (x, y). The length of the internal
// buffer is increased if the point is out of bounds. Overwrite mode is
// governed by the value of View.overwrite.
func (v *View) writeRune(x, y int, ch rune) error {
	v.tainted = true

	x, y, err := v.realPosition(x, y)
	if err != nil {
		return err
	}

	if x < 0 || y < 0 {
		return errors.New("invalid point")
	}

	if y >= len(v.lines) {
		s := make([][]cell, y-len(v.lines)+1)
		v.lines = append(v.lines, s...)
	}

	olen := len(v.lines[y])

	var s []cell
	if x >= len(v.lines[y]) {
		s = make([]cell, x-len(v.lines[y])+1)
	} else if !v.Overwrite {
		s = make([]cell, 1)
	}
	v.lines[y] = append(v.lines[y], s...)

	if !v.Overwrite || (v.Overwrite && x >= olen-1) {
		copy(v.lines[y][x+1:], v.lines[y][x:])
	}
	v.lines[y][x] = cell{
		fgColor: v.FgColor,
		bgColor: v.BgColor,
		chr:     ch,
	}

	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
}


================================================
FILE: escape.go
================================================
// 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
	mode                   OutputMode
}

type escapeState int

const (
	stateNone escapeState = iota
	stateEscape
	stateCSI
	stateParams
)

var (
	errNotCSI        = errors.New("Not a CSI escape sequence")
	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(mode OutputMode) *escapeInterpreter {
	ei := &escapeInterpreter{
		state:      stateNone,
		curFgColor: ColorDefault,
		curBgColor: ColorDefault,
		mode:       mode,
	}
	return ei
}

// reset sets the escapeInterpreter in initial state.
func (ei *escapeInterpreter) reset() {
	ei.state = stateNone
	ei.curFgColor = ColorDefault
	ei.curBgColor = ColorDefault
	ei.csiParam = nil
}

// 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
	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:
		switch {
		case ch >= '0' && ch <= '9':
			ei.csiParam = append(ei.csiParam, "")
		case ch == 'm':
			ei.csiParam = append(ei.csiParam, "0")
		default:
			return false, errCSIParseError
		}
		ei.state = stateParams
		fallthrough
	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':
			var err error
			switch ei.mode {
			case OutputNormal:
				err = ei.outputNormal()
			case Output256:
				err = ei.output256()
			}
			if err != nil {
				return false, errCSIParseError
			}

			ei.state = stateNone
			ei.csiParam = nil
			return true, nil
		default:
			return false, errCSIParseError
		}
	}
	return false, nil
}

// outputNormal provides 8 different colors:
//   black, red, green, yellow, blue, magenta, cyan, white
func (ei *escapeInterpreter) outputNormal() error {
	for _, param := range ei.csiParam {
		p, err := strconv.Atoi(param)
		if err != nil {
			return errCSIParseError
		}

		switch {
		case p >= 30 && p <= 37:
			ei.curFgColor = Attribute(p - 30 + 1)
		case p == 39:
			ei.curFgColor = ColorDefault
		case p >= 40 && p <= 47:
			ei.curBgColor = Attribute(p - 40 + 1)
		case p == 49:
			ei.curBgColor = ColorDefault
		case p == 1:
			ei.curFgColor |= AttrBold
		case p == 4:
			ei.curFgColor |= AttrUnderline
		case p == 7:
			ei.curFgColor |= AttrReverse
		case p == 0:
			ei.curFgColor = ColorDefault
			ei.curBgColor = ColorDefault
		}
	}

	return nil
}

// output256 allows you to leverage the 256-colors terminal mode:
//   0x01 - 0x08: the 8 colors as in OutputNormal
//   0x09 - 0x10: Color* | AttrBold
//   0x11 - 0xe8: 216 different colors
//   0xe9 - 0x1ff: 24 different shades of grey
func (ei *escapeInterpreter) output256() error {
	if len(ei.csiParam) < 3 {
		return ei.outputNormal()
	}

	mode, err := strconv.Atoi(ei.csiParam[1])
	if err != nil {
		return errCSIParseError
	}
	if mode != 5 {
		return ei.outputNormal()
	}

	fgbg, err := strconv.Atoi(ei.csiParam[0])
	if err != nil {
		return errCSIParseError
	}
	color, err := strconv.Atoi(ei.csiParam[2])
	if err != nil {
		return errCSIParseError
	}

	switch fgbg {
	case 38:
		ei.curFgColor = Attribute(color + 1)

		for _, param := range ei.csiParam[3:] {
			p, err := strconv.Atoi(param)
			if err != nil {
				return errCSIParseError
			}

			switch {
			case p == 1:
				ei.curFgColor |= AttrBold
			case p == 4:
				ei.curFgColor |= AttrUnderline
			case p == 7:
				ei.curFgColor |= AttrReverse
			}
		}
	case 48:
		ei.curBgColor = Attribute(color + 1)
	default:
		return errCSIParseError
	}

	return nil
}


================================================
FILE: go.mod
================================================
module github.com/jroimartin/gocui

go 1.16

require github.com/nsf/termbox-go v1.1.1


================================================
FILE: go.sum
================================================
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=


================================================
FILE: gui.go
================================================
// 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"
)

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")
)

// OutputMode represents the terminal's output mode (8 or 256 colors).
type OutputMode termbox.OutputMode

const (
	// OutputNormal provides 8-colors terminal mode.
	OutputNormal = OutputMode(termbox.OutputNormal)

	// Output256 provides 256-colors terminal mode.
	Output256 = OutputMode(termbox.Output256)
)

// 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
	managers    []Manager
	keybindings []*keybinding
	maxX, maxY  int
	outputMode  OutputMode

	// BgColor and FgColor allow to configure the background and foreground
	// colors of the GUI.
	BgColor, FgColor Attribute

	// SelBgColor and SelFgColor allow to configure the background and
	// foreground colors of the frame of the current view.
	SelBgColor, SelFgColor Attribute

	// If Highlight is true, Sel{Bg,Fg}Colors will be used to draw the
	// frame of the current view.
	Highlight bool

	// If Cursor is true then the cursor is enabled.
	Cursor bool

	// If Mouse is true then mouse events will be enabled.
	Mouse bool

	// If InputEsc is true, when ESC sequence is in the buffer and it doesn't
	// match any known sequence, ESC means KeyEsc.
	InputEsc bool

	// If ASCII is true then use ASCII instead of unicode to draw the
	// interface. Using ASCII is more portable.
	ASCII bool
}

// NewGui returns a new Gui object with a given output mode.
func NewGui(mode OutputMode) (*Gui, error) {
	if err := termbox.Init(); err != nil {
		return nil, err
	}

	g := &Gui{}

	g.outputMode = mode
	termbox.SetOutputMode(termbox.OutputMode(mode))

	g.tbEvents = make(chan termbox.Event, 20)
	g.userEvents = make(chan userEvent, 20)

	g.maxX, g.maxY = termbox.Size()

	g.BgColor, g.FgColor = ColorDefault, ColorDefault
	g.SelBgColor, g.SelFgColor = ColorDefault, ColorDefault

	return g, 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 given colors.
func (g *Gui) SetRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
	if x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {
		return errors.New("invalid point")
	}
	termbox.SetCell(x, y, ch, termbox.Attribute(fgColor), termbox.Attribute(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, g.outputMode)
	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
}

// SetViewOnBottom sets the given view on bottom of the existing ones.
func (g *Gui) SetViewOnBottom(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([]*View{v}, s...)
			return v, nil
		}
	}
	return nil, ErrUnknownView
}

// Views returns all the views in the GUI.
func (g *Gui) Views() []*View {
	return g.views
}

// 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) {
	// traverse views in reverse order checking top views first
	for i := len(g.views); i > 0; i-- {
		v := g.views[i-1]
		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) (*View, error) {
	for _, v := range g.views {
		if v.name == name {
			g.currentView = v
			return v, nil
		}
	}
	return nil, 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, handler func(*Gui, *View) error) error {
	var kb *keybinding

	k, ch, err := getKey(key)
	if err != nil {
		return err
	}
	kb = newKeybinding(viewname, k, ch, mod, handler)
	g.keybindings = append(g.keybindings, kb)
	return nil
}

// DeleteKeybinding deletes a keybinding.
func (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod Modifier) error {
	k, ch, err := getKey(key)
	if err != nil {
		return err
	}

	for i, kb := range g.keybindings {
		if kb.viewName == viewname && kb.ch == ch && kb.key == k && kb.mod == mod {
			g.keybindings = append(g.keybindings[:i], g.keybindings[i+1:]...)
			return nil
		}
	}
	return errors.New("keybinding not found")
}

// DeleteKeybindings deletes all keybindings of view.
func (g *Gui) DeleteKeybindings(viewname string) {
	var s []*keybinding
	for _, kb := range g.keybindings {
		if kb.viewName != viewname {
			s = append(s, kb)
		}
	}
	g.keybindings = s
}

// getKey takes an empty interface with a key and returns the corresponding
// typed Key or rune.
func getKey(key interface{}) (Key, rune, error) {
	switch t := key.(type) {
	case Key:
		return t, 0, nil
	case rune:
		return 0, t, nil
	default:
		return 0, 0, errors.New("unknown type")
	}
}

// userEvent represents an event triggered by the user.
type userEvent struct {
	f func(*Gui) error
}

// Update executes the passed function. This method can be called safely from a
// goroutine in order to update the GUI. It is important to note that the
// passed function won't be executed immediately, instead it will be added to
// the user events queue. Given that Update spawns a goroutine, the order in
// which the user events will be handled is not guaranteed.
func (g *Gui) Update(f func(*Gui) error) {
	go func() { g.userEvents <- userEvent{f: f} }()
}

// A Manager is in charge of GUI's layout and can be used to build widgets.
type Manager interface {
	// Layout is called every time the GUI is redrawn, it must contain the
	// base views and its initializations.
	Layout(*Gui) error
}

// The ManagerFunc type is an adapter to allow the use of ordinary functions as
// Managers. If f is a function with the appropriate signature, ManagerFunc(f)
// is an Manager object that calls f.
type ManagerFunc func(*Gui) error

// Layout calls f(g)
func (f ManagerFunc) Layout(g *Gui) error {
	return f(g)
}

// SetManager sets the given GUI managers. It deletes all views and
// keybindings.
func (g *Gui) SetManager(managers ...Manager) {
	g.managers = managers
	g.currentView = nil
	g.views = nil
	g.keybindings = nil

	go func() { g.tbEvents <- termbox.Event{Type: termbox.EventResize} }()
}

// SetManagerFunc sets the given manager function. It deletes all views and
// keybindings.
func (g *Gui) SetManagerFunc(manager func(*Gui) error) {
	g.SetManager(ManagerFunc(manager))
}

// MainLoop runs the main loop until an error is returned. A successful
// finish should return ErrQuit.
func (g *Gui) MainLoop() error {
	go func() {
		for {
			g.tbEvents <- termbox.PollEvent()
		}
	}()

	inputMode := termbox.InputAlt
	if g.InputEsc {
		inputMode = termbox.InputEsc
	}
	if g.Mouse {
		inputMode |= termbox.InputMouse
	}
	termbox.SetInputMode(inputMode)

	if err := g.flush(); err != nil {
		return err
	}
	for {
		select {
		case ev := <-g.tbEvents:
			if err := g.handleEvent(&ev); err != nil {
				return err
			}
		case ev := <-g.userEvents:
			if err := ev.f(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.f(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 {
	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

	for _, m := range g.managers {
		if err := m.Layout(g); err != nil {
			return err
		}
	}
	for _, v := range g.views {
		if v.Frame {
			var fgColor, bgColor Attribute
			if g.Highlight && v == g.currentView {
				fgColor = g.SelFgColor
				bgColor = g.SelBgColor
			} else {
				fgColor = g.FgColor
				bgColor = g.BgColor
			}

			if err := g.drawFrameEdges(v, fgColor, bgColor); err != nil {
				return err
			}
			if err := g.drawFrameCorners(v, fgColor, bgColor); err != nil {
				return err
			}
			if v.Title != "" {
				if err := g.drawTitle(v, fgColor, bgColor); err != nil {
					return err
				}
			}
		}
		if err := g.draw(v); err != nil {
			return err
		}
	}
	termbox.Flush()
	return nil
}

// drawFrameEdges draws the horizontal and vertical edges of a view.
func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error {
	runeH, runeV := '─', '│'
	if g.ASCII {
		runeH, runeV = '-', '|'
	}

	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, runeH, fgColor, bgColor); err != nil {
				return err
			}
		}
		if v.y1 > -1 && v.y1 < g.maxY {
			if err := g.SetRune(x, v.y1, runeH, fgColor, bgColor); 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, runeV, fgColor, bgColor); err != nil {
				return err
			}
		}
		if v.x1 > -1 && v.x1 < g.maxX {
			if err := g.SetRune(v.x1, y, runeV, fgColor, bgColor); err != nil {
				return err
			}
		}
	}
	return nil
}

// drawFrameCorners draws the corners of the view.
func (g *Gui) drawFrameCorners(v *View, fgColor, bgColor Attribute) error {
	runeTL, runeTR, runeBL, runeBR := '┌', '┐', '└', '┘'
	if g.ASCII {
		runeTL, runeTR, runeBL, runeBR = '+', '+', '+', '+'
	}

	corners := []struct {
		x, y int
		ch   rune
	}{{v.x0, v.y0, runeTL}, {v.x1, v.y0, runeTR}, {v.x0, v.y1, runeBL}, {v.x1, v.y1, runeBR}}

	for _, c := range corners {
		if c.x >= 0 && c.y >= 0 && c.x < g.maxX && c.y < g.maxY {
			if err := g.SetRune(c.x, c.y, c.ch, fgColor, bgColor); err != nil {
				return err
			}
		}
	}
	return nil
}

// drawTitle draws the title of the view.
func (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) 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, fgColor, bgColor); 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 curview := g.currentView; curview != nil {
			vMaxX, vMaxY := curview.Size()
			if curview.cx < 0 {
				curview.cx = 0
			} else if curview.cx >= vMaxX {
				curview.cx = vMaxX - 1
			}
			if curview.cy < 0 {
				curview.cy = 0
			} else if curview.cy >= vMaxY {
				curview.cy = vMaxY - 1
			}

			gMaxX, gMaxY := g.Size()
			cx, cy := curview.x0+curview.cx+1, curview.y0+curview.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
}

// onKey manages key-press events. A keybinding handler is called when
// a key-press or mouse event satisfies a configured keybinding. Furthermore,
// currentView's internal buffer is modified if currentView.Editable is true.
func (g *Gui) onKey(ev *termbox.Event) error {
	switch ev.Type {
	case termbox.EventKey:
		matched, err := g.execKeybindings(g.currentView, ev)
		if err != nil {
			return err
		}
		if matched {
			break
		}
		if g.currentView != nil && g.currentView.Editable && g.currentView.Editor != nil {
			g.currentView.Editor.Edit(g.currentView, Key(ev.Key), ev.Ch, Modifier(ev.Mod))
		}
	case termbox.EventMouse:
		mx, my := ev.MouseX, ev.MouseY
		v, err := g.ViewByPosition(mx, my)
		if err != nil {
			break
		}
		if err := v.SetCursor(mx-v.x0-1, my-v.y0-1); err != nil {
			return err
		}
		if _, err := g.execKeybindings(v, ev); err != nil {
			return err
		}
	}

	return nil
}

// execKeybindings executes the keybinding handlers that match the passed view
// and event. The value of matched is true if there is a match and no errors.
func (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched bool, err error) {
	matched = false
	for _, kb := range g.keybindings {
		if kb.handler == nil {
			continue
		}
		if kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) && kb.matchView(v) {
			if err := kb.handler(g, v); err != nil {
				return false, err
			}
			matched = true
		}
	}
	return matched, nil
}


================================================
FILE: keybinding.go
================================================
// 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"

// Keybidings are used to link a given key-press event with a handler.
type keybinding struct {
	viewName string
	key      Key
	ch       rune
	mod      Modifier
	handler  func(*Gui, *View) error
}

// newKeybinding returns a new Keybinding object.
func newKeybinding(viewname string, key Key, ch rune, mod Modifier, handler func(*Gui, *View) error) (kb *keybinding) {
	kb = &keybinding{
		viewName: viewname,
		key:      key,
		ch:       ch,
		mod:      mod,
		handler:  handler,
	}
	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
}

// Key represents special keys or keys combinations.
type Key termbox.Key

// 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)
	MouseRelease   = Key(termbox.MouseRelease)
	MouseWheelUp   = Key(termbox.MouseWheelUp)
	MouseWheelDown = Key(termbox.MouseWheelDown)
)

// 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)
)

// Modifier allows to define special keys combinations. They can be used
// in combination with Keys or Runes when a new keybinding is defined.
type Modifier termbox.Modifier

// Modifiers.
const (
	ModNone Modifier = Modifier(0)
	ModAlt           = Modifier(termbox.ModAlt)
)


================================================
FILE: view.go
================================================
// 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

	// Editor allows to define the editor that manages the edition mode,
	// including keybindings or cursor behaviour. DefaultEditor is used by
	// default.
	Editor Editor

	// 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, mode OutputMode) *View {
	v := &View{
		name:    name,
		x0:      x0,
		y0:      y0,
		x1:      x1,
		y1:      y1,
		Frame:   true,
		Editor:  DefaultEditor,
		tainted: true,
		ei:      newEscapeInterpreter(mode),
	}
	return v
}

// Size returns the number of visible columns and rows in the View.
func (v *View) Size() (x, y int) {
	return v.x1 - v.x0 - 1, v.y1 - v.y0 - 1
}

// Name returns the name of the view.
func (v *View) Name() string {
	return v.name
}

// setRune sets a rune at the given point relative to the view. It applies the
// specified colors, taking into account if the cell must be highlighted. Also,
// it checks if the position is valid.
func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {
	maxX, maxY := v.Size()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return errors.New("invalid point")
	}

	var (
		ry, rcy int
		err     error
	)
	if v.Highlight {
		_, ry, err = v.realPosition(x, y)
		if err != nil {
			return err
		}
		_, rcy, err = v.realPosition(v.cx, v.cy)
		if err != nil {
			return err
		}
	}

	if v.Mask != 0 {
		fgColor = v.FgColor
		bgColor = v.BgColor
		ch = v.Mask
	} else if v.Highlight && ry == rcy {
		fgColor = v.SelFgColor
		bgColor = v.SelBgColor
	}

	termbox.SetCell(v.x0+x+1, v.y0+y+1, ch,
		termbox.Attribute(fgColor), termbox.Attribute(bgColor))

	return nil
}

// SetCursor sets the cursor position of the view at the given point,
// relative to the view. It checks if the position is valid.
func (v *View) SetCursor(x, y int) error {
	maxX, maxY := v.Size()
	if x < 0 || x >= maxX || y < 0 || y >= maxY {
		return errors.New("invalid point")
	}
	v.cx = x
	v.cy = y
	return nil
}

// Cursor returns the cursor position of the view.
func (v *View) Cursor() (x, y int) {
	return v.cx, v.cy
}

// SetOrigin sets the origin position of the view's internal buffer,
// so the buffer starts to be printed from this point, which means that
// it is linked with the origin point of view. It can be used to
// implement Horizontal and Vertical scrolling with just incrementing
// or decrementing ox and oy.
func (v *View) SetOrigin(x, y int) error {
	if x < 0 || y < 0 {
		return errors.New("invalid point")
	}
	v.ox = x
	v.oy = y
	return nil
}

// Origin returns the origin position of the view.
func (v *View) Origin() (x, y int) {
	return v.ox, v.oy
}

// Write appends a byte slice into the view's internal buffer. Because
// View implements the io.Writer interface, it can be passed as parameter
// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must
// be called to clear the view's buffer.
func (v *View) Write(p []byte) (n int, err error) {
	v.tainted = true

	for _, ch := range bytes.Runes(p) {
		switch ch {
		case '\n':
			v.lines = append(v.lines, nil)
		case '\r':
			nl := len(v.lines)
			if nl > 0 {
				v.lines[nl-1] = nil
			} else {
				v.lines = make([][]cell, 1)
			}
		default:
			cells := v.parseInput(ch)
			if cells == nil {
				continue
			}

			nl := len(v.lines)
			if nl > 0 {
				v.lines[nl-1] = append(v.lines[nl-1], cells...)
			} else {
				v.lines = append(v.lines, cells)
			}
		}
	}
	return len(p), nil
}

// parseInput parses char by char the input written to the View. It returns nil
// while processing ESC sequences. Otherwise, it returns a cell slice that
// contains the processed data.
func (v *View) parseInput(ch rune) []cell {
	cells := []cell{}

	isEscape, err := v.ei.parseOne(ch)
	if err != nil {
		for _, r := range v.ei.runes() {
			c := cell{
				fgColor: v.FgColor,
				bgColor: v.BgColor,
				chr:     r,
			}
			cells = append(cells, c)
		}
		v.ei.reset()
	} else {
		if isEscape {
			return nil
		}
		c := cell{
			fgColor: v.ei.curFgColor,
			bgColor: v.ei.curBgColor,
			chr:     ch,
		}
		cells = append(cells, c)
	}

	return cells
}

// Read reads data into p. It returns the number of bytes read into p.
// At EOF, err will be io.EOF. Calling Read() after Rewind() makes the
// cache to be refreshed with the contents of the view.
func (v *View) Read(p []byte) (n int, err error) {
	if v.readOffset == 0 {
		v.readCache = v.Buffer()
	}
	if v.readOffset < len(v.readCache) {
		n = copy(p, v.readCache[v.readOffset:])
		v.readOffset += n
	} else {
		err = io.EOF
	}
	return
}

// Rewind sets the offset for the next Read to 0, which also refresh the
// read cache.
func (v *View) Rewind() {
	v.readOffset = 0
}

// draw re-draws the view's contents.
func (v *View) draw() error {
	maxX, maxY := v.Size()

	if v.Wrap {
		if maxX == 0 {
			return errors.New("X size of the view cannot be 0")
		}
		v.ox = 0
	}
	if v.tainted {
		v.viewLines = nil
		for i, line := range v.lines {
			if v.Wrap {
				if len(line) < maxX {
					vline := viewLine{linesX: 0, linesY: i, line: line}
					v.viewLines = append(v.viewLines, vline)
					continue
				} else {
					for n := 0; n <= len(line); n += maxX {
						if len(line[n:]) <= maxX {
							vline := viewLine{linesX: n, linesY: i, line: line[n:]}
							v.viewLines = append(v.viewLines, vline)
						} else {
							vline := viewLine{linesX: n, linesY: i, line: line[n : n+maxX]}
							v.viewLines = append(v.viewLines, vline)
						}
					}
				}
			} else {
				vline := viewLine{linesX: 0, linesY: i, line: line}
				v.viewLines = append(v.viewLines, vline)
			}
		}
		v.tainted = false
	}

	if v.Autoscroll && len(v.viewLines) > maxY {
		v.oy = len(v.viewLines) - maxY
	}
	y := 0
	for i, vline := range v.viewLines {
		if i < v.oy {
			continue
		}
		if y >= maxY {
			break
		}
		x := 0
		for j, c := range vline.line {
			if j < v.ox {
				continue
			}
			if x >= maxX {
				break
			}

			fgColor := c.fgColor
			if fgColor == ColorDefault {
				fgColor = v.FgColor
			}
			bgColor := c.bgColor
			if bgColor == ColorDefault {
				bgColor = v.BgColor
			}

			if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {
				return err
			}
			x++
		}
		y++
	}
	return nil
}

// realPosition returns the position in the internal buffer corresponding to the
// point (x, y) of the view.
func (v *View) realPosition(vx, vy int) (x, y int, err error) {
	vx = v.ox + vx
	vy = v.oy + vy

	if vx < 0 || vy < 0 {
		return 0, 0, errors.New("invalid point")
	}

	if len(v.viewLines) == 0 {
		return vx, vy, nil
	}

	if vy < len(v.viewLines) {
		vline := v.viewLines[vy]
		x = vline.linesX + vx
		y = vline.linesY
	} else {
		vline := v.viewLines[len(v.viewLines)-1]
		x = vx
		y = vline.linesY + vy - len(v.viewLines) + 1
	}

	return x, y, nil
}

// Clear empties the view's internal buffer.
func (v *View) Clear() {
	v.tainted = true

	v.lines = nil
	v.viewLines = nil
	v.readOffset = 0
	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))
		}
	}
}

// BufferLines returns the lines in the view's internal
// buffer.
func (v *View) BufferLines() []string {
	lines := make([]string, len(v.lines))
	for i, l := range v.lines {
		str := lineType(l).String()
		str = strings.Replace(str, "\x00", " ", -1)
		lines[i] = str
	}
	return lines
}

// 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)
}

// ViewBufferLines returns the lines in the view's internal
// buffer that is shown to the user.
func (v *View) ViewBufferLines() []string {
	lines := make([]string, len(v.viewLines))
	for i, l := range v.viewLines {
		str := lineType(l.line).String()
		str = strings.Replace(str, "\x00", " ", -1)
		lines[i] = str
	}
	return lines
}

// 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
}
Download .txt
gitextract_k_yugcw4/

├── .gitignore
├── AUTHORS
├── LICENSE
├── README.md
├── _examples/
│   ├── Mark.Twain-Tom.Sawyer.txt
│   ├── active.go
│   ├── bufs.go
│   ├── colors.go
│   ├── colors256.go
│   ├── demo.go
│   ├── dynamic.go
│   ├── flow_layout.go
│   ├── goroutine.go
│   ├── hello.go
│   ├── layout.go
│   ├── mask.go
│   ├── mouse.go
│   ├── ontop.go
│   ├── overlap.go
│   ├── size.go
│   ├── stdin.go
│   ├── title.go
│   ├── widgets.go
│   └── wrap.go
├── attribute.go
├── doc.go
├── edit.go
├── escape.go
├── go.mod
├── go.sum
├── gui.go
├── keybinding.go
└── view.go
Download .txt
SYMBOL INDEX (289 symbols across 25 files)

FILE: _examples/active.go
  function setCurrentViewOnTop (line 19) | func setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) {
  function nextView (line 26) | func nextView(g *gocui.Gui, v *gocui.View) error {
  function layout (line 50) | func layout(g *gocui.Gui) error {
  function quit (line 92) | func quit(g *gocui.Gui, v *gocui.View) error {
  function main (line 96) | func main() {

FILE: _examples/bufs.go
  function quit (line 18) | func quit(g *gocui.Gui, v *gocui.View) error {
  function overwrite (line 24) | func overwrite(g *gocui.Gui, v *gocui.View) error {
  function layout (line 29) | func layout(g *gocui.Gui) error {
  function main (line 44) | func main() {

FILE: _examples/colors.go
  function main (line 14) | func main() {
  function layout (line 32) | func layout(g *gocui.Gui) error {
  function quit (line 47) | func quit(g *gocui.Gui, v *gocui.View) error {

FILE: _examples/colors256.go
  function main (line 14) | func main() {
  function layout (line 33) | func layout(g *gocui.Gui) error {
  function quit (line 72) | func quit(g *gocui.Gui, v *gocui.View) error {

FILE: _examples/demo.go
  function nextView (line 17) | func nextView(g *gocui.Gui, v *gocui.View) error {
  function cursorDown (line 26) | func cursorDown(g *gocui.Gui, v *gocui.View) error {
  function cursorUp (line 39) | func cursorUp(g *gocui.Gui, v *gocui.View) error {
  function getLine (line 52) | func getLine(g *gocui.Gui, v *gocui.View) error {
  function delMsg (line 74) | func delMsg(g *gocui.Gui, v *gocui.View) error {
  function quit (line 84) | func quit(g *gocui.Gui, v *gocui.View) error {
  function keybindings (line 88) | func keybindings(g *gocui.Gui) error {
  function saveMain (line 120) | func saveMain(g *gocui.Gui, v *gocui.View) error {
  function saveVisualMain (line 146) | func saveVisualMain(g *gocui.Gui, v *gocui.View) error {
  function layout (line 160) | func layout(g *gocui.Gui) error {
  function main (line 193) | func main() {

FILE: _examples/dynamic.go
  constant delta (line 15) | delta = 1
  function main (line 23) | func main() {
  function layout (line 47) | func layout(g *gocui.Gui) error {
  function initKeybindings (line 66) | func initKeybindings(g *gocui.Gui) error {
  function newView (line 132) | func newView(g *gocui.Gui) error {
  function delView (line 153) | func delView(g *gocui.Gui) error {
  function nextView (line 166) | func nextView(g *gocui.Gui, disableCurrent bool) error {
  function moveView (line 180) | func moveView(g *gocui.Gui, v *gocui.View, dx, dy int) error {

FILE: _examples/flow_layout.go
  type Label (line 15) | type Label struct
    method Layout (line 36) | func (w *Label) Layout(g *gocui.Gui) error {
  function NewLabel (line 21) | func NewLabel(name string, body string) *Label {
  function flowLayout (line 47) | func flowLayout(g *gocui.Gui) error {
  function main (line 61) | func main() {
  function quit (line 85) | func quit(g *gocui.Gui, v *gocui.View) error {

FILE: _examples/goroutine.go
  constant NumGoroutines (line 16) | NumGoroutines = 10
  function main (line 26) | func main() {
  function layout (line 51) | func layout(g *gocui.Gui) error {
  function keybindings (line 61) | func keybindings(g *gocui.Gui) error {
  function quit (line 68) | func quit(g *gocui.Gui, v *gocui.View) error {
  function counter (line 73) | func counter(g *gocui.Gui) {

FILE: _examples/hello.go
  function main (line 14) | func main() {
  function layout (line 32) | func layout(g *gocui.Gui) error {
  function quit (line 43) | func quit(g *gocui.Gui, v *gocui.View) error {

FILE: _examples/layout.go
  function layout (line 13) | func layout(g *gocui.Gui) error {
  function quit (line 30) | func quit(g *gocui.Gui, v *gocui.View) error {
  function main (line 34) | func main() {

FILE: _examples/mask.go
  function main (line 14) | func main() {
  function layout (line 34) | func layout(g *gocui.Gui) error {
  function initKeybindings (line 60) | func initKeybindings(g *gocui.Gui) error {

FILE: _examples/mouse.go
  function main (line 14) | func main() {
  function layout (line 35) | func layout(g *gocui.Gui) error {
  function keybindings (line 60) | func keybindings(g *gocui.Gui) error {
  function quit (line 75) | func quit(g *gocui.Gui, v *gocui.View) error {
  function showMsg (line 79) | func showMsg(g *gocui.Gui, v *gocui.View) error {
  function delMsg (line 102) | func delMsg(g *gocui.Gui, v *gocui.View) error {

FILE: _examples/ontop.go
  function main (line 14) | func main() {
  function layout (line 32) | func layout(g *gocui.Gui) error {
  function keybindings (line 55) | func keybindings(g *gocui.Gui) error {

FILE: _examples/overlap.go
  function layout (line 13) | func layout(g *gocui.Gui) error {
  function quit (line 54) | func quit(g *gocui.Gui, v *gocui.View) error {
  function main (line 58) | func main() {

FILE: _examples/size.go
  function main (line 14) | func main() {
  function layout (line 32) | func layout(g *gocui.Gui) error {
  function quit (line 43) | func quit(g *gocui.Gui, v *gocui.View) error {

FILE: _examples/stdin.go
  function main (line 17) | func main() {
  function layout (line 37) | func layout(g *gocui.Gui) error {
  function initKeybindings (line 67) | func initKeybindings(g *gocui.Gui) error {
  function quit (line 91) | func quit(g *gocui.Gui, v *gocui.View) error {
  function autoscroll (line 95) | func autoscroll(g *gocui.Gui, v *gocui.View) error {
  function scrollView (line 100) | func scrollView(v *gocui.View, dy int) error {

FILE: _examples/title.go
  function main (line 13) | func main() {
  function quit (line 31) | func quit(g *gocui.Gui, v *gocui.View) error {
  function layout (line 35) | func layout(g *gocui.Gui) error {

FILE: _examples/widgets.go
  constant delta (line 16) | delta = 0.2
  type HelpWidget (line 18) | type HelpWidget struct
    method Layout (line 40) | func (w *HelpWidget) Layout(g *gocui.Gui) error {
  function NewHelpWidget (line 25) | func NewHelpWidget(name string, x, y int, body string) *HelpWidget {
  type StatusbarWidget (line 51) | type StatusbarWidget struct
    method SetVal (line 62) | func (w *StatusbarWidget) SetVal(val float64) error {
    method Val (line 70) | func (w *StatusbarWidget) Val() float64 {
    method Layout (line 74) | func (w *StatusbarWidget) Layout(g *gocui.Gui) error {
  function NewStatusbarWidget (line 58) | func NewStatusbarWidget(name string, x, y, w int) *StatusbarWidget {
  type ButtonWidget (line 86) | type ButtonWidget struct
    method Layout (line 98) | func (w *ButtonWidget) Layout(g *gocui.Gui) error {
  function NewButtonWidget (line 94) | func NewButtonWidget(name string, x, y int, label string, handler func(g...
  function main (line 115) | func main() {
  function quit (line 143) | func quit(g *gocui.Gui, v *gocui.View) error {
  function toggleButton (line 147) | func toggleButton(g *gocui.Gui, v *gocui.View) error {
  function statusUp (line 156) | func statusUp(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View)...
  function statusDown (line 162) | func statusDown(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.Vie...
  function statusSet (line 168) | func statusSet(sw *StatusbarWidget, inc float64) error {
  constant helpText (line 176) | helpText = `KEYBINDINGS

FILE: _examples/wrap.go
  function layout (line 15) | func layout(g *gocui.Gui) error {
  function quit (line 30) | func quit(g *gocui.Gui, v *gocui.View) error {
  function main (line 34) | func main() {

FILE: attribute.go
  type Attribute (line 12) | type Attribute
  constant ColorDefault (line 16) | ColorDefault Attribute = Attribute(termbox.ColorDefault)
  constant ColorBlack (line 17) | ColorBlack             = Attribute(termbox.ColorBlack)
  constant ColorRed (line 18) | ColorRed               = Attribute(termbox.ColorRed)
  constant ColorGreen (line 19) | ColorGreen             = Attribute(termbox.ColorGreen)
  constant ColorYellow (line 20) | ColorYellow            = Attribute(termbox.ColorYellow)
  constant ColorBlue (line 21) | ColorBlue              = Attribute(termbox.ColorBlue)
  constant ColorMagenta (line 22) | ColorMagenta           = Attribute(termbox.ColorMagenta)
  constant ColorCyan (line 23) | ColorCyan              = Attribute(termbox.ColorCyan)
  constant ColorWhite (line 24) | ColorWhite             = Attribute(termbox.ColorWhite)
  constant AttrBold (line 29) | AttrBold      Attribute = Attribute(termbox.AttrBold)
  constant AttrUnderline (line 30) | AttrUnderline           = Attribute(termbox.AttrUnderline)
  constant AttrReverse (line 31) | AttrReverse             = Attribute(termbox.AttrReverse)

FILE: edit.go
  constant maxInt (line 9) | maxInt = int(^uint(0) >> 1)
  type Editor (line 12) | type Editor interface
  type EditorFunc (line 19) | type EditorFunc
    method Edit (line 22) | func (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) {
  function simpleEditor (line 30) | func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
  method EditWrite (line 56) | func (v *View) EditWrite(ch rune) {
  method EditDelete (line 63) | func (v *View) EditDelete(back bool) {
  method EditNewLine (line 109) | func (v *View) EditNewLine() {
  method MoveCursor (line 118) | func (v *View) MoveCursor(dx, dy int, writeMode bool) {
  method writeRune (line 237) | func (v *View) writeRune(x, y int, ch rune) error {
  method deleteRune (line 278) | func (v *View) deleteRune(x, y int) error {
  method mergeLines (line 294) | func (v *View) mergeLines(y int) error {
  method breakLine (line 315) | func (v *View) breakLine(x, y int) error {

FILE: escape.go
  type escapeInterpreter (line 12) | type escapeInterpreter struct
    method runes (line 36) | func (ei *escapeInterpreter) runes() []rune {
    method reset (line 68) | func (ei *escapeInterpreter) reset() {
    method parseOne (line 78) | func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err err...
    method outputNormal (line 145) | func (ei *escapeInterpreter) outputNormal() error {
    method output256 (line 181) | func (ei *escapeInterpreter) output256() error {
  type escapeState (line 20) | type escapeState
  constant stateNone (line 23) | stateNone escapeState = iota
  constant stateEscape (line 24) | stateEscape
  constant stateCSI (line 25) | stateCSI
  constant stateParams (line 26) | stateParams
  function newEscapeInterpreter (line 57) | func newEscapeInterpreter(mode OutputMode) *escapeInterpreter {

FILE: gui.go
  type OutputMode (line 22) | type OutputMode
  constant OutputNormal (line 26) | OutputNormal = OutputMode(termbox.OutputNormal)
  constant Output256 (line 29) | Output256 = OutputMode(termbox.Output256)
  type Gui (line 34) | type Gui struct
    method Close (line 95) | func (g *Gui) Close() {
    method Size (line 100) | func (g *Gui) Size() (x, y int) {
    method SetRune (line 107) | func (g *Gui) SetRune(x, y int, ch rune, fgColor, bgColor Attribute) e...
    method Rune (line 117) | func (g *Gui) Rune(x, y int) (rune, error) {
    method SetView (line 130) | func (g *Gui) SetView(name string, x0, y0, x1, y1 int) (*View, error) {
    method SetViewOnTop (line 155) | func (g *Gui) SetViewOnTop(name string) (*View, error) {
    method SetViewOnBottom (line 167) | func (g *Gui) SetViewOnBottom(name string) (*View, error) {
    method Views (line 179) | func (g *Gui) Views() []*View {
    method View (line 185) | func (g *Gui) View(name string) (*View, error) {
    method ViewByPosition (line 196) | func (g *Gui) ViewByPosition(x, y int) (*View, error) {
    method ViewPosition (line 209) | func (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) {
    method DeleteView (line 219) | func (g *Gui) DeleteView(name string) error {
    method SetCurrentView (line 230) | func (g *Gui) SetCurrentView(name string) (*View, error) {
    method CurrentView (line 242) | func (g *Gui) CurrentView() *View {
    method SetKeybinding (line 249) | func (g *Gui) SetKeybinding(viewname string, key interface{}, mod Modi...
    method DeleteKeybinding (line 262) | func (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod M...
    method DeleteKeybindings (line 278) | func (g *Gui) DeleteKeybindings(viewname string) {
    method Update (line 311) | func (g *Gui) Update(f func(*Gui) error) {
    method SetManager (line 334) | func (g *Gui) SetManager(managers ...Manager) {
    method SetManagerFunc (line 345) | func (g *Gui) SetManagerFunc(manager func(*Gui) error) {
    method MainLoop (line 351) | func (g *Gui) MainLoop() error {
    method consumeevents (line 391) | func (g *Gui) consumeevents() error {
    method handleEvent (line 410) | func (g *Gui) handleEvent(ev *termbox.Event) error {
    method flush (line 422) | func (g *Gui) flush() error {
    method drawFrameEdges (line 471) | func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error {
    method drawFrameCorners (line 511) | func (g *Gui) drawFrameCorners(v *View, fgColor, bgColor Attribute) er...
    method drawTitle (line 533) | func (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) error {
    method draw (line 553) | func (g *Gui) draw(v *View) error {
    method onKey (line 590) | func (g *Gui) onKey(ev *termbox.Event) error {
    method execKeybindings (line 622) | func (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched boo...
  function NewGui (line 72) | func NewGui(mode OutputMode) (*Gui, error) {
  function getKey (line 290) | func getKey(key interface{}) (Key, rune, error) {
  type userEvent (line 302) | type userEvent struct
  type Manager (line 316) | type Manager interface
  type ManagerFunc (line 325) | type ManagerFunc
    method Layout (line 328) | func (f ManagerFunc) Layout(g *Gui) error {

FILE: keybinding.go
  type keybinding (line 10) | type keybinding struct
    method matchKeypress (line 31) | func (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bo...
    method matchView (line 36) | func (kb *keybinding) matchView(v *View) bool {
  function newKeybinding (line 19) | func newKeybinding(viewname string, key Key, ch rune, mod Modifier, hand...
  type Key (line 44) | type Key
  constant KeyF1 (line 48) | KeyF1         Key = Key(termbox.KeyF1)
  constant KeyF2 (line 49) | KeyF2             = Key(termbox.KeyF2)
  constant KeyF3 (line 50) | KeyF3             = Key(termbox.KeyF3)
  constant KeyF4 (line 51) | KeyF4             = Key(termbox.KeyF4)
  constant KeyF5 (line 52) | KeyF5             = Key(termbox.KeyF5)
  constant KeyF6 (line 53) | KeyF6             = Key(termbox.KeyF6)
  constant KeyF7 (line 54) | KeyF7             = Key(termbox.KeyF7)
  constant KeyF8 (line 55) | KeyF8             = Key(termbox.KeyF8)
  constant KeyF9 (line 56) | KeyF9             = Key(termbox.KeyF9)
  constant KeyF10 (line 57) | KeyF10            = Key(termbox.KeyF10)
  constant KeyF11 (line 58) | KeyF11            = Key(termbox.KeyF11)
  constant KeyF12 (line 59) | KeyF12            = Key(termbox.KeyF12)
  constant KeyInsert (line 60) | KeyInsert         = Key(termbox.KeyInsert)
  constant KeyDelete (line 61) | KeyDelete         = Key(termbox.KeyDelete)
  constant KeyHome (line 62) | KeyHome           = Key(termbox.KeyHome)
  constant KeyEnd (line 63) | KeyEnd            = Key(termbox.KeyEnd)
  constant KeyPgup (line 64) | KeyPgup           = Key(termbox.KeyPgup)
  constant KeyPgdn (line 65) | KeyPgdn           = Key(termbox.KeyPgdn)
  constant KeyArrowUp (line 66) | KeyArrowUp        = Key(termbox.KeyArrowUp)
  constant KeyArrowDown (line 67) | KeyArrowDown      = Key(termbox.KeyArrowDown)
  constant KeyArrowLeft (line 68) | KeyArrowLeft      = Key(termbox.KeyArrowLeft)
  constant KeyArrowRight (line 69) | KeyArrowRight     = Key(termbox.KeyArrowRight)
  constant MouseLeft (line 71) | MouseLeft      = Key(termbox.MouseLeft)
  constant MouseMiddle (line 72) | MouseMiddle    = Key(termbox.MouseMiddle)
  constant MouseRight (line 73) | MouseRight     = Key(termbox.MouseRight)
  constant MouseRelease (line 74) | MouseRelease   = Key(termbox.MouseRelease)
  constant MouseWheelUp (line 75) | MouseWheelUp   = Key(termbox.MouseWheelUp)
  constant MouseWheelDown (line 76) | MouseWheelDown = Key(termbox.MouseWheelDown)
  constant KeyCtrlTilde (line 81) | KeyCtrlTilde      Key = Key(termbox.KeyCtrlTilde)
  constant KeyCtrl2 (line 82) | KeyCtrl2              = Key(termbox.KeyCtrl2)
  constant KeyCtrlSpace (line 83) | KeyCtrlSpace          = Key(termbox.KeyCtrlSpace)
  constant KeyCtrlA (line 84) | KeyCtrlA              = Key(termbox.KeyCtrlA)
  constant KeyCtrlB (line 85) | KeyCtrlB              = Key(termbox.KeyCtrlB)
  constant KeyCtrlC (line 86) | KeyCtrlC              = Key(termbox.KeyCtrlC)
  constant KeyCtrlD (line 87) | KeyCtrlD              = Key(termbox.KeyCtrlD)
  constant KeyCtrlE (line 88) | KeyCtrlE              = Key(termbox.KeyCtrlE)
  constant KeyCtrlF (line 89) | KeyCtrlF              = Key(termbox.KeyCtrlF)
  constant KeyCtrlG (line 90) | KeyCtrlG              = Key(termbox.KeyCtrlG)
  constant KeyBackspace (line 91) | KeyBackspace          = Key(termbox.KeyBackspace)
  constant KeyCtrlH (line 92) | KeyCtrlH              = Key(termbox.KeyCtrlH)
  constant KeyTab (line 93) | KeyTab                = Key(termbox.KeyTab)
  constant KeyCtrlI (line 94) | KeyCtrlI              = Key(termbox.KeyCtrlI)
  constant KeyCtrlJ (line 95) | KeyCtrlJ              = Key(termbox.KeyCtrlJ)
  constant KeyCtrlK (line 96) | KeyCtrlK              = Key(termbox.KeyCtrlK)
  constant KeyCtrlL (line 97) | KeyCtrlL              = Key(termbox.KeyCtrlL)
  constant KeyEnter (line 98) | KeyEnter              = Key(termbox.KeyEnter)
  constant KeyCtrlM (line 99) | KeyCtrlM              = Key(termbox.KeyCtrlM)
  constant KeyCtrlN (line 100) | KeyCtrlN              = Key(termbox.KeyCtrlN)
  constant KeyCtrlO (line 101) | KeyCtrlO              = Key(termbox.KeyCtrlO)
  constant KeyCtrlP (line 102) | KeyCtrlP              = Key(termbox.KeyCtrlP)
  constant KeyCtrlQ (line 103) | KeyCtrlQ              = Key(termbox.KeyCtrlQ)
  constant KeyCtrlR (line 104) | KeyCtrlR              = Key(termbox.KeyCtrlR)
  constant KeyCtrlS (line 105) | KeyCtrlS              = Key(termbox.KeyCtrlS)
  constant KeyCtrlT (line 106) | KeyCtrlT              = Key(termbox.KeyCtrlT)
  constant KeyCtrlU (line 107) | KeyCtrlU              = Key(termbox.KeyCtrlU)
  constant KeyCtrlV (line 108) | KeyCtrlV              = Key(termbox.KeyCtrlV)
  constant KeyCtrlW (line 109) | KeyCtrlW              = Key(termbox.KeyCtrlW)
  constant KeyCtrlX (line 110) | KeyCtrlX              = Key(termbox.KeyCtrlX)
  constant KeyCtrlY (line 111) | KeyCtrlY              = Key(termbox.KeyCtrlY)
  constant KeyCtrlZ (line 112) | KeyCtrlZ              = Key(termbox.KeyCtrlZ)
  constant KeyEsc (line 113) | KeyEsc                = Key(termbox.KeyEsc)
  constant KeyCtrlLsqBracket (line 114) | KeyCtrlLsqBracket     = Key(termbox.KeyCtrlLsqBracket)
  constant KeyCtrl3 (line 115) | KeyCtrl3              = Key(termbox.KeyCtrl3)
  constant KeyCtrl4 (line 116) | KeyCtrl4              = Key(termbox.KeyCtrl4)
  constant KeyCtrlBackslash (line 117) | KeyCtrlBackslash      = Key(termbox.KeyCtrlBackslash)
  constant KeyCtrl5 (line 118) | KeyCtrl5              = Key(termbox.KeyCtrl5)
  constant KeyCtrlRsqBracket (line 119) | KeyCtrlRsqBracket     = Key(termbox.KeyCtrlRsqBracket)
  constant KeyCtrl6 (line 120) | KeyCtrl6              = Key(termbox.KeyCtrl6)
  constant KeyCtrl7 (line 121) | KeyCtrl7              = Key(termbox.KeyCtrl7)
  constant KeyCtrlSlash (line 122) | KeyCtrlSlash          = Key(termbox.KeyCtrlSlash)
  constant KeyCtrlUnderscore (line 123) | KeyCtrlUnderscore     = Key(termbox.KeyCtrlUnderscore)
  constant KeySpace (line 124) | KeySpace              = Key(termbox.KeySpace)
  constant KeyBackspace2 (line 125) | KeyBackspace2         = Key(termbox.KeyBackspace2)
  constant KeyCtrl8 (line 126) | KeyCtrl8              = Key(termbox.KeyCtrl8)
  type Modifier (line 131) | type Modifier
  constant ModNone (line 135) | ModNone Modifier = Modifier(0)
  constant ModAlt (line 136) | ModAlt           = Modifier(termbox.ModAlt)

FILE: view.go
  type View (line 18) | type View struct
    method Size (line 114) | func (v *View) Size() (x, y int) {
    method Name (line 119) | func (v *View) Name() string {
    method setRune (line 126) | func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) ...
    method SetCursor (line 164) | func (v *View) SetCursor(x, y int) error {
    method Cursor (line 175) | func (v *View) Cursor() (x, y int) {
    method SetOrigin (line 184) | func (v *View) SetOrigin(x, y int) error {
    method Origin (line 194) | func (v *View) Origin() (x, y int) {
    method Write (line 202) | func (v *View) Write(p []byte) (n int, err error) {
    method parseInput (line 236) | func (v *View) parseInput(ch rune) []cell {
    method Read (line 268) | func (v *View) Read(p []byte) (n int, err error) {
    method Rewind (line 283) | func (v *View) Rewind() {
    method draw (line 288) | func (v *View) draw() error {
    method realPosition (line 365) | func (v *View) realPosition(vx, vy int) (x, y int, err error) {
    method Clear (line 391) | func (v *View) Clear() {
    method clearRunes (line 401) | func (v *View) clearRunes() {
    method BufferLines (line 413) | func (v *View) BufferLines() []string {
    method Buffer (line 425) | func (v *View) Buffer() string {
    method ViewBufferLines (line 435) | func (v *View) ViewBufferLines() []string {
    method ViewBuffer (line 447) | func (v *View) ViewBuffer() string {
    method Line (line 457) | func (v *View) Line(y int) (string, error) {
    method Word (line 472) | func (v *View) Word(x, y int) (string, error) {
  type viewLine (line 76) | type viewLine struct
  type cell (line 81) | type cell struct
  type lineType (line 86) | type lineType
    method String (line 89) | func (l lineType) String() string {
  function newView (line 98) | func newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {
  function indexFunc (line 501) | func indexFunc(r rune) bool {
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (119K chars).
[
  {
    "path": ".gitignore",
    "chars": 6,
    "preview": "*.swp\n"
  },
  {
    "path": "AUTHORS",
    "chars": 730,
    "preview": "# This is the official list of gocui authors for copyright purposes.\n\n# Names should be added to this file as\n#\tName or "
  },
  {
    "path": "LICENSE",
    "chars": 1520,
    "preview": "Copyright (c) 2014 The gocui Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or w"
  },
  {
    "path": "README.md",
    "chars": 1936,
    "preview": "# GOCUI - Go Console User Interface\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/jroimartin/gocui.svg)](https:/"
  },
  {
    "path": "_examples/Mark.Twain-Tom.Sawyer.txt",
    "chars": 14757,
    "preview": "The Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete\nby Mark Twain (Samuel Clemens)\n\nThis eBook is for "
  },
  {
    "path": "_examples/active.go",
    "chars": 2447,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/bufs.go",
    "chars": 1384,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/colors.go",
    "chars": 997,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/colors256.go",
    "chars": 1371,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/demo.go",
    "chars": 4427,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/dynamic.go",
    "chars": 4212,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/flow_layout.go",
    "chars": 1618,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/goroutine.go",
    "chars": 1535,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/hello.go",
    "chars": 888,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/layout.go",
    "chars": 1100,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/mask.go",
    "chars": 1474,
    "preview": "// Copyright 2015 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/mouse.go",
    "chars": 2244,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/ontop.go",
    "chars": 1741,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/overlap.go",
    "chars": 1801,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/size.go",
    "chars": 893,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/stdin.go",
    "chars": 2196,
    "preview": "// Copyright 2015 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/title.go",
    "chars": 3442,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/widgets.go",
    "chars": 3900,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "_examples/wrap.go",
    "chars": 981,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "attribute.go",
    "chars": 1185,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "doc.go",
    "chars": 3286,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "edit.go",
    "chars": 7647,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "escape.go",
    "chars": 5101,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "go.mod",
    "chars": 86,
    "preview": "module github.com/jroimartin/gocui\n\ngo 1.16\n\nrequire github.com/nsf/termbox-go v1.1.1\n"
  },
  {
    "path": "go.sum",
    "chars": 346,
    "preview": "github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=\ngithub.com/mattn/go-runewidth v0.0."
  },
  {
    "path": "gui.go",
    "chars": 16219,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "keybinding.go",
    "chars": 4920,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  },
  {
    "path": "view.go",
    "chars": 11719,
    "preview": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// licen"
  }
]

About this extraction

This page contains the full source code of the jroimartin/gocui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (105.6 KB), approximately 34.1k tokens, and a symbol index with 289 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!