1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00

Merge pull request #401 from wtfutil/WTF-389-position-check

WTF-389 Don't load widgets that have invalid position co-ordinates in…

Closes #389
This commit is contained in:
Chris Cummer 2019-04-12 14:06:30 -07:00 committed by GitHub
commit 84f7cd8539
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 283 additions and 146 deletions

View File

@ -52,7 +52,7 @@ func (widget *Widget) Refresh() {
return return
} }
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
logLines := widget.tailFile() logLines := widget.tailFile()
widget.View.SetText(widget.contentFrom(logLines)) widget.View.SetText(widget.contentFrom(logLines))

156
main.go
View File

@ -68,7 +68,7 @@ import (
) )
var focusTracker wtf.FocusTracker var focusTracker wtf.FocusTracker
var widgets []wtf.Wtfable var runningWidgets []wtf.Wtfable
// Config parses the config.yml file and makes available the settings within // Config parses the config.yml file and makes available the settings within
var Config *config.Config var Config *config.Config
@ -81,13 +81,13 @@ var (
/* -------------------- Functions -------------------- */ /* -------------------- Functions -------------------- */
func disableAllWidgets() { func disableAllWidgets(widgets []wtf.Wtfable) {
for _, widget := range widgets { for _, widget := range widgets {
widget.Disable() widget.Disable()
} }
} }
func initializeFocusTracker(app *tview.Application) { func initializeFocusTracker(app *tview.Application, widgets []wtf.Wtfable) {
focusTracker = wtf.FocusTracker{ focusTracker = wtf.FocusTracker{
App: app, App: app,
Idx: -1, Idx: -1,
@ -100,7 +100,7 @@ func initializeFocusTracker(app *tview.Application) {
func keyboardIntercept(event *tcell.EventKey) *tcell.EventKey { func keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() { switch event.Key() {
case tcell.KeyCtrlR: case tcell.KeyCtrlR:
refreshAllWidgets() refreshAllWidgets(runningWidgets)
case tcell.KeyTab: case tcell.KeyTab:
focusTracker.Next() focusTracker.Next()
case tcell.KeyBacktab: case tcell.KeyBacktab:
@ -121,7 +121,7 @@ func loadConfigFile(filePath string) {
wtf.Config = Config wtf.Config = Config
} }
func refreshAllWidgets() { func refreshAllWidgets(widgets []wtf.Wtfable) {
for _, widget := range widgets { for _, widget := range widgets {
go widget.Refresh() go widget.Refresh()
} }
@ -138,19 +138,23 @@ func watchForConfigChanges(app *tview.Application, configFilePath string, grid *
watch := watcher.New() watch := watcher.New()
absPath, _ := wtf.ExpandHomeDir(configFilePath) absPath, _ := wtf.ExpandHomeDir(configFilePath)
// notify write events. // Notify write events
watch.FilterOps(watcher.Write) watch.FilterOps(watcher.Write)
go func() { go func() {
for { for {
select { select {
case <-watch.Event: case <-watch.Event:
loadConfigFile(absPath)
// Disable all widgets to stop scheduler goroutines and rmeove widgets from memory. // Disable all widgets to stop scheduler goroutines and rmeove widgets from memory.
disableAllWidgets() disableAllWidgets(runningWidgets)
widgets = nil
makeWidgets(app, pages) loadConfigFile(absPath)
initializeFocusTracker(app)
widgets := makeWidgets(app, pages)
validateWidgets(widgets)
initializeFocusTracker(app, widgets)
display := wtf.NewDisplay(widgets) display := wtf.NewDisplay(widgets)
pages.AddPage("grid", display.Grid, true, true) pages.AddPage("grid", display.Grid, true, true)
case err := <-watch.Error: case err := <-watch.Error:
@ -172,110 +176,133 @@ func watchForConfigChanges(app *tview.Application, configFilePath string, grid *
} }
} }
func addWidget(app *tview.Application, pages *tview.Pages, widgetName string) { func makeWidget(app *tview.Application, pages *tview.Pages, widgetName string) wtf.Wtfable {
var widget wtf.Wtfable
// Always in alphabetical order // Always in alphabetical order
switch widgetName { switch widgetName {
case "bamboohr": case "bamboohr":
widgets = append(widgets, bamboohr.NewWidget(app)) widget = bamboohr.NewWidget(app)
case "bargraph": case "bargraph":
widgets = append(widgets, bargraph.NewWidget(app)) widget = bargraph.NewWidget(app)
case "bittrex": case "bittrex":
widgets = append(widgets, bittrex.NewWidget(app)) widget = bittrex.NewWidget(app)
case "blockfolio": case "blockfolio":
widgets = append(widgets, blockfolio.NewWidget(app)) widget = blockfolio.NewWidget(app)
case "circleci": case "circleci":
widgets = append(widgets, circleci.NewWidget(app)) widget = circleci.NewWidget(app)
case "clocks": case "clocks":
widgets = append(widgets, clocks.NewWidget(app)) widget = clocks.NewWidget(app)
case "cmdrunner": case "cmdrunner":
widgets = append(widgets, cmdrunner.NewWidget(app)) widget = cmdrunner.NewWidget(app)
case "resourceusage":
widgets = append(widgets, resourceusage.NewWidget(app))
case "cryptolive": case "cryptolive":
widgets = append(widgets, cryptolive.NewWidget(app)) widget = cryptolive.NewWidget(app)
case "datadog": case "datadog":
widgets = append(widgets, datadog.NewWidget(app)) widget = datadog.NewWidget(app)
case "gcal": case "gcal":
widgets = append(widgets, gcal.NewWidget(app)) widget = gcal.NewWidget(app)
case "gerrit": case "gerrit":
widgets = append(widgets, gerrit.NewWidget(app, pages)) widget = gerrit.NewWidget(app, pages)
case "git": case "git":
widgets = append(widgets, git.NewWidget(app, pages)) widget = git.NewWidget(app, pages)
case "github": case "github":
widgets = append(widgets, github.NewWidget(app, pages)) widget = github.NewWidget(app, pages)
case "gitlab": case "gitlab":
widgets = append(widgets, gitlab.NewWidget(app, pages)) widget = gitlab.NewWidget(app, pages)
case "gitter": case "gitter":
widgets = append(widgets, gitter.NewWidget(app, pages)) widget = gitter.NewWidget(app, pages)
case "gspreadsheets": case "gspreadsheets":
widgets = append(widgets, gspreadsheets.NewWidget(app)) widget = gspreadsheets.NewWidget(app)
case "hackernews": case "hackernews":
widgets = append(widgets, hackernews.NewWidget(app, pages)) widget = hackernews.NewWidget(app, pages)
case "ipapi": case "ipapi":
widgets = append(widgets, ipapi.NewWidget(app)) widget = ipapi.NewWidget(app)
case "ipinfo": case "ipinfo":
widgets = append(widgets, ipinfo.NewWidget(app)) widget = ipinfo.NewWidget(app)
case "jenkins": case "jenkins":
widgets = append(widgets, jenkins.NewWidget(app, pages)) widget = jenkins.NewWidget(app, pages)
case "jira": case "jira":
widgets = append(widgets, jira.NewWidget(app, pages)) widget = jira.NewWidget(app, pages)
case "logger": case "logger":
widgets = append(widgets, logger.NewWidget(app)) widget = logger.NewWidget(app)
case "mercurial": case "mercurial":
widgets = append(widgets, mercurial.NewWidget(app, pages)) widget = mercurial.NewWidget(app, pages)
case "nbascore": case "nbascore":
widgets = append(widgets, nbascore.NewWidget(app, pages)) widget = nbascore.NewWidget(app, pages)
case "newrelic": case "newrelic":
widgets = append(widgets, newrelic.NewWidget(app)) widget = newrelic.NewWidget(app)
case "opsgenie": case "opsgenie":
widgets = append(widgets, opsgenie.NewWidget(app)) widget = opsgenie.NewWidget(app)
case "pagerduty": case "pagerduty":
widgets = append(widgets, pagerduty.NewWidget(app)) widget = pagerduty.NewWidget(app)
case "power": case "power":
widgets = append(widgets, power.NewWidget(app)) widget = power.NewWidget(app)
case "prettyweather": case "prettyweather":
widgets = append(widgets, prettyweather.NewWidget(app)) widget = prettyweather.NewWidget(app)
case "resourceusage":
widget = resourceusage.NewWidget(app)
case "security": case "security":
widgets = append(widgets, security.NewWidget(app)) widget = security.NewWidget(app)
case "status": case "status":
widgets = append(widgets, status.NewWidget(app)) widget = status.NewWidget(app)
case "system": case "system":
widgets = append(widgets, system.NewWidget(app, date, version)) widget = system.NewWidget(app, date, version)
case "spotify": case "spotify":
widgets = append(widgets, spotify.NewWidget(app, pages)) widget = spotify.NewWidget(app, pages)
case "spotifyweb": case "spotifyweb":
widgets = append(widgets, spotifyweb.NewWidget(app, pages)) widget = spotifyweb.NewWidget(app, pages)
case "textfile": case "textfile":
widgets = append(widgets, textfile.NewWidget(app, pages)) widget = textfile.NewWidget(app, pages)
case "todo": case "todo":
widgets = append(widgets, todo.NewWidget(app, pages)) widget = todo.NewWidget(app, pages)
case "todoist": case "todoist":
widgets = append(widgets, todoist.NewWidget(app, pages)) widget = todoist.NewWidget(app, pages)
case "travisci": case "travisci":
widgets = append(widgets, travisci.NewWidget(app, pages)) widget = travisci.NewWidget(app, pages)
case "rollbar": case "rollbar":
widgets = append(widgets, rollbar.NewWidget(app, pages)) widget = rollbar.NewWidget(app, pages)
case "trello": case "trello":
widgets = append(widgets, trello.NewWidget(app)) widget = trello.NewWidget(app)
case "twitter": case "twitter":
widgets = append(widgets, twitter.NewWidget(app, pages)) widget = twitter.NewWidget(app, pages)
case "victorops": case "victorops":
widgets = append(widgets, victorops.NewWidget(app)) widget = victorops.NewWidget(app)
case "weather": case "weather":
widgets = append(widgets, weather.NewWidget(app, pages)) widget = weather.NewWidget(app, pages)
case "zendesk": case "zendesk":
widgets = append(widgets, zendesk.NewWidget(app)) widget = zendesk.NewWidget(app)
default: default:
widgets = append(widgets, unknown.NewWidget(app, widgetName)) widget = unknown.NewWidget(app, widgetName)
} }
return widget
} }
func makeWidgets(app *tview.Application, pages *tview.Pages) { func makeWidgets(app *tview.Application, pages *tview.Pages) []wtf.Wtfable {
widgets := []wtf.Wtfable{}
mods, _ := Config.Map("wtf.mods") mods, _ := Config.Map("wtf.mods")
for mod := range mods { for mod := range mods {
if enabled := Config.UBool("wtf.mods."+mod+".enabled", false); enabled { if enabled := Config.UBool("wtf.mods."+mod+".enabled", false); enabled {
addWidget(app, pages, mod) widget := makeWidget(app, pages, mod)
widgets = append(widgets, widget)
}
}
// This is a hack to allow refreshAllWidgets and disableAllWidgets to work
// Need to implement a non-global way to track these
runningWidgets = widgets
return widgets
}
// Check that all the loaded widgets are valid for display
func validateWidgets(widgets []wtf.Wtfable) {
for _, widget := range widgets {
if widget.Enabled() && !widget.IsPositionable() {
errStr := fmt.Sprintf("Widget config has invalid values: %s", widget.Key())
log.Fatalln(errStr)
} }
} }
} }
@ -303,11 +330,14 @@ func main() {
app := tview.NewApplication() app := tview.NewApplication()
pages := tview.NewPages() pages := tview.NewPages()
makeWidgets(app, pages) widgets := makeWidgets(app, pages)
initializeFocusTracker(app) validateWidgets(widgets)
initializeFocusTracker(app, widgets)
display := wtf.NewDisplay(widgets) display := wtf.NewDisplay(widgets)
pages.AddPage("grid", display.Grid, true, true) pages.AddPage("grid", display.Grid, true, true)
app.SetInputCapture(keyboardIntercept) app.SetInputCapture(keyboardIntercept)
go watchForConfigChanges(app, flags.Config, display.Grid, pages) go watchForConfigChanges(app, flags.Config, display.Grid, pages)

View File

@ -40,7 +40,7 @@ func (widget *Widget) Refresh() {
wtf.Now().Format(wtf.DateFormat), wtf.Now().Format(wtf.DateFormat),
) )
widget.View.SetTitle(widget.ContextualTitle(widget.Name)) widget.View.SetTitle(widget.ContextualTitle(widget.Name()))
widget.View.SetText(widget.contentFrom(todayItems)) widget.View.SetText(widget.contentFrom(todayItems))
} }

View File

@ -38,7 +38,7 @@ func (widget *Widget) Refresh() {
builds, err := widget.Client.BuildsFor() builds, err := widget.Client.BuildsFor()
widget.View.SetTitle(fmt.Sprintf("%s - Builds", widget.Name)) widget.View.SetTitle(fmt.Sprintf("%s - Builds", widget.Name()))
var content string var content string
if err != nil { if err != nil {

View File

@ -25,7 +25,7 @@ func NewWidget(app *tview.Application) *Widget {
func (widget *Widget) Refresh() { func (widget *Widget) Refresh() {
monitors, monitorErr := Monitors() monitors, monitorErr := Monitors()
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s", widget.Name))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s", widget.Name())))
widget.View.Clear() widget.View.Clear()
var content string var content string

View File

@ -32,7 +32,7 @@ func (widget *Widget) display() {
widget.mutex.Lock() widget.mutex.Lock()
defer widget.mutex.Unlock() defer widget.mutex.Unlock()
widget.View.SetTitle(widget.ContextualTitle(widget.Name)) widget.View.SetTitle(widget.ContextualTitle(widget.Name()))
widget.View.SetText(widget.contentFrom(widget.calEvents)) widget.View.SetText(widget.contentFrom(widget.calEvents))
} }

View File

@ -14,7 +14,7 @@ func (widget *Widget) display() {
return return
} }
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s- %s", widget.Name, widget.title(project)))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s- %s", widget.Name(), widget.title(project))))
str := wtf.SigilStr(len(widget.GerritProjects), widget.Idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.GerritProjects), widget.Idx, widget.View) + "\n"
str = str + " [red]Stats[white]\n" str = str + " [red]Stats[white]\n"

View File

@ -94,7 +94,7 @@ func (widget *Widget) Refresh() {
gerrit, err := glb.NewClient(gerritUrl, httpClient) gerrit, err := glb.NewClient(gerritUrl, httpClient)
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
return return
} }

View File

@ -15,7 +15,7 @@ func (widget *Widget) display() {
return return
} }
title := fmt.Sprintf("%s - [green]%s[white]", widget.Name, repoData.Repository) title := fmt.Sprintf("%s - [green]%s[white]", widget.Name(), repoData.Repository)
widget.View.SetTitle(widget.ContextualTitle(title)) widget.View.SetTitle(widget.ContextualTitle(title))
str := wtf.SigilStr(len(widget.GitRepos), widget.Idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.GitRepos), widget.Idx, widget.View) + "\n"

View File

@ -14,7 +14,7 @@ func (widget *Widget) display() {
return return
} }
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.Name, widget.title(repo)))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.Name(), widget.title(repo))))
str := wtf.SigilStr(len(widget.GithubRepos), widget.Idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.GithubRepos), widget.Idx, widget.View) + "\n"
str = str + " [red]Stats[white]\n" str = str + " [red]Stats[white]\n"

