diff --git a/.all-contributorsrc b/.all-contributorsrc
index ffcfda6e..3f2e2922 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -469,6 +469,13 @@
"name": "Levi Baber",
"avatar_url": "https://avatars0.githubusercontent.com/u/5819098?v=4",
"profile": "http://researchit.las.iastate.edu",
+ "contributions": []
+ },
+ {
+ "login": "gnanderson",
+ "name": "Graham Anderson",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/38514?v=4",
+ "profile": "https://github.com/gnanderson",
"contributions": [
]
}
diff --git a/.goreleaser.yml b/.goreleaser.yml
index ba068113..28c8c267 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -7,6 +7,7 @@ builds:
goos:
- darwin
- linux
+ - windows
goarch:
- 386
- amd64
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ceb890e2..16260f07 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,22 @@
### ⚡️ Added
+* DataDog module is now scrollable and interactive, by [@Seanstoppable](https://github.com/Seanstoppable)
+* Focusable hot key numbers are now assigned in a stable order, [#435](https://github.com/wtfutil/wtf/issues/435) by [@Seanstoppable](https://github.com/Seanstoppable)
+* Zendesk widget now has help text, by [@Seanstoppable](https://github.com/Seanstoppable)
+* Scrollable widget added to provide common keyboard-navigation list functionality, by [@Seanstoppable](https://github.com/Seanstoppable)
+* Logging functionality extracted out from Log module, by [@Seanstoppable](https://github.com/Seanstoppable)
+
+## v0.9.2
+
+### ⚡️ Added
+
* Keyboard management system for modules reworked. Now has a KeyboardWidget to simplify adding keyboard commands
+### Fixed
+
+* WTF versions are now prefixed with `v` again so module systems pick up the latest versions
+
## 0.9.1
### ⚡️ Added
diff --git a/README.md b/README.md
index 55b185c9..5af71087 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-[](#contributors)
+[](#contributors)
[](https://travis-ci.com/wtfutil/wtf)
[](https://gitter.im/wtfutil/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[](https://twitter.com/wtfutil)
@@ -97,7 +97,7 @@ Dependency management in WTF is handled by [Go modules](https://github.com/golan
| [
Renán Romero](http://www.romeroruiz.com)
| [
Bastian Groß](https://github.com/sticreations)
| [
nicholas-eden](https://github.com/nicholas-eden)
| [
Dan Rabinowitz](https://github.com/danrabinowitz)
| [
David Missmann](https://github.com/dvdmssmnn)
| [
Mathias Weber](https://github.com/mweb)
| [
TheRedSpy15](https://github.com/TheRedSpy15)
|
| [
Harald Nordgren](https://www.linkedin.com/in/harald-nordgren-44778192)
| [
Matei Alexandru Gardus](http://stormfirefox1.github.io)
| [
Sean Smith](https://github.com/Seanstoppable)
| [
Halil Kaskavalci](http://kaskavalci.com)
| [
Johan Denoyer](http://www.johandenoyer.fr)
| [
Jelle Vink](https://skymeyer.be)
| [
Devin Collins](http://imdevinc.com)
|
| [
Danne Stayskal](http://danne.stayskal.com/)
| [
Max Beizer](https://www.maxbeizer.com)
| [
E:V:A](http://tinyurl.com/nwmj4as)
| [
Gabriel](https://github.com/GaboFDC)
| [
Andrew Scibek](https://github.com/AndrewScibek)
| [
FriedCosey](https://github.com/FriedCosey)
| [
Michele Gerarduzzi](https://michelegera.dev/)
|
-| [
Jack Morris](https://github.com/rudolphjacksonm)
| [
foorb](https://github.com/foorb)
| [
Levi Baber](http://researchit.las.iastate.edu)
|
+| [
Jack Morris](https://github.com/rudolphjacksonm)
| [
foorb](https://github.com/foorb)
| [
Levi Baber](http://researchit.las.iastate.edu)
| [
Graham Anderson](https://github.com/gnanderson)
|
## Acknowledgments
diff --git a/flags/flags.go b/flags/flags.go
index 8f3e9af9..05da8042 100644
--- a/flags/flags.go
+++ b/flags/flags.go
@@ -7,7 +7,7 @@ import (
goFlags "github.com/jessevdk/go-flags"
"github.com/wtfutil/wtf/help"
- "github.com/wtfutil/wtf/wtf"
+ "github.com/wtfutil/wtf/utils"
)
type Flags struct {
@@ -63,7 +63,7 @@ func (flags *Flags) Parse() {
// If no config file is explicitly passed in as a param,
// set the flag to the default config file
if !flags.HasConfig() {
- homeDir, err := wtf.Home()
+ homeDir, err := utils.Home()
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
diff --git a/generator/textwidget.tpl b/generator/textwidget.tpl
index 3c1e6513..f39df08e 100644
--- a/generator/textwidget.tpl
+++ b/generator/textwidget.tpl
@@ -18,7 +18,6 @@ type Widget struct {
wtf.KeyboardWidget
wtf.TextWidget
- app *tview.Application
settings *Settings
}
@@ -28,15 +27,12 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
KeyboardWidget: wtf.NewKeyboardWidget(),
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
- widget.unselect()
-
widget.View.SetScrollable(true)
widget.View.SetRegions(true)
@@ -50,22 +46,11 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
func (widget *Widget) Refresh() {
// The last call should always be to the display function
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
}
/* -------------------- Unexported Functions -------------------- */
func (widget *Widget) display() {
- widget.View.SetWrap(false)
-
- widget.View.Clear()
- widget.View.SetText("Some Text")
- widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
+ widget.Redraw(widget.CommonSettings.Title, "Some text", false)
}
-
-func (widget *Widget) unselect() {
- widget.selected = -1
- widget.display()
-}
\ No newline at end of file
diff --git a/logger/log.go b/logger/log.go
index 3e45aac8..c095ea42 100644
--- a/logger/log.go
+++ b/logger/log.go
@@ -1,46 +1,21 @@
package logger
import (
- "fmt"
"log"
"os"
"path/filepath"
- "strings"
- "github.com/rivo/tview"
- "github.com/wtfutil/wtf/wtf"
+ "github.com/wtfutil/wtf/utils"
)
-const maxBufferSize int64 = 1024
-
-type Widget struct {
- wtf.TextWidget
-
- app *tview.Application
- filePath string
- settings *Settings
-}
-
-func NewWidget(app *tview.Application, settings *Settings) *Widget {
- widget := Widget{
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
-
- app: app,
- filePath: logFilePath(),
- settings: settings,
- }
-
- return &widget
-}
-
/* -------------------- Exported Functions -------------------- */
func Log(msg string) {
- if logFileMissing() {
+ if LogFileMissing() {
return
}
- f, err := os.OpenFile(logFilePath(), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
+ f, err := os.OpenFile(LogFilePath(), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
@@ -50,87 +25,15 @@ func Log(msg string) {
log.Println(msg)
}
-// Refresh updates the onscreen contents of the widget
-func (widget *Widget) Refresh() {
- if logFileMissing() {
- return
- }
-
- logLines := widget.tailFile()
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.CommonSettings.Title)
- widget.View.SetText(widget.contentFrom(logLines))
- })
+func LogFileMissing() bool {
+ return LogFilePath() == ""
}
-/* -------------------- Unexported Functions -------------------- */
-
-func (widget *Widget) contentFrom(logLines []string) string {
- str := ""
-
- for _, line := range logLines {
- chunks := strings.Split(line, " ")
-
- if len(chunks) >= 4 {
- str = str + fmt.Sprintf(
- "[green]%s[white] [yellow]%s[white] %s\n",
- chunks[0],
- chunks[1],
- strings.Join(chunks[3:], " "),
- )
- }
- }
-
- return str
-}
-
-func logFileMissing() bool {
- return logFilePath() == ""
-}
-
-func logFilePath() string {
- dir, err := wtf.Home()
+func LogFilePath() string {
+ dir, err := utils.Home()
if err != nil {
return ""
}
return filepath.Join(dir, ".config", "wtf", "log.txt")
}
-
-func (widget *Widget) tailFile() []string {
- file, err := os.Open(widget.filePath)
- if err != nil {
- return []string{}
- }
- defer file.Close()
-
- stat, err := file.Stat()
- if err != nil {
- return []string{}
- }
-
- bufferSize := maxBufferSize
- if maxBufferSize > stat.Size() {
- bufferSize = stat.Size()
- }
-
- startPos := stat.Size() - bufferSize
-
- buff := make([]byte, bufferSize)
- _, err = file.ReadAt(buff, startPos)
- if err != nil {
- return []string{}
- }
-
- logLines := strings.Split(string(buff), "\n")
-
- // Reverse the array of lines
- // Offset by two to account for the blank line at the end
- last := len(logLines) - 2
- for i := 0; i < len(logLines)/2; i++ {
- logLines[i], logLines[last-i] = logLines[last-i], logLines[i]
- }
-
- return logLines
-}
diff --git a/main.go b/main.go
index 6cc080a3..1b6cb4e3 100644
--- a/main.go
+++ b/main.go
@@ -18,6 +18,7 @@ import (
"github.com/wtfutil/wtf/cfg"
"github.com/wtfutil/wtf/flags"
"github.com/wtfutil/wtf/maker"
+ "github.com/wtfutil/wtf/utils"
"github.com/wtfutil/wtf/wtf"
)
@@ -65,7 +66,7 @@ func refreshAllWidgets(widgets []wtf.Wtfable) {
func watchForConfigChanges(app *tview.Application, configFilePath string, grid *tview.Grid, pages *tview.Pages) {
watch := watcher.New()
- absPath, _ := wtf.ExpandHomeDir(configFilePath)
+ absPath, _ := utils.ExpandHomeDir(configFilePath)
// Notify write events
watch.FilterOps(watcher.Write)
diff --git a/maker/widget_maker.go b/maker/widget_maker.go
index 521559a1..40e528a3 100644
--- a/maker/widget_maker.go
+++ b/maker/widget_maker.go
@@ -3,7 +3,6 @@ package maker
import (
"github.com/olebedev/config"
"github.com/rivo/tview"
- "github.com/wtfutil/wtf/logger"
"github.com/wtfutil/wtf/modules/bamboohr"
"github.com/wtfutil/wtf/modules/bargraph"
"github.com/wtfutil/wtf/modules/circleci"
@@ -25,6 +24,7 @@ import (
"github.com/wtfutil/wtf/modules/ipaddresses/ipinfo"
"github.com/wtfutil/wtf/modules/jenkins"
"github.com/wtfutil/wtf/modules/jira"
+ "github.com/wtfutil/wtf/modules/logger"
"github.com/wtfutil/wtf/modules/mercurial"
"github.com/wtfutil/wtf/modules/nbascore"
"github.com/wtfutil/wtf/modules/newrelic"
@@ -90,7 +90,7 @@ func MakeWidget(
widget = cryptolive.NewWidget(app, settings)
case "datadog":
settings := datadog.NewSettingsFromYAML(widgetName, moduleConfig, globalConfig)
- widget = datadog.NewWidget(app, settings)
+ widget = datadog.NewWidget(app, pages, settings)
case "gcal":
settings := gcal.NewSettingsFromYAML(widgetName, moduleConfig, globalConfig)
widget = gcal.NewWidget(app, settings)
@@ -198,7 +198,7 @@ func MakeWidget(
widget = weather.NewWidget(app, pages, settings)
case "zendesk":
settings := zendesk.NewSettingsFromYAML(widgetName, moduleConfig, globalConfig)
- widget = zendesk.NewWidget(app, settings)
+ widget = zendesk.NewWidget(app, pages, settings)
default:
settings := unknown.NewSettingsFromYAML(widgetName, moduleConfig, globalConfig)
widget = unknown.NewWidget(app, settings)
diff --git a/modules/bamboohr/widget.go b/modules/bamboohr/widget.go
index 890144b1..8885fe6c 100644
--- a/modules/bamboohr/widget.go
+++ b/modules/bamboohr/widget.go
@@ -42,10 +42,7 @@ func (widget *Widget) Refresh() {
wtf.Now().Format(wtf.DateFormat),
)
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.View.SetText(widget.contentFrom(todayItems))
- })
+ widget.Redraw(widget.CommonSettings.Title, widget.contentFrom(todayItems), false)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/circleci/widget.go b/modules/circleci/widget.go
index 718d6998..64f09b1b 100644
--- a/modules/circleci/widget.go
+++ b/modules/circleci/widget.go
@@ -11,7 +11,6 @@ type Widget struct {
wtf.TextWidget
*Client
- app *tview.Application
settings *Settings
}
@@ -20,7 +19,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
TextWidget: wtf.NewTextWidget(app, settings.common, false),
Client: NewClient(settings.apiKey),
- app: app,
settings: settings,
}
@@ -36,19 +34,17 @@ func (widget *Widget) Refresh() {
builds, err := widget.Client.BuildsFor()
+ title := fmt.Sprintf("%s - Builds", widget.CommonSettings.Title)
var content string
+ wrap := false
if err != nil {
- widget.View.SetWrap(true)
+ wrap = true
content = err.Error()
} else {
- widget.View.SetWrap(false)
content = widget.contentFrom(builds)
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(fmt.Sprintf("%s - Builds", widget.CommonSettings.Title))
- widget.View.SetText(content)
- })
+ widget.Redraw(title, content, wrap)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/clocks/display.go b/modules/clocks/display.go
index 9448aa06..58e46e52 100644
--- a/modules/clocks/display.go
+++ b/modules/clocks/display.go
@@ -27,5 +27,5 @@ func (widget *Widget) display(clocks []Clock, dateFormat string, timeFormat stri
)
}
- widget.View.SetText(str)
+ widget.Redraw(widget.CommonSettings.Title, str, false)
}
diff --git a/modules/cmdrunner/widget.go b/modules/cmdrunner/widget.go
index 83cd37fc..6ecbdf6e 100644
--- a/modules/cmdrunner/widget.go
+++ b/modules/cmdrunner/widget.go
@@ -12,7 +12,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
args []string
cmd string
settings *Settings
@@ -23,7 +22,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
args: settings.args,
cmd: settings.cmd,
settings: settings,
@@ -41,10 +39,7 @@ func (widget *Widget) Refresh() {
ansiTitle := tview.TranslateANSI(widget.String())
ansiResult := tview.TranslateANSI(result)
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(ansiTitle)
- widget.View.SetText(ansiResult)
- })
+ widget.Redraw(ansiTitle, ansiResult, false)
}
// String returns the string representation of the widget
diff --git a/modules/datadog/keyboard.go b/modules/datadog/keyboard.go
new file mode 100644
index 00000000..58daa141
--- /dev/null
+++ b/modules/datadog/keyboard.go
@@ -0,0 +1,17 @@
+package datadog
+
+import (
+ "github.com/gdamore/tcell"
+)
+
+func (widget *Widget) initializeKeyboardControls() {
+ widget.SetKeyboardChar("/", widget.ShowHelp)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
+ widget.SetKeyboardChar("o", widget.openItem)
+
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
+ widget.SetKeyboardKey(tcell.KeyEnter, widget.openItem)
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
+}
diff --git a/modules/datadog/widget.go b/modules/datadog/widget.go
index c8a9665c..3f9dbb79 100644
--- a/modules/datadog/widget.go
+++ b/modules/datadog/widget.go
@@ -8,21 +8,43 @@ import (
datadog "github.com/zorkian/go-datadog-api"
)
-type Widget struct {
- wtf.TextWidget
+const HelpText = `
+ Keyboard commands for Datadog:
- app *tview.Application
+ /: Show/hide this help window
+ j: Select the next item in the list
+ k: Select the previous item in the list
+
+ arrow down: Select the next item in the list
+ arrow up: Select the previous item in the list
+
+ return: Open the selected issue in a browser
+`
+
+type Widget struct {
+ wtf.HelpfulWidget
+ wtf.KeyboardWidget
+ wtf.ScrollableWidget
+
+ monitors []datadog.Monitor
settings *Settings
}
-func NewWidget(app *tview.Application, settings *Settings) *Widget {
+func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
- TextWidget: wtf.NewTextWidget(app, settings.common, false),
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
+ KeyboardWidget: wtf.NewKeyboardWidget(),
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
- app: app,
settings: settings,
}
+ widget.SetRenderFunction(widget.Render)
+ widget.initializeKeyboardControls()
+ widget.View.SetInputCapture(widget.InputCapture)
+
+ widget.HelpfulWidget.SetView(widget.View)
+
return &widget
}
@@ -31,26 +53,12 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
func (widget *Widget) Refresh() {
monitors, monitorErr := widget.Monitors()
- var content string
if monitorErr != nil {
- widget.View.SetWrap(true)
- content = monitorErr.Error()
- } else {
- widget.View.SetWrap(false)
- content = widget.contentFrom(monitors)
+ widget.monitors = nil
+ widget.SetItemCount(0)
+ widget.Redraw(widget.CommonSettings.Title, monitorErr.Error(), true)
+ return
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.View.Clear()
- widget.View.SetText(content)
- })
-}
-
-/* -------------------- Unexported Functions -------------------- */
-
-func (widget *Widget) contentFrom(monitors []datadog.Monitor) string {
- var str string
-
triggeredMonitors := []datadog.Monitor{}
for _, monitor := range monitors {
@@ -60,13 +68,34 @@ func (widget *Widget) contentFrom(monitors []datadog.Monitor) string {
triggeredMonitors = append(triggeredMonitors, monitor)
}
}
+ widget.monitors = triggeredMonitors
+ widget.SetItemCount(len(widget.monitors))
+
+ widget.Render()
+}
+
+func (widget *Widget) Render() {
+ content := widget.contentFrom(widget.monitors)
+ widget.Redraw(widget.CommonSettings.Title, content, false)
+}
+
+/* -------------------- Unexported Functions -------------------- */
+
+func (widget *Widget) contentFrom(triggeredMonitors []datadog.Monitor) string {
+ var str string
+
if len(triggeredMonitors) > 0 {
str = str + fmt.Sprintf(
" %s\n",
"[red]Triggered Monitors[white]",
)
- for _, triggeredMonitor := range triggeredMonitors {
- str = str + fmt.Sprintf("[red] %s\n", *triggeredMonitor.Name)
+ for idx, triggeredMonitor := range triggeredMonitors {
+ str = str + fmt.Sprintf(`["%d"][%s][red] %s[%s][""]`,
+ idx,
+ widget.RowColor(idx),
+ *triggeredMonitor.Name,
+ widget.RowColor(idx),
+ ) + "\n"
}
} else {
str = str + fmt.Sprintf(
@@ -77,3 +106,12 @@ func (widget *Widget) contentFrom(monitors []datadog.Monitor) string {
return str
}
+
+func (widget *Widget) openItem() {
+
+ sel := widget.GetSelected()
+ if sel >= 0 && widget.monitors != nil && sel < len(widget.monitors) {
+ item := &widget.monitors[sel]
+ wtf.OpenFile(fmt.Sprintf("https://app.datadoghq.com/monitors/%d?q=*", *item.Id))
+ }
+}
diff --git a/modules/gcal/client.go b/modules/gcal/client.go
index ee475af5..23c45601 100644
--- a/modules/gcal/client.go
+++ b/modules/gcal/client.go
@@ -19,7 +19,7 @@ import (
"time"
"github.com/wtfutil/wtf/cfg"
- "github.com/wtfutil/wtf/wtf"
+ "github.com/wtfutil/wtf/utils"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/calendar/v3"
@@ -30,7 +30,7 @@ import (
func (widget *Widget) Fetch() ([]*CalEvent, error) {
ctx := context.Background()
- secretPath, _ := wtf.ExpandHomeDir(widget.settings.secretFile)
+ secretPath, _ := utils.ExpandHomeDir(widget.settings.secretFile)
b, err := ioutil.ReadFile(secretPath)
if err != nil {
@@ -123,7 +123,7 @@ func isAuthenticated() bool {
}
func (widget *Widget) authenticate() {
- secretPath, _ := wtf.ExpandHomeDir(widget.settings.secretFile)
+ secretPath, _ := utils.ExpandHomeDir(widget.settings.secretFile)
b, err := ioutil.ReadFile(secretPath)
if err != nil {
diff --git a/modules/gcal/display.go b/modules/gcal/display.go
index 749fa81b..65ee7221 100644
--- a/modules/gcal/display.go
+++ b/modules/gcal/display.go
@@ -29,16 +29,12 @@ func (widget *Widget) display() {
return
}
- widget.mutex.Lock()
- defer widget.mutex.Unlock()
-
- widget.View.SetTitle(widget.ContextualTitle(widget.settings.common.Title))
- widget.View.SetText(widget.contentFrom(widget.calEvents))
+ widget.TextWidget.Redraw(widget.settings.common.Title, widget.contentFrom(widget.calEvents), false)
}
func (widget *Widget) contentFrom(calEvents []*CalEvent) string {
if (calEvents == nil) || (len(calEvents) == 0) {
- return ""
+ return "No calendar events"
}
var str string
@@ -217,7 +213,7 @@ func (widget *Widget) responseIcon(calEvent *CalEvent) string {
switch calEvent.ResponseFor(widget.settings.email) {
case "accepted":
- return icon + "✔︎"
+ return icon + "✔"
case "declined":
return icon + "✘"
case "needsAction":
diff --git a/modules/gcal/widget.go b/modules/gcal/widget.go
index ccc22efc..964fc4e3 100644
--- a/modules/gcal/widget.go
+++ b/modules/gcal/widget.go
@@ -1,9 +1,6 @@
package gcal
import (
- "sync"
- "time"
-
"github.com/rivo/tview"
"github.com/wtfutil/wtf/wtf"
)
@@ -13,8 +10,6 @@ type Widget struct {
app *tview.Application
calEvents []*CalEvent
- ch chan struct{}
- mutex sync.Mutex
settings *Settings
}
@@ -23,27 +18,21 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
TextWidget: wtf.NewTextWidget(app, settings.common, true),
app: app,
- ch: make(chan struct{}),
settings: settings,
}
- go updateLoop(&widget)
-
return &widget
}
/* -------------------- Exported Functions -------------------- */
func (widget *Widget) Disable() {
- close(widget.ch)
widget.TextWidget.Disable()
}
func (widget *Widget) Refresh() {
if isAuthenticated() {
- widget.app.QueueUpdateDraw(func() {
- widget.fetchAndDisplayEvents()
- })
+ widget.fetchAndDisplayEvents()
return
}
@@ -61,27 +50,5 @@ func (widget *Widget) fetchAndDisplayEvents() {
widget.calEvents = calEvents
}
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
-}
-
-func updateLoop(widget *Widget) {
- if widget.settings.textInterval == 0 {
- return
- }
-
- tick := time.NewTicker(time.Duration(widget.settings.textInterval) * time.Second)
- defer tick.Stop()
-outer:
- for {
- select {
- case <-tick.C:
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
- case <-widget.ch:
- break outer
- }
- }
+ widget.display()
}
diff --git a/modules/gerrit/display.go b/modules/gerrit/display.go
index ecb048a7..8fc9e188 100644
--- a/modules/gerrit/display.go
+++ b/modules/gerrit/display.go
@@ -8,11 +8,11 @@ func (widget *Widget) display() {
project := widget.currentGerritProject()
if project == nil {
- widget.View.SetText(fmt.Sprintf("%s", " Gerrit project data is unavailable (1)"))
+ widget.Redraw(widget.CommonSettings.Title, "Gerrit project data is unavailable", true)
return
}
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s- %s", widget.CommonSettings.Title, widget.title(project))))
+ title := fmt.Sprintf("%s- %s", widget.CommonSettings.Title, widget.title(project))
_, _, width, _ := widget.View.GetRect()
str := widget.settings.common.SigilStr(len(widget.GerritProjects), widget.Idx, width) + "\n"
@@ -25,7 +25,7 @@ func (widget *Widget) display() {
str = str + " [red]My Outgoing Reviews[white]\n"
str = str + widget.displayMyOutgoingReviews(project, widget.settings.username)
- widget.View.SetText(str)
+ widget.Redraw(title, str, false)
}
func (widget *Widget) displayMyIncomingReviews(project *GerritProject, username string) string {
diff --git a/modules/gerrit/widget.go b/modules/gerrit/widget.go
index 41de5bce..e1536ce0 100644
--- a/modules/gerrit/widget.go
+++ b/modules/gerrit/widget.go
@@ -39,7 +39,6 @@ type Widget struct {
GerritProjects []*GerritProject
Idx int
- app *tview.Application
selected int
settings *Settings
}
@@ -56,7 +55,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
Idx: 0,
- app: app,
settings: settings,
}
@@ -99,9 +97,7 @@ func (widget *Widget) Refresh() {
if err != nil {
widget.View.SetWrap(true)
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(err.Error())
- })
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
return
}
widget.gerrit = gerrit
@@ -111,10 +107,7 @@ func (widget *Widget) Refresh() {
project.Refresh(widget.settings.username)
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.display()
- })
+ widget.display()
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/git/display.go b/modules/git/display.go
index 4db18818..85712c2c 100644
--- a/modules/git/display.go
+++ b/modules/git/display.go
@@ -9,12 +9,11 @@ import (
func (widget *Widget) display() {
repoData := widget.currentData()
if repoData == nil {
- widget.View.SetText(" Git repo data is unavailable ")
+ widget.Redraw(widget.CommonSettings.Title, " Git repo data is unavailable ", false)
return
}
title := fmt.Sprintf("%s - [green]%s[white]", widget.CommonSettings.Title, repoData.Repository)
- widget.View.SetTitle(widget.ContextualTitle(title))
_, _, width, _ := widget.View.GetRect()
str := widget.settings.common.SigilStr(len(widget.GitRepos), widget.Idx, width) + "\n"
@@ -25,7 +24,7 @@ func (widget *Widget) display() {
str = str + "\n"
str = str + widget.formatCommits(repoData.Commits)
- widget.View.SetText(str)
+ widget.Redraw(title, str, false)
}
func (widget *Widget) formatChanges(data []string) string {
diff --git a/modules/git/widget.go b/modules/git/widget.go
index 0c44252c..41026d6c 100644
--- a/modules/git/widget.go
+++ b/modules/git/widget.go
@@ -97,9 +97,7 @@ func (widget *Widget) Refresh() {
return widget.GitRepos[i].Path < widget.GitRepos[j].Path
})
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
}
/* -------------------- Unexported Functions -------------------- */
@@ -125,9 +123,11 @@ func (widget *Widget) addCancelButton(form *tview.Form) {
}
func (widget *Widget) modalFocus(form *tview.Form) {
- frame := widget.modalFrame(form)
- widget.pages.AddPage("modal", frame, false, true)
- widget.app.SetFocus(frame)
+ widget.app.QueueUpdateDraw(func() {
+ frame := widget.modalFrame(form)
+ widget.pages.AddPage("modal", frame, false, true)
+ widget.app.SetFocus(frame)
+ })
}
func (widget *Widget) modalForm(lbl, text string) *tview.Form {
diff --git a/modules/github/display.go b/modules/github/display.go
index 68f8edf0..8d49d65d 100644
--- a/modules/github/display.go
+++ b/modules/github/display.go
@@ -8,13 +8,12 @@ import (
func (widget *Widget) display() {
repo := widget.currentGithubRepo()
+ title := fmt.Sprintf("%s - %s", widget.CommonSettings.Title, widget.title(repo))
if repo == nil {
- widget.View.SetText(" GitHub repo data is unavailable ")
+ widget.TextWidget.Redraw(title, " GitHub repo data is unavailable ", false)
return
}
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.CommonSettings.Title, widget.title(repo))))
-
_, _, width, _ := widget.View.GetRect()
str := widget.settings.common.SigilStr(len(widget.GithubRepos), widget.Idx, width) + "\n"
str = str + " [red]Stats[white]\n"
@@ -26,7 +25,7 @@ func (widget *Widget) display() {
str = str + " [red]My Pull Requests[white]\n"
str = str + widget.displayMyPullRequests(repo, widget.settings.username)
- widget.View.SetText(str)
+ widget.TextWidget.Redraw(title, str, false)
}
func (widget *Widget) displayMyPullRequests(repo *GithubRepo, username string) string {
diff --git a/modules/gitlab/display.go b/modules/gitlab/display.go
index 2501d11c..040bef5f 100644
--- a/modules/gitlab/display.go
+++ b/modules/gitlab/display.go
@@ -8,11 +8,11 @@ func (widget *Widget) display() {
project := widget.currentGitlabProject()
if project == nil {
- widget.View.SetText(" Gitlab project data is unavailable ")
+ widget.Redraw(widget.CommonSettings.Title, " Gitlab project data is unavailable ", true)
return
}
- widget.View.SetTitle(fmt.Sprintf("%s- %s", widget.CommonSettings.Title, widget.title(project)))
+ title := fmt.Sprintf("%s- %s", widget.CommonSettings.Title, widget.title(project))
_, _, width, _ := widget.View.GetRect()
str := widget.settings.common.SigilStr(len(widget.GitlabProjects), widget.Idx, width) + "\n"
@@ -24,8 +24,7 @@ func (widget *Widget) display() {
str = str + "\n"
str = str + " [red]My Merge Requests[white]\n"
str = str + widget.displayMyMergeRequests(project, widget.settings.username)
-
- widget.View.SetText(str)
+ widget.Redraw(title, str, false)
}
func (widget *Widget) displayMyMergeRequests(project *GitlabProject, username string) string {
diff --git a/modules/gitlab/widget.go b/modules/gitlab/widget.go
index d28ffaed..05aebe62 100644
--- a/modules/gitlab/widget.go
+++ b/modules/gitlab/widget.go
@@ -26,7 +26,6 @@ type Widget struct {
GitlabProjects []*GitlabProject
Idx int
- app *tview.Application
gitlab *glb.Client
settings *Settings
}
@@ -46,7 +45,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
Idx: 0,
- app: app,
gitlab: gitlab,
settings: settings,
}
@@ -68,9 +66,7 @@ func (widget *Widget) Refresh() {
project.Refresh()
}
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
}
func (widget *Widget) Next() {
diff --git a/modules/gitter/keyboard.go b/modules/gitter/keyboard.go
index 250b2f8a..77abbc84 100644
--- a/modules/gitter/keyboard.go
+++ b/modules/gitter/keyboard.go
@@ -4,11 +4,11 @@ import "github.com/gdamore/tcell"
func (widget *Widget) initializeKeyboardControls() {
widget.SetKeyboardChar("/", widget.ShowHelp)
- widget.SetKeyboardChar("j", widget.next)
- widget.SetKeyboardChar("k", widget.prev)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
widget.SetKeyboardChar("r", widget.Refresh)
- widget.SetKeyboardKey(tcell.KeyDown, widget.next)
- widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect)
- widget.SetKeyboardKey(tcell.KeyUp, widget.prev)
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
}
diff --git a/modules/gitter/widget.go b/modules/gitter/widget.go
index 2acf0893..a0976871 100644
--- a/modules/gitter/widget.go
+++ b/modules/gitter/widget.go
@@ -2,7 +2,6 @@ package gitter
import (
"fmt"
- "strconv"
"github.com/rivo/tview"
"github.com/wtfutil/wtf/wtf"
@@ -24,33 +23,26 @@ const HelpText = `
type Widget struct {
wtf.HelpfulWidget
wtf.KeyboardWidget
- wtf.TextWidget
+ wtf.ScrollableWidget
- app *tview.Application
messages []Message
- selected int
settings *Settings
}
// NewWidget creates a new instance of a widget
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
- HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
- KeyboardWidget: wtf.NewKeyboardWidget(),
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
+ KeyboardWidget: wtf.NewKeyboardWidget(),
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
- app: app,
settings: settings,
}
+ widget.SetRenderFunction(widget.Refresh)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
- widget.unselect()
-
- widget.View.SetScrollable(true)
- widget.View.SetRegions(true)
-
widget.HelpfulWidget.SetView(widget.View)
return &widget
@@ -65,34 +57,25 @@ func (widget *Widget) Refresh() {
room, err := GetRoom(widget.settings.roomURI, widget.settings.apiToken)
if err != nil {
- widget.View.SetWrap(true)
- widget.View.SetTitle(widget.CommonSettings.Title)
- widget.View.SetText(err.Error())
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
return
}
if room == nil {
+ widget.Redraw(widget.CommonSettings.Title, "No room", true)
return
}
messages, err := GetMessages(room.ID, widget.settings.numberOfMessages, widget.settings.apiToken)
if err != nil {
- widget.View.SetWrap(true)
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.CommonSettings.Title)
- widget.View.SetText(err.Error())
- })
- } else {
- widget.messages = messages
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
+ return
}
+ widget.messages = messages
+ widget.SetItemCount(len(messages))
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.display()
- widget.View.ScrollToEnd()
- })
+ widget.display()
}
/* -------------------- Unexported Functions -------------------- */
@@ -102,23 +85,21 @@ func (widget *Widget) display() {
return
}
- widget.View.SetWrap(true)
- widget.View.Clear()
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.CommonSettings.Title, widget.settings.roomURI)))
- widget.View.SetText(widget.contentFrom(widget.messages))
- widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
+ title := fmt.Sprintf("%s - %s", widget.CommonSettings.Title, widget.settings.roomURI)
+
+ widget.Redraw(title, widget.contentFrom(widget.messages), true)
}
func (widget *Widget) contentFrom(messages []Message) string {
var str string
for idx, message := range messages {
str = str + fmt.Sprintf(
- `["%d"][""][%s] [blue]%s [lightslategray]%s: [%s]%s [aqua]%s`,
+ `["%d"][%s] [blue]%s [lightslategray]%s: [%s]%s [aqua]%s[""]`,
idx,
- widget.rowColor(idx),
+ widget.RowColor(idx),
message.From.DisplayName,
message.From.Username,
- widget.rowColor(idx),
+ widget.RowColor(idx),
message.Text,
message.Sent.Format("Jan 02, 15:04 MST"),
)
@@ -129,41 +110,10 @@ func (widget *Widget) contentFrom(messages []Message) string {
return str
}
-func (widget *Widget) rowColor(idx int) string {
- if widget.View.HasFocus() && (idx == widget.selected) {
- return widget.settings.common.DefaultFocussedRowColor()
- }
-
- return widget.settings.common.RowColor(idx)
-}
-
-func (widget *Widget) next() {
- widget.selected++
- if widget.messages != nil && widget.selected >= len(widget.messages) {
- widget.selected = 0
- }
-
- widget.display()
-}
-
-func (widget *Widget) prev() {
- widget.selected--
- if widget.selected < 0 && widget.messages != nil {
- widget.selected = len(widget.messages) - 1
- }
-
- widget.display()
-}
-
func (widget *Widget) openMessage() {
- sel := widget.selected
+ sel := widget.GetSelected()
if sel >= 0 && widget.messages != nil && sel < len(widget.messages) {
- message := &widget.messages[widget.selected]
+ message := &widget.messages[sel]
wtf.OpenFile(message.Text)
}
}
-
-func (widget *Widget) unselect() {
- widget.selected = -1
- widget.display()
-}
diff --git a/modules/gspreadsheets/client.go b/modules/gspreadsheets/client.go
index 929f9748..e4adf75f 100644
--- a/modules/gspreadsheets/client.go
+++ b/modules/gspreadsheets/client.go
@@ -18,6 +18,7 @@ import (
"path/filepath"
"strings"
+ "github.com/wtfutil/wtf/utils"
"github.com/wtfutil/wtf/wtf"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
@@ -29,7 +30,7 @@ import (
func (widget *Widget) Fetch() ([]*sheets.ValueRange, error) {
ctx := context.Background()
- secretPath, _ := wtf.ExpandHomeDir(widget.settings.secretFile)
+ secretPath, _ := utils.ExpandHomeDir(widget.settings.secretFile)
b, err := ioutil.ReadFile(secretPath)
if err != nil {
diff --git a/modules/gspreadsheets/widget.go b/modules/gspreadsheets/widget.go
index b52b9455..d1728474 100644
--- a/modules/gspreadsheets/widget.go
+++ b/modules/gspreadsheets/widget.go
@@ -11,7 +11,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
settings *Settings
}
@@ -19,7 +18,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -31,9 +29,7 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
func (widget *Widget) Refresh() {
cells, _ := widget.Fetch()
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(widget.contentFrom(cells))
- })
+ widget.Redraw(widget.CommonSettings.Title, widget.contentFrom(cells), false)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/hackernews/keyboard.go b/modules/hackernews/keyboard.go
index afa89ff6..ef305ba4 100644
--- a/modules/hackernews/keyboard.go
+++ b/modules/hackernews/keyboard.go
@@ -1,18 +1,17 @@
-
package hackernews
import "github.com/gdamore/tcell"
func (widget *Widget) initializeKeyboardControls() {
widget.SetKeyboardChar("/", widget.ShowHelp)
- widget.SetKeyboardChar("j", widget.next)
- widget.SetKeyboardChar("k", widget.prev)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
widget.SetKeyboardChar("o", widget.openStory)
widget.SetKeyboardChar("r", widget.Refresh)
widget.SetKeyboardChar("c", widget.openComments)
- widget.SetKeyboardKey(tcell.KeyDown, widget.next)
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
widget.SetKeyboardKey(tcell.KeyEnter, widget.openStory)
- widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect)
- widget.SetKeyboardKey(tcell.KeyUp, widget.prev)
-}
\ No newline at end of file
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
+}
diff --git a/modules/hackernews/widget.go b/modules/hackernews/widget.go
index d2a3f68f..9131f88d 100644
--- a/modules/hackernews/widget.go
+++ b/modules/hackernews/widget.go
@@ -3,7 +3,6 @@ package hackernews
import (
"fmt"
"net/url"
- "strconv"
"strings"
"github.com/rivo/tview"
@@ -28,32 +27,25 @@ const HelpText = `
type Widget struct {
wtf.HelpfulWidget
wtf.KeyboardWidget
- wtf.TextWidget
+ wtf.ScrollableWidget
- app *tview.Application
stories []Story
- selected int
settings *Settings
}
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
- HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
- KeyboardWidget: wtf.NewKeyboardWidget(),
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
+ KeyboardWidget: wtf.NewKeyboardWidget(),
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
- app: app,
settings: settings,
}
+ widget.SetRenderFunction(widget.Render)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
- widget.unselect()
-
- widget.View.SetScrollable(true)
- widget.View.SetRegions(true)
-
widget.HelpfulWidget.SetView(widget.View)
return &widget
@@ -72,53 +64,47 @@ func (widget *Widget) Refresh() {
}
if err != nil {
- widget.View.SetWrap(true)
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.View.SetText(err.Error())
- } else {
- var stories []Story
- for idx := 0; idx < widget.settings.numberOfStories; idx++ {
- story, e := GetStory(storyIds[idx])
- if e != nil {
- // panic(e)
- } else {
- stories = append(stories, story)
- }
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
+ return
+ }
+ var stories []Story
+ for idx := 0; idx < widget.settings.numberOfStories; idx++ {
+ story, e := GetStory(storyIds[idx])
+ if e != nil {
+ // panic(e)
+ } else {
+ stories = append(stories, story)
}
-
- widget.stories = stories
}
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.stories = stories
+ widget.SetItemCount(len(stories))
+
+ widget.Render()
}
/* -------------------- Unexported Functions -------------------- */
-func (widget *Widget) display() {
+func (widget *Widget) Render() {
if widget.stories == nil {
return
}
- widget.View.SetWrap(false)
-
- widget.View.Clear()
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %sstories", widget.CommonSettings.Title, widget.settings.storyType)))
- widget.View.SetText(widget.contentFrom(widget.stories))
- widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
+ title := fmt.Sprintf("%s - %sstories", widget.CommonSettings.Title, widget.settings.storyType)
+ widget.Redraw(title, widget.contentFrom(widget.stories), false)
}
func (widget *Widget) contentFrom(stories []Story) string {
var str string
for idx, story := range stories {
+
u, _ := url.Parse(story.URL)
+
str = str + fmt.Sprintf(
- `["%d"][""][%s] [yellow]%d. [%s]%s [blue](%s)`,
+ `["%d"][""][%s]%2d. %s [lightblue](%s)[white][""]`,
idx,
- widget.rowColor(idx),
+ widget.RowColor(idx),
idx+1,
- widget.rowColor(idx),
story.Title,
strings.TrimPrefix(u.Host, "www."),
)
@@ -129,49 +115,18 @@ func (widget *Widget) contentFrom(stories []Story) string {
return str
}
-func (widget *Widget) rowColor(idx int) string {
- if widget.View.HasFocus() && (idx == widget.selected) {
- return widget.settings.common.DefaultFocussedRowColor()
- }
-
- return widget.settings.common.RowColor(idx)
-}
-
-func (widget *Widget) next() {
- widget.selected++
- if widget.stories != nil && widget.selected >= len(widget.stories) {
- widget.selected = 0
- }
-
- widget.display()
-}
-
-func (widget *Widget) prev() {
- widget.selected--
- if widget.selected < 0 && widget.stories != nil {
- widget.selected = len(widget.stories) - 1
- }
-
- widget.display()
-}
-
func (widget *Widget) openStory() {
- sel := widget.selected
+ sel := widget.GetSelected()
if sel >= 0 && widget.stories != nil && sel < len(widget.stories) {
- story := &widget.stories[widget.selected]
+ story := &widget.stories[sel]
wtf.OpenFile(story.URL)
}
}
func (widget *Widget) openComments() {
- sel := widget.selected
+ sel := widget.GetSelected()
if sel >= 0 && widget.stories != nil && sel < len(widget.stories) {
- story := &widget.stories[widget.selected]
+ story := &widget.stories[sel]
wtf.OpenFile(fmt.Sprintf("https://news.ycombinator.com/item?id=%d", story.ID))
}
}
-
-func (widget *Widget) unselect() {
- widget.selected = -1
- widget.display()
-}
diff --git a/modules/ipaddresses/ipinfo/widget.go b/modules/ipaddresses/ipinfo/widget.go
index 5edc3a40..1454d987 100644
--- a/modules/ipaddresses/ipinfo/widget.go
+++ b/modules/ipaddresses/ipinfo/widget.go
@@ -14,7 +14,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
result string
settings *Settings
}
@@ -34,7 +33,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -46,10 +44,7 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
func (widget *Widget) Refresh() {
widget.ipinfo()
- widget.app.QueueUpdateDraw(func() {
- widget.View.Clear()
- widget.View.SetText(widget.result)
- })
+ widget.TextWidget.Redraw(widget.CommonSettings.Title, widget.result, false)
}
//this method reads the config and calls ipinfo for ip information
diff --git a/modules/jenkins/keyboard.go b/modules/jenkins/keyboard.go
index 1ed01883..20735a3f 100644
--- a/modules/jenkins/keyboard.go
+++ b/modules/jenkins/keyboard.go
@@ -4,13 +4,13 @@ import "github.com/gdamore/tcell"
func (widget *Widget) initializeKeyboardControls() {
widget.SetKeyboardChar("/", widget.ShowHelp)
- widget.SetKeyboardChar("j", widget.next)
- widget.SetKeyboardChar("k", widget.prev)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
widget.SetKeyboardChar("o", widget.openJob)
widget.SetKeyboardChar("r", widget.Refresh)
- widget.SetKeyboardKey(tcell.KeyDown, widget.next)
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
widget.SetKeyboardKey(tcell.KeyEnter, widget.openJob)
- widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect)
- widget.SetKeyboardKey(tcell.KeyUp, widget.prev)
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
}
diff --git a/modules/jenkins/widget.go b/modules/jenkins/widget.go
index 64d76270..9db9a7d1 100644
--- a/modules/jenkins/widget.go
+++ b/modules/jenkins/widget.go
@@ -2,8 +2,6 @@ package jenkins
import (
"fmt"
- "strconv"
-
"regexp"
"github.com/rivo/tview"
@@ -27,32 +25,25 @@ const HelpText = `
type Widget struct {
wtf.HelpfulWidget
wtf.KeyboardWidget
- wtf.TextWidget
+ wtf.ScrollableWidget
- app *tview.Application
- selected int
settings *Settings
view *View
}
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
- HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
- KeyboardWidget: wtf.NewKeyboardWidget(),
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
+ KeyboardWidget: wtf.NewKeyboardWidget(),
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
- app: app,
settings: settings,
}
+ widget.SetRenderFunction(widget.Render)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
- widget.unselect()
-
- widget.View.SetScrollable(true)
- widget.View.SetRegions(true)
-
widget.HelpfulWidget.SetView(widget.View)
return &widget
@@ -73,32 +64,25 @@ func (widget *Widget) Refresh() {
widget.view = view
if err != nil {
- widget.View.SetWrap(true)
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(err.Error())
- })
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
+ return
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.display()
- })
+ widget.SetItemCount(len(widget.view.Jobs))
+
+ widget.Render()
}
/* -------------------- Unexported Functions -------------------- */
-func (widget *Widget) display() {
+func (widget *Widget) Render() {
if widget.view == nil {
return
}
- widget.View.SetWrap(false)
+ title := fmt.Sprintf("%s: [red]%s", widget.CommonSettings.Title, widget.view.Name)
- widget.View.Clear()
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s: [red]%s", widget.CommonSettings.Title, widget.view.Name)))
- widget.View.SetText(widget.contentFrom(widget.view))
- widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
+ widget.Redraw(title, widget.contentFrom(widget.view), false)
}
func (widget *Widget) contentFrom(view *View) string {
@@ -108,9 +92,9 @@ func (widget *Widget) contentFrom(view *View) string {
if validID.MatchString(job.Name) {
str = str + fmt.Sprintf(
- `["%d"][""][%s] [%s]%-6s[white]`,
+ `["%d"][%s] [%s]%-6s[white][""]`,
idx,
- widget.rowColor(idx),
+ widget.RowColor(idx),
widget.jobColor(&job),
job.Name,
)
@@ -122,14 +106,6 @@ func (widget *Widget) contentFrom(view *View) string {
return str
}
-func (widget *Widget) rowColor(idx int) string {
- if widget.View.HasFocus() && (idx == widget.selected) {
- return widget.settings.common.DefaultFocussedRowColor()
- }
-
- return widget.settings.common.RowColor(idx)
-}
-
func (widget *Widget) jobColor(job *Job) string {
switch job.Color {
case "blue":
@@ -142,33 +118,10 @@ func (widget *Widget) jobColor(job *Job) string {
}
}
-func (widget *Widget) next() {
- widget.selected++
- if widget.view != nil && widget.selected >= len(widget.view.Jobs) {
- widget.selected = 0
- }
-
- widget.display()
-}
-
-func (widget *Widget) prev() {
- widget.selected--
- if widget.selected < 0 && widget.view != nil {
- widget.selected = len(widget.view.Jobs) - 1
- }
-
- widget.display()
-}
-
func (widget *Widget) openJob() {
- sel := widget.selected
+ sel := widget.GetSelected()
if sel >= 0 && widget.view != nil && sel < len(widget.view.Jobs) {
- job := &widget.view.Jobs[widget.selected]
+ job := &widget.view.Jobs[sel]
wtf.OpenFile(job.Url)
}
}
-
-func (widget *Widget) unselect() {
- widget.selected = -1
- widget.display()
-}
diff --git a/modules/jira/keyboard.go b/modules/jira/keyboard.go
index e6178a8a..b89b27da 100644
--- a/modules/jira/keyboard.go
+++ b/modules/jira/keyboard.go
@@ -6,22 +6,12 @@ import (
func (widget *Widget) initializeKeyboardControls() {
widget.SetKeyboardChar("/", widget.ShowHelp)
- widget.SetKeyboardChar("j", widget.selectNext)
- widget.SetKeyboardChar("k", widget.selectPrev)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
widget.SetKeyboardChar("o", widget.openItem)
- widget.SetKeyboardKey(tcell.KeyDown, widget.selectNext)
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
widget.SetKeyboardKey(tcell.KeyEnter, widget.openItem)
- widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect)
- widget.SetKeyboardKey(tcell.KeyUp, widget.selectPrev)
-}
-
-func (widget *Widget) selectNext() {
- widget.next()
- widget.display()
-}
-
-func (widget *Widget) selectPrev() {
- widget.prev()
- widget.display()
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
}
diff --git a/modules/jira/widget.go b/modules/jira/widget.go
index 1621eaa9..ba1b8008 100644
--- a/modules/jira/widget.go
+++ b/modules/jira/widget.go
@@ -3,8 +3,6 @@ package jira
import (
"fmt"
- "strconv"
-
"github.com/rivo/tview"
"github.com/wtfutil/wtf/wtf"
)
@@ -25,32 +23,25 @@ const HelpText = `
type Widget struct {
wtf.HelpfulWidget
wtf.KeyboardWidget
- wtf.TextWidget
+ wtf.ScrollableWidget
- app *tview.Application
result *SearchResult
- selected int
settings *Settings
}
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
- HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
- KeyboardWidget: wtf.NewKeyboardWidget(),
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
+ KeyboardWidget: wtf.NewKeyboardWidget(),
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
- app: app,
settings: settings,
}
+ widget.SetRenderFunction(widget.Render)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
- widget.unselect()
-
- widget.View.SetScrollable(true)
- widget.View.SetRegions(true)
-
widget.HelpfulWidget.SetView(widget.View)
return &widget
@@ -67,76 +58,47 @@ func (widget *Widget) Refresh() {
if err != nil {
widget.result = nil
- widget.View.SetWrap(true)
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.CommonSettings.Title)
- widget.View.SetText(err.Error())
- })
- } else {
- widget.result = searchResult
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
+ return
}
-
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.result = searchResult
+ widget.SetItemCount(len(searchResult.Issues))
+ widget.Render()
}
/* -------------------- Unexported Functions -------------------- */
-func (widget *Widget) display() {
+func (widget *Widget) Render() {
if widget.result == nil {
return
}
- widget.View.SetWrap(false)
str := fmt.Sprintf("%s- [green]%s[white]", widget.CommonSettings.Title, widget.settings.projects)
- widget.View.Clear()
- widget.View.SetTitle(widget.ContextualTitle(str))
- widget.View.SetText(fmt.Sprintf("%s", widget.contentFrom(widget.result)))
- widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
-}
-
-func (widget *Widget) next() {
- widget.selected++
- if widget.result != nil && widget.selected >= len(widget.result.Issues) {
- widget.selected = 0
- }
-}
-
-func (widget *Widget) prev() {
- widget.selected--
- if widget.selected < 0 && widget.result != nil {
- widget.selected = len(widget.result.Issues) - 1
- }
+ widget.Redraw(str, widget.contentFrom(widget.result), false)
}
func (widget *Widget) openItem() {
- sel := widget.selected
+ sel := widget.GetSelected()
if sel >= 0 && widget.result != nil && sel < len(widget.result.Issues) {
- issue := &widget.result.Issues[widget.selected]
+ issue := &widget.result.Issues[sel]
wtf.OpenFile(widget.settings.domain + "/browse/" + issue.Key)
}
}
-func (widget *Widget) unselect() {
- widget.selected = -1
-}
-
func (widget *Widget) contentFrom(searchResult *SearchResult) string {
str := " [red]Assigned Issues[white]\n"
for idx, issue := range searchResult.Issues {
fmtStr := fmt.Sprintf(
- `["%d"][""][%s] [%s]%-6s[white] [green]%-10s[white] [yellow][%s][white] [%s]%s`,
+ `["%d"][%s] [%s]%-6s[white] [green]%-10s[white] [yellow][%s][white] [%s]%s[""]`,
idx,
- widget.rowColor(idx),
+ widget.RowColor(idx),
widget.issueTypeColor(&issue),
issue.IssueFields.IssueType.Name,
issue.Key,
issue.IssueFields.IssueStatus.IName,
- widget.rowColor(idx),
+ widget.RowColor(idx),
issue.IssueFields.Summary,
)
@@ -149,14 +111,6 @@ func (widget *Widget) contentFrom(searchResult *SearchResult) string {
return str
}
-func (widget *Widget) rowColor(idx int) string {
- if widget.View.HasFocus() && (idx == widget.selected) {
- widget.settings.common.DefaultFocussedRowColor()
- }
-
- return widget.settings.common.RowColor(idx)
-}
-
func (widget *Widget) issueTypeColor(issue *Issue) string {
switch issue.IssueFields.IssueType.Name {
case "Bug":
diff --git a/logger/settings.go b/modules/logger/settings.go
similarity index 100%
rename from logger/settings.go
rename to modules/logger/settings.go
diff --git a/modules/logger/widget.go b/modules/logger/widget.go
new file mode 100644
index 00000000..b58d10e6
--- /dev/null
+++ b/modules/logger/widget.go
@@ -0,0 +1,105 @@
+package logger
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/rivo/tview"
+ log "github.com/wtfutil/wtf/logger"
+ "github.com/wtfutil/wtf/wtf"
+)
+
+const maxBufferSize int64 = 1024
+
+type Widget struct {
+ wtf.TextWidget
+
+ app *tview.Application
+ filePath string
+ settings *Settings
+}
+
+func NewWidget(app *tview.Application, settings *Settings) *Widget {
+ widget := Widget{
+ TextWidget: wtf.NewTextWidget(app, settings.common, true),
+
+ app: app,
+ filePath: log.LogFilePath(),
+ settings: settings,
+ }
+
+ return &widget
+}
+
+// Refresh updates the onscreen contents of the widget
+func (widget *Widget) Refresh() {
+ if log.LogFileMissing() {
+ return
+ }
+
+ logLines := widget.tailFile()
+
+ widget.app.QueueUpdateDraw(func() {
+ widget.View.SetTitle(widget.CommonSettings.Title)
+ widget.View.SetText(widget.contentFrom(logLines))
+ })
+}
+
+/* -------------------- Unexported Functions -------------------- */
+
+func (widget *Widget) contentFrom(logLines []string) string {
+ str := ""
+
+ for _, line := range logLines {
+ chunks := strings.Split(line, " ")
+
+ if len(chunks) >= 4 {
+ str = str + fmt.Sprintf(
+ "[green]%s[white] [yellow]%s[white] %s\n",
+ chunks[0],
+ chunks[1],
+ strings.Join(chunks[3:], " "),
+ )
+ }
+ }
+
+ return str
+}
+
+func (widget *Widget) tailFile() []string {
+ file, err := os.Open(widget.filePath)
+ if err != nil {
+ return []string{}
+ }
+ defer file.Close()
+
+ stat, err := file.Stat()
+ if err != nil {
+ return []string{}
+ }
+
+ bufferSize := maxBufferSize
+ if maxBufferSize > stat.Size() {
+ bufferSize = stat.Size()
+ }
+
+ startPos := stat.Size() - bufferSize
+
+ buff := make([]byte, bufferSize)
+ _, err = file.ReadAt(buff, startPos)
+ if err != nil {
+ return []string{}
+ }
+
+ logLines := strings.Split(string(buff), "\n")
+
+ // Reverse the array of lines
+ // Offset by two to account for the blank line at the end
+ last := len(logLines) - 2
+ for i := 0; i < len(logLines)/2; i++ {
+ logLines[i], logLines[last-i] = logLines[last-i], logLines[i]
+ }
+
+ return logLines
+}
diff --git a/modules/mercurial/display.go b/modules/mercurial/display.go
index 8dae5e94..9ffbc3b0 100644
--- a/modules/mercurial/display.go
+++ b/modules/mercurial/display.go
@@ -9,12 +9,11 @@ import (
func (widget *Widget) display() {
repoData := widget.currentData()
if repoData == nil {
- widget.View.SetText(" Mercurial repo data is unavailable ")
+ widget.Redraw(widget.CommonSettings.Title, " Mercurial repo data is unavailable ", false)
return
}
title := fmt.Sprintf("%s - [green]%s[white]", widget.CommonSettings.Title, repoData.Repository)
- widget.View.SetTitle(widget.ContextualTitle(title))
_, _, width, _ := widget.View.GetRect()
str := widget.settings.common.SigilStr(len(widget.Data), widget.Idx, width) + "\n"
@@ -25,7 +24,7 @@ func (widget *Widget) display() {
str = str + "\n"
str = str + widget.formatCommits(repoData.Commits)
- widget.View.SetText(str)
+ widget.Redraw(title, str, false)
}
func (widget *Widget) formatChanges(data []string) string {
diff --git a/modules/mercurial/widget.go b/modules/mercurial/widget.go
index d6625c20..36748dd4 100644
--- a/modules/mercurial/widget.go
+++ b/modules/mercurial/widget.go
@@ -71,9 +71,7 @@ func (widget *Widget) Checkout() {
widget.pages.RemovePage("modal")
widget.app.SetFocus(widget.View)
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
widget.Refresh()
}
@@ -86,7 +84,6 @@ func (widget *Widget) Pull() {
repoToPull := widget.Data[widget.Idx]
repoToPull.pull()
widget.Refresh()
-
}
func (widget *Widget) Refresh() {
@@ -94,9 +91,7 @@ func (widget *Widget) Refresh() {
widget.Data = widget.mercurialRepos(repoPaths)
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
}
/* -------------------- Unexported Functions -------------------- */
@@ -122,9 +117,11 @@ func (widget *Widget) addCancelButton(form *tview.Form) {
}
func (widget *Widget) modalFocus(form *tview.Form) {
- frame := widget.modalFrame(form)
- widget.pages.AddPage("modal", frame, false, true)
- widget.app.SetFocus(frame)
+ widget.app.QueueUpdateDraw(func() {
+ frame := widget.modalFrame(form)
+ widget.pages.AddPage("modal", frame, false, true)
+ widget.app.SetFocus(frame)
+ })
}
func (widget *Widget) modalForm(lbl, text string) *tview.Form {
diff --git a/modules/nbascore/widget.go b/modules/nbascore/widget.go
index 6f6cd9bd..ac7a47d6 100644
--- a/modules/nbascore/widget.go
+++ b/modules/nbascore/widget.go
@@ -25,7 +25,6 @@ type Widget struct {
wtf.KeyboardWidget
wtf.TextWidget
- app *tview.Application
language string
result string
settings *Settings
@@ -40,7 +39,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
KeyboardWidget: wtf.NewKeyboardWidget(),
TextWidget: wtf.NewTextWidget(app, settings.common, true),
- app: app,
settings: settings,
}
@@ -55,39 +53,32 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
}
func (widget *Widget) Refresh() {
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.nbascore()
- })
+ widget.Redraw(widget.CommonSettings.Title, widget.nbascore(), false)
}
-func (widget *Widget) nbascore() {
+func (widget *Widget) nbascore() string {
cur := time.Now().AddDate(0, 0, offset) // Go back/forward offset days
curString := cur.Format("20060102") // Need 20060102 format to feed to api
client := &http.Client{}
req, err := http.NewRequest("GET", "http://data.nba.net/10s/prod/v1/"+curString+"/scoreboard.json", nil)
if err != nil {
- widget.result = err.Error()
- return
+ return err.Error()
}
req.Header.Set("Accept-Language", widget.language)
req.Header.Set("User-Agent", "curl")
response, err := client.Do(req)
if err != nil {
- widget.result = err.Error()
- return
+ return err.Error()
}
defer response.Body.Close()
if response.StatusCode != 200 {
- widget.result = err.Error()
- return
+ return err.Error()
} // Get data from data.nba.net and check if successful
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
- widget.result = err.Error()
- return
+ return err.Error()
}
result := map[string]interface{}{}
json.Unmarshal(contents, &result)
@@ -146,6 +137,5 @@ func (widget *Widget) nbascore() {
}
allGame += fmt.Sprintf("%s%5s%v[white] %s %3s [white]vs %s%-3s %s\n", qColor, "Q", quarter, vTeam, vScore, hColor, hScore, hTeam) // Format the score and store in allgame
}
- widget.View.SetText(allGame)
-
+ return allGame
}
diff --git a/modules/newrelic/widget.go b/modules/newrelic/widget.go
index 3a6b611b..62d7d971 100644
--- a/modules/newrelic/widget.go
+++ b/modules/newrelic/widget.go
@@ -11,7 +11,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
client *Client
settings *Settings
}
@@ -20,7 +19,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -41,19 +39,16 @@ func (widget *Widget) Refresh() {
}
var content string
+ title := fmt.Sprintf("%s - [green]%s[white]", widget.CommonSettings.Title, appName)
+ wrap := false
if depErr != nil {
- widget.View.SetWrap(true)
+ wrap = true
content = depErr.Error()
} else {
- widget.View.SetWrap(false)
content = widget.contentFrom(deploys)
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - [green]%s[white]", widget.CommonSettings.Title, appName)))
- widget.View.Clear()
- widget.View.SetText(content)
- })
+ widget.Redraw(title, content, wrap)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/opsgenie/widget.go b/modules/opsgenie/widget.go
index 149e2a74..aef05445 100644
--- a/modules/opsgenie/widget.go
+++ b/modules/opsgenie/widget.go
@@ -11,7 +11,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
settings *Settings
}
@@ -19,7 +18,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -35,18 +33,15 @@ func (widget *Widget) Refresh() {
)
var content string
+ wrap := false
if err != nil {
- widget.View.SetWrap(true)
+ wrap = true
content = err.Error()
} else {
- widget.View.SetWrap(false)
content = widget.contentFrom(data)
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.View.SetText(content)
- })
+ widget.Redraw(widget.CommonSettings.Title, content, wrap)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/pagerduty/widget.go b/modules/pagerduty/widget.go
index 70d931de..a032e43f 100644
--- a/modules/pagerduty/widget.go
+++ b/modules/pagerduty/widget.go
@@ -12,7 +12,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
settings *Settings
}
@@ -20,7 +19,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -44,14 +42,10 @@ func (widget *Widget) Refresh() {
incidents, err2 = GetIncidents(widget.settings.apiKey)
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.View.Clear()
- })
-
var content string
+ wrap := false
if err1 != nil || err2 != nil {
- widget.View.SetWrap(true)
+ wrap = true
if err1 != nil {
content = content + err1.Error()
}
@@ -63,9 +57,7 @@ func (widget *Widget) Refresh() {
content = widget.contentFrom(onCalls, incidents)
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(content)
- })
+ widget.Redraw(widget.CommonSettings.Title, content, wrap)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/power/widget.go b/modules/power/widget.go
index 5ef57f08..0dfa167c 100644
--- a/modules/power/widget.go
+++ b/modules/power/widget.go
@@ -12,7 +12,6 @@ type Widget struct {
Battery *Battery
- app *tview.Application
settings *Settings
}
@@ -22,7 +21,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
Battery: NewBattery(),
- app: app,
settings: settings,
}
@@ -39,7 +37,5 @@ func (widget *Widget) Refresh() {
content = content + "\n"
content = content + widget.Battery.String()
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(content)
- })
+ widget.Redraw(widget.CommonSettings.Title, content, true)
}
diff --git a/modules/rollbar/keyboard.go b/modules/rollbar/keyboard.go
index 7a43b83a..a89e6ec1 100644
--- a/modules/rollbar/keyboard.go
+++ b/modules/rollbar/keyboard.go
@@ -4,14 +4,14 @@ import "github.com/gdamore/tcell"
func (widget *Widget) initializeKeyboardControls() {
widget.SetKeyboardChar("/", widget.ShowHelp)
- widget.SetKeyboardChar("j", widget.next)
- widget.SetKeyboardChar("k", widget.prev)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
widget.SetKeyboardChar("o", widget.openBuild)
widget.SetKeyboardChar("r", widget.Refresh)
- widget.SetKeyboardChar("u", widget.unselect)
+ widget.SetKeyboardChar("u", widget.Unselect)
- widget.SetKeyboardKey(tcell.KeyDown, widget.next)
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
widget.SetKeyboardKey(tcell.KeyEnter, widget.openBuild)
- widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect)
- widget.SetKeyboardKey(tcell.KeyUp, widget.prev)
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
}
diff --git a/modules/rollbar/widget.go b/modules/rollbar/widget.go
index 95a6e2d5..fa847ae0 100644
--- a/modules/rollbar/widget.go
+++ b/modules/rollbar/widget.go
@@ -26,30 +26,26 @@ const HelpText = `
type Widget struct {
wtf.HelpfulWidget
wtf.KeyboardWidget
- wtf.TextWidget
+ wtf.ScrollableWidget
- app *tview.Application
items *Result
- selected int
settings *Settings
}
// NewWidget creates a new instance of a widget
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
- HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
- KeyboardWidget: wtf.NewKeyboardWidget(),
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
+ KeyboardWidget: wtf.NewKeyboardWidget(),
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
- app: app,
settings: settings,
}
+ widget.SetRenderFunction(widget.Render)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
- widget.unselect()
-
widget.HelpfulWidget.SetView(widget.View)
return &widget
@@ -69,34 +65,30 @@ func (widget *Widget) Refresh() {
)
if err != nil {
- widget.View.SetWrap(true)
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(err.Error())
- })
- } else {
- widget.items = &items.Results
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
+ return
}
+ widget.items = &items.Results
+ widget.SetItemCount(len(widget.items.Items))
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.display()
- })
+ widget.Refresh()
}
/* -------------------- Unexported Functions -------------------- */
-func (widget *Widget) display() {
+func (widget *Widget) Render() {
if widget.items == nil {
return
}
- widget.View.SetWrap(false)
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.CommonSettings.Title, widget.settings.projectName)))
- widget.View.SetText(widget.contentFrom(widget.items))
+ title := fmt.Sprintf("%s - %s", widget.CommonSettings.Title, widget.settings.projectName)
+ widget.Redraw(title, widget.contentFrom(widget.items), false)
}
func (widget *Widget) contentFrom(result *Result) string {
+ if result == nil {
+ return "No results"
+ }
var str string
if len(result.Items) > widget.settings.count {
result.Items = result.Items[:widget.settings.count]
@@ -105,12 +97,12 @@ func (widget *Widget) contentFrom(result *Result) string {
str = str + fmt.Sprintf(
"[%s] [%s] %s [%s] %s [%s]count: %d [%s]%s\n",
- widget.rowColor(idx),
+ widget.RowColor(idx),
levelColor(&item),
item.Level,
statusColor(&item),
item.Title,
- widget.rowColor(idx),
+ widget.RowColor(idx),
item.TotalOccurrences,
"blue",
item.Environment,
@@ -120,14 +112,6 @@ func (widget *Widget) contentFrom(result *Result) string {
return str
}
-func (widget *Widget) rowColor(idx int) string {
- if widget.View.HasFocus() && (idx == widget.selected) {
- return widget.settings.common.DefaultFocussedRowColor()
- }
-
- return widget.settings.common.RowColor(idx)
-}
-
func statusColor(item *Item) string {
switch item.Status {
case "active":
@@ -151,27 +135,9 @@ func levelColor(item *Item) string {
}
}
-func (widget *Widget) next() {
- widget.selected++
- if widget.items != nil && widget.selected >= len(widget.items.Items) {
- widget.selected = 0
- }
-
- widget.display()
-}
-
-func (widget *Widget) prev() {
- widget.selected--
- if widget.selected < 0 && widget.items.Items != nil {
- widget.selected = len(widget.items.Items) - 1
- }
-
- widget.display()
-}
-
func (widget *Widget) openBuild() {
- if widget.selected >= 0 && widget.items != nil && widget.selected < len(widget.items.Items) {
- item := &widget.items.Items[widget.selected]
+ if widget.GetSelected() >= 0 && widget.items != nil && widget.GetSelected() < len(widget.items.Items) {
+ item := &widget.items.Items[widget.GetSelected()]
wtf.OpenFile(
fmt.Sprintf(
@@ -184,8 +150,3 @@ func (widget *Widget) openBuild() {
)
}
}
-
-func (widget *Widget) unselect() {
- widget.selected = -1
- widget.display()
-}
diff --git a/modules/security/widget.go b/modules/security/widget.go
index b10b7013..368aaa1f 100644
--- a/modules/security/widget.go
+++ b/modules/security/widget.go
@@ -11,7 +11,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
settings *Settings
}
@@ -19,7 +18,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -37,9 +35,7 @@ func (widget *Widget) Refresh() {
data := NewSecurityData()
data.Fetch()
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(widget.contentFrom(data))
- })
+ widget.Redraw(widget.CommonSettings.Title, widget.contentFrom(data), false)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/spotify/widget.go b/modules/spotify/widget.go
index dc82836b..dfb151fb 100644
--- a/modules/spotify/widget.go
+++ b/modules/spotify/widget.go
@@ -21,7 +21,6 @@ type Widget struct {
wtf.KeyboardWidget
wtf.TextWidget
- app *tview.Application
settings *Settings
spotigopher.Info
spotigopher.SpotifyClient
@@ -38,7 +37,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
Info: spotigopher.Info{},
SpotifyClient: spotifyClient,
- app: app,
settings: settings,
}
@@ -63,19 +61,18 @@ func (w *Widget) refreshSpotifyInfos() error {
}
func (w *Widget) Refresh() {
- w.app.QueueUpdateDraw(func() {
- w.render()
- })
+ w.render()
}
func (w *Widget) render() {
err := w.refreshSpotifyInfos()
- w.View.Clear()
+ var content string
if err != nil {
- w.TextWidget.View.SetText(err.Error())
+ content = err.Error()
} else {
- w.TextWidget.View.SetText(w.createOutput())
+ content = w.createOutput()
}
+ w.Redraw(w.CommonSettings.Title, content, true)
}
func (w *Widget) createOutput() string {
diff --git a/modules/spotifyweb/widget.go b/modules/spotifyweb/widget.go
index a5747c26..047b37ae 100644
--- a/modules/spotifyweb/widget.go
+++ b/modules/spotifyweb/widget.go
@@ -48,7 +48,6 @@ type Widget struct {
Info
- app *tview.Application
client *spotify.Client
clientChan chan *spotify.Client
playerState *spotify.PlayerState
@@ -99,7 +98,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
Info: Info{},
- app: app,
client: client,
clientChan: tempClientChan,
playerState: playerState,
@@ -181,18 +179,11 @@ func (w *Widget) refreshSpotifyInfos() error {
// Refresh refreshes the current view of the widget
func (w *Widget) Refresh() {
- w.app.QueueUpdateDraw(func() {
- w.render()
- })
-}
-
-func (w *Widget) render() {
err := w.refreshSpotifyInfos()
- w.View.Clear()
if err != nil {
- w.TextWidget.View.SetText(err.Error())
+ w.Redraw(w.CommonSettings.Title, err.Error(), true)
} else {
- w.TextWidget.View.SetText(w.createOutput())
+ w.Redraw(w.CommonSettings.Title, w.createOutput(), false)
}
}
diff --git a/modules/status/widget.go b/modules/status/widget.go
index cf02188d..e205dae8 100644
--- a/modules/status/widget.go
+++ b/modules/status/widget.go
@@ -10,7 +10,6 @@ type Widget struct {
CurrentIcon int
- app *tview.Application
settings *Settings
}
@@ -20,7 +19,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
CurrentIcon: 0,
- app: app,
settings: settings,
}
@@ -30,9 +28,7 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
/* -------------------- Exported Functions -------------------- */
func (widget *Widget) Refresh() {
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(widget.animation())
- })
+ widget.Redraw(widget.CommonSettings.Title, widget.animation(), false)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/system/widget.go b/modules/system/widget.go
index 802d9a2b..d3f249b9 100644
--- a/modules/system/widget.go
+++ b/modules/system/widget.go
@@ -14,7 +14,6 @@ type Widget struct {
Date string
Version string
- app *tview.Application
settings *Settings
systemInfo *SystemInfo
}
@@ -25,7 +24,6 @@ func NewWidget(app *tview.Application, date, version string, settings *Settings)
Date: date,
- app: app,
settings: settings,
Version: version,
}
@@ -36,21 +34,18 @@ func NewWidget(app *tview.Application, date, version string, settings *Settings)
}
func (widget *Widget) Refresh() {
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(
- fmt.Sprintf(
- "%8s: %s\n%8s: %s\n\n%8s: %s\n%8s: %s",
- "Built",
- widget.prettyDate(),
- "Vers",
- widget.Version,
- "OS",
- widget.systemInfo.ProductVersion,
- "Build",
- widget.systemInfo.BuildVersion,
- ),
- )
- })
+ content := fmt.Sprintf(
+ "%8s: %s\n%8s: %s\n\n%8s: %s\n%8s: %s",
+ "Built",
+ widget.prettyDate(),
+ "Vers",
+ widget.Version,
+ "OS",
+ widget.systemInfo.ProductVersion,
+ "Build",
+ widget.systemInfo.BuildVersion,
+ )
+ widget.Redraw(widget.CommonSettings.Title, content, false)
}
func (widget *Widget) prettyDate() string {
diff --git a/modules/textfile/widget.go b/modules/textfile/widget.go
index d27fb24b..7a53752d 100644
--- a/modules/textfile/widget.go
+++ b/modules/textfile/widget.go
@@ -14,6 +14,7 @@ import (
"github.com/alecthomas/chroma/styles"
"github.com/radovskyb/watcher"
"github.com/rivo/tview"
+ "github.com/wtfutil/wtf/utils"
"github.com/wtfutil/wtf/wtf"
)
@@ -73,16 +74,13 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
// Refresh is only called once on start-up. Its job is to display the
// text files that first time. After that, the watcher takes over
func (widget *Widget) Refresh() {
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
}
/* -------------------- Unexported Functions -------------------- */
func (widget *Widget) display() {
title := fmt.Sprintf("[green]%s[white]", widget.CurrentSource())
- title = widget.ContextualTitle(title)
_, _, width, _ := widget.View.GetRect()
text := widget.settings.common.SigilStr(len(widget.Sources), widget.Idx, width) + "\n"
@@ -93,8 +91,7 @@ func (widget *Widget) display() {
text = text + widget.plainText()
}
- widget.View.SetTitle(title) // <- Writes to TextView's title
- widget.View.SetText(text) // <- Writes to TextView's text
+ widget.Redraw(title, text, true)
}
func (widget *Widget) fileName() string {
@@ -102,7 +99,7 @@ func (widget *Widget) fileName() string {
}
func (widget *Widget) formattedText() string {
- filePath, _ := wtf.ExpandHomeDir(widget.CurrentSource())
+ filePath, _ := utils.ExpandHomeDir(widget.CurrentSource())
file, err := os.Open(filePath)
if err != nil {
@@ -133,7 +130,7 @@ func (widget *Widget) formattedText() string {
}
func (widget *Widget) plainText() string {
- filePath, _ := wtf.ExpandHomeDir(widget.CurrentSource())
+ filePath, _ := utils.ExpandHomeDir(widget.CurrentSource())
fmt.Println(filePath)
@@ -163,7 +160,7 @@ func (widget *Widget) watchForFileChanges() {
// Watch each textfile for changes
for _, source := range widget.Sources {
- fullPath, err := wtf.ExpandHomeDir(source)
+ fullPath, err := utils.ExpandHomeDir(source)
if err == nil {
if err := watch.Add(fullPath); err != nil {
log.Fatalln(err)
diff --git a/modules/todo/display.go b/modules/todo/display.go
index dae2a963..179e81a3 100644
--- a/modules/todo/display.go
+++ b/modules/todo/display.go
@@ -2,7 +2,6 @@ package todo
import (
"fmt"
- "strconv"
"github.com/rivo/tview"
"github.com/wtfutil/wtf/checklist"
@@ -34,9 +33,7 @@ func (widget *Widget) display() {
newList.SetSelectedByItem(widget.list.SelectedItem())
widget.SetList(newList)
- widget.View.Clear()
- widget.View.SetText(str)
- widget.View.Highlight(strconv.Itoa(widget.list.Selected())).ScrollToHighlight()
+ widget.Redraw(widget.CommonSettings.Title, str, false)
}
func (widget *Widget) formattedItemLine(idx int, item *checklist.ChecklistItem, selectedItem *checklist.ChecklistItem, maxLen int) string {
@@ -52,7 +49,7 @@ func (widget *Widget) formattedItemLine(idx int, item *checklist.ChecklistItem,
}
str := fmt.Sprintf(
- `["%d"][""][%s:%s]|%s| %s[white]`,
+ `["%d"][""][%s:%s]|%s| %s[white][""]`,
idx,
foreColor,
backColor,
diff --git a/modules/todo/widget.go b/modules/todo/widget.go
index 13713d4d..bc8e3852 100644
--- a/modules/todo/widget.go
+++ b/modules/todo/widget.go
@@ -79,13 +79,7 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
func (widget *Widget) Refresh() {
widget.load()
-
- widget.app.QueueUpdateDraw(func() {
- title := widget.ContextualTitle(widget.CommonSettings.Title)
- widget.View.SetTitle(title)
- widget.display()
- })
-
+ widget.display()
}
func (widget *Widget) SetList(list checklist.Checklist) {
@@ -150,6 +144,10 @@ func (widget *Widget) newItem() {
widget.addButtons(form, saveFctn)
widget.modalFocus(form)
+
+ widget.app.QueueUpdate(func() {
+ widget.app.Draw()
+ })
}
// persist writes the todo list to Yaml file
@@ -198,10 +196,9 @@ func (widget *Widget) addSaveButton(form *tview.Form, fctn func()) {
}
func (widget *Widget) modalFocus(form *tview.Form) {
- frame := widget.modalFrame(form)
- widget.pages.AddPage("modal", frame, false, true)
-
widget.app.QueueUpdateDraw(func() {
+ frame := widget.modalFrame(form)
+ widget.pages.AddPage("modal", frame, false, true)
widget.app.SetFocus(frame)
})
}
diff --git a/modules/todoist/display.go b/modules/todoist/display.go
index fbd7d3f2..ca4aeaba 100644
--- a/modules/todoist/display.go
+++ b/modules/todoist/display.go
@@ -17,7 +17,6 @@ func (widget *Widget) display() {
}
title := fmt.Sprintf("[green]%s[white]", proj.Project.Name)
- widget.View.SetTitle(widget.ContextualTitle(title))
_, _, width, _ := widget.View.GetRect()
str := widget.settings.common.SigilStr(len(widget.projects), widget.idx, width) + "\n"
@@ -47,5 +46,5 @@ func (widget *Widget) display() {
str = str + row + wtf.PadRow((checkWidth+len(item.Content)), (checkWidth+maxLen+1)) + "\n"
}
- widget.View.SetText(str)
+ widget.TextWidget.Redraw(title, str, false)
}
diff --git a/modules/todoist/widget.go b/modules/todoist/widget.go
index 0cb3540f..329ef96c 100644
--- a/modules/todoist/widget.go
+++ b/modules/todoist/widget.go
@@ -31,7 +31,6 @@ type Widget struct {
wtf.KeyboardWidget
wtf.TextWidget
- app *tview.Application
idx int
projects []*Project
settings *Settings
@@ -44,7 +43,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
KeyboardWidget: wtf.NewKeyboardWidget(),
TextWidget: wtf.NewTextWidget(app, settings.common, true),
- app: app,
settings: settings,
}
@@ -96,9 +94,7 @@ func (w *Widget) Refresh() {
return
}
- w.app.QueueUpdateDraw(func() {
- w.display()
- })
+ w.display()
}
/* -------------------- Keyboard Movement -------------------- */
diff --git a/modules/travisci/keyboard.go b/modules/travisci/keyboard.go
index 55f9d455..b8143aec 100644
--- a/modules/travisci/keyboard.go
+++ b/modules/travisci/keyboard.go
@@ -4,13 +4,13 @@ import "github.com/gdamore/tcell"
func (widget *Widget) initializeKeyboardControls() {
widget.SetKeyboardChar("/", widget.ShowHelp)
- widget.SetKeyboardChar("j", widget.next)
- widget.SetKeyboardChar("k", widget.prev)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
widget.SetKeyboardChar("o", widget.openBuild)
widget.SetKeyboardChar("r", widget.Refresh)
- widget.SetKeyboardKey(tcell.KeyDown, widget.next)
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
widget.SetKeyboardKey(tcell.KeyEnter, widget.openBuild)
- widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect)
- widget.SetKeyboardKey(tcell.KeyUp, widget.prev)
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
}
diff --git a/modules/travisci/widget.go b/modules/travisci/widget.go
index e13925ba..49170a43 100644
--- a/modules/travisci/widget.go
+++ b/modules/travisci/widget.go
@@ -25,29 +25,25 @@ const HelpText = `
type Widget struct {
wtf.HelpfulWidget
wtf.KeyboardWidget
- wtf.TextWidget
+ wtf.ScrollableWidget
- app *tview.Application
builds *Builds
- selected int
settings *Settings
}
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
- HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
- KeyboardWidget: wtf.NewKeyboardWidget(),
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
+ KeyboardWidget: wtf.NewKeyboardWidget(),
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
- app: app,
settings: settings,
}
+ widget.SetRenderFunction(widget.Render)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
- widget.unselect()
-
widget.HelpfulWidget.SetView(widget.View)
return &widget
@@ -63,32 +59,23 @@ func (widget *Widget) Refresh() {
builds, err := BuildsFor(widget.settings.apiKey, widget.settings.pro)
if err != nil {
- widget.View.SetWrap(true)
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(err.Error())
- })
- } else {
- widget.builds = builds
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
+ return
}
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.display()
- })
+ widget.builds = builds
+ widget.SetItemCount(len(builds.Builds))
+ widget.Render()
}
/* -------------------- Unexported Functions -------------------- */
-func (widget *Widget) display() {
+func (widget *Widget) Render() {
if widget.builds == nil {
return
}
- widget.View.SetWrap(false)
-
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - Builds", widget.CommonSettings.Title)))
- widget.View.SetText(widget.contentFrom(widget.builds))
+ title := fmt.Sprintf("%s - Builds", widget.CommonSettings.Title)
+ widget.Redraw(title, widget.contentFrom(widget.builds), false)
}
func (widget *Widget) contentFrom(builds *Builds) string {
@@ -97,12 +84,12 @@ func (widget *Widget) contentFrom(builds *Builds) string {
str = str + fmt.Sprintf(
"[%s] [%s] %s-%s (%s) [%s]%s - [blue]%s\n",
- widget.rowColor(idx),
+ widget.RowColor(idx),
buildColor(&build),
build.Repository.Name,
build.Number,
build.Branch.Name,
- widget.rowColor(idx),
+ widget.RowColor(idx),
strings.Split(build.Commit.Message, "\n")[0],
build.CreatedBy.Login,
)
@@ -111,14 +98,6 @@ func (widget *Widget) contentFrom(builds *Builds) string {
return str
}
-func (widget *Widget) rowColor(idx int) string {
- if widget.View.HasFocus() && (idx == widget.selected) {
- return widget.settings.common.DefaultFocussedRowColor()
- }
-
- return widget.settings.common.RowColor(idx)
-}
-
func buildColor(build *Build) string {
switch build.State {
case "broken":
@@ -140,34 +119,11 @@ func buildColor(build *Build) string {
}
}
-func (widget *Widget) next() {
- widget.selected++
- if widget.builds != nil && widget.selected >= len(widget.builds.Builds) {
- widget.selected = 0
- }
-
- widget.display()
-}
-
-func (widget *Widget) prev() {
- widget.selected--
- if widget.selected < 0 && widget.builds != nil {
- widget.selected = len(widget.builds.Builds) - 1
- }
-
- widget.display()
-}
-
func (widget *Widget) openBuild() {
- sel := widget.selected
+ sel := widget.GetSelected()
if sel >= 0 && widget.builds != nil && sel < len(widget.builds.Builds) {
- build := &widget.builds.Builds[widget.selected]
+ build := &widget.builds.Builds[sel]
travisHost := TRAVIS_HOSTS[widget.settings.pro]
wtf.OpenFile(fmt.Sprintf("https://%s/%s/%s/%d", travisHost, build.Repository.Slug, "builds", build.ID))
}
}
-
-func (widget *Widget) unselect() {
- widget.selected = -1
- widget.display()
-}
diff --git a/modules/trello/widget.go b/modules/trello/widget.go
index a4afbe58..dbac1389 100644
--- a/modules/trello/widget.go
+++ b/modules/trello/widget.go
@@ -11,7 +11,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
settings *Settings
}
@@ -19,7 +18,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -45,8 +43,9 @@ func (widget *Widget) Refresh() {
var title string
var content string
+ wrap := false
if err != nil {
- widget.View.SetWrap(true)
+ wrap = true
title = widget.CommonSettings.Title
content = err.Error()
} else {
@@ -59,10 +58,7 @@ func (widget *Widget) Refresh() {
content = widget.contentFrom(searchResult)
}
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(title)
- widget.View.SetText(content)
- })
+ widget.Redraw(title, content, wrap)
}
/* -------------------- Unexported Functions -------------------- */
diff --git a/modules/twitter/widget.go b/modules/twitter/widget.go
index 9fd9e2b4..f26564a0 100644
--- a/modules/twitter/widget.go
+++ b/modules/twitter/widget.go
@@ -28,7 +28,6 @@ type Widget struct {
wtf.MultiSourceWidget
wtf.TextWidget
- app *tview.Application
client *Client
idx int
settings *Settings
@@ -42,7 +41,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
MultiSourceWidget: wtf.NewMultiSourceWidget(settings.common, "screenName", "screenNames"),
TextWidget: wtf.NewTextWidget(app, settings.common, true),
- app: app,
idx: 0,
settings: settings,
}
@@ -67,9 +65,7 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
// Refresh is called on the interval and refreshes the data
func (widget *Widget) Refresh() {
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
}
/* -------------------- Unexported Functions -------------------- */
@@ -78,10 +74,10 @@ func (widget *Widget) display() {
widget.client.screenName = widget.CurrentSource()
tweets := widget.client.Tweets()
- widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("Twitter - [green]@%s[white]", widget.CurrentSource())))
+ title := fmt.Sprintf("Twitter - [green]@%s[white]", widget.CurrentSource())
if len(tweets) == 0 {
- str := fmt.Sprintf("\n\n\n%s", wtf.CenterText("[blue]No Tweets[white]", 50))
+ str := fmt.Sprintf("\n\n\n%s", wtf.CenterText("[lightblue]No Tweets[white]", 50))
widget.View.SetText(str)
return
}
@@ -92,7 +88,7 @@ func (widget *Widget) display() {
str = str + widget.format(tweet)
}
- widget.View.SetText(str)
+ widget.Redraw(title, str, true)
}
// If the tweet's Username is the same as the account we're watching, no
@@ -116,7 +112,7 @@ func (widget *Widget) formatText(text string) string {
// @name mentions
atRegExp := regexp.MustCompile(`@[0-9A-Za-z_]*`)
- result = atRegExp.ReplaceAllString(result, "[blue]${0}[white]")
+ result = atRegExp.ReplaceAllString(result, "[lightblue]${0}[white]")
// HTTP(S) links
linkRegExp := regexp.MustCompile(`http[s:\/.0-9A-Za-z]*`)
diff --git a/modules/unknown/widget.go b/modules/unknown/widget.go
index 6493c6c1..8232aa7a 100644
--- a/modules/unknown/widget.go
+++ b/modules/unknown/widget.go
@@ -10,7 +10,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
settings *Settings
}
@@ -18,7 +17,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -28,10 +26,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
/* -------------------- Exported Functions -------------------- */
func (widget *Widget) Refresh() {
- widget.app.QueueUpdateDraw(func() {
- widget.View.Clear()
-
- content := fmt.Sprintf("Widget %s and/or type %s does not exist", widget.Name(), widget.CommonSettings.Module.Type)
- widget.View.SetText(content)
- })
+ content := fmt.Sprintf("Widget %s and/or type %s does not exist", widget.Name(), widget.CommonSettings.Module.Type)
+ widget.Redraw(widget.CommonSettings.Title, content, true)
}
diff --git a/modules/victorops/widget.go b/modules/victorops/widget.go
index cc57118a..735c3dcd 100644
--- a/modules/victorops/widget.go
+++ b/modules/victorops/widget.go
@@ -20,7 +20,6 @@ const HelpText = `
type Widget struct {
wtf.TextWidget
- app *tview.Application
teams []OnCallTeam
settings *Settings
}
@@ -47,19 +46,11 @@ func (widget *Widget) Refresh() {
widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
if err != nil {
- widget.View.SetWrap(true)
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(err.Error())
- })
+ widget.Redraw(widget.CommonSettings.Title, err.Error(), true)
} else {
widget.teams = teams
+ widget.Redraw(widget.CommonSettings.Title, widget.contentFrom(widget.teams), true)
}
-
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
- widget.display()
- })
}
func (widget *Widget) display() {
@@ -75,6 +66,10 @@ func (widget *Widget) display() {
func (widget *Widget) contentFrom(teams []OnCallTeam) string {
var str string
+ if teams == nil || len(teams) == 0 {
+ return "No teams specified"
+ }
+
for _, team := range teams {
if len(widget.settings.team) > 0 && widget.settings.team != team.Slug {
continue
diff --git a/modules/weatherservices/prettyweather/widget.go b/modules/weatherservices/prettyweather/widget.go
index f7b7a500..a88b209d 100644
--- a/modules/weatherservices/prettyweather/widget.go
+++ b/modules/weatherservices/prettyweather/widget.go
@@ -12,7 +12,6 @@ import (
type Widget struct {
wtf.TextWidget
- app *tview.Application
result string
settings *Settings
}
@@ -21,7 +20,6 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
widget := Widget{
TextWidget: wtf.NewTextWidget(app, settings.common, false),
- app: app,
settings: settings,
}
@@ -31,9 +29,7 @@ func NewWidget(app *tview.Application, settings *Settings) *Widget {
func (widget *Widget) Refresh() {
widget.prettyWeather()
- widget.app.QueueUpdateDraw(func() {
- widget.View.SetText(widget.result)
- })
+ widget.Redraw(widget.CommonSettings.Title, widget.result, false)
}
//this method reads the config and calls wttr.in for pretty weather
diff --git a/modules/weatherservices/weather/display.go b/modules/weatherservices/weather/display.go
index cc357cc2..ba852095 100644
--- a/modules/weatherservices/weather/display.go
+++ b/modules/weatherservices/weather/display.go
@@ -9,31 +9,35 @@ import (
)
func (widget *Widget) display() {
+ err := ""
if widget.apiKeyValid() == false {
- widget.View.SetText(" Environment variable WTF_OWM_API_KEY is not set")
- return
+ err += " Environment variable WTF_OWM_API_KEY is not set\n"
}
cityData := widget.currentData()
if cityData == nil {
- widget.View.SetText(" Weather data is unavailable: no city data")
- return
+ err += " Weather data is unavailable: no city data\n"
}
if len(cityData.Weather) == 0 {
- widget.View.SetText(" Weather data is unavailable: no weather data")
- return
+ err += " Weather data is unavailable: no weather data"
}
- widget.View.SetTitle(widget.title(cityData))
+ title := widget.CommonSettings.Title
- _, _, width, _ := widget.View.GetRect()
- content := widget.settings.common.SigilStr(len(widget.Data), widget.Idx, width) + "\n"
- content = content + widget.description(cityData) + "\n\n"
- content = content + widget.temperatures(cityData) + "\n"
- content = content + widget.sunInfo(cityData)
+ var content string
+ if err != "" {
+ content = err
+ } else {
+ title = widget.buildTitle(cityData)
+ _, _, width, _ := widget.View.GetRect()
+ content = widget.settings.common.SigilStr(len(widget.Data), widget.Idx, width) + "\n"
+ content = content + widget.description(cityData) + "\n\n"
+ content = content + widget.temperatures(cityData) + "\n"
+ content = content + widget.sunInfo(cityData)
+ }
- widget.View.SetText(content)
+ widget.Redraw(title, content, false)
}
func (widget *Widget) description(cityData *owm.CurrentWeatherData) string {
@@ -69,7 +73,6 @@ func (widget *Widget) temperatures(cityData *owm.CurrentWeatherData) string {
return str
}
-func (widget *Widget) title(cityData *owm.CurrentWeatherData) string {
- str := fmt.Sprintf("%s %s", widget.emojiFor(cityData), cityData.Name)
- return widget.ContextualTitle(str)
+func (widget *Widget) buildTitle(cityData *owm.CurrentWeatherData) string {
+ return fmt.Sprintf("%s %s", widget.emojiFor(cityData), cityData.Name)
}
diff --git a/modules/weatherservices/weather/widget.go b/modules/weatherservices/weather/widget.go
index 586123b8..458d08af 100644
--- a/modules/weatherservices/weather/widget.go
+++ b/modules/weatherservices/weather/widget.go
@@ -27,7 +27,6 @@ type Widget struct {
Data []*owm.CurrentWeatherData
Idx int
- app *tview.Application
settings *Settings
}
@@ -40,7 +39,6 @@ func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *
Idx: 0,
- app: app,
settings: settings,
}
@@ -77,9 +75,7 @@ func (widget *Widget) Refresh() {
widget.Data = widget.Fetch(wtf.ToInts(widget.settings.cityIDs))
}
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.display()
}
// Next displays data for the next city data in the list. If the current city is the last
diff --git a/modules/zendesk/keyboard.go b/modules/zendesk/keyboard.go
index 9ccc6e31..0c59044c 100644
--- a/modules/zendesk/keyboard.go
+++ b/modules/zendesk/keyboard.go
@@ -3,22 +3,12 @@ package zendesk
import "github.com/gdamore/tcell"
func (widget *Widget) initializeKeyboardControls() {
- widget.SetKeyboardChar("j", widget.selectNext)
- widget.SetKeyboardChar("k", widget.selectPrev)
+ widget.SetKeyboardChar("j", widget.Next)
+ widget.SetKeyboardChar("k", widget.Prev)
widget.SetKeyboardChar("o", widget.openTicket)
- widget.SetKeyboardKey(tcell.KeyDown, widget.selectNext)
- widget.SetKeyboardKey(tcell.KeyUp, widget.selectPrev)
+ widget.SetKeyboardKey(tcell.KeyDown, widget.Next)
+ widget.SetKeyboardKey(tcell.KeyUp, widget.Prev)
widget.SetKeyboardKey(tcell.KeyEnter, widget.openTicket)
- widget.SetKeyboardKey(tcell.KeyEsc, widget.unselect)
-}
-
-func (widget *Widget) selectNext() {
- widget.next()
- widget.display()
-}
-
-func (widget *Widget) selectPrev() {
- widget.prev()
- widget.display()
+ widget.SetKeyboardKey(tcell.KeyEsc, widget.Unselect)
}
diff --git a/modules/zendesk/widget.go b/modules/zendesk/widget.go
index 79224237..47a20ebf 100644
--- a/modules/zendesk/widget.go
+++ b/modules/zendesk/widget.go
@@ -8,27 +8,41 @@ import (
"github.com/wtfutil/wtf/wtf"
)
+const HelpText = `
+ Keyboard commands for Zendesk:
+
+ /: Show/hide this help window
+ j: Select the next item in the list
+ k: Select the previous item in the list
+ o: Open the selected item in a browser
+
+ arrow down: Select the next item in the list
+ arrow up: Select the previous item in the list
+
+ return: Open the selected item in a browser
+`
+
// A Widget represents a Zendesk widget
type Widget struct {
+ wtf.HelpfulWidget
wtf.KeyboardWidget
- wtf.TextWidget
+ wtf.ScrollableWidget
- app *tview.Application
result *TicketArray
- selected int
settings *Settings
}
// NewWidget creates a new instance of a widget
-func NewWidget(app *tview.Application, settings *Settings) *Widget {
+func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
widget := Widget{
+ HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
KeyboardWidget: wtf.NewKeyboardWidget(),
- TextWidget: wtf.NewTextWidget(app, settings.common, true),
-
- app: app,
+ ScrollableWidget: wtf.NewScrollableWidget(app, settings.common, true),
+
settings: settings,
}
+ widget.SetRenderFunction(widget.Render)
widget.initializeKeyboardControls()
widget.View.SetInputCapture(widget.InputCapture)
@@ -46,16 +60,14 @@ func (widget *Widget) Refresh() {
widget.result = ticketArray
}
- widget.app.QueueUpdateDraw(func() {
- widget.display()
- })
+ widget.Render()
}
/* -------------------- Unexported Functions -------------------- */
-func (widget *Widget) display() {
- widget.View.SetTitle(fmt.Sprintf("%s (%d)", widget.CommonSettings.Title, widget.result.Count))
- widget.View.SetText(widget.textContent(widget.result.Tickets))
+func (widget *Widget) Render() {
+ title := fmt.Sprintf("%s (%d)", widget.CommonSettings.Title, widget.result.Count)
+ widget.Redraw(title, widget.textContent(widget.result.Tickets), false)
}
func (widget *Widget) textContent(items []Ticket) string {
@@ -73,7 +85,7 @@ func (widget *Widget) textContent(items []Ticket) string {
func (widget *Widget) format(ticket Ticket, idx int) string {
textColor := widget.settings.common.Colors.Background
- if idx == widget.selected {
+ if idx == widget.GetSelected() {
textColor = widget.settings.common.Colors.BorderFocused
}
@@ -95,29 +107,11 @@ func (widget *Widget) parseRequester(ticket Ticket) interface{} {
return fromName
}
-func (widget *Widget) next() {
- widget.selected++
- if widget.result != nil && widget.selected >= len(widget.result.Tickets) {
- widget.selected = 0
- }
-}
-
-func (widget *Widget) prev() {
- widget.selected--
- if widget.selected < 0 && widget.result != nil {
- widget.selected = len(widget.result.Tickets) - 1
- }
-}
-
func (widget *Widget) openTicket() {
- sel := widget.selected
+ sel := widget.GetSelected()
if sel >= 0 && widget.result != nil && sel < len(widget.result.Tickets) {
- issue := &widget.result.Tickets[widget.selected]
+ issue := &widget.result.Tickets[sel]
ticketURL := fmt.Sprintf("https://%s.zendesk.com/agent/tickets/%d", widget.settings.subdomain, issue.Id)
wtf.OpenFile(ticketURL)
}
}
-
-func (widget *Widget) unselect() {
- widget.selected = -1
-}
diff --git a/wtf/homedir.go b/utils/homedir.go
similarity index 98%
rename from wtf/homedir.go
rename to utils/homedir.go
index ef43abf7..7c208de7 100644
--- a/wtf/homedir.go
+++ b/utils/homedir.go
@@ -2,7 +2,7 @@
// Copied (mostly) verbatim from https://github.com/Atrox/homedir
-package wtf
+package utils
import (
"errors"
diff --git a/wtf/focus_tracker.go b/wtf/focus_tracker.go
index 002c5e10..de935c96 100644
--- a/wtf/focus_tracker.go
+++ b/wtf/focus_tracker.go
@@ -1,6 +1,8 @@
package wtf
import (
+ "sort"
+
"github.com/olebedev/config"
"github.com/rivo/tview"
)
@@ -177,6 +179,17 @@ func (tracker *FocusTracker) focusables() []Wtfable {
}
}
+ // Sort for deterministic ordering
+ sort.SliceStable(focusable[:], func(i, j int) bool {
+ if focusable[i].Top() < focusable[j].Top() {
+ return true
+ }
+ if focusable[i].Top() == focusable[j].Top() {
+ return focusable[i].Left() < focusable[j].Left()
+ }
+ return false
+ })
+
return focusable
}
diff --git a/wtf/scrollable.go b/wtf/scrollable.go
new file mode 100644
index 00000000..fe716a32
--- /dev/null
+++ b/wtf/scrollable.go
@@ -0,0 +1,79 @@
+package wtf
+
+import (
+ "strconv"
+
+ "github.com/rivo/tview"
+ "github.com/wtfutil/wtf/cfg"
+)
+
+type ScrollableWidget struct {
+ TextWidget
+
+ selected int
+ maxItems int
+ RenderFunction func()
+}
+
+func NewScrollableWidget(app *tview.Application, commonSettings *cfg.Common, focusable bool) ScrollableWidget {
+
+ widget := ScrollableWidget{
+ TextWidget: NewTextWidget(app, commonSettings, focusable),
+ }
+
+ widget.Unselect()
+ widget.View.SetScrollable(true)
+ widget.View.SetRegions(true)
+ return widget
+}
+
+func (widget *ScrollableWidget) SetRenderFunction(displayFunc func()) {
+ widget.RenderFunction = displayFunc
+}
+
+func (widget *ScrollableWidget) SetItemCount(items int) {
+ widget.maxItems = items
+}
+
+func (widget *ScrollableWidget) GetSelected() int {
+ return widget.selected
+}
+
+func (widget *ScrollableWidget) RowColor(idx int) string {
+ if widget.View.HasFocus() && (idx == widget.selected) {
+ return widget.CommonSettings.DefaultFocussedRowColor()
+ }
+
+ return widget.CommonSettings.RowColor(idx)
+}
+
+func (widget *ScrollableWidget) Next() {
+ widget.selected++
+ if widget.selected >= widget.maxItems {
+ widget.selected = 0
+ }
+ widget.RenderFunction()
+}
+
+func (widget *ScrollableWidget) Prev() {
+ widget.selected--
+ if widget.selected < 0 {
+ widget.selected = widget.maxItems - 1
+ }
+ widget.RenderFunction()
+}
+
+func (widget *ScrollableWidget) Unselect() {
+ widget.selected = -1
+ if widget.RenderFunction != nil {
+ widget.RenderFunction()
+ }
+}
+
+func (widget *ScrollableWidget) Redraw(title, content string, wrap bool) {
+
+ widget.TextWidget.Redraw(title, content, wrap)
+ widget.app.QueueUpdateDraw(func() {
+ widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
+ })
+}
diff --git a/wtf/text_widget.go b/wtf/text_widget.go
index de403606..a6016ca4 100644
--- a/wtf/text_widget.go
+++ b/wtf/text_widget.go
@@ -13,6 +13,7 @@ type TextWidget struct {
focusChar string
name string
refreshInterval int
+ app *tview.Application
View *tview.TextView
@@ -24,6 +25,7 @@ func NewTextWidget(app *tview.Application, commonSettings *cfg.Common, focusable
widget := TextWidget{
CommonSettings: commonSettings,
+ app: app,
enabled: commonSettings.Enabled,
focusable: focusable,
focusChar: commonSettings.FocusChar(),
@@ -107,6 +109,16 @@ func (widget *TextWidget) TextView() *tview.TextView {
return widget.View
}
+func (widget *TextWidget) Redraw(title, text string, wrap bool) {
+
+ widget.app.QueueUpdateDraw(func() {
+ widget.View.Clear()
+ widget.View.SetWrap(wrap)
+ widget.View.SetTitle(widget.ContextualTitle(title))
+ widget.View.SetText(text)
+ })
+}
+
/* -------------------- Unexported Functions -------------------- */
func (widget *TextWidget) addView() *tview.TextView {
@@ -119,7 +131,6 @@ func (widget *TextWidget) addView() *tview.TextView {
view.SetBorder(true)
view.SetDynamicColors(true)
- view.SetTitle(widget.ContextualTitle(widget.CommonSettings.Title))
view.SetWrap(false)
return view
diff --git a/wtf/utils.go b/wtf/utils.go
index a5a2f60a..fc743dec 100644
--- a/wtf/utils.go
+++ b/wtf/utils.go
@@ -7,6 +7,8 @@ import (
"regexp"
"runtime"
"strings"
+
+ "github.com/wtfutil/wtf/utils"
)
const SimpleDateFormat = "Jan 2"
@@ -92,7 +94,7 @@ func OpenFile(path string) {
default:
}
} else {
- filePath, _ := ExpandHomeDir(path)
+ filePath, _ := utils.ExpandHomeDir(path)
cmd := exec.Command(OpenFileUtil, filePath)
ExecuteCommand(cmd)
}