jroimartin / gocui Goto Github PK
View Code? Open in Web Editor NEWMinimalist Go package aimed at creating Console User Interfaces.
License: BSD 3-Clause "New" or "Revised" License
Minimalist Go package aimed at creating Console User Interfaces.
License: BSD 3-Clause "New" or "Revised" License
Currently, if a view is wrapped, there seems to be no way to actually return the new view content, including the extra newlines. Buffer returns the content before the newlines have been calculated. This makes implementing scrolling with boundaries impossible.
Hi,
Using the gocui for creating a Terminal application. We have a main view more like a dialog which we would like to set the title. Right now the title comes to the left end of the layout. Any way to add the alignment for the title, so that it aligns to the middle?
Implement most typical KB handlers to help users:
I need to get the text a line n but len(line) is off because of "\x00" at end of line.
Example:
line := v.Line(n)
if len(line) > 10 {
// Do something
}
The above doesn't work as expected because len is off by 1. Would be nice if Line func would do the following before it returns value:
strings.Replace(lineValue, "\x00", "", -1)
Hi,
How to define a View over a collection of structs ?
An idea?
Thank you
For example, fmt.Fprint(v, "More text") should append the string "More text" to the last line in the buffer.
When defining my keybindings, I use this helper function:
func setkey(g *gocui.Gui, key gocui.Key, fn gocui.KeybindingHandler) {
if err := g.SetKeybinding("", key, gocui.ModNone, fn); err != nil {
log.Panicln(err)
}
}
An example invocation that works is:
setKey(g, gocui.KeyCtrlC, quit)
...but the following fails:
setKey(g, 'q', quit)
...while the following correctly binds the q
key:
if err := g.SetKeybinding("", 'q', gocui.ModNone, quit); err != nil {
log.Panicln(err)
}
I'm pretty sure I'm missing something obvious here.
After adding support for coloured text, changing view's bgcolor is not possible.
When printing to view
fmt.Fprint(v, "\r test")
casts:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x80 pc=0x4e1e95]
goroutine 1 [running]:
panic(0x7ca780, 0xc82000e1a0)
/usr/local/go/src/runtime/panic.go:481 +0x3e6
github.com/jroimartin/gocui.(*View).Write(0x0, 0xc820263c40, 0x6, 0x8, 0x720000, 0x0, 0x0)
/home/janbo/src/github.com/jroimartin/gocui/view.go:197 +0x45
fmt.Fprint(0x7f5a542ad1c8, 0x0, 0xc82004ba50, 0x1, 0x1, 0x0, 0x0, 0x0)
/usr/local/go/src/fmt/print.go:223 +0xa5
Hi jroimartin,
Thanks for answering my earlier question. I am asking this question as a new thread, thinking that others who want to use this fantastic library may find these Q&A helpful.
The issue/question I am having is, I have to draw a UI and ask for the user input. I would like to show the cursor in the screen (may be blinking as well) so user knows where the cursor is. I created a sample using gocui https://github.com/shibukraj/synapseconsole/blob/master/console-dev.go
While running I am not able to draw the cursor at all. Can you guide me please.
Thanks again
I have an idea about create an interactive session bebind a ssh server.
thus I want to get a interactive console interface build by gocui, so I want to know how to build gocui with a pty.
I think it would be cool to have a section on the readme highlighting projects built using your awesome package. I have been working on an IRC client using it https://github.com/mephux/komanda-cli and I'm sure there are hundreds of others.
Anyway, thought it would be a good idea to highlight how easy this package makes it building pretty complex terminal UI's outside of the examples in the package itself.
Greetings,
I may have stumbled across a bug, otherwise requesting clarification :-)
Here goes:
I need to implement a simple text entry, this is done inside a View
. Just 1 line of text entry is desired - think a password / IP address / hostname etc., something short.
I implemented this using the View.Editable = true
functionality so that a user can comfortably enter text. Wrote a handler for the Enter key in order to handle OK / submit.
Try running it, enter some text, press Enter.
In the handler, tried to get the entered text using view.Line(0), but ... the resulting string is empty.
But, when I enter some text, then press left arrow key a few times = move cursor into middle of entered text, then press the Enter key, then view.Line(0)
returns everything right of the cursor.
From the documentation and the name of the function (Line
) I would expect to receive the whole line of text, not just what is right of the cursor.
Is this a bug or am I understanding the use of this function wrong?
Sure, using view.Buffer()
returns everything and this is a possible workaround in this case - but then how does one get a specific line if there are multiple lines? That use case will show up soon. I would expect view.Line(i)
to cover that functionality. As in give me the view's i-th line in the internal buffer.
Example code for cut and paste:
package main
import (
"fmt"
"log"
"strings"
"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.SetKeybinding("token", gocui.KeyEnter, gocui.ModNone, readToken); err != nil {
log.Panicln(err)
}
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
func readToken(g *gocui.Gui, v *gocui.View) error {
//FIXME issue is here
token := strings.TrimSpace(v.Line(0))
//token := strings.TrimSpace(v.Buffer())
g.Close()
fmt.Println("user has entered", token)
return nil
}
func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
// Overlap (front)
passLen := 25
// calculate position for centering
//TODO is this possible more easily to center a view of given size?
x0 := (maxX - passLen - 2) / 2
y0 := (maxY - 3) / 2
if v, err := g.SetView("token", x0, y0, x0+passLen+2, y0+2); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Title = "Enter security token"
v.Editable = true
v.Wrap = false
if err := g.SetCurrentView("token"); err != nil {
return err
}
}
return nil
}
Add support for editable views
Then you could transform this code:
if err := g.SetKeybinding("main", '0', 0, key0); err != nil {
return err
}
if err := g.SetKeybinding("main", '1', 0, key1); err != nil {
return err
}
// 0..9
if err := g.SetKeybinding("main", '9', 0, key9); err != nil {
return err
}
...
func key0(g *gocui.Gui, v *gocui.View) error {
}
func key1(g *gocui.Gui, v *gocui.View) error {
}
// 0..9
func key9(g *gocui.Gui, v *gocui.View) error {
}
Into something like this:
if err := g.SetKeybinding("main", '0', 0, keyPressed); err != nil {
return err
}
if err := g.SetKeybinding("main", '1', 0, keyPressed); err != nil {
return err
}
// 0..9
if err := g.SetKeybinding("main", '9', 0, keyPressed); err != nil {
return err
}
...
func keyPressed(g *gocui.Gui, v *gocui.View, key interface{}, mod Modifier) error {
}
The reason is because I want to accumulate the keys, like VI 'gg', so the keyPressed
will only accumulate the keys until the execution.
Running gocui on Microsoft Windows with a cygwin shell, no views are shown. E.g., running _example/hello.go results in no output. Looks like it hangs, but ctrl-c does exit the app.
Autoscroll view when the text overflows.
Do you have any examples that shows the right usage of editor struct?
This might be a really stupid question, but what is the easiest way to get all text from a particular view's internal buffer?
e.g. Say we Fprint
a couple of things to a view
// v being our view
fmt.Fprint(v, "My Text")
fmt.Fprint(v, "My other Text")
How can I then easily get all the text from that view, preiferbabrly as a string?
Sorry if it's a dumb question I'm still really new to Go and I've had a look around the code here but I couldn't figure it out.
Add support for colored text. E.g.: fmt.Println(v, "Regular text and [yb:Yellow bold text]")
Include the following information in README.md:
At first I was confused why your demos all exit on CTRL-C instead of ESC. Then I noticed that any handler I install for KeyEsc will be ignored. I eventually traced this back to gocui hardcoding the termbox.InputAlt input mode in the MainLoop method in gui.go. If I hack the code to set termbox.InputEsc instead, I get the behavior I want. My first instinct is that this should be the application's choice, not gocui's. However, I may be missing something about what gocui needs in order to work. Any hints?
Add helpers to read view contents:
Currently, when the Wrap flag is set to true for a view, the Line() method doesn't return the whole line, but only the part that fit in one row. The same problem exists for line highlighting as it only highlight the part on the same row instead of the whole wrapped line.
Thanks for putting together such a helpful project!
There are a lot of api breaking changes between the 0.3.0
tag and the tip of master, is there any chance the next version could bump the major version to 1
?
The _examples/stdin.go won't run for me on os/x in go 1.5 or 1.6. The program just hangs and when you kill it from another terminal it outputs this
2016/04/01 00:27:04 read /dev/stdin: input/output error
Could it be a problem with the way it's reading from stdin maybe interfering with the keybindings?
Greetings, I just wanted to catch the Escape key via a key binding, but it did not work. I used other key bindings, so they generally seem to work. I tried in different terminal emulators, checked escape sequence options. System here: recent Ubuntu Linux.
Copy-paste test program:
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.SetKeybinding("main", gocui.KeyEnter, gocui.ModNone, enterKey); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("main", gocui.KeyEsc, gocui.ModNone, escKey); err != nil {
log.Panicln(err)
}
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
}
func layout(g *gocui.Gui) error {
if v, err := g.SetView("main", 0, 0, 50, 10); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Frame = true
v.Editable = true
if err := g.SetCurrentView("main"); err != nil {
return err
}
}
return nil
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
func escKey(g *gocui.Gui, v *gocui.View) error {
fmt.Fprint(v, "ESC KEY")
return nil
}
func enterKey(g *gocui.Gui, v *gocui.View) error {
fmt.Fprint(v, "ENTER KEY")
return nil
}
Maybe this is just a wrong keycode taken over from termbox
, I dont know.
In my layout function, I am creating the view messages_box using g.SetView("messages_box", 0, 0, maxX, maxY-5)
. After using g.SetLayout(layout), I try to call messageView, err := g.View("messages_box")
, but I keep getting "unknown view."
I want to create an autocomplete widget, so I want a callback any time the user types a letter. I obviously don't want to override CtrlC (globally bound), but everything else.
Hi Roi, i think this is an awesome tool. I have a question for you in demo2.go the layout function. When I take setCurrentView() (line 165) out of the if/else, the nextView no longer works.
nextView workds as :
if v, err := g.SetView("main", 30, -1, maxX, maxY); err != nil {
......
v.Editable = true
if err := g.SetCurrentView("main"); err != nil {
return err
}
}
return nil
nextView doesn't work when :
if v, err := g.SetView("main", 30, -1, maxX, maxY); err != nil {
......
v.Editable = true
}
if err := g.SetCurrentView("main"); err != nil {
return err
}
return nil
thanks
km
Write API documentation
Then you could transform this kind of code:
if err := g.SetKeybinding("side", gocui.KeyCtrlSpace, 0, nextView); err != nil {
return err
}
if err := g.SetKeybinding("main", gocui.KeyCtrlSpace, 0, nextView); err != nil {
return err
}
Into something like this:
if err := g.SetKeybinding([]string{"main","side"}, gocui.KeyCtrlSpace, 0, nextView); err != nil {
return err
}
Need an option for a view to have no Frame.
When you do:
v.Frame = false
you still get a border, its just spaces instead of a visible line. I need a view option that consume no visual space for its border.
At this moment everything (view contets, frames, intersections) is re-drawed with every event. Only those views that have been modified should be refreshed, unless a resize event is detected.
Add mouse support (plan9).
The border characters are not good for windows. You expect │
or ┐
are single width character. but it's ambiguous width characters in unicode. They are displayed as double width characters in east asia. http://www.unicode.org/reports/tr11/
And also, I'm looking _example/demo.go, it seems not support multi-byte characters. for example, when typing あ
, it should move the cursor forwarding two cells.
It seems like delete view is not removing the associated key bindings and it causes issues on dynamic UIs.
For example, demo2.go has been used for testing purposes and its source code is not clear enough.
Implement full edition mode:
Hey! First of all, thank you so much for an awesome library! I have only been using it for a few days but I already have a version of my app working really well, thanks to how great your library is.
I am building a simple cui note taking app (https://github.com/jameycribbs/cribbnotes_cui). So far, I've been able to get pretty much everything working that I want, but I have run into an issue when saving a note to a json file. When I use the view.Buffer() method to grab the internal buffer, and I have view.Wrap=true, then the json file I save has all of the carriage returns that are getting inserted into the text because Wrap is set to true.
Is there any way to keep Wrap=true, but be able to grab the contents of the internal buffer without the carriage returns that are being inserted?
I took a look at the source code, but I didn't see a way to do this. I'm fairly new to Go, so I am probably missing something.
Thanks for any help you can give and thanks again for such a great library!
Jamey Cribbs
This looks like an awesome tool, but since it involves UI, a screenshot of a console showing off gocui would be nice.
I am trying to write some code that edits a view with vim like key-bindings. The problem I am running into is the key I press is also getting inserted. I have put together some test code to hopefully explain better.
package main
import (
"log"
"github.com/jroimartin/gocui"
)
func edit(g *gocui.Gui, v *gocui.View) error {
v.Editable = true
return nil
}
func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}
func keybindings(g *gocui.Gui) error {
if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {return err}
if err := g.SetKeybinding("main", 'i', gocui.ModNone, edit); err != nil {return err}
return nil
}
func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
if v, err := g.SetView("main", 30, -1, maxX, maxY); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Editable = false
v.Wrap = true
if _, err := g.SetCurrentView("main"); err != nil {return err}
}
return nil
}
func main() {
g, _ := gocui.NewGui()
defer g.Close()
g.SetManagerFunc(layout)
keybindings(g);
g.Cursor = true
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {log.Panicln(err)}
}
What happens is when I press the 'i' key to change the main view from not-Editable to Editable it also inserts an i character. Is there a way to prevent this?
Thank you for any help!
This is not a bug in gocui. It should be fixed in OSX (making iTerm2/Terminal.app's xterm emulation to send ESC sequences atomically) or in termbox-go (supporting the way used by iTerm2/Terminal.app to report mouse events).
More information: nsf/termbox-go#120
On OSX, when Gui.Mouse is enabled and the focus is in an editable buffer, if the terminal receives mouse events, the event loop receives an EventKey for each byte of the ESC sequence that corresponds to the mouse event. Because it is an editable buffer, these sequences end up being written in the buffer, as can be seen in the following screenshot:
This happens because iTerm2 or Terminal.app do not send the ESC sequence atomically.
Hello.
I made some roughing (but working well) code to close issue #3.
But with an independent View'ers redraw, I have a some troubles with the windows hierarchy.
If we create, for example, first window (at level "0") and second on top of previous (at level "1"), then inactive "top level" window may fall through under level "0" (in situation, when level "0" need redraw, and level "1" dosen' need, but we want level "1" on top).
I see several solutions to this situation:
I need a strong opinion of the author of the project :)
PS: sorry for my bad English
Edition mode (edit.go) is getting complex, it should be rewritten at some point.
I have a top-like application that updates views vi coroutines. I am able to update the views fine but get panic (panic: bytes.Buffer: truncation out of range) when the terminal is reset. I notice that if I do not call flush from my update code the error does not occur, but the ui does not refresh until an event is processed. How do I correctly signal to gocui that a view has changed?
Is this possible ATM with multiple windows with the same demolitions?
hi,
is there a way to add a title to the view?
If not, that'd be nice to have, it can be in the same level as the frame like https://github.com/gizak/termui does.
The syntax could be something like this:
if v, err := g.SetView(...); err != nil {
v.Title = "Title"
v.TitleAlign = "left|right|center"
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.