View File

@ -14,7 +14,7 @@ func (widget *Widget) display() {
return return
} }
widget.View.SetTitle(fmt.Sprintf("%s- %s", widget.Name, widget.title(project))) widget.View.SetTitle(fmt.Sprintf("%s- %s", widget.Name(), widget.title(project)))
str := wtf.SigilStr(len(widget.GitlabProjects), widget.Idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.GitlabProjects), widget.Idx, widget.View) + "\n"
str = str + " [red]Stats[white]\n" str = str + " [red]Stats[white]\n"

View File

@ -54,7 +54,7 @@ func (widget *Widget) Refresh() {
room, err := GetRoom(wtf.Config.UString("wtf.mods.gitter.roomUri", "wtfutil/Lobby")) room, err := GetRoom(wtf.Config.UString("wtf.mods.gitter.roomUri", "wtfutil/Lobby"))
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
return return
} }
@ -67,7 +67,7 @@ func (widget *Widget) Refresh() {
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
} else { } else {
widget.messages = messages widget.messages = messages
@ -86,7 +86,7 @@ func (widget *Widget) display() {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.Clear() widget.View.Clear()
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.Name, wtf.Config.UString("wtf.mods.gitter.roomUri", "wtfutil/Lobby")))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.Name(), wtf.Config.UString("wtf.mods.gitter.roomUri", "wtfutil/Lobby"))))
widget.View.SetText(widget.contentFrom(widget.messages)) widget.View.SetText(widget.contentFrom(widget.messages))
widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight() widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
} }

