-
Notifications
You must be signed in to change notification settings - Fork 608
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- View contents are stored as cells (rune + colors) instead of runes. - Uses the escape interpreter coded by @deweerdt in #39.
- Loading branch information
1 parent
4901994
commit b342d3a
Showing
4 changed files
with
323 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright 2014 The gocui Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/jroimartin/gocui" | ||
) | ||
|
||
func main() { | ||
g := gocui.NewGui() | ||
if err := g.Init(); err != nil { | ||
log.Panicln(err) | ||
} | ||
defer g.Close() | ||
|
||
g.SetLayout(layout) | ||
|
||
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { | ||
log.Panicln(err) | ||
} | ||
|
||
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit { | ||
log.Panicln(err) | ||
} | ||
} | ||
|
||
func layout(g *gocui.Gui) error { | ||
maxX, maxY := g.Size() | ||
if v, err := g.SetView("hello", maxX/2-6, maxY/2-5, maxX/2+6, maxY/2+5); err != nil { | ||
if err != gocui.ErrUnknownView { | ||
return err | ||
} | ||
fmt.Fprintln(v, "\x1b[0;30;47mHello world") | ||
fmt.Fprintln(v, "\x1b[0;31mHello world") | ||
fmt.Fprintln(v, "\x1b[0;32mHello world") | ||
fmt.Fprintln(v, "\x1b[0;33mHello world") | ||
fmt.Fprintln(v, "\x1b[0;34mHello world") | ||
fmt.Fprintln(v, "\x1b[0;35mHello world") | ||
fmt.Fprintln(v, "\x1b[0;36mHello world") | ||
fmt.Fprintln(v, "\x1b[0;37mHello world") | ||
fmt.Fprintln(v, "\x1b[0;30;41mHello world") | ||
} | ||
return nil | ||
} | ||
|
||
func quit(g *gocui.Gui, v *gocui.View) error { | ||
return gocui.ErrQuit | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
// Copyright 2014 The gocui Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package gocui | ||
|
||
import ( | ||
"errors" | ||
"strconv" | ||
) | ||
|
||
type ( | ||
escapeState int | ||
interpreterReturn int | ||
) | ||
|
||
const ( | ||
stateNone escapeState = iota | ||
stateEscape | ||
stateCSI | ||
stateParams | ||
) | ||
|
||
type escapeInterpreter struct { | ||
state escapeState | ||
curch rune | ||
csiParam []string | ||
curFgColor, curBgColor Attribute | ||
defaultFgColor, defaultBgColor Attribute | ||
} | ||
|
||
var ( | ||
errNotCSI = errors.New("Not a CSI escape sequence") | ||
errCSINotANumber = errors.New("CSI escape sequence was expecting a number or a ;") | ||
errCSIParseError = errors.New("CSI escape sequence parsing error") | ||
errCSITooLong = errors.New("CSI escape sequence is too long") | ||
) | ||
|
||
// runes in case of error will output the non-parsed runes as a string. | ||
func (ei *escapeInterpreter) runes() []rune { | ||
switch ei.state { | ||
case stateNone: | ||
return []rune{0x1b} | ||
case stateEscape: | ||
return []rune{0x1b, ei.curch} | ||
case stateCSI: | ||
return []rune{0x1b, '[', ei.curch} | ||
case stateParams: | ||
ret := []rune{0x1b, '['} | ||
for _, s := range ei.csiParam { | ||
ret = append(ret, []rune(s)...) | ||
ret = append(ret, ';') | ||
} | ||
return append(ret, ei.curch) | ||
} | ||
return nil | ||
} | ||
|
||
// newEscapeInterpreter returns an escapeInterpreter that will be able to parse | ||
// terminal escape sequences. | ||
func newEscapeInterpreter() *escapeInterpreter { | ||
ei := &escapeInterpreter{ | ||
defaultFgColor: ColorWhite, | ||
defaultBgColor: ColorBlack, | ||
state: stateNone, | ||
curFgColor: ColorWhite, | ||
curBgColor: ColorBlack, | ||
} | ||
return ei | ||
} | ||
|
||
// reset sets the escapeInterpreter in inital state. | ||
func (ei *escapeInterpreter) reset() { | ||
ei.state = stateNone | ||
ei.curFgColor = ei.defaultFgColor | ||
ei.curBgColor = ei.defaultBgColor | ||
ei.csiParam = nil | ||
} | ||
|
||
// paramToColor returns an attribute given a terminfo coloring. | ||
func paramToColor(p int) Attribute { | ||
switch p { | ||
case 0: | ||
return ColorBlack | ||
case 1: | ||
return ColorRed | ||
case 2: | ||
return ColorGreen | ||
case 3: | ||
return ColorYellow | ||
case 4: | ||
return ColorBlue | ||
case 5: | ||
return ColorMagenta | ||
case 6: | ||
return ColorCyan | ||
case 7: | ||
return ColorWhite | ||
} | ||
return ColorDefault | ||
} | ||
|
||
// parseOne parses a rune. If isEscape is true, it means that the rune is part | ||
// of an scape sequence, and as such should not be printed verbatim. Otherwise, | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
// it's not an escape sequence. | ||
func (ei *escapeInterpreter) parseOne(ch rune) (isEscape bool, err error) { | ||
// Sanity checks to make sure we're not parsing something totally bogus. | ||
if len(ei.csiParam) > 20 { | ||
return false, errCSITooLong | ||
} | ||
if len(ei.csiParam) > 0 && len(ei.csiParam[len(ei.csiParam)-1]) > 255 { | ||
return false, errCSITooLong | ||
} | ||
ei.curch = ch | ||
switch ei.state { | ||
case stateNone: | ||
if ch == 0x1b { | ||
ei.state = stateEscape | ||
return true, nil | ||
} | ||
return false, nil | ||
case stateEscape: | ||
if ch == '[' { | ||
ei.state = stateCSI | ||
return true, nil | ||
} | ||
return false, errNotCSI | ||
case stateCSI: | ||
if ch >= '0' && ch <= '9' { | ||
ei.state = stateParams | ||
ei.csiParam = append(ei.csiParam, string(ch)) | ||
return true, nil | ||
} | ||
return false, errCSINotANumber | ||
case stateParams: | ||
switch { | ||
case ch >= '0' && ch <= '9': | ||
ei.csiParam[len(ei.csiParam)-1] += string(ch) | ||
return true, nil | ||
case ch == ';': | ||
ei.csiParam = append(ei.csiParam, "") | ||
return true, nil | ||
case ch == 'm': | ||
if len(ei.csiParam) < 1 { | ||
return false, errCSIParseError | ||
} | ||
for _, param := range ei.csiParam { | ||
p, err := strconv.Atoi(param) | ||
if err != nil { | ||
return false, errCSIParseError | ||
} | ||
switch { | ||
case p >= 30 && p <= 37: | ||
ei.curFgColor = paramToColor(p - 30) | ||
case p >= 40 && p <= 47: | ||
ei.curBgColor = paramToColor(p - 40) | ||
case p == 1: | ||
ei.curFgColor |= AttrBold | ||
case p == 4: | ||
ei.curFgColor |= AttrUnderline | ||
case p == 7: | ||
ei.curFgColor |= AttrReverse | ||
case p == 0 || p == 39: | ||
ei.curFgColor = ei.defaultFgColor | ||
ei.curBgColor = ei.defaultBgColor | ||
} | ||
} | ||
ei.state = stateNone | ||
ei.csiParam = nil | ||
return true, nil | ||
} | ||
} | ||
return false, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
A minor typo coming from the original commit: s/space/escape/