Editor refactoring. Add doc. Simplify _examples.

This commit is contained in:
Roi Martin 2016-01-30 02:36:10 +01:00
parent f42f45fad3
commit 4aed924ceb
12 changed files with 123 additions and 70 deletions

View File

@ -21,8 +21,6 @@ var (
)
func main() {
var err error
g := gocui.NewGui()
if err := g.Init(); err != nil {
log.Panicln(err)
@ -37,8 +35,7 @@ func main() {
log.Panicln(err)
}
err = g.MainLoop()
if err != nil && err != gocui.ErrQuit {
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}

View File

@ -187,8 +187,6 @@ func layout(g *gocui.Gui) error {
}
func main() {
var err error
g := gocui.NewGui()
if err := g.Init(); err != nil {
log.Panicln(err)
@ -203,8 +201,7 @@ func main() {
g.SelFgColor = gocui.ColorBlack
g.Cursor = true
err = g.MainLoop()
if err != nil && err != gocui.ErrQuit {
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}

View File

@ -79,20 +79,18 @@ func counter(g *gocui.Gui) {
case <-done:
return
case <-time.After(500 * time.Millisecond):
mu.Lock()
n := ctr
ctr++
mu.Unlock()
g.Execute(func(g *gocui.Gui) error {
v, err := g.View("ctr")
if err != nil {
return err
}
mu.Lock()
n := ctr
ctr++
mu.Unlock()
v.Clear()
fmt.Fprintln(v, n)
return nil
})
}

View File

@ -32,8 +32,6 @@ func quit(g *gocui.Gui, v *gocui.View) error {
}
func main() {
var err error
g := gocui.NewGui()
if err := g.Init(); err != nil {
log.Panicln(err)
@ -46,8 +44,7 @@ func main() {
log.Panicln(err)
}
err = g.MainLoop()
if err != nil && err != gocui.ErrQuit {
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}

View File

@ -12,8 +12,6 @@ import (
)
func main() {
var err error
g := gocui.NewGui()
if err := g.Init(); err != nil {
log.Panicln(err)
@ -29,8 +27,7 @@ func main() {
g.Cursor = true
g.Mouse = true
err = g.MainLoop()
if err != nil && err != gocui.ErrQuit {
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}

View File

@ -56,8 +56,6 @@ func quit(g *gocui.Gui, v *gocui.View) error {
}
func main() {
var err error
g := gocui.NewGui()
if err := g.Init(); err != nil {
log.Panicln(err)
@ -69,8 +67,7 @@ func main() {
log.Panicln(err)
}
err = g.MainLoop()
if err != nil && err != gocui.ErrQuit {
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}

View File

@ -27,8 +27,7 @@ func main() {
}
g.Cursor = true
err := g.MainLoop()
if err != nil && err != gocui.ErrQuit {
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Fatalln(err)
}
}

View File

@ -32,8 +32,6 @@ func quit(g *gocui.Gui, v *gocui.View) error {
}
func main() {
var err error
g := gocui.NewGui()
if err := g.Init(); err != nil {
log.Panicln(err)
@ -45,8 +43,7 @@ func main() {
log.Panicln(err)
}
err = g.MainLoop()
if err != nil && err != gocui.ErrQuit {
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}

118
doc.go
View File

@ -5,36 +5,106 @@
/*
Package gocui allows to create console user interfaces.
Example:
Create a new GUI:
func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
if v, err := g.SetView("center", maxX/2-10, maxY/2, maxX/2+10, maxY/2+2); err != nil {
if err != gocui.ErrUnknownView {
return err
}
fmt.Fprintln(v, "This is an example")
g := gocui.NewGui()
if err := g.Init(); err != nil {
// handle error
}
defer g.Close()
// Set layout and key bindings
// ...
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
// handle error
}
Set the layout function:
g.SetLayout(fcn)
On each iteration of the GUI's main loop, the "layout function" will be
executed. These layout functions can be used to set-up and update the main
application views, being possible to freely switch between them. Also, it is
important to mention that a main loop iteration is executed on each reported
event (key-press, mouse event, window resize, etc).
GUIs are composed by Views, you can think of it as free text buffers. Views
implement the io.ReadWriter interface, so you can just write to them if you
want to modify their content and the same is valid for reading.
Create and intialize a view with absolute coordinates:
if v, err := g.SetView("viewname", 2, 2, 22, 7); err != nil {
if err != gocui.ErrUnknownView {
// handle error
}
fmt.Fprintln(v, "This is a new view")
// ...
}
Views can also being created using relative coordinates:
maxX, maxY := g.Size()
if v, err := g.SetView("viewname", maxX/2-30, maxY/2, maxX/2+30, maxY/2+2); err != nil {
// ...
}
IMPORTANT: Views can only be created, destroyed or updated in two ways: from a
layout funcion or via *Gui.Execute(). The reason for this is that it allows
gocui to be conccurent-safe. So, if you want to update your GUI from a
goroutine, you must use *Gui.Execute(). For example:
g.Execute(func(g *gocui.Gui) error {
v, err := g.View("viewname")
if err != nil {
// handle error
}
v.Clear()
fmt.Fprintln(v, "Writing from different goroutines")
return nil
})
Configure keybindings:
if err := g.SetKeybinding("viewname", gocui.KeyEnter, gocui.ModNone, fcn); err != nil {
// handle error
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
gocui implements full mouse support than can be enabled with:
g.Mouse = true
Mouse events are handled like any other keybinding:
if err := g.SetKeybinding("viewname", gocui.MouseLeft, gocui.ModNone, fcn); err != nil {
// handle error
}
func main() {
var err error
g := gocui.NewGui()
if err := g.Init(); err != nil {
log.Panicln(err)
}
defer g.Close()
g.SetLayout(layout)
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
log.Panicln(err)
}
err = g.MainLoop()
if err != nil && err != gocui.ErrQuit {
log.Panicln(err)
By default, gocui provides a basic edition mode. This mode can be extended
and customized creating a new Editor and asigning it to *Gui.Editor:
type Editor interface {
Edit(v *View, key Key, ch rune, mod Modifier)
}
DefaultEditor can be taken as example to create your own custom Editor:
var DefaultEditor = EditorFunc(simpleEditor)
func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
switch {
case ch != 0 && mod == 0:
v.EditWrite(ch)
case key == KeySpace:
v.EditWrite(' ')
case key == KeyBackspace || key == KeyBackspace2:
v.EditDelete(true)
// ...
}
}
For more information, see the examples in folder "_examples/".
*/
package gocui

12
edit.go
View File

@ -6,11 +6,6 @@ package gocui
const maxInt = int(^uint(0) >> 1)
// Edit allows to define the editor that manages the edition mode,
// including keybindings or cursor behaviour. DefaultEditor is used by
// default.
var Edit = EditorFunc(DefaultEditor)
// Editor interface must be satisfied by gocui editors.
type Editor interface {
Edit(v *View, key Key, ch rune, mod Modifier)
@ -26,8 +21,11 @@ func (f EditorFunc) Edit(v *View, key Key, ch rune, mod Modifier) {
f(v, key, ch, mod)
}
// DefaultEditor is used as the default gocui editor.
func DefaultEditor(v *View, key Key, ch rune, mod Modifier) {
// DefaultEditor is the default editor.
var DefaultEditor Editor = EditorFunc(simpleEditor)
// simpleEditor is used as the default gocui editor.
func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
switch {
case ch != 0 && mod == 0:
v.EditWrite(ch)

14
gui.go
View File

@ -19,7 +19,7 @@ type userEvent struct {
}
var (
// ErrQuit is used to decide if the MainLoop finished succesfully.
// ErrQuit is used to decide if the MainLoop finished successfully.
ErrQuit = errors.New("quit")
// ErrUnknownView allows to assert if a View must be initialized.
@ -50,6 +50,11 @@ type Gui struct {
// If Mouse is true then mouse events will be enabled.
Mouse bool
// Editor allows to define the editor that manages the edition mode,
// including keybindings or cursor behaviour. DefaultEditor is used by
// default.
Editor Editor
}
// NewGui returns a new Gui object.
@ -68,6 +73,7 @@ func (g *Gui) Init() error {
g.maxX, g.maxY = termbox.Size()
g.BgColor = ColorBlack
g.FgColor = ColorWhite
g.Editor = DefaultEditor
return nil
}
@ -220,7 +226,7 @@ func (g *Gui) Execute(h Handler) {
}
// SetLayout sets the current layout. A layout is a function that
// will be called everytime the gui is re-drawed, it must contain
// will be called every time the gui is redrawn, it must contain
// the base views and its initializations.
func (g *Gui) SetLayout(layout Handler) {
g.layout = layout
@ -493,8 +499,8 @@ func (g *Gui) onKey(ev *termbox.Event) error {
switch ev.Type {
case termbox.EventKey:
if g.currentView != nil && g.currentView.Editable && Edit != nil {
Edit(g.currentView, Key(ev.Key), ev.Ch, Modifier(ev.Mod))
if g.currentView != nil && g.currentView.Editable && g.Editor != nil {
g.Editor.Edit(g.currentView, Key(ev.Key), ev.Ch, Modifier(ev.Mod))
}
curView = g.currentView
case termbox.EventMouse:

View File

@ -419,7 +419,7 @@ func (v *View) breakLine(x, y int) error {
}
// Buffer returns a string with the contents of the view's internal
// buffer
// buffer.
func (v *View) Buffer() string {
str := ""
for _, l := range v.lines {
@ -429,7 +429,7 @@ func (v *View) Buffer() string {
}
// ViewBuffer returns a string with the contents of the view's buffer that is
// showed to the user
// shown to the user.
func (v *View) ViewBuffer() string {
str := ""
for _, l := range v.viewLines {