View File

@ -64,7 +64,7 @@ func (widget *Widget) Refresh() {
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
} else { } else {
var stories []Story var stories []Story
@ -94,7 +94,7 @@ func (widget *Widget) display() {
widget.View.SetWrap(false) widget.View.SetWrap(false)
widget.View.Clear() widget.View.Clear()
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %sstories", widget.Name, wtf.Config.UString("wtf.mods.hackernews.storyType", "top")))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %sstories", widget.Name(), wtf.Config.UString("wtf.mods.hackernews.storyType", "top"))))
widget.View.SetText(widget.contentFrom(widget.stories)) widget.View.SetText(widget.contentFrom(widget.stories))
widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight() widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
} }

View File

@ -63,7 +63,7 @@ func (widget *Widget) Refresh() {
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.ContextualTitle(widget.Name)) widget.View.SetTitle(widget.ContextualTitle(widget.Name()))
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
} }
@ -80,7 +80,7 @@ func (widget *Widget) display() {
widget.View.SetWrap(false) widget.View.SetWrap(false)
widget.View.Clear() widget.View.Clear()
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s: [red]%s", widget.Name, widget.view.Name))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s: [red]%s", widget.Name(), widget.view.Name)))
widget.View.SetText(widget.contentFrom(widget.view)) widget.View.SetText(widget.contentFrom(widget.view))
widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight() widget.View.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight()
} }

