[
  {
    "path": ".gitignore",
    "content": "*.swp\n"
  },
  {
    "path": "AUTHORS",
    "content": "# This is the official list of gocui authors for copyright purposes.\n\n# Names should be added to this file as\n#\tName or Organization <email address> contribution\n#\t\tContribution\n# The email address is not required for organizations.\n\nRoi Martin <jroi.martin@gmail.com>\n\tMain developer\n\nRyan Sullivan <kayoticsully@gmail.com>\n\tToggleable view frames\n\nMatthieu Rakotojaona <matthieu.rakotojaona@gmail.com>\n\tWrapped views\n\nHarry Lawrence <hazbo@gmx.com>\n\tBasic mouse support\n\nDanny Tylman <dtylman@gmail.com>\n\tMasked views\n\nFrederik Deweerdt <frederik.deweerdt@gmail.com>\n\tColored fonts\n\nHenri Koski <henri.t.koski@gmail.com>\n\tCustom current view color\n\nDustin Willis Webber <dustin.webber@gmail.com>\n\t256-colors output mode support\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2014 The gocui Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of the gocui Authors nor the names of its contributors\n      may be used to endorse or promote products derived from this software\n      without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# GOCUI - Go Console User Interface\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/jroimartin/gocui.svg)](https://pkg.go.dev/github.com/jroimartin/gocui)\n\nMinimalist Go package aimed at creating Console User Interfaces.\n\n## Features\n\n* Minimalist API.\n* Views (the \"windows\" in the GUI) implement the interface io.ReadWriter.\n* Support for overlapping views.\n* The GUI can be modified at runtime (concurrent-safe).\n* Global and view-level keybindings.\n* Mouse support.\n* Colored text.\n* Customizable edition mode.\n* Easy to build reusable widgets, complex layouts...\n\n## Installation\n\nExecute:\n\n```sh\ngo get github.com/jroimartin/gocui\n```\n\n## Documentation\n\nExecute:\n\n```sh\ngo doc github.com/jroimartin/gocui\n```\n\nOr visit [pkg.go.dev](https://pkg.go.dev/github.com/jroimartin/gocui) to read\nit online.\n\n## Example\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"hello\", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"Hello world!\")\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n```\n\n## Screenshots\n\n![r2cui](https://cloud.githubusercontent.com/assets/1223476/19418932/63645052-93ce-11e6-867c-da5e97e37237.png)\n\n![_examples/demo.go](https://cloud.githubusercontent.com/assets/1223476/5992750/720b84f0-aa36-11e4-88ec-296fa3247b52.png)\n\n![_examples/dynamic.go](https://cloud.githubusercontent.com/assets/1223476/5992751/76ad5cc2-aa36-11e4-8204-6a90269db827.png)\n"
  },
  {
    "path": "_examples/Mark.Twain-Tom.Sawyer.txt",
    "content": "The Project Gutenberg EBook of The Adventures of Tom Sawyer, Complete\nby Mark Twain (Samuel Clemens)\n\nThis eBook is for the use of anyone anywhere at no cost and with\nalmost no restrictions whatsoever.  You may copy it, give it away or\nre-use it under the terms of the Project Gutenberg License included\nwith this eBook or online at www.gutenberg.net\n\n\nTitle: The Adventures of Tom Sawyer, Complete\n\nAuthor: Mark Twain (Samuel Clemens)\n\nRelease Date: August 20, 2006 [EBook #74]\n[Last updated: May 3, 2011]\n\nLanguage: English\n\n\n*** START OF THIS PROJECT GUTENBERG EBOOK TOM SAWYER ***\n\n\n\n\nProduced by David Widger. The previous edition was updated by Jose\nMenendez.\n\n\n\n\n\n                   THE ADVENTURES OF TOM SAWYER\n                                BY\n                            MARK TWAIN\n                     (Samuel Langhorne Clemens)\n\n\n\n\n                           P R E F A C E\n\nMOST of the adventures recorded in this book really occurred; one or\ntwo were experiences of my own, the rest those of boys who were\nschoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but\nnot from an individual--he is a combination of the characteristics of\nthree boys whom I knew, and therefore belongs to the composite order of\narchitecture.\n\nThe odd superstitions touched upon were all prevalent among children\nand slaves in the West at the period of this story--that is to say,\nthirty or forty years ago.\n\nAlthough my book is intended mainly for the entertainment of boys and\ngirls, I hope it will not be shunned by men and women on that account,\nfor part of my plan has been to try to pleasantly remind adults of what\nthey once were themselves, and of how they felt and thought and talked,\nand what queer enterprises they sometimes engaged in.\n\n                                                            THE AUTHOR.\n\nHARTFORD, 1876.\n\n\n\n                          T O M   S A W Y E R\n\n\n\nCHAPTER I\n\n\"TOM!\"\n\nNo answer.\n\n\"TOM!\"\n\nNo answer.\n\n\"What's gone with that boy,  I wonder? You TOM!\"\n\nNo answer.\n\nThe old lady pulled her spectacles down and looked over them about the\nroom; then she put them up and looked out under them. She seldom or\nnever looked THROUGH them for so small a thing as a boy; they were her\nstate pair, the pride of her heart, and were built for \"style,\" not\nservice--she could have seen through a pair of stove-lids just as well.\nShe looked perplexed for a moment, and then said, not fiercely, but\nstill loud enough for the furniture to hear:\n\n\"Well, I lay if I get hold of you I'll--\"\n\nShe did not finish, for by this time she was bending down and punching\nunder the bed with the broom, and so she needed breath to punctuate the\npunches with. She resurrected nothing but the cat.\n\n\"I never did see the beat of that boy!\"\n\nShe went to the open door and stood in it and looked out among the\ntomato vines and \"jimpson\" weeds that constituted the garden. No Tom.\nSo she lifted up her voice at an angle calculated for distance and\nshouted:\n\n\"Y-o-u-u TOM!\"\n\nThere was a slight noise behind her and she turned just in time to\nseize a small boy by the slack of his roundabout and arrest his flight.\n\n\"There! I might 'a' thought of that closet. What you been doing in\nthere?\"\n\n\"Nothing.\"\n\n\"Nothing! Look at your hands. And look at your mouth. What IS that\ntruck?\"\n\n\"I don't know, aunt.\"\n\n\"Well, I know. It's jam--that's what it is. Forty times I've said if\nyou didn't let that jam alone I'd skin you. Hand me that switch.\"\n\nThe switch hovered in the air--the peril was desperate--\n\n\"My! Look behind you, aunt!\"\n\nThe old lady whirled round, and snatched her skirts out of danger. The\nlad fled on the instant, scrambled up the high board-fence, and\ndisappeared over it.\n\nHis aunt Polly stood surprised a moment, and then broke into a gentle\nlaugh.\n\n\"Hang the boy, can't I never learn anything? Ain't he played me tricks\nenough like that for me to be looking out for him by this time? But old\nfools is the biggest fools there is. Can't learn an old dog new tricks,\nas the saying is. But my goodness, he never plays them alike, two days,\nand how is a body to know what's coming? He 'pears to know just how\nlong he can torment me before I get my dander up, and he knows if he\ncan make out to put me off for a minute or make me laugh, it's all down\nagain and I can't hit him a lick. I ain't doing my duty by that boy,\nand that's the Lord's truth, goodness knows. Spare the rod and spile\nthe child, as the Good Book says. I'm a laying up sin and suffering for\nus both, I know. He's full of the Old Scratch, but laws-a-me! he's my\nown dead sister's boy, poor thing, and I ain't got the heart to lash\nhim, somehow. Every time I let him off, my conscience does hurt me so,\nand every time I hit him my old heart most breaks. Well-a-well, man\nthat is born of woman is of few days and full of trouble, as the\nScripture says, and I reckon it's so. He'll play hookey this evening, *\nand [* Southwestern for \"afternoon\"] I'll just be obleeged to make him\nwork, to-morrow, to punish him. It's mighty hard to make him work\nSaturdays, when all the boys is having holiday, but he hates work more\nthan he hates anything else, and I've GOT to do some of my duty by him,\nor I'll be the ruination of the child.\"\n\nTom did play hookey, and he had a very good time. He got back home\nbarely in season to help Jim, the small colored boy, saw next-day's\nwood and split the kindlings before supper--at least he was there in\ntime to tell his adventures to Jim while Jim did three-fourths of the\nwork. Tom's younger brother (or rather half-brother) Sid was already\nthrough with his part of the work (picking up chips), for he was a\nquiet boy, and had no adventurous, troublesome ways.\n\nWhile Tom was eating his supper, and stealing sugar as opportunity\noffered, Aunt Polly asked him questions that were full of guile, and\nvery deep--for she wanted to trap him into damaging revealments. Like\nmany other simple-hearted souls, it was her pet vanity to believe she\nwas endowed with a talent for dark and mysterious diplomacy, and she\nloved to contemplate her most transparent devices as marvels of low\ncunning. Said she:\n\n\"Tom, it was middling warm in school, warn't it?\"\n\n\"Yes'm.\"\n\n\"Powerful warm, warn't it?\"\n\n\"Yes'm.\"\n\n\"Didn't you want to go in a-swimming, Tom?\"\n\nA bit of a scare shot through Tom--a touch of uncomfortable suspicion.\nHe searched Aunt Polly's face, but it told him nothing. So he said:\n\n\"No'm--well, not very much.\"\n\nThe old lady reached out her hand and felt Tom's shirt, and said:\n\n\"But you ain't too warm now, though.\" And it flattered her to reflect\nthat she had discovered that the shirt was dry without anybody knowing\nthat that was what she had in her mind. But in spite of her, Tom knew\nwhere the wind lay, now. So he forestalled what might be the next move:\n\n\"Some of us pumped on our heads--mine's damp yet. See?\"\n\nAunt Polly was vexed to think she had overlooked that bit of\ncircumstantial evidence, and missed a trick. Then she had a new\ninspiration:\n\n\"Tom, you didn't have to undo your shirt collar where I sewed it, to\npump on your head, did you? Unbutton your jacket!\"\n\nThe trouble vanished out of Tom's face. He opened his jacket. His\nshirt collar was securely sewed.\n\n\"Bother! Well, go 'long with you. I'd made sure you'd played hookey\nand been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a\nsinged cat, as the saying is--better'n you look. THIS time.\"\n\nShe was half sorry her sagacity had miscarried, and half glad that Tom\nhad stumbled into obedient conduct for once.\n\nBut Sidney said:\n\n\"Well, now, if I didn't think you sewed his collar with white thread,\nbut it's black.\"\n\n\"Why, I did sew it with white! Tom!\"\n\nBut Tom did not wait for the rest. As he went out at the door he said:\n\n\"Siddy, I'll lick you for that.\"\n\nIn a safe place Tom examined two large needles which were thrust into\nthe lapels of his jacket, and had thread bound about them--one needle\ncarried white thread and the other black. He said:\n\n\"She'd never noticed if it hadn't been for Sid. Confound it! sometimes\nshe sews it with white, and sometimes she sews it with black. I wish to\ngeeminy she'd stick to one or t'other--I can't keep the run of 'em. But\nI bet you I'll lam Sid for that. I'll learn him!\"\n\nHe was not the Model Boy of the village. He knew the model boy very\nwell though--and loathed him.\n\nWithin two minutes, or even less, he had forgotten all his troubles.\nNot because his troubles were one whit less heavy and bitter to him\nthan a man's are to a man, but because a new and powerful interest bore\nthem down and drove them out of his mind for the time--just as men's\nmisfortunes are forgotten in the excitement of new enterprises. This\nnew interest was a valued novelty in whistling, which he had just\nacquired from a negro, and he was suffering to practise it undisturbed.\nIt consisted in a peculiar bird-like turn, a sort of liquid warble,\nproduced by touching the tongue to the roof of the mouth at short\nintervals in the midst of the music--the reader probably remembers how\nto do it, if he has ever been a boy. Diligence and attention soon gave\nhim the knack of it, and he strode down the street with his mouth full\nof harmony and his soul full of gratitude. He felt much as an\nastronomer feels who has discovered a new planet--no doubt, as far as\nstrong, deep, unalloyed pleasure is concerned, the advantage was with\nthe boy, not the astronomer.\n\nThe summer evenings were long. It was not dark, yet. Presently Tom\nchecked his whistle. A stranger was before him--a boy a shade larger\nthan himself. A new-comer of any age or either sex was an impressive\ncuriosity in the poor little shabby village of St. Petersburg. This boy\nwas well dressed, too--well dressed on a week-day. This was simply\nastounding. His cap was a dainty thing, his close-buttoned blue cloth\nroundabout was new and natty, and so were his pantaloons. He had shoes\non--and it was only Friday. He even wore a necktie, a bright bit of\nribbon. He had a citified air about him that ate into Tom's vitals. The\nmore Tom stared at the splendid marvel, the higher he turned up his\nnose at his finery and the shabbier and shabbier his own outfit seemed\nto him to grow. Neither boy spoke. If one moved, the other moved--but\nonly sidewise, in a circle; they kept face to face and eye to eye all\nthe time. Finally Tom said:\n\n\"I can lick you!\"\n\n\"I'd like to see you try it.\"\n\n\"Well, I can do it.\"\n\n\"No you can't, either.\"\n\n\"Yes I can.\"\n\n\"No you can't.\"\n\n\"I can.\"\n\n\"You can't.\"\n\n\"Can!\"\n\n\"Can't!\"\n\nAn uncomfortable pause. Then Tom said:\n\n\"What's your name?\"\n\n\"'Tisn't any of your business, maybe.\"\n\n\"Well I 'low I'll MAKE it my business.\"\n\n\"Well why don't you?\"\n\n\"If you say much, I will.\"\n\n\"Much--much--MUCH. There now.\"\n\n\"Oh, you think you're mighty smart, DON'T you? I could lick you with\none hand tied behind me, if I wanted to.\"\n\n\"Well why don't you DO it? You SAY you can do it.\"\n\n\"Well I WILL, if you fool with me.\"\n\n\"Oh yes--I've seen whole families in the same fix.\"\n\n\"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!\"\n\n\"You can lump that hat if you don't like it. I dare you to knock it\noff--and anybody that'll take a dare will suck eggs.\"\n\n\"You're a liar!\"\n\n\"You're another.\"\n\n\"You're a fighting liar and dasn't take it up.\"\n\n\"Aw--take a walk!\"\n\n\"Say--if you give me much more of your sass I'll take and bounce a\nrock off'n your head.\"\n\n\"Oh, of COURSE you will.\"\n\n\"Well I WILL.\"\n\n\"Well why don't you DO it then? What do you keep SAYING you will for?\nWhy don't you DO it? It's because you're afraid.\"\n\n\"I AIN'T afraid.\"\n\n\"You are.\"\n\n\"I ain't.\"\n\n\"You are.\"\n\nAnother pause, and more eying and sidling around each other. Presently\nthey were shoulder to shoulder. Tom said:\n\n\"Get away from here!\"\n\n\"Go away yourself!\"\n\n\"I won't.\"\n\n\"I won't either.\"\n\nSo they stood, each with a foot placed at an angle as a brace, and\nboth shoving with might and main, and glowering at each other with\nhate. But neither could get an advantage. After struggling till both\nwere hot and flushed, each relaxed his strain with watchful caution,\nand Tom said:\n\n\"You're a coward and a pup. I'll tell my big brother on you, and he\ncan thrash you with his little finger, and I'll make him do it, too.\"\n\n\"What do I care for your big brother? I've got a brother that's bigger\nthan he is--and what's more, he can throw him over that fence, too.\"\n[Both brothers were imaginary.]\n\n\"That's a lie.\"\n\n\"YOUR saying so don't make it so.\"\n\nTom drew a line in the dust with his big toe, and said:\n\n\"I dare you to step over that, and I'll lick you till you can't stand\nup. Anybody that'll take a dare will steal sheep.\"\n\nThe new boy stepped over promptly, and said:\n\n\"Now you said you'd do it, now let's see you do it.\"\n\n\"Don't you crowd me now; you better look out.\"\n\n\"Well, you SAID you'd do it--why don't you do it?\"\n\n\"By jingo! for two cents I WILL do it.\"\n\nThe new boy took two broad coppers out of his pocket and held them out\nwith derision. Tom struck them to the ground. In an instant both boys\nwere rolling and tumbling in the dirt, gripped together like cats; and\nfor the space of a minute they tugged and tore at each other's hair and\nclothes, punched and scratched each other's nose, and covered\nthemselves with dust and glory. Presently the confusion took form, and\nthrough the fog of battle Tom appeared, seated astride the new boy, and\npounding him with his fists. \"Holler 'nuff!\" said he.\n\nThe boy only struggled to free himself. He was crying--mainly from rage.\n\n\"Holler 'nuff!\"--and the pounding went on.\n\nAt last the stranger got out a smothered \"'Nuff!\" and Tom let him up\nand said:\n\n\"Now that'll learn you. Better look out who you're fooling with next\ntime.\"\n\nThe new boy went off brushing the dust from his clothes, sobbing,\nsnuffling, and occasionally looking back and shaking his head and\nthreatening what he would do to Tom the \"next time he caught him out.\"\nTo which Tom responded with jeers, and started off in high feather, and\nas soon as his back was turned the new boy snatched up a stone, threw\nit and hit him between the shoulders and then turned tail and ran like\nan antelope. Tom chased the traitor home, and thus found out where he\nlived. He then held a position at the gate for some time, daring the\nenemy to come outside, but the enemy only made faces at him through the\nwindow and declined. At last the enemy's mother appeared, and called\nTom a bad, vicious, vulgar child, and ordered him away. So he went\naway; but he said he \"'lowed\" to \"lay\" for that boy.\n\nHe got home pretty late that night, and when he climbed cautiously in\nat the window, he uncovered an ambuscade, in the person of his aunt;\nand when she saw the state his clothes were in her resolution to turn\nhis Saturday holiday into captivity at hard labor became adamantine in\nits firmness.\n"
  },
  {
    "path": "_examples/active.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nvar (\n\tviewArr = []string{\"v1\", \"v2\", \"v3\", \"v4\"}\n\tactive  = 0\n)\n\nfunc setCurrentViewOnTop(g *gocui.Gui, name string) (*gocui.View, error) {\n\tif _, err := g.SetCurrentView(name); err != nil {\n\t\treturn nil, err\n\t}\n\treturn g.SetViewOnTop(name)\n}\n\nfunc nextView(g *gocui.Gui, v *gocui.View) error {\n\tnextIndex := (active + 1) % len(viewArr)\n\tname := viewArr[nextIndex]\n\n\tout, err := g.View(\"v2\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tfmt.Fprintln(out, \"Going from view \"+v.Name()+\" to \"+name)\n\n\tif _, err := setCurrentViewOnTop(g, name); err != nil {\n\t\treturn err\n\t}\n\n\tif nextIndex == 0 || nextIndex == 3 {\n\t\tg.Cursor = true\n\t} else {\n\t\tg.Cursor = false\n\t}\n\n\tactive = nextIndex\n\treturn nil\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"v1\", 0, 0, maxX/2-1, maxY/2-1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"v1 (editable)\"\n\t\tv.Editable = true\n\t\tv.Wrap = true\n\n\t\tif _, err = setCurrentViewOnTop(g, \"v1\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif v, err := g.SetView(\"v2\", maxX/2-1, 0, maxX-1, maxY/2-1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"v2\"\n\t\tv.Wrap = true\n\t\tv.Autoscroll = true\n\t}\n\tif v, err := g.SetView(\"v3\", 0, maxY/2-1, maxX/2-1, maxY-1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"v3\"\n\t\tv.Wrap = true\n\t\tv.Autoscroll = true\n\t\tfmt.Fprint(v, \"Press TAB to change current view\")\n\t}\n\tif v, err := g.SetView(\"v4\", maxX/2, maxY/2, maxX-1, maxY-1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"v4 (editable)\"\n\t\tv.Editable = true\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.Highlight = true\n\tg.Cursor = true\n\tg.SelFgColor = gocui.ColorGreen\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyTab, gocui.ModNone, nextView); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n"
  },
  {
    "path": "_examples/bufs.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n// WARNING: tricky code just for testing purposes, do not use as reference.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nvar vbuf, buf string\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\tvbuf = v.ViewBuffer()\n\tbuf = v.Buffer()\n\treturn gocui.ErrQuit\n}\n\nfunc overwrite(g *gocui.Gui, v *gocui.View) error {\n\tv.Overwrite = !v.Overwrite\n\treturn nil\n}\n\nfunc layout(g *gocui.Gui) error {\n\t_, maxY := g.Size()\n\tif v, err := g.SetView(\"main\", 0, 0, 20, maxY-1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Editable = true\n\t\tv.Wrap = true\n\t\tif _, err := g.SetCurrentView(\"main\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tg.Cursor = true\n\tg.Mouse = true\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"main\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tif err := g.SetKeybinding(\"main\", gocui.KeyCtrlI, gocui.ModNone, overwrite); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n\n\tg.Close()\n\n\tfmt.Printf(\"VBUF:\\n%s\\n\", vbuf)\n\tfmt.Printf(\"BUF:\\n%s\\n\", buf)\n}\n"
  },
  {
    "path": "_examples/colors.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"colors\", maxX/2-7, maxY/2-12, maxX/2+7, maxY/2+13); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfor i := 0; i <= 7; i++ {\n\t\t\tfor _, j := range []int{1, 4, 7} {\n\t\t\t\tfmt.Fprintf(v, \"Hello \\033[3%d;%dmcolors!\\033[0m\\n\", i, j)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n"
  },
  {
    "path": "_examples/colors256.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.Output256)\n\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"colors\", -1, -1, maxX, maxY); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\n\t\t// 256-colors escape codes\n\t\tfor i := 0; i < 256; i++ {\n\t\t\tstr := fmt.Sprintf(\"\\x1b[48;5;%dm\\x1b[30m%3d\\x1b[0m \", i, i)\n\t\t\tstr += fmt.Sprintf(\"\\x1b[38;5;%dm%3d\\x1b[0m \", i, i)\n\n\t\t\tif (i+1)%10 == 0 {\n\t\t\t\tstr += \"\\n\"\n\t\t\t}\n\n\t\t\tfmt.Fprint(v, str)\n\t\t}\n\n\t\tfmt.Fprint(v, \"\\n\\n\")\n\n\t\t// 8-colors escape codes\n\t\tctr := 0\n\t\tfor i := 0; i <= 7; i++ {\n\t\t\tfor _, j := range []int{1, 4, 7} {\n\t\t\t\tstr := fmt.Sprintf(\"\\x1b[3%d;%dm%d:%d\\x1b[0m \", i, j, i, j)\n\t\t\t\tif (ctr+1)%20 == 0 {\n\t\t\t\t\tstr += \"\\n\"\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprint(v, str)\n\n\t\t\t\tctr++\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n"
  },
  {
    "path": "_examples/demo.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc nextView(g *gocui.Gui, v *gocui.View) error {\n\tif v == nil || v.Name() == \"side\" {\n\t\t_, err := g.SetCurrentView(\"main\")\n\t\treturn err\n\t}\n\t_, err := g.SetCurrentView(\"side\")\n\treturn err\n}\n\nfunc cursorDown(g *gocui.Gui, v *gocui.View) error {\n\tif v != nil {\n\t\tcx, cy := v.Cursor()\n\t\tif err := v.SetCursor(cx, cy+1); err != nil {\n\t\t\tox, oy := v.Origin()\n\t\t\tif err := v.SetOrigin(ox, oy+1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc cursorUp(g *gocui.Gui, v *gocui.View) error {\n\tif v != nil {\n\t\tox, oy := v.Origin()\n\t\tcx, cy := v.Cursor()\n\t\tif err := v.SetCursor(cx, cy-1); err != nil && oy > 0 {\n\t\t\tif err := v.SetOrigin(ox, oy-1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc getLine(g *gocui.Gui, v *gocui.View) error {\n\tvar l string\n\tvar err error\n\n\t_, cy := v.Cursor()\n\tif l, err = v.Line(cy); err != nil {\n\t\tl = \"\"\n\t}\n\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"msg\", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, l)\n\t\tif _, err := g.SetCurrentView(\"msg\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc delMsg(g *gocui.Gui, v *gocui.View) error {\n\tif err := g.DeleteView(\"msg\"); err != nil {\n\t\treturn err\n\t}\n\tif _, err := g.SetCurrentView(\"side\"); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc keybindings(g *gocui.Gui) error {\n\tif err := g.SetKeybinding(\"side\", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"main\", gocui.KeyCtrlSpace, gocui.ModNone, nextView); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"side\", gocui.KeyArrowDown, gocui.ModNone, cursorDown); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"side\", gocui.KeyArrowUp, gocui.ModNone, cursorUp); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"side\", gocui.KeyEnter, gocui.ModNone, getLine); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"msg\", gocui.KeyEnter, gocui.ModNone, delMsg); err != nil {\n\t\treturn err\n\t}\n\n\tif err := g.SetKeybinding(\"main\", gocui.KeyCtrlS, gocui.ModNone, saveMain); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"main\", gocui.KeyCtrlW, gocui.ModNone, saveVisualMain); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc saveMain(g *gocui.Gui, v *gocui.View) error {\n\tf, err := ioutil.TempFile(\"\", \"gocui_demo_\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\tp := make([]byte, 5)\n\tv.Rewind()\n\tfor {\n\t\tn, err := v.Read(p)\n\t\tif n > 0 {\n\t\t\tif _, err := f.Write(p[:n]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc saveVisualMain(g *gocui.Gui, v *gocui.View) error {\n\tf, err := ioutil.TempFile(\"\", \"gocui_demo_\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\tvb := v.ViewBuffer()\n\tif _, err := io.Copy(f, strings.NewReader(vb)); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"side\", -1, -1, 30, maxY); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Highlight = true\n\t\tv.SelBgColor = gocui.ColorGreen\n\t\tv.SelFgColor = gocui.ColorBlack\n\t\tfmt.Fprintln(v, \"Item 1\")\n\t\tfmt.Fprintln(v, \"Item 2\")\n\t\tfmt.Fprintln(v, \"Item 3\")\n\t\tfmt.Fprint(v, \"\\rWill be\")\n\t\tfmt.Fprint(v, \"deleted\\rItem 4\\nItem 5\")\n\t}\n\tif v, err := g.SetView(\"main\", 30, -1, maxX, maxY); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tb, err := ioutil.ReadFile(\"Mark.Twain-Tom.Sawyer.txt\")\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tfmt.Fprintf(v, \"%s\", b)\n\t\tv.Editable = true\n\t\tv.Wrap = true\n\t\tif _, err := g.SetCurrentView(\"main\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.Cursor = true\n\n\tg.SetManagerFunc(layout)\n\n\tif err := keybindings(g); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n"
  },
  {
    "path": "_examples/dynamic.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nconst delta = 1\n\nvar (\n\tviews   = []string{}\n\tcurView = -1\n\tidxView = 0\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.Highlight = true\n\tg.SelFgColor = gocui.ColorRed\n\n\tg.SetManagerFunc(layout)\n\n\tif err := initKeybindings(g); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tif err := newView(g); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, _ := g.Size()\n\tv, err := g.SetView(\"help\", maxX-25, 0, maxX-1, 9)\n\tif err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"KEYBINDINGS\")\n\t\tfmt.Fprintln(v, \"Space: New View\")\n\t\tfmt.Fprintln(v, \"Tab: Next View\")\n\t\tfmt.Fprintln(v, \"← ↑ → ↓: Move View\")\n\t\tfmt.Fprintln(v, \"Backspace: Delete View\")\n\t\tfmt.Fprintln(v, \"t: Set view on top\")\n\t\tfmt.Fprintln(v, \"b: Set view on bottom\")\n\t\tfmt.Fprintln(v, \"^C: Exit\")\n\t}\n\treturn nil\n}\n\nfunc initKeybindings(g *gocui.Gui) error {\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn gocui.ErrQuit\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeySpace, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn newView(g)\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyBackspace2, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn delView(g)\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyTab, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn nextView(g, true)\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyArrowLeft, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn moveView(g, v, -delta, 0)\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyArrowRight, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn moveView(g, v, delta, 0)\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyArrowDown, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn moveView(g, v, 0, delta)\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyArrowUp, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn moveView(g, v, 0, -delta)\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", 't', gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\t_, err := g.SetViewOnTop(views[curView])\n\t\t\treturn err\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"\", 'b', gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\t_, err := g.SetViewOnBottom(views[curView])\n\t\t\treturn err\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc newView(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tname := fmt.Sprintf(\"v%v\", idxView)\n\tv, err := g.SetView(name, maxX/2-5, maxY/2-5, maxX/2+5, maxY/2+5)\n\tif err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Wrap = true\n\t\tfmt.Fprintln(v, strings.Repeat(name+\" \", 30))\n\t}\n\tif _, err := g.SetCurrentView(name); err != nil {\n\t\treturn err\n\t}\n\n\tviews = append(views, name)\n\tcurView = len(views) - 1\n\tidxView += 1\n\treturn nil\n}\n\nfunc delView(g *gocui.Gui) error {\n\tif len(views) <= 1 {\n\t\treturn nil\n\t}\n\n\tif err := g.DeleteView(views[curView]); err != nil {\n\t\treturn err\n\t}\n\tviews = append(views[:curView], views[curView+1:]...)\n\n\treturn nextView(g, false)\n}\n\nfunc nextView(g *gocui.Gui, disableCurrent bool) error {\n\tnext := curView + 1\n\tif next > len(views)-1 {\n\t\tnext = 0\n\t}\n\n\tif _, err := g.SetCurrentView(views[next]); err != nil {\n\t\treturn err\n\t}\n\n\tcurView = next\n\treturn nil\n}\n\nfunc moveView(g *gocui.Gui, v *gocui.View, dx, dy int) error {\n\tname := v.Name()\n\tx0, y0, x1, y1, err := g.ViewPosition(name)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(name, x0+dx, y0+dy, x1+dx, y1+dy); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "_examples/flow_layout.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\ntype Label struct {\n\tname string\n\tw, h int\n\tbody string\n}\n\nfunc NewLabel(name string, body string) *Label {\n\tlines := strings.Split(body, \"\\n\")\n\n\tw := 0\n\tfor _, l := range lines {\n\t\tif len(l) > w {\n\t\t\tw = len(l)\n\t\t}\n\t}\n\th := len(lines) + 1\n\tw = w + 1\n\n\treturn &Label{name: name, w: w, h: h, body: body}\n}\n\nfunc (w *Label) Layout(g *gocui.Gui) error {\n\tv, err := g.SetView(w.name, 0, 0, w.w, w.h)\n\tif err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprint(v, w.body)\n\t}\n\treturn nil\n}\n\nfunc flowLayout(g *gocui.Gui) error {\n\tviews := g.Views()\n\tx := 0\n\tfor _, v := range views {\n\t\tw, h := v.Size()\n\t\t_, err := g.SetView(v.Name(), x, 0, x+w+1, h+1)\n\t\tif err != nil && err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tx += w + 2\n\t}\n\treturn nil\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tl1 := NewLabel(\"l1\", \"This\")\n\tl2 := NewLabel(\"l2\", \"is\")\n\tl3 := NewLabel(\"l3\", \"a\")\n\tl4 := NewLabel(\"l4\", \"flow\\nlayout\")\n\tl5 := NewLabel(\"l5\", \"!\")\n\tfl := gocui.ManagerFunc(flowLayout)\n\tg.SetManager(l1, l2, l3, l4, l5, fl)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n"
  },
  {
    "path": "_examples/goroutine.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nconst NumGoroutines = 10\n\nvar (\n\tdone = make(chan struct{})\n\twg   sync.WaitGroup\n\n\tmu  sync.Mutex // protects ctr\n\tctr = 0\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := keybindings(g); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tfor i := 0; i < NumGoroutines; i++ {\n\t\twg.Add(1)\n\t\tgo counter(g)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n\n\twg.Wait()\n}\n\nfunc layout(g *gocui.Gui) error {\n\tif v, err := g.SetView(\"ctr\", 2, 2, 12, 4); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"0\")\n\t}\n\treturn nil\n}\n\nfunc keybindings(g *gocui.Gui) error {\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\tclose(done)\n\treturn gocui.ErrQuit\n}\n\nfunc counter(g *gocui.Gui) {\n\tdefer wg.Done()\n\n\tfor {\n\t\tselect {\n\t\tcase <-done:\n\t\t\treturn\n\t\tcase <-time.After(500 * time.Millisecond):\n\t\t\tmu.Lock()\n\t\t\tn := ctr\n\t\t\tctr++\n\t\t\tmu.Unlock()\n\n\t\t\tg.Update(func(g *gocui.Gui) error {\n\t\t\t\tv, err := g.View(\"ctr\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tv.Clear()\n\t\t\t\tfmt.Fprintln(v, n)\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "_examples/hello.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"hello\", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"Hello world!\")\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n"
  },
  {
    "path": "_examples/layout.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif _, err := g.SetView(\"side\", -1, -1, int(0.2*float32(maxX)), maxY-5); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"main\", int(0.2*float32(maxX)), -1, maxX, maxY-5); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"cmdline\", -1, maxY-5, maxX, maxY); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n"
  },
  {
    "path": "_examples/mask.go",
    "content": "// Copyright 2015 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer g.Close()\n\n\tg.Cursor = true\n\n\tg.SetManagerFunc(layout)\n\n\tif err := initKeybindings(g); err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Fatalln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\n\tif v, err := g.SetView(\"help\", maxX-23, 0, maxX-1, 3); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Keybindings\"\n\t\tfmt.Fprintln(v, \"^a: Set mask\")\n\t\tfmt.Fprintln(v, \"^c: Exit\")\n\t}\n\n\tif v, err := g.SetView(\"input\", 0, 0, maxX-24, maxY-1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := g.SetCurrentView(\"input\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tv.Editable = true\n\t\tv.Wrap = true\n\t}\n\n\treturn nil\n}\n\nfunc initKeybindings(g *gocui.Gui) error {\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\treturn gocui.ErrQuit\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"input\", gocui.KeyCtrlA, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\tv.Mask ^= '*'\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "_examples/mouse.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.Cursor = true\n\tg.Mouse = true\n\n\tg.SetManagerFunc(layout)\n\n\tif err := keybindings(g); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tif v, err := g.SetView(\"but1\", 2, 2, 22, 7); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Highlight = true\n\t\tv.SelBgColor = gocui.ColorGreen\n\t\tv.SelFgColor = gocui.ColorBlack\n\t\tfmt.Fprintln(v, \"Button 1 - line 1\")\n\t\tfmt.Fprintln(v, \"Button 1 - line 2\")\n\t\tfmt.Fprintln(v, \"Button 1 - line 3\")\n\t\tfmt.Fprintln(v, \"Button 1 - line 4\")\n\t}\n\tif v, err := g.SetView(\"but2\", 24, 2, 44, 4); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Highlight = true\n\t\tv.SelBgColor = gocui.ColorGreen\n\t\tv.SelFgColor = gocui.ColorBlack\n\t\tfmt.Fprintln(v, \"Button 2 - line 1\")\n\t}\n\treturn nil\n}\n\nfunc keybindings(g *gocui.Gui) error {\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\treturn err\n\t}\n\tfor _, n := range []string{\"but1\", \"but2\"} {\n\t\tif err := g.SetKeybinding(n, gocui.MouseLeft, gocui.ModNone, showMsg); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := g.SetKeybinding(\"msg\", gocui.MouseLeft, gocui.ModNone, delMsg); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc showMsg(g *gocui.Gui, v *gocui.View) error {\n\tvar l string\n\tvar err error\n\n\tif _, err := g.SetCurrentView(v.Name()); err != nil {\n\t\treturn err\n\t}\n\n\t_, cy := v.Cursor()\n\tif l, err = v.Line(cy); err != nil {\n\t\tl = \"\"\n\t}\n\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"msg\", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, l)\n\t}\n\treturn nil\n}\n\nfunc delMsg(g *gocui.Gui, v *gocui.View) error {\n\tif err := g.DeleteView(\"msg\"); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "_examples/ontop.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := keybindings(g); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tif v, err := g.SetView(\"v1\", 10, 2, 30, 6); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"View #1\")\n\t}\n\tif v, err := g.SetView(\"v2\", 20, 4, 40, 8); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"View #2\")\n\t}\n\tif v, err := g.SetView(\"v3\", 30, 6, 50, 10); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"View #3\")\n\t}\n\n\treturn nil\n}\n\nfunc keybindings(g *gocui.Gui) error {\n\terr := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {\n\t\treturn gocui.ErrQuit\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = g.SetKeybinding(\"\", '1', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {\n\t\t_, err := g.SetViewOnTop(\"v1\")\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = g.SetKeybinding(\"\", '2', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {\n\t\t_, err := g.SetViewOnTop(\"v2\")\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = g.SetKeybinding(\"\", '3', gocui.ModNone, func(g *gocui.Gui, v *gocui.View) error {\n\t\t_, err := g.SetViewOnTop(\"v3\")\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "_examples/overlap.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif _, err := g.SetView(\"v1\", -1, -1, 10, 10); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v2\", maxX-10, -1, maxX, 10); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v3\", maxX/2-5, -1, maxX/2+5, 10); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v4\", -1, maxY/2-5, 10, maxY/2+5); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v5\", maxX-10, maxY/2-5, maxX, maxY/2+5); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v6\", -1, maxY-10, 10, maxY); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v7\", maxX-10, maxY-10, maxX, maxY); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v8\", maxX/2-5, maxY-10, maxX/2+5, maxY); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tif _, err := g.SetView(\"v9\", maxX/2-5, maxY/2-5, maxX/2+5, maxY/2+5); err != nil &&\n\t\terr != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n"
  },
  {
    "path": "_examples/size.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tv, err := g.SetView(\"size\", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2)\n\tif err != nil && err != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tv.Clear()\n\tfmt.Fprintf(v, \"%d, %d\", maxX, maxY)\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n"
  },
  {
    "path": "_examples/stdin.go",
    "content": "// Copyright 2015 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tdefer g.Close()\n\n\tg.Cursor = true\n\n\tg.SetManagerFunc(layout)\n\n\tif err := initKeybindings(g); err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Fatalln(err)\n\t}\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, _ := g.Size()\n\n\tif v, err := g.SetView(\"help\", maxX-23, 0, maxX-1, 5); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprintln(v, \"KEYBINDINGS\")\n\t\tfmt.Fprintln(v, \"↑ ↓: Seek input\")\n\t\tfmt.Fprintln(v, \"a: Enable autoscroll\")\n\t\tfmt.Fprintln(v, \"^C: Exit\")\n\t}\n\n\tif v, err := g.SetView(\"stdin\", 0, 0, 80, 35); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := g.SetCurrentView(\"stdin\"); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdumper := hex.Dumper(v)\n\t\tif _, err := io.Copy(dumper, os.Stdin); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tv.Wrap = true\n\t}\n\n\treturn nil\n}\n\nfunc initKeybindings(g *gocui.Gui) error {\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"stdin\", 'a', gocui.ModNone, autoscroll); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"stdin\", gocui.KeyArrowUp, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\tscrollView(v, -1)\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\tif err := g.SetKeybinding(\"stdin\", gocui.KeyArrowDown, gocui.ModNone,\n\t\tfunc(g *gocui.Gui, v *gocui.View) error {\n\t\t\tscrollView(v, 1)\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc autoscroll(g *gocui.Gui, v *gocui.View) error {\n\tv.Autoscroll = true\n\treturn nil\n}\n\nfunc scrollView(v *gocui.View, dy int) error {\n\tif v != nil {\n\t\tv.Autoscroll = false\n\t\tox, oy := v.Origin()\n\t\tif err := v.SetOrigin(ox, oy+dy); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "_examples/title.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"log\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\n\t// Overlap (front)\n\tif v, err := g.SetView(\"v1\", 10, 2, 30, 6); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v2\", 20, 4, 40, 8); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\n\t// Overlap (back)\n\tif v, err := g.SetView(\"v3\", 60, 4, 80, 8); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v4\", 50, 2, 70, 6); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\n\t// Overlap (frame)\n\tif v, err := g.SetView(\"v15\", 90, 2, 110, 5); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v16\", 100, 5, 120, 8); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v17\", 140, 5, 160, 8); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v18\", 130, 2, 150, 5); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\n\t// Long title\n\tif v, err := g.SetView(\"v5\", 10, 12, 30, 16); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Long long long long title\"\n\t}\n\n\t// No title\n\tif v, err := g.SetView(\"v6\", 35, 12, 55, 16); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"\"\n\t}\n\tif _, err := g.SetView(\"v7\", 60, 12, 80, 16); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Small view\n\tif v, err := g.SetView(\"v8\", 85, 12, 88, 16); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\n\t// Screen borders\n\tif v, err := g.SetView(\"v9\", -10, 20, 10, 24); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v10\", maxX-10, 20, maxX+10, 24); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\n\t// Out of screen\n\tif v, err := g.SetView(\"v11\", -21, 28, -1, 32); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v12\", maxX, 28, maxX+20, 32); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v13\", 10, -7, 30, -1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\tif v, err := g.SetView(\"v14\", 10, maxY, 30, maxY+6); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Title = \"Regular title\"\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "_examples/widgets.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nconst delta = 0.2\n\ntype HelpWidget struct {\n\tname string\n\tx, y int\n\tw, h int\n\tbody string\n}\n\nfunc NewHelpWidget(name string, x, y int, body string) *HelpWidget {\n\tlines := strings.Split(body, \"\\n\")\n\n\tw := 0\n\tfor _, l := range lines {\n\t\tif len(l) > w {\n\t\t\tw = len(l)\n\t\t}\n\t}\n\th := len(lines) + 1\n\tw = w + 1\n\n\treturn &HelpWidget{name: name, x: x, y: y, w: w, h: h, body: body}\n}\n\nfunc (w *HelpWidget) Layout(g *gocui.Gui) error {\n\tv, err := g.SetView(w.name, w.x, w.y, w.x+w.w, w.y+w.h)\n\tif err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprint(v, w.body)\n\t}\n\treturn nil\n}\n\ntype StatusbarWidget struct {\n\tname string\n\tx, y int\n\tw    int\n\tval  float64\n}\n\nfunc NewStatusbarWidget(name string, x, y, w int) *StatusbarWidget {\n\treturn &StatusbarWidget{name: name, x: x, y: y, w: w}\n}\n\nfunc (w *StatusbarWidget) SetVal(val float64) error {\n\tif val < 0 || val > 1 {\n\t\treturn errors.New(\"invalid value\")\n\t}\n\tw.val = val\n\treturn nil\n}\n\nfunc (w *StatusbarWidget) Val() float64 {\n\treturn w.val\n}\n\nfunc (w *StatusbarWidget) Layout(g *gocui.Gui) error {\n\tv, err := g.SetView(w.name, w.x, w.y, w.x+w.w, w.y+2)\n\tif err != nil && err != gocui.ErrUnknownView {\n\t\treturn err\n\t}\n\tv.Clear()\n\n\trep := int(w.val * float64(w.w-1))\n\tfmt.Fprint(v, strings.Repeat(\"▒\", rep))\n\treturn nil\n}\n\ntype ButtonWidget struct {\n\tname    string\n\tx, y    int\n\tw       int\n\tlabel   string\n\thandler func(g *gocui.Gui, v *gocui.View) error\n}\n\nfunc NewButtonWidget(name string, x, y int, label string, handler func(g *gocui.Gui, v *gocui.View) error) *ButtonWidget {\n\treturn &ButtonWidget{name: name, x: x, y: y, w: len(label) + 1, label: label, handler: handler}\n}\n\nfunc (w *ButtonWidget) Layout(g *gocui.Gui) error {\n\tv, err := g.SetView(w.name, w.x, w.y, w.x+w.w, w.y+2)\n\tif err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := g.SetCurrentView(w.name); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := g.SetKeybinding(w.name, gocui.KeyEnter, gocui.ModNone, w.handler); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfmt.Fprint(v, w.label)\n\t}\n\treturn nil\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.Highlight = true\n\tg.SelFgColor = gocui.ColorRed\n\n\thelp := NewHelpWidget(\"help\", 1, 1, helpText)\n\tstatus := NewStatusbarWidget(\"status\", 1, 7, 50)\n\tbutdown := NewButtonWidget(\"butdown\", 52, 7, \"DOWN\", statusDown(status))\n\tbutup := NewButtonWidget(\"butup\", 58, 7, \"UP\", statusUp(status))\n\tg.SetManager(help, status, butdown, butup)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tif err := g.SetKeybinding(\"\", gocui.KeyTab, gocui.ModNone, toggleButton); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc toggleButton(g *gocui.Gui, v *gocui.View) error {\n\tnextview := \"butdown\"\n\tif v != nil && v.Name() == \"butdown\" {\n\t\tnextview = \"butup\"\n\t}\n\t_, err := g.SetCurrentView(nextview)\n\treturn err\n}\n\nfunc statusUp(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error {\n\treturn func(g *gocui.Gui, v *gocui.View) error {\n\t\treturn statusSet(status, delta)\n\t}\n}\n\nfunc statusDown(status *StatusbarWidget) func(g *gocui.Gui, v *gocui.View) error {\n\treturn func(g *gocui.Gui, v *gocui.View) error {\n\t\treturn statusSet(status, -delta)\n\t}\n}\n\nfunc statusSet(sw *StatusbarWidget, inc float64) error {\n\tval := sw.Val() + inc\n\tif val < 0 || val > 1 {\n\t\treturn nil\n\t}\n\treturn sw.SetVal(val)\n}\n\nconst helpText = `KEYBINDINGS\nTab: Move between buttons\nEnter: Push button\n^C: Exit`\n"
  },
  {
    "path": "_examples/wrap.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/jroimartin/gocui\"\n)\n\nfunc layout(g *gocui.Gui) error {\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"main\", 1, 1, maxX-1, maxY-1); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\treturn err\n\t\t}\n\t\tv.Wrap = true\n\n\t\tline := strings.Repeat(\"This is a long line -- \", 10)\n\t\tfmt.Fprintf(v, \"%s\\n\\n\", line)\n\t\tfmt.Fprintln(v, \"Short\")\n\t}\n\treturn nil\n}\n\nfunc quit(g *gocui.Gui, v *gocui.View) error {\n\treturn gocui.ErrQuit\n}\n\nfunc main() {\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\tlog.Panicln(err)\n\t}\n\tdefer g.Close()\n\n\tg.SetManagerFunc(layout)\n\n\tif err := g.SetKeybinding(\"\", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {\n\t\tlog.Panicln(err)\n\t}\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\tlog.Panicln(err)\n\t}\n}\n"
  },
  {
    "path": "attribute.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage gocui\n\nimport \"github.com/nsf/termbox-go\"\n\n// Attribute represents a terminal attribute, like color, font style, etc. They\n// can be combined using bitwise OR (|). Note that it is not possible to\n// combine multiple color attributes.\ntype Attribute termbox.Attribute\n\n// Color attributes.\nconst (\n\tColorDefault Attribute = Attribute(termbox.ColorDefault)\n\tColorBlack             = Attribute(termbox.ColorBlack)\n\tColorRed               = Attribute(termbox.ColorRed)\n\tColorGreen             = Attribute(termbox.ColorGreen)\n\tColorYellow            = Attribute(termbox.ColorYellow)\n\tColorBlue              = Attribute(termbox.ColorBlue)\n\tColorMagenta           = Attribute(termbox.ColorMagenta)\n\tColorCyan              = Attribute(termbox.ColorCyan)\n\tColorWhite             = Attribute(termbox.ColorWhite)\n)\n\n// Text style attributes.\nconst (\n\tAttrBold      Attribute = Attribute(termbox.AttrBold)\n\tAttrUnderline           = Attribute(termbox.AttrUnderline)\n\tAttrReverse             = Attribute(termbox.AttrReverse)\n)\n"
  },
  {
    "path": "doc.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n/*\nPackage gocui allows to create console user interfaces.\n\nCreate a new GUI:\n\n\tg, err := gocui.NewGui(gocui.OutputNormal)\n\tif err != nil {\n\t\t// handle error\n\t}\n\tdefer g.Close()\n\n\t// Set GUI managers and key bindings\n\t// ...\n\n\tif err := g.MainLoop(); err != nil && err != gocui.ErrQuit {\n\t\t// handle error\n\t}\n\nSet GUI managers:\n\n\tg.SetManager(mgr1, mgr2)\n\nManagers are in charge of GUI's layout and can be used to build widgets. On\neach iteration of the GUI's main loop, the Layout function of each configured\nmanager is executed. Managers are used to set-up and update the application's\nmain views, being possible to freely change them during execution. Also, it is\nimportant to mention that a main loop iteration is executed on each reported\nevent (key-press, mouse event, window resize, etc).\n\nGUIs are composed by Views, you can think of it as buffers. Views implement the\nio.ReadWriter interface, so you can just write to them if you want to modify\ntheir content. The same is valid for reading.\n\nCreate and initialize a view with absolute coordinates:\n\n\tif v, err := g.SetView(\"viewname\", 2, 2, 22, 7); err != nil {\n\t\tif err != gocui.ErrUnknownView {\n\t\t\t// handle error\n\t\t}\n\t\tfmt.Fprintln(v, \"This is a new view\")\n\t\t// ...\n\t}\n\nViews can also be created using relative coordinates:\n\n\tmaxX, maxY := g.Size()\n\tif v, err := g.SetView(\"viewname\", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {\n\t\t// ...\n\t}\n\nConfigure keybindings:\n\n\tif err := g.SetKeybinding(\"viewname\", gocui.KeyEnter, gocui.ModNone, fcn); err != nil {\n\t\t// handle error\n\t}\n\ngocui implements full mouse support that can be enabled with:\n\n\tg.Mouse = true\n\nMouse events are handled like any other keybinding:\n\n\tif err := g.SetKeybinding(\"viewname\", gocui.MouseLeft, gocui.ModNone, fcn); err != nil {\n\t\t// handle error\n\t}\n\nIMPORTANT: Views can only be created, destroyed or updated in three ways: from\nthe Layout function within managers, from keybinding callbacks or via\n*Gui.Update(). The reason for this is that it allows gocui to be\nconcurrent-safe. So, if you want to update your GUI from a goroutine, you must\nuse *Gui.Update(). For example:\n\n\tg.Update(func(g *gocui.Gui) error {\n\t\tv, err := g.View(\"viewname\")\n\t\tif err != nil {\n\t\t\t// handle error\n\t\t}\n\t\tv.Clear()\n\t\tfmt.Fprintln(v, \"Writing from different goroutines\")\n\t\treturn nil\n\t})\n\nBy default, gocui provides a basic edition mode. This mode can be extended\nand customized creating a new Editor and assigning it to *View.Editor:\n\n\ttype Editor interface {\n\t\tEdit(v *View, key Key, ch rune, mod Modifier)\n\t}\n\nDefaultEditor can be taken as example to create your own custom Editor:\n\n\tvar DefaultEditor Editor = EditorFunc(simpleEditor)\n\n\tfunc simpleEditor(v *View, key Key, ch rune, mod Modifier) {\n\t\tswitch {\n\t\tcase ch != 0 && mod == 0:\n\t\t\tv.EditWrite(ch)\n\t\tcase key == KeySpace:\n\t\t\tv.EditWrite(' ')\n\t\tcase key == KeyBackspace || key == KeyBackspace2:\n\t\t\tv.EditDelete(true)\n\t\t// ...\n\t\t}\n\t}\n\nColored text:\n\nViews allow to add colored text using ANSI colors. For example:\n\n\tfmt.Fprintln(v, \"\\x1b[0;31mHello world\")\n\nFor more information, see the examples in folder \"_examples/\".\n*/\npackage gocui\n"
  },
  {
    "path": "edit.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage gocui\n\nimport \"errors\"\n\nconst maxInt = int(^uint(0) >> 1)\n\n// Editor interface must be satisfied by gocui editors.\ntype Editor interface {\n\tEdit(v *View, key Key, ch rune, mod Modifier)\n}\n\n// The EditorFunc type is an adapter to allow the use of ordinary functions as\n// Editors. If f is a function with the appropriate signature, EditorFunc(f)\n// is an Editor object that calls f.\ntype EditorFunc func(v *View, key Key, ch rune, mod Modifier)\n\n// Edit calls f(v, key, ch, mod)\nfunc (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) {\n\tf(v, key, ch, mod)\n}\n\n// DefaultEditor is the default editor.\nvar DefaultEditor Editor = EditorFunc(simpleEditor)\n\n// simpleEditor is used as the default gocui editor.\nfunc simpleEditor(v *View, key Key, ch rune, mod Modifier) {\n\tswitch {\n\tcase ch != 0 && mod == 0:\n\t\tv.EditWrite(ch)\n\tcase key == KeySpace:\n\t\tv.EditWrite(' ')\n\tcase key == KeyBackspace || key == KeyBackspace2:\n\t\tv.EditDelete(true)\n\tcase key == KeyDelete:\n\t\tv.EditDelete(false)\n\tcase key == KeyInsert:\n\t\tv.Overwrite = !v.Overwrite\n\tcase key == KeyEnter:\n\t\tv.EditNewLine()\n\tcase key == KeyArrowDown:\n\t\tv.MoveCursor(0, 1, false)\n\tcase key == KeyArrowUp:\n\t\tv.MoveCursor(0, -1, false)\n\tcase key == KeyArrowLeft:\n\t\tv.MoveCursor(-1, 0, false)\n\tcase key == KeyArrowRight:\n\t\tv.MoveCursor(1, 0, false)\n\t}\n}\n\n// EditWrite writes a rune at the cursor position.\nfunc (v *View) EditWrite(ch rune) {\n\tv.writeRune(v.cx, v.cy, ch)\n\tv.MoveCursor(1, 0, true)\n}\n\n// EditDelete deletes a rune at the cursor position. back determines the\n// direction.\nfunc (v *View) EditDelete(back bool) {\n\tx, y := v.ox+v.cx, v.oy+v.cy\n\tif y < 0 {\n\t\treturn\n\t} else if y >= len(v.viewLines) {\n\t\tv.MoveCursor(-1, 0, true)\n\t\treturn\n\t}\n\n\tmaxX, _ := v.Size()\n\tif back {\n\t\tif x == 0 { // start of the line\n\t\t\tif y < 1 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tvar maxPrevWidth int\n\t\t\tif v.Wrap {\n\t\t\t\tmaxPrevWidth = maxX\n\t\t\t} else {\n\t\t\t\tmaxPrevWidth = maxInt\n\t\t\t}\n\n\t\t\tif v.viewLines[y].linesX == 0 { // regular line\n\t\t\t\tv.mergeLines(v.cy - 1)\n\t\t\t\tif len(v.viewLines[y-1].line) < maxPrevWidth {\n\t\t\t\t\tv.MoveCursor(-1, 0, true)\n\t\t\t\t}\n\t\t\t} else { // wrapped line\n\t\t\t\tv.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)\n\t\t\t\tv.MoveCursor(-1, 0, true)\n\t\t\t}\n\t\t} else { // middle/end of the line\n\t\t\tv.deleteRune(v.cx-1, v.cy)\n\t\t\tv.MoveCursor(-1, 0, true)\n\t\t}\n\t} else {\n\t\tif x == len(v.viewLines[y].line) { // end of the line\n\t\t\tv.mergeLines(v.cy)\n\t\t} else { // start/middle of the line\n\t\t\tv.deleteRune(v.cx, v.cy)\n\t\t}\n\t}\n}\n\n// EditNewLine inserts a new line under the cursor.\nfunc (v *View) EditNewLine() {\n\tv.breakLine(v.cx, v.cy)\n\tv.ox = 0\n\tv.cx = 0\n\tv.MoveCursor(0, 1, true)\n}\n\n// MoveCursor moves the cursor taking into account the width of the line/view,\n// displacing the origin if necessary.\nfunc (v *View) MoveCursor(dx, dy int, writeMode bool) {\n\tmaxX, maxY := v.Size()\n\tcx, cy := v.cx+dx, v.cy+dy\n\tx, y := v.ox+cx, v.oy+cy\n\n\tvar curLineWidth, prevLineWidth int\n\t// get the width of the current line\n\tif writeMode {\n\t\tif v.Wrap {\n\t\t\tcurLineWidth = maxX - 1\n\t\t} else {\n\t\t\tcurLineWidth = maxInt\n\t\t}\n\t} else {\n\t\tif y >= 0 && y < len(v.viewLines) {\n\t\t\tcurLineWidth = len(v.viewLines[y].line)\n\t\t\tif v.Wrap && curLineWidth >= maxX {\n\t\t\t\tcurLineWidth = maxX - 1\n\t\t\t}\n\t\t} else {\n\t\t\tcurLineWidth = 0\n\t\t}\n\t}\n\t// get the width of the previous line\n\tif y-1 >= 0 && y-1 < len(v.viewLines) {\n\t\tprevLineWidth = len(v.viewLines[y-1].line)\n\t} else {\n\t\tprevLineWidth = 0\n\t}\n\n\t// adjust cursor's x position and view's x origin\n\tif x > curLineWidth { // move to next line\n\t\tif dx > 0 { // horizontal movement\n\t\t\tcy++\n\t\t\tif writeMode || v.oy+cy < len(v.viewLines) {\n\t\t\t\tif !v.Wrap {\n\t\t\t\t\tv.ox = 0\n\t\t\t\t}\n\t\t\t\tv.cx = 0\n\t\t\t}\n\t\t} else { // vertical movement\n\t\t\tif curLineWidth > 0 { // move cursor to the EOL\n\t\t\t\tif v.Wrap {\n\t\t\t\t\tv.cx = curLineWidth\n\t\t\t\t} else {\n\t\t\t\t\tncx := curLineWidth - v.ox\n\t\t\t\t\tif ncx < 0 {\n\t\t\t\t\t\tv.ox += ncx\n\t\t\t\t\t\tif v.ox < 0 {\n\t\t\t\t\t\t\tv.ox = 0\n\t\t\t\t\t\t}\n\t\t\t\t\t\tv.cx = 0\n\t\t\t\t\t} else {\n\t\t\t\t\t\tv.cx = ncx\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif writeMode || v.oy+cy < len(v.viewLines) {\n\t\t\t\t\tif !v.Wrap {\n\t\t\t\t\t\tv.ox = 0\n\t\t\t\t\t}\n\t\t\t\t\tv.cx = 0\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else if cx < 0 {\n\t\tif !v.Wrap && v.ox > 0 { // move origin to the left\n\t\t\tv.ox += cx\n\t\t\tv.cx = 0\n\t\t} else { // move to previous line\n\t\t\tcy--\n\t\t\tif prevLineWidth > 0 {\n\t\t\t\tif !v.Wrap { // set origin so the EOL is visible\n\t\t\t\t\tnox := prevLineWidth - maxX + 1\n\t\t\t\t\tif nox < 0 {\n\t\t\t\t\t\tv.ox = 0\n\t\t\t\t\t} else {\n\t\t\t\t\t\tv.ox = nox\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tv.cx = prevLineWidth\n\t\t\t} else {\n\t\t\t\tif !v.Wrap {\n\t\t\t\t\tv.ox = 0\n\t\t\t\t}\n\t\t\t\tv.cx = 0\n\t\t\t}\n\t\t}\n\t} else { // stay on the same line\n\t\tif v.Wrap {\n\t\t\tv.cx = cx\n\t\t} else {\n\t\t\tif cx >= maxX {\n\t\t\t\tv.ox += cx - maxX + 1\n\t\t\t\tv.cx = maxX\n\t\t\t} else {\n\t\t\t\tv.cx = cx\n\t\t\t}\n\t\t}\n\t}\n\n\t// adjust cursor's y position and view's y origin\n\tif cy < 0 {\n\t\tif v.oy > 0 {\n\t\t\tv.oy--\n\t\t}\n\t} else if writeMode || v.oy+cy < len(v.viewLines) {\n\t\tif cy >= maxY {\n\t\t\tv.oy++\n\t\t} else {\n\t\t\tv.cy = cy\n\t\t}\n\t}\n}\n\n// writeRune writes a rune into the view's internal buffer, at the\n// position corresponding to the point (x, y). The length of the internal\n// buffer is increased if the point is out of bounds. Overwrite mode is\n// governed by the value of View.overwrite.\nfunc (v *View) writeRune(x, y int, ch rune) error {\n\tv.tainted = true\n\n\tx, y, err := v.realPosition(x, y)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif x < 0 || y < 0 {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\n\tif y >= len(v.lines) {\n\t\ts := make([][]cell, y-len(v.lines)+1)\n\t\tv.lines = append(v.lines, s...)\n\t}\n\n\tolen := len(v.lines[y])\n\n\tvar s []cell\n\tif x >= len(v.lines[y]) {\n\t\ts = make([]cell, x-len(v.lines[y])+1)\n\t} else if !v.Overwrite {\n\t\ts = make([]cell, 1)\n\t}\n\tv.lines[y] = append(v.lines[y], s...)\n\n\tif !v.Overwrite || (v.Overwrite && x >= olen-1) {\n\t\tcopy(v.lines[y][x+1:], v.lines[y][x:])\n\t}\n\tv.lines[y][x] = cell{\n\t\tfgColor: v.FgColor,\n\t\tbgColor: v.BgColor,\n\t\tchr:     ch,\n\t}\n\n\treturn nil\n}\n\n// deleteRune removes a rune from the view's internal buffer, at the\n// position corresponding to the point (x, y).\nfunc (v *View) deleteRune(x, y int) error {\n\tv.tainted = true\n\n\tx, y, err := v.realPosition(x, y)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\tv.lines[y] = append(v.lines[y][:x], v.lines[y][x+1:]...)\n\treturn nil\n}\n\n// mergeLines merges the lines \"y\" and \"y+1\" if possible.\nfunc (v *View) mergeLines(y int) error {\n\tv.tainted = true\n\n\t_, y, err := v.realPosition(0, y)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif y < 0 || y >= len(v.lines) {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\n\tif y < len(v.lines)-1 { // otherwise we don't need to merge anything\n\t\tv.lines[y] = append(v.lines[y], v.lines[y+1]...)\n\t\tv.lines = append(v.lines[:y+1], v.lines[y+2:]...)\n\t}\n\treturn nil\n}\n\n// breakLine breaks a line of the internal buffer at the position corresponding\n// to the point (x, y).\nfunc (v *View) breakLine(x, y int) error {\n\tv.tainted = true\n\n\tx, y, err := v.realPosition(x, y)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif y < 0 || y >= len(v.lines) {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\n\tvar left, right []cell\n\tif x < len(v.lines[y]) { // break line\n\t\tleft = make([]cell, len(v.lines[y][:x]))\n\t\tcopy(left, v.lines[y][:x])\n\t\tright = make([]cell, len(v.lines[y][x:]))\n\t\tcopy(right, v.lines[y][x:])\n\t} else { // new empty line\n\t\tleft = v.lines[y]\n\t}\n\n\tlines := make([][]cell, len(v.lines)+1)\n\tlines[y] = left\n\tlines[y+1] = right\n\tcopy(lines, v.lines[:y])\n\tcopy(lines[y+2:], v.lines[y+1:])\n\tv.lines = lines\n\treturn nil\n}\n"
  },
  {
    "path": "escape.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage gocui\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n)\n\ntype escapeInterpreter struct {\n\tstate                  escapeState\n\tcurch                  rune\n\tcsiParam               []string\n\tcurFgColor, curBgColor Attribute\n\tmode                   OutputMode\n}\n\ntype escapeState int\n\nconst (\n\tstateNone escapeState = iota\n\tstateEscape\n\tstateCSI\n\tstateParams\n)\n\nvar (\n\terrNotCSI        = errors.New(\"Not a CSI escape sequence\")\n\terrCSIParseError = errors.New(\"CSI escape sequence parsing error\")\n\terrCSITooLong    = errors.New(\"CSI escape sequence is too long\")\n)\n\n// runes in case of error will output the non-parsed runes as a string.\nfunc (ei *escapeInterpreter) runes() []rune {\n\tswitch ei.state {\n\tcase stateNone:\n\t\treturn []rune{0x1b}\n\tcase stateEscape:\n\t\treturn []rune{0x1b, ei.curch}\n\tcase stateCSI:\n\t\treturn []rune{0x1b, '[', ei.curch}\n\tcase stateParams:\n\t\tret := []rune{0x1b, '['}\n\t\tfor _, s := range ei.csiParam {\n\t\t\tret = append(ret, []rune(s)...)\n\t\t\tret = append(ret, ';')\n\t\t}\n\t\treturn append(ret, ei.curch)\n\t}\n\treturn nil\n}\n\n// newEscapeInterpreter returns an escapeInterpreter that will be able to parse\n// terminal escape sequences.\nfunc newEscapeInterpreter(mode OutputMode) *escapeInterpreter {\n\tei := &escapeInterpreter{\n\t\tstate:      stateNone,\n\t\tcurFgColor: ColorDefault,\n\t\tcurBgColor: ColorDefault,\n\t\tmode:       mode,\n\t}\n\treturn ei\n}\n\n// reset sets the escapeInterpreter in initial state.\nfunc (ei *escapeInterpreter) reset() {\n\tei.state = stateNone\n\tei.curFgColor = ColorDefault\n\tei.curBgColor = ColorDefault\n\tei.csiParam = nil\n}\n\n// parseOne parses a rune. If isEscape is true, it means that the rune is part\n// of an escape sequence, and as such should not be printed verbatim. Otherwise,\n// it's not an escape sequence.\nfunc (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) {\n\t// Sanity checks\n\tif len(ei.csiParam) > 20 {\n\t\treturn false, errCSITooLong\n\t}\n\tif len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 {\n\t\treturn false, errCSITooLong\n\t}\n\n\tei.curch = ch\n\n\tswitch ei.state {\n\tcase stateNone:\n\t\tif ch == 0x1b {\n\t\t\tei.state = stateEscape\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, nil\n\tcase stateEscape:\n\t\tif ch == '[' {\n\t\t\tei.state = stateCSI\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, errNotCSI\n\tcase stateCSI:\n\t\tswitch {\n\t\tcase ch >= '0' && ch <= '9':\n\t\t\tei.csiParam = append(ei.csiParam, \"\")\n\t\tcase ch == 'm':\n\t\t\tei.csiParam = append(ei.csiParam, \"0\")\n\t\tdefault:\n\t\t\treturn false, errCSIParseError\n\t\t}\n\t\tei.state = stateParams\n\t\tfallthrough\n\tcase stateParams:\n\t\tswitch {\n\t\tcase ch >= '0' && ch <= '9':\n\t\t\tei.csiParam[len(ei.csiParam)-1] += string(ch)\n\t\t\treturn true, nil\n\t\tcase ch == ';':\n\t\t\tei.csiParam = append(ei.csiParam, \"\")\n\t\t\treturn true, nil\n\t\tcase ch == 'm':\n\t\t\tvar err error\n\t\t\tswitch ei.mode {\n\t\t\tcase OutputNormal:\n\t\t\t\terr = ei.outputNormal()\n\t\t\tcase Output256:\n\t\t\t\terr = ei.output256()\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn false, errCSIParseError\n\t\t\t}\n\n\t\t\tei.state = stateNone\n\t\t\tei.csiParam = nil\n\t\t\treturn true, nil\n\t\tdefault:\n\t\t\treturn false, errCSIParseError\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// outputNormal provides 8 different colors:\n//   black, red, green, yellow, blue, magenta, cyan, white\nfunc (ei *escapeInterpreter) outputNormal() error {\n\tfor _, param := range ei.csiParam {\n\t\tp, err := strconv.Atoi(param)\n\t\tif err != nil {\n\t\t\treturn errCSIParseError\n\t\t}\n\n\t\tswitch {\n\t\tcase p >= 30 && p <= 37:\n\t\t\tei.curFgColor = Attribute(p - 30 + 1)\n\t\tcase p == 39:\n\t\t\tei.curFgColor = ColorDefault\n\t\tcase p >= 40 && p <= 47:\n\t\t\tei.curBgColor = Attribute(p - 40 + 1)\n\t\tcase p == 49:\n\t\t\tei.curBgColor = ColorDefault\n\t\tcase p == 1:\n\t\t\tei.curFgColor |= AttrBold\n\t\tcase p == 4:\n\t\t\tei.curFgColor |= AttrUnderline\n\t\tcase p == 7:\n\t\t\tei.curFgColor |= AttrReverse\n\t\tcase p == 0:\n\t\t\tei.curFgColor = ColorDefault\n\t\t\tei.curBgColor = ColorDefault\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// output256 allows you to leverage the 256-colors terminal mode:\n//   0x01 - 0x08: the 8 colors as in OutputNormal\n//   0x09 - 0x10: Color* | AttrBold\n//   0x11 - 0xe8: 216 different colors\n//   0xe9 - 0x1ff: 24 different shades of grey\nfunc (ei *escapeInterpreter) output256() error {\n\tif len(ei.csiParam) < 3 {\n\t\treturn ei.outputNormal()\n\t}\n\n\tmode, err := strconv.Atoi(ei.csiParam[1])\n\tif err != nil {\n\t\treturn errCSIParseError\n\t}\n\tif mode != 5 {\n\t\treturn ei.outputNormal()\n\t}\n\n\tfgbg, err := strconv.Atoi(ei.csiParam[0])\n\tif err != nil {\n\t\treturn errCSIParseError\n\t}\n\tcolor, err := strconv.Atoi(ei.csiParam[2])\n\tif err != nil {\n\t\treturn errCSIParseError\n\t}\n\n\tswitch fgbg {\n\tcase 38:\n\t\tei.curFgColor = Attribute(color + 1)\n\n\t\tfor _, param := range ei.csiParam[3:] {\n\t\t\tp, err := strconv.Atoi(param)\n\t\t\tif err != nil {\n\t\t\t\treturn errCSIParseError\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase p == 1:\n\t\t\t\tei.curFgColor |= AttrBold\n\t\t\tcase p == 4:\n\t\t\t\tei.curFgColor |= AttrUnderline\n\t\t\tcase p == 7:\n\t\t\t\tei.curFgColor |= AttrReverse\n\t\t\t}\n\t\t}\n\tcase 48:\n\t\tei.curBgColor = Attribute(color + 1)\n\tdefault:\n\t\treturn errCSIParseError\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/jroimartin/gocui\n\ngo 1.16\n\nrequire github.com/nsf/termbox-go v1.1.1\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=\ngithub.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=\ngithub.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=\ngithub.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=\n"
  },
  {
    "path": "gui.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage gocui\n\nimport (\n\t\"errors\"\n\n\t\"github.com/nsf/termbox-go\"\n)\n\nvar (\n\t// ErrQuit is used to decide if the MainLoop finished successfully.\n\tErrQuit = errors.New(\"quit\")\n\n\t// ErrUnknownView allows to assert if a View must be initialized.\n\tErrUnknownView = errors.New(\"unknown view\")\n)\n\n// OutputMode represents the terminal's output mode (8 or 256 colors).\ntype OutputMode termbox.OutputMode\n\nconst (\n\t// OutputNormal provides 8-colors terminal mode.\n\tOutputNormal = OutputMode(termbox.OutputNormal)\n\n\t// Output256 provides 256-colors terminal mode.\n\tOutput256 = OutputMode(termbox.Output256)\n)\n\n// Gui represents the whole User Interface, including the views, layouts\n// and keybindings.\ntype Gui struct {\n\ttbEvents    chan termbox.Event\n\tuserEvents  chan userEvent\n\tviews       []*View\n\tcurrentView *View\n\tmanagers    []Manager\n\tkeybindings []*keybinding\n\tmaxX, maxY  int\n\toutputMode  OutputMode\n\n\t// BgColor and FgColor allow to configure the background and foreground\n\t// colors of the GUI.\n\tBgColor, FgColor Attribute\n\n\t// SelBgColor and SelFgColor allow to configure the background and\n\t// foreground colors of the frame of the current view.\n\tSelBgColor, SelFgColor Attribute\n\n\t// If Highlight is true, Sel{Bg,Fg}Colors will be used to draw the\n\t// frame of the current view.\n\tHighlight bool\n\n\t// If Cursor is true then the cursor is enabled.\n\tCursor bool\n\n\t// If Mouse is true then mouse events will be enabled.\n\tMouse bool\n\n\t// If InputEsc is true, when ESC sequence is in the buffer and it doesn't\n\t// match any known sequence, ESC means KeyEsc.\n\tInputEsc bool\n\n\t// If ASCII is true then use ASCII instead of unicode to draw the\n\t// interface. Using ASCII is more portable.\n\tASCII bool\n}\n\n// NewGui returns a new Gui object with a given output mode.\nfunc NewGui(mode OutputMode) (*Gui, error) {\n\tif err := termbox.Init(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tg := &Gui{}\n\n\tg.outputMode = mode\n\ttermbox.SetOutputMode(termbox.OutputMode(mode))\n\n\tg.tbEvents = make(chan termbox.Event, 20)\n\tg.userEvents = make(chan userEvent, 20)\n\n\tg.maxX, g.maxY = termbox.Size()\n\n\tg.BgColor, g.FgColor = ColorDefault, ColorDefault\n\tg.SelBgColor, g.SelFgColor = ColorDefault, ColorDefault\n\n\treturn g, nil\n}\n\n// Close finalizes the library. It should be called after a successful\n// initialization and when gocui is not needed anymore.\nfunc (g *Gui) Close() {\n\ttermbox.Close()\n}\n\n// Size returns the terminal's size.\nfunc (g *Gui) Size() (x, y int) {\n\treturn g.maxX, g.maxY\n}\n\n// SetRune writes a rune at the given point, relative to the top-left\n// corner of the terminal. It checks if the position is valid and applies\n// the given colors.\nfunc (g *Gui) SetRune(x, y int, ch rune, fgColor, bgColor Attribute) error {\n\tif x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\ttermbox.SetCell(x, y, ch, termbox.Attribute(fgColor), termbox.Attribute(bgColor))\n\treturn nil\n}\n\n// Rune returns the rune contained in the cell at the given position.\n// It checks if the position is valid.\nfunc (g *Gui) Rune(x, y int) (rune, error) {\n\tif x < 0 || y < 0 || x >= g.maxX || y >= g.maxY {\n\t\treturn ' ', errors.New(\"invalid point\")\n\t}\n\tc := termbox.CellBuffer()[y*g.maxX+x]\n\treturn c.Ch, nil\n}\n\n// SetView creates a new view with its top-left corner at (x0, y0)\n// and the bottom-right one at (x1, y1). If a view with the same name\n// already exists, its dimensions are updated; otherwise, the error\n// ErrUnknownView is returned, which allows to assert if the View must\n// be initialized. It checks if the position is valid.\nfunc (g *Gui) SetView(name string, x0, y0, x1, y1 int) (*View, error) {\n\tif x0 >= x1 || y0 >= y1 {\n\t\treturn nil, errors.New(\"invalid dimensions\")\n\t}\n\tif name == \"\" {\n\t\treturn nil, errors.New(\"invalid name\")\n\t}\n\n\tif v, err := g.View(name); err == nil {\n\t\tv.x0 = x0\n\t\tv.y0 = y0\n\t\tv.x1 = x1\n\t\tv.y1 = y1\n\t\tv.tainted = true\n\t\treturn v, nil\n\t}\n\n\tv := newView(name, x0, y0, x1, y1, g.outputMode)\n\tv.BgColor, v.FgColor = g.BgColor, g.FgColor\n\tv.SelBgColor, v.SelFgColor = g.SelBgColor, g.SelFgColor\n\tg.views = append(g.views, v)\n\treturn v, ErrUnknownView\n}\n\n// SetViewOnTop sets the given view on top of the existing ones.\nfunc (g *Gui) SetViewOnTop(name string) (*View, error) {\n\tfor i, v := range g.views {\n\t\tif v.name == name {\n\t\t\ts := append(g.views[:i], g.views[i+1:]...)\n\t\t\tg.views = append(s, v)\n\t\t\treturn v, nil\n\t\t}\n\t}\n\treturn nil, ErrUnknownView\n}\n\n// SetViewOnBottom sets the given view on bottom of the existing ones.\nfunc (g *Gui) SetViewOnBottom(name string) (*View, error) {\n\tfor i, v := range g.views {\n\t\tif v.name == name {\n\t\t\ts := append(g.views[:i], g.views[i+1:]...)\n\t\t\tg.views = append([]*View{v}, s...)\n\t\t\treturn v, nil\n\t\t}\n\t}\n\treturn nil, ErrUnknownView\n}\n\n// Views returns all the views in the GUI.\nfunc (g *Gui) Views() []*View {\n\treturn g.views\n}\n\n// View returns a pointer to the view with the given name, or error\n// ErrUnknownView if a view with that name does not exist.\nfunc (g *Gui) View(name string) (*View, error) {\n\tfor _, v := range g.views {\n\t\tif v.name == name {\n\t\t\treturn v, nil\n\t\t}\n\t}\n\treturn nil, ErrUnknownView\n}\n\n// ViewByPosition returns a pointer to a view matching the given position, or\n// error ErrUnknownView if a view in that position does not exist.\nfunc (g *Gui) ViewByPosition(x, y int) (*View, error) {\n\t// traverse views in reverse order checking top views first\n\tfor i := len(g.views); i > 0; i-- {\n\t\tv := g.views[i-1]\n\t\tif x > v.x0 && x < v.x1 && y > v.y0 && y < v.y1 {\n\t\t\treturn v, nil\n\t\t}\n\t}\n\treturn nil, ErrUnknownView\n}\n\n// ViewPosition returns the coordinates of the view with the given name, or\n// error ErrUnknownView if a view with that name does not exist.\nfunc (g *Gui) ViewPosition(name string) (x0, y0, x1, y1 int, err error) {\n\tfor _, v := range g.views {\n\t\tif v.name == name {\n\t\t\treturn v.x0, v.y0, v.x1, v.y1, nil\n\t\t}\n\t}\n\treturn 0, 0, 0, 0, ErrUnknownView\n}\n\n// DeleteView deletes a view by name.\nfunc (g *Gui) DeleteView(name string) error {\n\tfor i, v := range g.views {\n\t\tif v.name == name {\n\t\t\tg.views = append(g.views[:i], g.views[i+1:]...)\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn ErrUnknownView\n}\n\n// SetCurrentView gives the focus to a given view.\nfunc (g *Gui) SetCurrentView(name string) (*View, error) {\n\tfor _, v := range g.views {\n\t\tif v.name == name {\n\t\t\tg.currentView = v\n\t\t\treturn v, nil\n\t\t}\n\t}\n\treturn nil, ErrUnknownView\n}\n\n// CurrentView returns the currently focused view, or nil if no view\n// owns the focus.\nfunc (g *Gui) CurrentView() *View {\n\treturn g.currentView\n}\n\n// SetKeybinding creates a new keybinding. If viewname equals to \"\"\n// (empty string) then the keybinding will apply to all views. key must\n// be a rune or a Key.\nfunc (g *Gui) SetKeybinding(viewname string, key interface{}, mod Modifier, handler func(*Gui, *View) error) error {\n\tvar kb *keybinding\n\n\tk, ch, err := getKey(key)\n\tif err != nil {\n\t\treturn err\n\t}\n\tkb = newKeybinding(viewname, k, ch, mod, handler)\n\tg.keybindings = append(g.keybindings, kb)\n\treturn nil\n}\n\n// DeleteKeybinding deletes a keybinding.\nfunc (g *Gui) DeleteKeybinding(viewname string, key interface{}, mod Modifier) error {\n\tk, ch, err := getKey(key)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor i, kb := range g.keybindings {\n\t\tif kb.viewName == viewname && kb.ch == ch && kb.key == k && kb.mod == mod {\n\t\t\tg.keybindings = append(g.keybindings[:i], g.keybindings[i+1:]...)\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn errors.New(\"keybinding not found\")\n}\n\n// DeleteKeybindings deletes all keybindings of view.\nfunc (g *Gui) DeleteKeybindings(viewname string) {\n\tvar s []*keybinding\n\tfor _, kb := range g.keybindings {\n\t\tif kb.viewName != viewname {\n\t\t\ts = append(s, kb)\n\t\t}\n\t}\n\tg.keybindings = s\n}\n\n// getKey takes an empty interface with a key and returns the corresponding\n// typed Key or rune.\nfunc getKey(key interface{}) (Key, rune, error) {\n\tswitch t := key.(type) {\n\tcase Key:\n\t\treturn t, 0, nil\n\tcase rune:\n\t\treturn 0, t, nil\n\tdefault:\n\t\treturn 0, 0, errors.New(\"unknown type\")\n\t}\n}\n\n// userEvent represents an event triggered by the user.\ntype userEvent struct {\n\tf func(*Gui) error\n}\n\n// Update executes the passed function. This method can be called safely from a\n// goroutine in order to update the GUI. It is important to note that the\n// passed function won't be executed immediately, instead it will be added to\n// the user events queue. Given that Update spawns a goroutine, the order in\n// which the user events will be handled is not guaranteed.\nfunc (g *Gui) Update(f func(*Gui) error) {\n\tgo func() { g.userEvents <- userEvent{f: f} }()\n}\n\n// A Manager is in charge of GUI's layout and can be used to build widgets.\ntype Manager interface {\n\t// Layout is called every time the GUI is redrawn, it must contain the\n\t// base views and its initializations.\n\tLayout(*Gui) error\n}\n\n// The ManagerFunc type is an adapter to allow the use of ordinary functions as\n// Managers. If f is a function with the appropriate signature, ManagerFunc(f)\n// is an Manager object that calls f.\ntype ManagerFunc func(*Gui) error\n\n// Layout calls f(g)\nfunc (f ManagerFunc) Layout(g *Gui) error {\n\treturn f(g)\n}\n\n// SetManager sets the given GUI managers. It deletes all views and\n// keybindings.\nfunc (g *Gui) SetManager(managers ...Manager) {\n\tg.managers = managers\n\tg.currentView = nil\n\tg.views = nil\n\tg.keybindings = nil\n\n\tgo func() { g.tbEvents <- termbox.Event{Type: termbox.EventResize} }()\n}\n\n// SetManagerFunc sets the given manager function. It deletes all views and\n// keybindings.\nfunc (g *Gui) SetManagerFunc(manager func(*Gui) error) {\n\tg.SetManager(ManagerFunc(manager))\n}\n\n// MainLoop runs the main loop until an error is returned. A successful\n// finish should return ErrQuit.\nfunc (g *Gui) MainLoop() error {\n\tgo func() {\n\t\tfor {\n\t\t\tg.tbEvents <- termbox.PollEvent()\n\t\t}\n\t}()\n\n\tinputMode := termbox.InputAlt\n\tif g.InputEsc {\n\t\tinputMode = termbox.InputEsc\n\t}\n\tif g.Mouse {\n\t\tinputMode |= termbox.InputMouse\n\t}\n\ttermbox.SetInputMode(inputMode)\n\n\tif err := g.flush(); err != nil {\n\t\treturn err\n\t}\n\tfor {\n\t\tselect {\n\t\tcase ev := <-g.tbEvents:\n\t\t\tif err := g.handleEvent(&ev); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase ev := <-g.userEvents:\n\t\t\tif err := ev.f(g); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif err := g.consumeevents(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := g.flush(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n}\n\n// consumeevents handles the remaining events in the events pool.\nfunc (g *Gui) consumeevents() error {\n\tfor {\n\t\tselect {\n\t\tcase ev := <-g.tbEvents:\n\t\t\tif err := g.handleEvent(&ev); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase ev := <-g.userEvents:\n\t\t\tif err := ev.f(g); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\n// handleEvent handles an event, based on its type (key-press, error,\n// etc.)\nfunc (g *Gui) handleEvent(ev *termbox.Event) error {\n\tswitch ev.Type {\n\tcase termbox.EventKey, termbox.EventMouse:\n\t\treturn g.onKey(ev)\n\tcase termbox.EventError:\n\t\treturn ev.Err\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// flush updates the gui, re-drawing frames and buffers.\nfunc (g *Gui) flush() error {\n\ttermbox.Clear(termbox.Attribute(g.FgColor), termbox.Attribute(g.BgColor))\n\n\tmaxX, maxY := termbox.Size()\n\t// if GUI's size has changed, we need to redraw all views\n\tif maxX != g.maxX || maxY != g.maxY {\n\t\tfor _, v := range g.views {\n\t\t\tv.tainted = true\n\t\t}\n\t}\n\tg.maxX, g.maxY = maxX, maxY\n\n\tfor _, m := range g.managers {\n\t\tif err := m.Layout(g); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, v := range g.views {\n\t\tif v.Frame {\n\t\t\tvar fgColor, bgColor Attribute\n\t\t\tif g.Highlight && v == g.currentView {\n\t\t\t\tfgColor = g.SelFgColor\n\t\t\t\tbgColor = g.SelBgColor\n\t\t\t} else {\n\t\t\t\tfgColor = g.FgColor\n\t\t\t\tbgColor = g.BgColor\n\t\t\t}\n\n\t\t\tif err := g.drawFrameEdges(v, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := g.drawFrameCorners(v, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif v.Title != \"\" {\n\t\t\t\tif err := g.drawTitle(v, fgColor, bgColor); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif err := g.draw(v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\ttermbox.Flush()\n\treturn nil\n}\n\n// drawFrameEdges draws the horizontal and vertical edges of a view.\nfunc (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error {\n\truneH, runeV := '─', '│'\n\tif g.ASCII {\n\t\truneH, runeV = '-', '|'\n\t}\n\n\tfor x := v.x0 + 1; x < v.x1 && x < g.maxX; x++ {\n\t\tif x < 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif v.y0 > -1 && v.y0 < g.maxY {\n\t\t\tif err := g.SetRune(x, v.y0, runeH, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif v.y1 > -1 && v.y1 < g.maxY {\n\t\t\tif err := g.SetRune(x, v.y1, runeH, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tfor y := v.y0 + 1; y < v.y1 && y < g.maxY; y++ {\n\t\tif y < 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif v.x0 > -1 && v.x0 < g.maxX {\n\t\t\tif err := g.SetRune(v.x0, y, runeV, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif v.x1 > -1 && v.x1 < g.maxX {\n\t\t\tif err := g.SetRune(v.x1, y, runeV, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// drawFrameCorners draws the corners of the view.\nfunc (g *Gui) drawFrameCorners(v *View, fgColor, bgColor Attribute) error {\n\truneTL, runeTR, runeBL, runeBR := '┌', '┐', '└', '┘'\n\tif g.ASCII {\n\t\truneTL, runeTR, runeBL, runeBR = '+', '+', '+', '+'\n\t}\n\n\tcorners := []struct {\n\t\tx, y int\n\t\tch   rune\n\t}{{v.x0, v.y0, runeTL}, {v.x1, v.y0, runeTR}, {v.x0, v.y1, runeBL}, {v.x1, v.y1, runeBR}}\n\n\tfor _, c := range corners {\n\t\tif c.x >= 0 && c.y >= 0 && c.x < g.maxX && c.y < g.maxY {\n\t\t\tif err := g.SetRune(c.x, c.y, c.ch, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// drawTitle draws the title of the view.\nfunc (g *Gui) drawTitle(v *View, fgColor, bgColor Attribute) error {\n\tif v.y0 < 0 || v.y0 >= g.maxY {\n\t\treturn nil\n\t}\n\n\tfor i, ch := range v.Title {\n\t\tx := v.x0 + i + 2\n\t\tif x < 0 {\n\t\t\tcontinue\n\t\t} else if x > v.x1-2 || x >= g.maxX {\n\t\t\tbreak\n\t\t}\n\t\tif err := g.SetRune(x, v.y0, ch, fgColor, bgColor); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// draw manages the cursor and calls the draw function of a view.\nfunc (g *Gui) draw(v *View) error {\n\tif g.Cursor {\n\t\tif curview := g.currentView; curview != nil {\n\t\t\tvMaxX, vMaxY := curview.Size()\n\t\t\tif curview.cx < 0 {\n\t\t\t\tcurview.cx = 0\n\t\t\t} else if curview.cx >= vMaxX {\n\t\t\t\tcurview.cx = vMaxX - 1\n\t\t\t}\n\t\t\tif curview.cy < 0 {\n\t\t\t\tcurview.cy = 0\n\t\t\t} else if curview.cy >= vMaxY {\n\t\t\t\tcurview.cy = vMaxY - 1\n\t\t\t}\n\n\t\t\tgMaxX, gMaxY := g.Size()\n\t\t\tcx, cy := curview.x0+curview.cx+1, curview.y0+curview.cy+1\n\t\t\tif cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY {\n\t\t\t\ttermbox.SetCursor(cx, cy)\n\t\t\t} else {\n\t\t\t\ttermbox.HideCursor()\n\t\t\t}\n\t\t}\n\t} else {\n\t\ttermbox.HideCursor()\n\t}\n\n\tv.clearRunes()\n\tif err := v.draw(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// onKey manages key-press events. A keybinding handler is called when\n// a key-press or mouse event satisfies a configured keybinding. Furthermore,\n// currentView's internal buffer is modified if currentView.Editable is true.\nfunc (g *Gui) onKey(ev *termbox.Event) error {\n\tswitch ev.Type {\n\tcase termbox.EventKey:\n\t\tmatched, err := g.execKeybindings(g.currentView, ev)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif matched {\n\t\t\tbreak\n\t\t}\n\t\tif g.currentView != nil && g.currentView.Editable && g.currentView.Editor != nil {\n\t\t\tg.currentView.Editor.Edit(g.currentView, Key(ev.Key), ev.Ch, Modifier(ev.Mod))\n\t\t}\n\tcase termbox.EventMouse:\n\t\tmx, my := ev.MouseX, ev.MouseY\n\t\tv, err := g.ViewByPosition(mx, my)\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif err := v.SetCursor(mx-v.x0-1, my-v.y0-1); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, err := g.execKeybindings(v, ev); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// execKeybindings executes the keybinding handlers that match the passed view\n// and event. The value of matched is true if there is a match and no errors.\nfunc (g *Gui) execKeybindings(v *View, ev *termbox.Event) (matched bool, err error) {\n\tmatched = false\n\tfor _, kb := range g.keybindings {\n\t\tif kb.handler == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif kb.matchKeypress(Key(ev.Key), ev.Ch, Modifier(ev.Mod)) && kb.matchView(v) {\n\t\t\tif err := kb.handler(g, v); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tmatched = true\n\t\t}\n\t}\n\treturn matched, nil\n}\n"
  },
  {
    "path": "keybinding.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage gocui\n\nimport \"github.com/nsf/termbox-go\"\n\n// Keybidings are used to link a given key-press event with a handler.\ntype keybinding struct {\n\tviewName string\n\tkey      Key\n\tch       rune\n\tmod      Modifier\n\thandler  func(*Gui, *View) error\n}\n\n// newKeybinding returns a new Keybinding object.\nfunc newKeybinding(viewname string, key Key, ch rune, mod Modifier, handler func(*Gui, *View) error) (kb *keybinding) {\n\tkb = &keybinding{\n\t\tviewName: viewname,\n\t\tkey:      key,\n\t\tch:       ch,\n\t\tmod:      mod,\n\t\thandler:  handler,\n\t}\n\treturn kb\n}\n\n// matchKeypress returns if the keybinding matches the keypress.\nfunc (kb *keybinding) matchKeypress(key Key, ch rune, mod Modifier) bool {\n\treturn kb.key == key && kb.ch == ch && kb.mod == mod\n}\n\n// matchView returns if the keybinding matches the current view.\nfunc (kb *keybinding) matchView(v *View) bool {\n\tif kb.viewName == \"\" {\n\t\treturn true\n\t}\n\treturn v != nil && kb.viewName == v.name\n}\n\n// Key represents special keys or keys combinations.\ntype Key termbox.Key\n\n// Special keys.\nconst (\n\tKeyF1         Key = Key(termbox.KeyF1)\n\tKeyF2             = Key(termbox.KeyF2)\n\tKeyF3             = Key(termbox.KeyF3)\n\tKeyF4             = Key(termbox.KeyF4)\n\tKeyF5             = Key(termbox.KeyF5)\n\tKeyF6             = Key(termbox.KeyF6)\n\tKeyF7             = Key(termbox.KeyF7)\n\tKeyF8             = Key(termbox.KeyF8)\n\tKeyF9             = Key(termbox.KeyF9)\n\tKeyF10            = Key(termbox.KeyF10)\n\tKeyF11            = Key(termbox.KeyF11)\n\tKeyF12            = Key(termbox.KeyF12)\n\tKeyInsert         = Key(termbox.KeyInsert)\n\tKeyDelete         = Key(termbox.KeyDelete)\n\tKeyHome           = Key(termbox.KeyHome)\n\tKeyEnd            = Key(termbox.KeyEnd)\n\tKeyPgup           = Key(termbox.KeyPgup)\n\tKeyPgdn           = Key(termbox.KeyPgdn)\n\tKeyArrowUp        = Key(termbox.KeyArrowUp)\n\tKeyArrowDown      = Key(termbox.KeyArrowDown)\n\tKeyArrowLeft      = Key(termbox.KeyArrowLeft)\n\tKeyArrowRight     = Key(termbox.KeyArrowRight)\n\n\tMouseLeft      = Key(termbox.MouseLeft)\n\tMouseMiddle    = Key(termbox.MouseMiddle)\n\tMouseRight     = Key(termbox.MouseRight)\n\tMouseRelease   = Key(termbox.MouseRelease)\n\tMouseWheelUp   = Key(termbox.MouseWheelUp)\n\tMouseWheelDown = Key(termbox.MouseWheelDown)\n)\n\n// Keys combinations.\nconst (\n\tKeyCtrlTilde      Key = Key(termbox.KeyCtrlTilde)\n\tKeyCtrl2              = Key(termbox.KeyCtrl2)\n\tKeyCtrlSpace          = Key(termbox.KeyCtrlSpace)\n\tKeyCtrlA              = Key(termbox.KeyCtrlA)\n\tKeyCtrlB              = Key(termbox.KeyCtrlB)\n\tKeyCtrlC              = Key(termbox.KeyCtrlC)\n\tKeyCtrlD              = Key(termbox.KeyCtrlD)\n\tKeyCtrlE              = Key(termbox.KeyCtrlE)\n\tKeyCtrlF              = Key(termbox.KeyCtrlF)\n\tKeyCtrlG              = Key(termbox.KeyCtrlG)\n\tKeyBackspace          = Key(termbox.KeyBackspace)\n\tKeyCtrlH              = Key(termbox.KeyCtrlH)\n\tKeyTab                = Key(termbox.KeyTab)\n\tKeyCtrlI              = Key(termbox.KeyCtrlI)\n\tKeyCtrlJ              = Key(termbox.KeyCtrlJ)\n\tKeyCtrlK              = Key(termbox.KeyCtrlK)\n\tKeyCtrlL              = Key(termbox.KeyCtrlL)\n\tKeyEnter              = Key(termbox.KeyEnter)\n\tKeyCtrlM              = Key(termbox.KeyCtrlM)\n\tKeyCtrlN              = Key(termbox.KeyCtrlN)\n\tKeyCtrlO              = Key(termbox.KeyCtrlO)\n\tKeyCtrlP              = Key(termbox.KeyCtrlP)\n\tKeyCtrlQ              = Key(termbox.KeyCtrlQ)\n\tKeyCtrlR              = Key(termbox.KeyCtrlR)\n\tKeyCtrlS              = Key(termbox.KeyCtrlS)\n\tKeyCtrlT              = Key(termbox.KeyCtrlT)\n\tKeyCtrlU              = Key(termbox.KeyCtrlU)\n\tKeyCtrlV              = Key(termbox.KeyCtrlV)\n\tKeyCtrlW              = Key(termbox.KeyCtrlW)\n\tKeyCtrlX              = Key(termbox.KeyCtrlX)\n\tKeyCtrlY              = Key(termbox.KeyCtrlY)\n\tKeyCtrlZ              = Key(termbox.KeyCtrlZ)\n\tKeyEsc                = Key(termbox.KeyEsc)\n\tKeyCtrlLsqBracket     = Key(termbox.KeyCtrlLsqBracket)\n\tKeyCtrl3              = Key(termbox.KeyCtrl3)\n\tKeyCtrl4              = Key(termbox.KeyCtrl4)\n\tKeyCtrlBackslash      = Key(termbox.KeyCtrlBackslash)\n\tKeyCtrl5              = Key(termbox.KeyCtrl5)\n\tKeyCtrlRsqBracket     = Key(termbox.KeyCtrlRsqBracket)\n\tKeyCtrl6              = Key(termbox.KeyCtrl6)\n\tKeyCtrl7              = Key(termbox.KeyCtrl7)\n\tKeyCtrlSlash          = Key(termbox.KeyCtrlSlash)\n\tKeyCtrlUnderscore     = Key(termbox.KeyCtrlUnderscore)\n\tKeySpace              = Key(termbox.KeySpace)\n\tKeyBackspace2         = Key(termbox.KeyBackspace2)\n\tKeyCtrl8              = Key(termbox.KeyCtrl8)\n)\n\n// Modifier allows to define special keys combinations. They can be used\n// in combination with Keys or Runes when a new keybinding is defined.\ntype Modifier termbox.Modifier\n\n// Modifiers.\nconst (\n\tModNone Modifier = Modifier(0)\n\tModAlt           = Modifier(termbox.ModAlt)\n)\n"
  },
  {
    "path": "view.go",
    "content": "// Copyright 2014 The gocui Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage gocui\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/nsf/termbox-go\"\n)\n\n// A View is a window. It maintains its own internal buffer and cursor\n// position.\ntype View struct {\n\tname           string\n\tx0, y0, x1, y1 int\n\tox, oy         int\n\tcx, cy         int\n\tlines          [][]cell\n\treadOffset     int\n\treadCache      string\n\n\ttainted   bool       // marks if the viewBuffer must be updated\n\tviewLines []viewLine // internal representation of the view's buffer\n\n\tei *escapeInterpreter // used to decode ESC sequences on Write\n\n\t// BgColor and FgColor allow to configure the background and foreground\n\t// colors of the View.\n\tBgColor, FgColor Attribute\n\n\t// SelBgColor and SelFgColor are used to configure the background and\n\t// foreground colors of the selected line, when it is highlighted.\n\tSelBgColor, SelFgColor Attribute\n\n\t// If Editable is true, keystrokes will be added to the view's internal\n\t// buffer at the cursor position.\n\tEditable bool\n\n\t// Editor allows to define the editor that manages the edition mode,\n\t// including keybindings or cursor behaviour. DefaultEditor is used by\n\t// default.\n\tEditor Editor\n\n\t// Overwrite enables or disables the overwrite mode of the view.\n\tOverwrite bool\n\n\t// If Highlight is true, Sel{Bg,Fg}Colors will be used\n\t// for the line under the cursor position.\n\tHighlight bool\n\n\t// If Frame is true, a border will be drawn around the view.\n\tFrame bool\n\n\t// If Wrap is true, the content that is written to this View is\n\t// automatically wrapped when it is longer than its width. If true the\n\t// view's x-origin will be ignored.\n\tWrap bool\n\n\t// If Autoscroll is true, the View will automatically scroll down when the\n\t// text overflows. If true the view's y-origin will be ignored.\n\tAutoscroll bool\n\n\t// If Frame is true, Title allows to configure a title for the view.\n\tTitle string\n\n\t// If Mask is true, the View will display the mask instead of the real\n\t// content\n\tMask rune\n}\n\ntype viewLine struct {\n\tlinesX, linesY int // coordinates relative to v.lines\n\tline           []cell\n}\n\ntype cell struct {\n\tchr              rune\n\tbgColor, fgColor Attribute\n}\n\ntype lineType []cell\n\n// String returns a string from a given cell slice.\nfunc (l lineType) String() string {\n\tstr := \"\"\n\tfor _, c := range l {\n\t\tstr += string(c.chr)\n\t}\n\treturn str\n}\n\n// newView returns a new View object.\nfunc newView(name string, x0, y0, x1, y1 int, mode OutputMode) *View {\n\tv := &View{\n\t\tname:    name,\n\t\tx0:      x0,\n\t\ty0:      y0,\n\t\tx1:      x1,\n\t\ty1:      y1,\n\t\tFrame:   true,\n\t\tEditor:  DefaultEditor,\n\t\ttainted: true,\n\t\tei:      newEscapeInterpreter(mode),\n\t}\n\treturn v\n}\n\n// Size returns the number of visible columns and rows in the View.\nfunc (v *View) Size() (x, y int) {\n\treturn v.x1 - v.x0 - 1, v.y1 - v.y0 - 1\n}\n\n// Name returns the name of the view.\nfunc (v *View) Name() string {\n\treturn v.name\n}\n\n// setRune sets a rune at the given point relative to the view. It applies the\n// specified colors, taking into account if the cell must be highlighted. Also,\n// it checks if the position is valid.\nfunc (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) error {\n\tmaxX, maxY := v.Size()\n\tif x < 0 || x >= maxX || y < 0 || y >= maxY {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\n\tvar (\n\t\try, rcy int\n\t\terr     error\n\t)\n\tif v.Highlight {\n\t\t_, ry, err = v.realPosition(x, y)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_, rcy, err = v.realPosition(v.cx, v.cy)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif v.Mask != 0 {\n\t\tfgColor = v.FgColor\n\t\tbgColor = v.BgColor\n\t\tch = v.Mask\n\t} else if v.Highlight && ry == rcy {\n\t\tfgColor = v.SelFgColor\n\t\tbgColor = v.SelBgColor\n\t}\n\n\ttermbox.SetCell(v.x0+x+1, v.y0+y+1, ch,\n\t\ttermbox.Attribute(fgColor), termbox.Attribute(bgColor))\n\n\treturn nil\n}\n\n// SetCursor sets the cursor position of the view at the given point,\n// relative to the view. It checks if the position is valid.\nfunc (v *View) SetCursor(x, y int) error {\n\tmaxX, maxY := v.Size()\n\tif x < 0 || x >= maxX || y < 0 || y >= maxY {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\tv.cx = x\n\tv.cy = y\n\treturn nil\n}\n\n// Cursor returns the cursor position of the view.\nfunc (v *View) Cursor() (x, y int) {\n\treturn v.cx, v.cy\n}\n\n// SetOrigin sets the origin position of the view's internal buffer,\n// so the buffer starts to be printed from this point, which means that\n// it is linked with the origin point of view. It can be used to\n// implement Horizontal and Vertical scrolling with just incrementing\n// or decrementing ox and oy.\nfunc (v *View) SetOrigin(x, y int) error {\n\tif x < 0 || y < 0 {\n\t\treturn errors.New(\"invalid point\")\n\t}\n\tv.ox = x\n\tv.oy = y\n\treturn nil\n}\n\n// Origin returns the origin position of the view.\nfunc (v *View) Origin() (x, y int) {\n\treturn v.ox, v.oy\n}\n\n// Write appends a byte slice into the view's internal buffer. Because\n// View implements the io.Writer interface, it can be passed as parameter\n// of functions like fmt.Fprintf, fmt.Fprintln, io.Copy, etc. Clear must\n// be called to clear the view's buffer.\nfunc (v *View) Write(p []byte) (n int, err error) {\n\tv.tainted = true\n\n\tfor _, ch := range bytes.Runes(p) {\n\t\tswitch ch {\n\t\tcase '\\n':\n\t\t\tv.lines = append(v.lines, nil)\n\t\tcase '\\r':\n\t\t\tnl := len(v.lines)\n\t\t\tif nl > 0 {\n\t\t\t\tv.lines[nl-1] = nil\n\t\t\t} else {\n\t\t\t\tv.lines = make([][]cell, 1)\n\t\t\t}\n\t\tdefault:\n\t\t\tcells := v.parseInput(ch)\n\t\t\tif cells == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tnl := len(v.lines)\n\t\t\tif nl > 0 {\n\t\t\t\tv.lines[nl-1] = append(v.lines[nl-1], cells...)\n\t\t\t} else {\n\t\t\t\tv.lines = append(v.lines, cells)\n\t\t\t}\n\t\t}\n\t}\n\treturn len(p), nil\n}\n\n// parseInput parses char by char the input written to the View. It returns nil\n// while processing ESC sequences. Otherwise, it returns a cell slice that\n// contains the processed data.\nfunc (v *View) parseInput(ch rune) []cell {\n\tcells := []cell{}\n\n\tisEscape, err := v.ei.parseOne(ch)\n\tif err != nil {\n\t\tfor _, r := range v.ei.runes() {\n\t\t\tc := cell{\n\t\t\t\tfgColor: v.FgColor,\n\t\t\t\tbgColor: v.BgColor,\n\t\t\t\tchr:     r,\n\t\t\t}\n\t\t\tcells = append(cells, c)\n\t\t}\n\t\tv.ei.reset()\n\t} else {\n\t\tif isEscape {\n\t\t\treturn nil\n\t\t}\n\t\tc := cell{\n\t\t\tfgColor: v.ei.curFgColor,\n\t\t\tbgColor: v.ei.curBgColor,\n\t\t\tchr:     ch,\n\t\t}\n\t\tcells = append(cells, c)\n\t}\n\n\treturn cells\n}\n\n// Read reads data into p. It returns the number of bytes read into p.\n// At EOF, err will be io.EOF. Calling Read() after Rewind() makes the\n// cache to be refreshed with the contents of the view.\nfunc (v *View) Read(p []byte) (n int, err error) {\n\tif v.readOffset == 0 {\n\t\tv.readCache = v.Buffer()\n\t}\n\tif v.readOffset < len(v.readCache) {\n\t\tn = copy(p, v.readCache[v.readOffset:])\n\t\tv.readOffset += n\n\t} else {\n\t\terr = io.EOF\n\t}\n\treturn\n}\n\n// Rewind sets the offset for the next Read to 0, which also refresh the\n// read cache.\nfunc (v *View) Rewind() {\n\tv.readOffset = 0\n}\n\n// draw re-draws the view's contents.\nfunc (v *View) draw() error {\n\tmaxX, maxY := v.Size()\n\n\tif v.Wrap {\n\t\tif maxX == 0 {\n\t\t\treturn errors.New(\"X size of the view cannot be 0\")\n\t\t}\n\t\tv.ox = 0\n\t}\n\tif v.tainted {\n\t\tv.viewLines = nil\n\t\tfor i, line := range v.lines {\n\t\t\tif v.Wrap {\n\t\t\t\tif len(line) < maxX {\n\t\t\t\t\tvline := viewLine{linesX: 0, linesY: i, line: line}\n\t\t\t\t\tv.viewLines = append(v.viewLines, vline)\n\t\t\t\t\tcontinue\n\t\t\t\t} else {\n\t\t\t\t\tfor n := 0; n <= len(line); n += maxX {\n\t\t\t\t\t\tif len(line[n:]) <= maxX {\n\t\t\t\t\t\t\tvline := viewLine{linesX: n, linesY: i, line: line[n:]}\n\t\t\t\t\t\t\tv.viewLines = append(v.viewLines, vline)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvline := viewLine{linesX: n, linesY: i, line: line[n : n+maxX]}\n\t\t\t\t\t\t\tv.viewLines = append(v.viewLines, vline)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvline := viewLine{linesX: 0, linesY: i, line: line}\n\t\t\t\tv.viewLines = append(v.viewLines, vline)\n\t\t\t}\n\t\t}\n\t\tv.tainted = false\n\t}\n\n\tif v.Autoscroll && len(v.viewLines) > maxY {\n\t\tv.oy = len(v.viewLines) - maxY\n\t}\n\ty := 0\n\tfor i, vline := range v.viewLines {\n\t\tif i < v.oy {\n\t\t\tcontinue\n\t\t}\n\t\tif y >= maxY {\n\t\t\tbreak\n\t\t}\n\t\tx := 0\n\t\tfor j, c := range vline.line {\n\t\t\tif j < v.ox {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif x >= maxX {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tfgColor := c.fgColor\n\t\t\tif fgColor == ColorDefault {\n\t\t\t\tfgColor = v.FgColor\n\t\t\t}\n\t\t\tbgColor := c.bgColor\n\t\t\tif bgColor == ColorDefault {\n\t\t\t\tbgColor = v.BgColor\n\t\t\t}\n\n\t\t\tif err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tx++\n\t\t}\n\t\ty++\n\t}\n\treturn nil\n}\n\n// realPosition returns the position in the internal buffer corresponding to the\n// point (x, y) of the view.\nfunc (v *View) realPosition(vx, vy int) (x, y int, err error) {\n\tvx = v.ox + vx\n\tvy = v.oy + vy\n\n\tif vx < 0 || vy < 0 {\n\t\treturn 0, 0, errors.New(\"invalid point\")\n\t}\n\n\tif len(v.viewLines) == 0 {\n\t\treturn vx, vy, nil\n\t}\n\n\tif vy < len(v.viewLines) {\n\t\tvline := v.viewLines[vy]\n\t\tx = vline.linesX + vx\n\t\ty = vline.linesY\n\t} else {\n\t\tvline := v.viewLines[len(v.viewLines)-1]\n\t\tx = vx\n\t\ty = vline.linesY + vy - len(v.viewLines) + 1\n\t}\n\n\treturn x, y, nil\n}\n\n// Clear empties the view's internal buffer.\nfunc (v *View) Clear() {\n\tv.tainted = true\n\n\tv.lines = nil\n\tv.viewLines = nil\n\tv.readOffset = 0\n\tv.clearRunes()\n}\n\n// clearRunes erases all the cells in the view.\nfunc (v *View) clearRunes() {\n\tmaxX, maxY := v.Size()\n\tfor x := 0; x < maxX; x++ {\n\t\tfor y := 0; y < maxY; y++ {\n\t\t\ttermbox.SetCell(v.x0+x+1, v.y0+y+1, ' ',\n\t\t\t\ttermbox.Attribute(v.FgColor), termbox.Attribute(v.BgColor))\n\t\t}\n\t}\n}\n\n// BufferLines returns the lines in the view's internal\n// buffer.\nfunc (v *View) BufferLines() []string {\n\tlines := make([]string, len(v.lines))\n\tfor i, l := range v.lines {\n\t\tstr := lineType(l).String()\n\t\tstr = strings.Replace(str, \"\\x00\", \" \", -1)\n\t\tlines[i] = str\n\t}\n\treturn lines\n}\n\n// Buffer returns a string with the contents of the view's internal\n// buffer.\nfunc (v *View) Buffer() string {\n\tstr := \"\"\n\tfor _, l := range v.lines {\n\t\tstr += lineType(l).String() + \"\\n\"\n\t}\n\treturn strings.Replace(str, \"\\x00\", \" \", -1)\n}\n\n// ViewBufferLines returns the lines in the view's internal\n// buffer that is shown to the user.\nfunc (v *View) ViewBufferLines() []string {\n\tlines := make([]string, len(v.viewLines))\n\tfor i, l := range v.viewLines {\n\t\tstr := lineType(l.line).String()\n\t\tstr = strings.Replace(str, \"\\x00\", \" \", -1)\n\t\tlines[i] = str\n\t}\n\treturn lines\n}\n\n// ViewBuffer returns a string with the contents of the view's buffer that is\n// shown to the user.\nfunc (v *View) ViewBuffer() string {\n\tstr := \"\"\n\tfor _, l := range v.viewLines {\n\t\tstr += lineType(l.line).String() + \"\\n\"\n\t}\n\treturn strings.Replace(str, \"\\x00\", \" \", -1)\n}\n\n// Line returns a string with the line of the view's internal buffer\n// at the position corresponding to the point (x, y).\nfunc (v *View) Line(y int) (string, error) {\n\t_, y, err := v.realPosition(0, y)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif y < 0 || y >= len(v.lines) {\n\t\treturn \"\", errors.New(\"invalid point\")\n\t}\n\n\treturn lineType(v.lines[y]).String(), nil\n}\n\n// Word returns a string with the word of the view's internal buffer\n// at the position corresponding to the point (x, y).\nfunc (v *View) Word(x, y int) (string, error) {\n\tx, y, err := v.realPosition(x, y)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {\n\t\treturn \"\", errors.New(\"invalid point\")\n\t}\n\n\tstr := lineType(v.lines[y]).String()\n\n\tnl := strings.LastIndexFunc(str[:x], indexFunc)\n\tif nl == -1 {\n\t\tnl = 0\n\t} else {\n\t\tnl = nl + 1\n\t}\n\tnr := strings.IndexFunc(str[x:], indexFunc)\n\tif nr == -1 {\n\t\tnr = len(str)\n\t} else {\n\t\tnr = nr + x\n\t}\n\treturn string(str[nl:nr]), nil\n}\n\n// indexFunc allows to split lines by words taking into account spaces\n// and 0.\nfunc indexFunc(r rune) bool {\n\treturn r == ' ' || r == 0\n}\n"
  }
]