Add tview-and-you

This commit is contained in:
Trevor Slocum 2019-11-20 04:48:44 -08:00
parent 7387321838
commit ed8cd6d64f
8 changed files with 368 additions and 13 deletions

View File

@ -16,7 +16,7 @@ baseurl = "https://rocketnine.space/"
copyright = ""
# Enable analytics by entering your Google Analytics tracking ID
googleAnalytics = "UA-71983-61"
googleAnalytics = ""
############################
## Advanced options below ##

View File

@ -8,10 +8,10 @@
url = "#about"
weight = 10
#[[main]]
# name = "Posts"
# url = "#posts"
# weight = 20
[[main]]
name = "Posts"
url = "#posts"
weight = 20
[[main]]
name = "Projects"
@ -34,3 +34,6 @@
# name = "CV"
# url = "files/cv.pdf"
# weight = 70
[[post]]

View File

@ -36,7 +36,7 @@ logo = ""
# Enable source code highlighting? true/false
# Documentation: https://sourcethemes.com/academic/docs/writing-markdown-latex/#highlighting-options
highlight = true
highlight_languages = ["r"] # Add support for highlighting additional languages
highlight_languages = ["r", "go", "golang"] # Add support for highlighting additional languages
# highlight_style = "github" # For supported styles, see https://cdnjs.com/libraries/highlight.js/
# Enable LaTeX math rendering? true/false

View File