View File

@ -57,7 +57,7 @@ func (widget *Widget) Refresh() {
if err != nil { if err != nil {
widget.result = nil widget.result = nil
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
} else { } else {
widget.result = searchResult widget.result = searchResult
@ -74,7 +74,7 @@ func (widget *Widget) display() {
} }
widget.View.SetWrap(false) widget.View.SetWrap(false)
str := fmt.Sprintf("%s- [green]%s[white]", widget.Name, wtf.Config.UString("wtf.mods.jira.project")) str := fmt.Sprintf("%s- [green]%s[white]", widget.Name(), wtf.Config.UString("wtf.mods.jira.project"))
widget.View.Clear() widget.View.Clear()
widget.View.SetTitle(widget.ContextualTitle(str)) widget.View.SetTitle(widget.ContextualTitle(str))

View File

@ -15,7 +15,7 @@ func (widget *Widget) display() {
return return
} }
title := fmt.Sprintf("%s - [green]%s[white]", widget.Name, repoData.Repository) title := fmt.Sprintf("%s - [green]%s[white]", widget.Name(), repoData.Repository)
widget.View.SetTitle(widget.ContextualTitle(title)) widget.View.SetTitle(widget.ContextualTitle(title))
str := wtf.SigilStr(len(widget.Data), widget.Idx, widget.View) + "\n" str := wtf.SigilStr(len(widget.Data), widget.Idx, widget.View) + "\n"

View File

@ -47,7 +47,7 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
func (widget *Widget) Refresh() { func (widget *Widget) Refresh() {
widget.nbascore() widget.nbascore()
widget.View.SetTitle(widget.ContextualTitle(widget.Name)) widget.View.SetTitle(widget.ContextualTitle(widget.Name()))
} }
func (widget *Widget) nbascore() { func (widget *Widget) nbascore() {

View File

@ -34,7 +34,7 @@ func (widget *Widget) Refresh() {
appName = app.Name appName = app.Name
} }
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - [green]%s[white]", widget.Name, appName))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - [green]%s[white]", widget.Name(), appName)))
widget.View.Clear() widget.View.Clear()
var content string var content string

View File

@ -27,7 +27,7 @@ func (widget *Widget) Refresh() {
wtf.Config.UString("wtf.mods.opsgenie.scheduleIdentifierType"), wtf.Config.UString("wtf.mods.opsgenie.scheduleIdentifierType"),
getSchedules(), getSchedules(),
) )
widget.View.SetTitle(widget.ContextualTitle(widget.Name)) widget.View.SetTitle(widget.ContextualTitle(widget.Name()))
var content string var content string
if err != nil { if err != nil {

View File

@ -38,7 +38,7 @@ func (widget *Widget) Refresh() {
incidents, err2 = GetIncidents() incidents, err2 = GetIncidents()
} }
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s", widget.Name))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s", widget.Name())))
widget.View.Clear() widget.View.Clear()
var content string var content string

View File

@ -55,7 +55,7 @@ func (widget *Widget) Refresh() {
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
} else { } else {
widget.items = &items.Results widget.items = &items.Results
@ -73,7 +73,7 @@ func (widget *Widget) display() {
widget.View.SetWrap(false) widget.View.SetWrap(false)
projectName := wtf.Config.UString("wtf.mods.rollbar.projectName", "Items") projectName := wtf.Config.UString("wtf.mods.rollbar.projectName", "Items")
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.Name, projectName))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - %s", widget.Name(), projectName)))
widget.View.SetText(widget.contentFrom(widget.items)) widget.View.SetText(widget.contentFrom(widget.items))
} }