@ -18,7 +18,7 @@ role: Developer &amp;<br>System Administrator
# url: ""
# Short bio (displayed in user profile at end of posts)
bio: Install Gentoo
bio:
#interests:
#- Open source software
@ -72,7 +72,6 @@ email: "trevor@rocketnine.space"
I use [Linux](https://en.wikipedia.org/wiki/Linux) to write [open-source software](https://en.wikipedia.org/wiki/Open-source_software).
My projects are available on [sourcehut](https://sr.ht) and [GitLab](https://gitlab.com/users/tslocum/projects).
Be sure to check out [stick](https://git.sr.ht/~tslocum/stick) and [gophast](https://git.sr.ht/~tslocum/gophast).
My projects are available on [sourcehut](https://git.sr.ht/~tslocum) and [GitLab](https://gitlab.com/users/tslocum/projects).
Be sure to check out [stick](https://git.sr.ht/~tslocum/stick) and [netris](https://git.sr.ht/~tslocum/netris).

View File

@ -4,7 +4,7 @@
widget = "pages" # See https://sourcethemes.com/academic/docs/page-builder/
headless = true # This file represents a page section.
active = false # Activate this widget? true/false
active = true # Activate this widget? true/false
weight = 60 # Order that this section will appear.
title = "Recent Posts"

View File

@ -1,7 +1,31 @@
---
title: "Gotcha - Overiting a shared backing array when calling append"
title: "Gotcha - Up-ending a backing array"
date: 2019-09-26T21:42:18-07:00
categories: [gotcha]
draft: true
---
Test
To give better context to the problem being presented in this article, we must go over how slices work.
A slice value consists of three parts: a pointer to a backing array, a length and a capacity.
Excerpt of **runtime/slice.go** from the standard library:
```go
type slice struct {
array unsafe.Pointer
len int
cap int
}
```
When calling append on a slice whose length is the same as its capacity, a new backing array of greater size is created. The previous backing array's contents are copied.
A range of elements from a slice may be selected like so:
```go
bar := foo[4:7]
```
When calling append on such a slice,

View File

@ -0,0 +1,321 @@
---
title: "tview and you - Creating Rich Terminal User Interfaces"
date: 2019-11-08T01:42:18-07:00
categories: [tutorial]
---
<a href="https://github.com/rivo/tview/tree/master/demos/presentation"><img src="https://raw.githubusercontent.com/rivo/tview/master/tview.gif" width=640" height="446" border="0" title="tview presentation demo"></a>
This is an introduction to using [tview](https://github.com/rivo/tview) to create rich terminal-based user interfaces with Go.
## Contents
* [Primitives](#primitives)
* [Widgets](#widgets)
* [Elements](#widget-elements)
* [Containers](#widget-containers)
* [Thread Safety](#thread-safety)
* [Example Application](#example-application)
# Primitives
The [Primitive](https://godoc.org/github.com/rivo/tview#Primitive) interface is as follows:
```go
type Primitive interface {
Draw(screen tcell.Screen)
GetRect() (int, int, int, int)
SetRect(x, y, width, height int)
InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive))
Focus(delegate func(p Primitive))
Blur()
GetFocusable() Focusable
}
```
[Box](https://godoc.org/github.com/rivo/tview#Box) is the only primitive implemented.
It has a size, padding amount, optional border, optional title and background color.
# Widgets
Widgets are structs which embed a [Box](https://godoc.org/github.com/rivo/tview#Box) and build upon it.
From the [TextView](https://godoc.org/github.com/rivo/tview#TextView) declaration:
```go
type TextView struct {
*Box
// The text buffer.
buffer []string
// The text alignment, one of AlignLeft, AlignCenter, or AlignRight.
align int
// ...
}
```
Some widgets allow nesting other widgets within them, such as [Grid](https://godoc.org/github.com/rivo/tview#Grid).
Most widget commands may be chained together:
```go
nameLabel := tview.NewTextView().
SetTextAlign(tview.AlignRight).
SetDynamicColors(true).
SetWrap(true).
SetWordWrap(true).
SetText("Please enter your name:")
```
New widgets may be defined, as documented in the [Primitive demo](https://github.com/rivo/tview/tree/master/demos/primitive).
## Widget Elements
---
[**Button**](https://godoc.org/github.com/rivo/tview#Button) is a labeled box that triggers an action when selected.
```go
button := tview.NewButton("OK").SetSelectedFunc(func() {
pressedOK()
})
```
---
[**Checkbox**](https://godoc.org/github.com/rivo/tview#Checkbox) holds a label and boolean value which may be checked and unchecked.
```go
checkbox := tview.NewCheckbox().SetLabel("Toggle value with Enter: ")
```
---
[**DropDown**](https://godoc.org/github.com/rivo/tview#DropDown) holds one or more options which may be selected as a dropdown list.
```go
dropdown := tview.NewDropDown().
SetLabel("Select an option with Enter: ").
SetOptions([]string{"Foo", "Bar", "Baz"}, nil)
```
---
[**InputField**](https://godoc.org/github.com/rivo/tview#InputField) is a box where text may be entered.
```go
inputField := tview.NewInputField().
SetLabel("Name: ").
SetPlaceholder("John Smith").
SetFieldWidth(14).
SetDoneFunc(func(key tcell.Key) {
processName()
})
```
---
[**Modal**](https://godoc.org/github.com/rivo/tview#Modal) is a centered message window which may have one or more buttons.
```go
modal := tview.NewModal().
SetText("Are you sure you want to exit?").
AddButtons([]string{"Cancel", "Quit"}).
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
if buttonIndex == 1 {
app.Stop()
}
})
```
---
[**TextView**](https://godoc.org/github.com/rivo/tview#TextView) is a box containing text.
[Colored text](https://godoc.org/github.com/rivo/tview#hdr-Colors) is supported when enabled.
```go
textView := tview.NewTextView().
SetWrap(true).
SetWordWrap(true).
SetText("Hello, World!")
```
---
## Widget Containers
---
[**Flex**](https://godoc.org/github.com/rivo/tview#Flex) is a [flexbox layout](https://en.wikipedia.org/wiki/CSS_Flexible_Box_Layout) container.
See the [Flex demo](https://github.com/rivo/tview/tree/master/demos/flex) for example usage.
---
[**Grid**](https://godoc.org/github.com/rivo/tview#Grid) is a [grid layout](https://en.wikipedia.org/wiki/CSS_grid_layout) container.
See the [Grid demo](https://github.com/rivo/tview/tree/master/demos/grid) for example usage.
---
[**Form**](https://godoc.org/github.com/rivo/tview#Form) displays one or more form elements in a vertical or horizontal layout.
See the [Form demo](https://github.com/rivo/tview/tree/master/demos/form) for example usage.
---
[**List**](https://godoc.org/github.com/rivo/tview#List) displays one or more widgets as a selectable list.
See the [List demo](https://github.com/rivo/tview/tree/master/demos/list) for example usage.
---
[**Pages**](https://godoc.org/github.com/rivo/tview#Pages) displays one or more widgets at a time.
See the [Pages demo](https://github.com/rivo/tview/tree/master/demos/pages) for example usage.
---
[**Table**](https://godoc.org/github.com/rivo/tview#Table) displays one or more widgets in rows and columns.
See the [Table demo](https://github.com/rivo/tview/tree/master/demos/table) for example usage.
---
[**TreeView**](https://godoc.org/github.com/rivo/tview#TreeView) displays one or more widgets in a tree.
See the [TreeView demo](https://github.com/rivo/tview/tree/master/demos/treeview) for example usage.
---
# Thread Safety
**Most tview functions cannot safely be called from any thread except the main one**.
Using either of the following functions, we can queue a function to be executed in the main thread.
* [Application.QueueUpdate](https://godoc.org/github.com/rivo/tview#Application.QueueUpdate)
* [Application.QueueUpdateDraw](https://godoc.org/github.com/rivo/tview#Application.QueueUpdateDraw)
The only difference between the two is that QueueUpdateDraw calls [Application.Draw](https://godoc.org/github.com/rivo/tview#Application.Draw) after the queued function returns.
One exception is [TextView.Write](https://godoc.org/github.com/rivo/tview#TextView.Write), which may safely be called from multiple goroutines.
Below is an example of setting a new root primitive from another goroutine.
```go
app.QueueUpdateDraw(func() {
app.SetRoot(appGrid, true)
})
```
# Example Application
A tview application is constructed of a running [Application](https://godoc.org/github.com/rivo/tview#Application) with at least one root widget.
To display a primitive (and its contents), we call [Application.SetRoot](https://godoc.org/github.com/rivo/tview#Application.SetRoot).
This function has two arguments, a primitive which will become the root of the screen, and a boolean which controls whether the primitive will be resized to fit the screen.
In this example, the root is a Grid containing a label, an input and a submit button. For a more complex example, see [netris](https://git.sr.ht/~tslocum/netris).
Install tview if you haven't already:
```command
go get -u github.com/rivo/tview
```
Then create a file named greet.go:
```go
package main
import (
"fmt"
"log"
"strings"
"github.com/gdamore/tcell"
"github.com/rivo/tview"
)
func main() {
// Initialize application
app := tview.NewApplication()
// Create label
label := tview.NewTextView().SetText("Please enter your name:")
// Create input field
input := tview.NewInputField()
// Create submit button
btn := tview.NewButton("Submit")
// Create empty Box to pad each side of appGrid
bx := tview.NewBox()
// Create Grid containing the application's widgets
appGrid := tview.NewGrid().
SetColumns(-1, 24, 16, -1).
SetRows(-1, 2, 3, -1).
AddItem(bx, 0, 0, 3, 1, 0, 0, false). // Left - 3 rows
AddItem(bx, 0, 1, 1, 1, 0, 0, false). // Top - 1 row
AddItem(bx, 0, 3, 3, 1, 0, 0, false). // Right - 3 rows
AddItem(bx, 3, 1, 1, 1, 0, 0, false). // Bottom - 1 row
AddItem(label, 1, 1, 1, 1, 0, 0, false).
AddItem(input, 1, 2, 1, 1, 0, 0, false).
AddItem(btn, 2, 1, 1, 2, 0, 0, false)
// submittedName is toggled each time Enter is pressed
var submittedName bool
// Capture user input
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
// Anything handled here will be executed on the main thread
switch event.Key() {
case tcell.KeyEnter:
submittedName = !submittedName
if submittedName {
name := input.GetText()
if strings.TrimSpace(name) == "" {
name = "Anonymous"
}
// Create a modal dialog
m := tview.NewModal().
SetText(fmt.Sprintf("Greetings, %s!", name)).
AddButtons([]string{"Hello"})
// Display and focus the dialog
app.SetRoot(m, true).SetFocus(m)
} else {
// Clear the input field
input.SetText("")
// Display appGrid and focus the input field
app.SetRoot(appGrid, true).SetFocus(input)
}
return nil
case tcell.KeyEsc:
// Exit the application
app.Stop()
return nil
}
return event
})
// Set the grid as the application root and focus the input field
app.SetRoot(appGrid, true).SetFocus(input)
// Run the application
err := app.Run()
if err != nil {
log.Fatal(err)
}
}
```

View File

@ -0,0 +1,8 @@
---
title: netris
summary: Multiplayer Tetris clone
tags:
- Go
external_link: "https://git.sr.ht/~tslocum/netris"
---