View File

@ -72,7 +72,7 @@ func (widget *Widget) Refresh() {
widget.load() widget.load()
widget.display() widget.display()
widget.View.SetTitle(widget.ContextualTitle(widget.Name)) widget.View.SetTitle(widget.ContextualTitle(widget.Name()))
} }
func (widget *Widget) SetList(newList checklist.Checklist) { func (widget *Widget) SetList(newList checklist.Checklist) {

View File

@ -55,7 +55,7 @@ func (widget *Widget) Refresh() {
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
widget.View.SetText(err.Error()) widget.View.SetText(err.Error())
} else { } else {
widget.builds = builds widget.builds = builds
@ -73,7 +73,7 @@ func (widget *Widget) display() {
widget.View.SetWrap(false) widget.View.SetWrap(false)
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - Builds", widget.Name))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s - Builds", widget.Name())))
widget.View.SetText(widget.contentFrom(widget.builds)) widget.View.SetText(widget.contentFrom(widget.builds))
} }

View File

@ -35,14 +35,14 @@ func (widget *Widget) Refresh() {
var content string var content string
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)
widget.View.SetTitle(widget.Name) widget.View.SetTitle(widget.Name())
content = err.Error() content = err.Error()
} else { } else {
widget.View.SetWrap(false) widget.View.SetWrap(false)
widget.View.SetTitle( widget.View.SetTitle(
fmt.Sprintf( fmt.Sprintf(
"[white]%s: [green]%s ", "[white]%s: [green]%s ",
widget.Name, widget.Name(),
wtf.Config.UString("wtf.mods.trello.board"), wtf.Config.UString("wtf.mods.trello.board"),
), ),
) )

View File

@ -23,9 +23,9 @@ func NewWidget(app *tview.Application, name string) *Widget {
func (widget *Widget) Refresh() { func (widget *Widget) Refresh() {
widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s", widget.Name))) widget.View.SetTitle(widget.ContextualTitle(fmt.Sprintf("%s", widget.Name())))
widget.View.Clear() widget.View.Clear()
content := fmt.Sprintf("Widget %s does not exist", widget.Name) content := fmt.Sprintf("Widget %s does not exist", widget.Name())
widget.View.SetText(content) widget.View.SetText(content)
} }

View File

@ -41,7 +41,7 @@ func (widget *Widget) Refresh() {
} }
teams, err := Fetch() teams, err := Fetch()
widget.View.SetTitle(widget.ContextualTitle(widget.Name)) widget.View.SetTitle(widget.ContextualTitle(widget.Name()))
if err != nil { if err != nil {
widget.View.SetWrap(true) widget.View.SetWrap(true)

View File

@ -43,7 +43,7 @@ func (widget *Widget) Refresh() {
/* -------------------- Unexported Functions -------------------- */ /* -------------------- Unexported Functions -------------------- */
func (widget *Widget) display() { func (widget *Widget) display() {
widget.View.SetTitle(fmt.Sprintf("%s (%d)", widget.Name, widget.result.Count)) widget.View.SetTitle(fmt.Sprintf("%s (%d)", widget.Name(), widget.result.Count))
widget.View.SetText(widget.textContent(widget.result.Tickets)) widget.View.SetText(widget.textContent(widget.result.Tickets))
} }

View File

@ -11,14 +11,15 @@ import (
type BarGraph struct { type BarGraph struct {
enabled bool enabled bool
focusable bool focusable bool
starChar string key string
maxStars int maxStars int
Name string name string
starChar string
RefreshInt int RefreshInt int
View *tview.TextView View *tview.TextView
Position Position
} }
type Bar struct { type Bar struct {
@ -32,9 +33,10 @@ func NewBarGraph(app *tview.Application, name string, configKey string, focusabl
widget := BarGraph{ widget := BarGraph{
enabled: Config.UBool(fmt.Sprintf("wtf.mods.%s.enabled", configKey), false), enabled: Config.UBool(fmt.Sprintf("wtf.mods.%s.enabled", configKey), false),
focusable: focusable, focusable: focusable,
starChar: Config.UString(fmt.Sprintf("wtf.mods.%s.graphIcon", configKey), "|"), key: configKey,
maxStars: Config.UInt(fmt.Sprintf("wtf.mods.%s.graphStars", configKey), 20), maxStars: Config.UInt(fmt.Sprintf("wtf.mods.%s.graphStars", configKey), 20),
Name: Config.UString(fmt.Sprintf("wtf.mods.%s.title", configKey), name), name: Config.UString(fmt.Sprintf("wtf.mods.%s.title", configKey), name),
starChar: Config.UString(fmt.Sprintf("wtf.mods.%s.graphIcon", configKey), "|"),
RefreshInt: Config.UInt(fmt.Sprintf("wtf.mods.%s.refreshInterval", configKey), 1), RefreshInt: Config.UInt(fmt.Sprintf("wtf.mods.%s.refreshInterval", configKey), 1),
} }
@ -78,6 +80,20 @@ func (widget *BarGraph) FocusChar() string {
return "" return ""
} }
// IsPositionable returns TRUE if the widget has valid position parameters, FALSE if it has
// invalid position parameters (ie: cannot be placed onscreen)
func (widget *BarGraph) IsPositionable() bool {
return widget.Position.IsValid()
}
func (widget *BarGraph) Key() string {
return widget.key
}
func (widget *BarGraph) Name() string {
return widget.name
}
func (widget *BarGraph) RefreshInterval() int { func (widget *BarGraph) RefreshInterval() int {
return widget.RefreshInt return widget.RefreshInt
} }
@ -99,7 +115,7 @@ func (widget *BarGraph) addView(app *tview.Application, configKey string) {
view.SetBorder(true) view.SetBorder(true)
view.SetBorderColor(ColorFor(widget.BorderColor())) view.SetBorderColor(ColorFor(widget.BorderColor()))
view.SetDynamicColors(true) view.SetDynamicColors(true)
view.SetTitle(widget.Name) view.SetTitle(widget.Name())
view.SetTitleColor(ColorFor( view.SetTitleColor(ColorFor(
Config.UString( Config.UString(
fmt.Sprintf("wtf.mods.%s.colors.title", configKey), fmt.Sprintf("wtf.mods.%s.colors.title", configKey),
@ -154,9 +170,9 @@ func BuildStars(data []Bar, maxStars int, starChar string) string {
fmt.Sprintf( fmt.Sprintf(
"%s%s[[red]%s[white]%s] %s\n", "%s%s[[red]%s[white]%s] %s\n",
bar.Label, bar.Label,
strings.Repeat(" ", longestLabel - len(bar.Label)), strings.Repeat(" ", longestLabel-len(bar.Label)),
strings.Repeat(starChar, starCount), strings.Repeat(starChar, starCount),
strings.Repeat(" ", maxStars - starCount), strings.Repeat(" ", maxStars-starCount),
label, label,
), ),
) )

View File

@ -26,6 +26,10 @@ func (display *Display) add(widget Wtfable) {
return return
} }
if !widget.IsPositionable() {
return
}
display.Grid.AddItem( display.Grid.AddItem(
widget.TextView(), widget.TextView(),
widget.Top(), widget.Top(),

View File

@ -3,5 +3,7 @@ package wtf
type Enabler interface { type Enabler interface {
Disabled() bool Disabled() bool
Enabled() bool Enabled() bool
IsPositionable() bool
Disable() Disable()
} }

View File

@ -18,18 +18,26 @@ func NewPosition(top, left, width, height int) Position {
return pos return pos
} }
func (pos *Position) Top() int { func (pos *Position) IsValid() bool {
return pos.top if pos.height < 1 || pos.left < 0 || pos.top < 0 || pos.width < 1 {
return false
}
return true
}
func (pos *Position) Height() int {
return pos.height
} }
func (pos *Position) Left() int { func (pos *Position) Left() int {
return pos.left return pos.left
} }
func (pos *Position) Top() int {
return pos.top
}
func (pos *Position) Width() int { func (pos *Position) Width() int {
return pos.width return pos.width
} }
func (pos *Position) Height() int {
return pos.height
}

86
wtf/position_test.go Normal file
View File

@ -0,0 +1,86 @@
package wtf
import (
"testing"
)
func Test_NewPosition(t *testing.T) {
pos := NewPosition(0, 1, 2, 3)
if pos.Height() != 3 {
t.Fatalf("Expected 3 but got %d", pos.Height())
}
if pos.Left() != 1 {
t.Fatalf("Expected 1 but got %d", pos.Left())
}
if pos.Top() != 0 {
t.Fatalf("Expected 0 but got %d", pos.Top())
}
if pos.Width() != 2 {
t.Fatalf("Expected 2 but got %d", pos.Width())
}
}
func Test_IsValid(t *testing.T) {
tests := []struct {
name string
height int
left int
top int
width int
expected bool
}{
{
name: "valid position",
height: 2,
left: 0,
top: 1,
width: 2,
expected: true,
},
{
name: "invalid height",
height: 0,
left: 0,
top: 1,
width: 2,
expected: false,
},
{
name: "invalid left",
height: 2,
left: -1,
top: 1,
width: 2,
expected: false,
},
{
name: "invalid top",
height: 2,
left: 0,
top: -1,
width: 2,
expected: false,
},
{
name: "invalid width",
height: 2,
left: 0,
top: 1,
width: 0,
expected: false,
},
}
for _, tt := range tests {
pos := NewPosition(tt.top, tt.left, tt.width, tt.height)
actual := pos.IsValid()
if actual != tt.expected {
t.Errorf("%s: expected: %v, got: %v", tt.name, tt.expected, actual)
}
}
}

View File

@ -13,8 +13,9 @@ type TextWidget struct {
enabled bool enabled bool
focusable bool focusable bool
focusChar string focusChar string
key string
name string
Name string
RefreshInt int RefreshInt int
View *tview.TextView View *tview.TextView
@ -32,7 +33,8 @@ func NewTextWidget(app *tview.Application, name string, configKey string, focusa
enabled: Config.UBool(fmt.Sprintf("wtf.mods.%s.enabled", configKey), false), enabled: Config.UBool(fmt.Sprintf("wtf.mods.%s.enabled", configKey), false),
focusable: focusable, focusable: focusable,
focusChar: focusChar, focusChar: focusChar,
Name: Config.UString(fmt.Sprintf("wtf.mods.%s.title", configKey), name), key: configKey,
name: Config.UString(fmt.Sprintf("wtf.mods.%s.title", configKey), name),
RefreshInt: Config.UInt(fmt.Sprintf("wtf.mods.%s.refreshInterval", configKey)), RefreshInt: Config.UInt(fmt.Sprintf("wtf.mods.%s.refreshInterval", configKey)),
} }
@ -86,6 +88,20 @@ func (widget *TextWidget) FocusChar() string {
return widget.focusChar return widget.focusChar
} }
// IsPositionable returns TRUE if the widget has valid position parameters, FALSE if it has
// invalid position parameters (ie: cannot be placed onscreen)
func (widget *TextWidget) IsPositionable() bool {
return widget.Position.IsValid()
}
func (widget *TextWidget) Key() string {
return widget.key
}
func (widget *TextWidget) Name() string {
return widget.name
}
func (widget *TextWidget) RefreshInterval() int { func (widget *TextWidget) RefreshInterval() int {
return widget.RefreshInt return widget.RefreshInt
} }
@ -129,7 +145,7 @@ func (widget *TextWidget) addView(app *tview.Application, configKey string) {
app.Draw() app.Draw()
}) })
view.SetDynamicColors(true) view.SetDynamicColors(true)
view.SetTitle(widget.ContextualTitle(widget.Name)) view.SetTitle(widget.ContextualTitle(widget.name))
view.SetWrap(false) view.SetWrap(false)
widget.View = view widget.View = view

View File

@ -11,6 +11,8 @@ type Wtfable interface {
BorderColor() string BorderColor() string
Focusable() bool Focusable() bool
FocusChar() string FocusChar() string
Key() string
Name() string
SetFocusChar(string) SetFocusChar(string)
TextView() *tview.TextView TextView() *tview.TextView

View File

@ -1,27 +0,0 @@
package wtf_tests
import (
"testing"
. "github.com/wtfutil/wtf/wtf"
)
func TestPosition(t *testing.T) {
pos := NewPosition(0, 1, 2, 3)
if pos.Top() != 0 {
t.Fatalf("Expected 0 but got %d", pos.Top())
}
if pos.Left() != 1 {
t.Fatalf("Expected 1 but got %d", pos.Left())
}
if pos.Width() != 2 {
t.Fatalf("Expected 2 but got %d", pos.Width())
}
if pos.Height() != 3 {
t.Fatalf("Expected 3 but got %d", pos.Height())
}
}