diff --git a/logger/log.go b/logger/log.go index 084f6fe8..0e40dc0d 100644 --- a/logger/log.go +++ b/logger/log.go @@ -52,7 +52,7 @@ func (widget *Widget) Refresh() { return } - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) logLines := widget.tailFile() widget.View.SetText(widget.contentFrom(logLines)) diff --git a/main.go b/main.go index 079f407f..a9f92bbd 100644 --- a/main.go +++ b/main.go @@ -68,7 +68,7 @@ import ( ) var focusTracker wtf.FocusTracker -var widgets []wtf.Wtfable +var runningWidgets []wtf.Wtfable // Config parses the config.yml file and makes available the settings within var Config *config.Config @@ -81,13 +81,13 @@ var ( /* -------------------- Functions -------------------- */ -func disableAllWidgets() { +func disableAllWidgets(widgets []wtf.Wtfable) { for _, widget := range widgets { widget.Disable() } } -func initializeFocusTracker(app *tview.Application) { +func initializeFocusTracker(app *tview.Application, widgets []wtf.Wtfable) { focusTracker = wtf.FocusTracker{ App: app, Idx: -1, @@ -100,7 +100,7 @@ func initializeFocusTracker(app *tview.Application) { func keyboardIntercept(event *tcell.EventKey) *tcell.EventKey { switch event.Key() { case tcell.KeyCtrlR: - refreshAllWidgets() + refreshAllWidgets(runningWidgets) case tcell.KeyTab: focusTracker.Next() case tcell.KeyBacktab: @@ -121,7 +121,7 @@ func loadConfigFile(filePath string) { wtf.Config = Config } -func refreshAllWidgets() { +func refreshAllWidgets(widgets []wtf.Wtfable) { for _, widget := range widgets { go widget.Refresh() } @@ -138,19 +138,23 @@ func watchForConfigChanges(app *tview.Application, configFilePath string, grid * watch := watcher.New() absPath, _ := wtf.ExpandHomeDir(configFilePath) - // notify write events. + // Notify write events watch.FilterOps(watcher.Write) go func() { for { select { case <-watch.Event: - loadConfigFile(absPath) // Disable all widgets to stop scheduler goroutines and rmeove widgets from memory. - disableAllWidgets() - widgets = nil - makeWidgets(app, pages) - initializeFocusTracker(app) + disableAllWidgets(runningWidgets) + + loadConfigFile(absPath) + + widgets := makeWidgets(app, pages) + validateWidgets(widgets) + + initializeFocusTracker(app, widgets) + display := wtf.NewDisplay(widgets) pages.AddPage("grid", display.Grid, true, true) 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 switch widgetName { case "bamboohr": - widgets = append(widgets, bamboohr.NewWidget(app)) + widget = bamboohr.NewWidget(app) case "bargraph": - widgets = append(widgets, bargraph.NewWidget(app)) + widget = bargraph.NewWidget(app) case "bittrex": - widgets = append(widgets, bittrex.NewWidget(app)) + widget = bittrex.NewWidget(app) case "blockfolio": - widgets = append(widgets, blockfolio.NewWidget(app)) + widget = blockfolio.NewWidget(app) case "circleci": - widgets = append(widgets, circleci.NewWidget(app)) + widget = circleci.NewWidget(app) case "clocks": - widgets = append(widgets, clocks.NewWidget(app)) + widget = clocks.NewWidget(app) case "cmdrunner": - widgets = append(widgets, cmdrunner.NewWidget(app)) - case "resourceusage": - widgets = append(widgets, resourceusage.NewWidget(app)) + widget = cmdrunner.NewWidget(app) case "cryptolive": - widgets = append(widgets, cryptolive.NewWidget(app)) + widget = cryptolive.NewWidget(app) case "datadog": - widgets = append(widgets, datadog.NewWidget(app)) + widget = datadog.NewWidget(app) case "gcal": - widgets = append(widgets, gcal.NewWidget(app)) + widget = gcal.NewWidget(app) case "gerrit": - widgets = append(widgets, gerrit.NewWidget(app, pages)) + widget = gerrit.NewWidget(app, pages) case "git": - widgets = append(widgets, git.NewWidget(app, pages)) + widget = git.NewWidget(app, pages) case "github": - widgets = append(widgets, github.NewWidget(app, pages)) + widget = github.NewWidget(app, pages) case "gitlab": - widgets = append(widgets, gitlab.NewWidget(app, pages)) + widget = gitlab.NewWidget(app, pages) case "gitter": - widgets = append(widgets, gitter.NewWidget(app, pages)) + widget = gitter.NewWidget(app, pages) case "gspreadsheets": - widgets = append(widgets, gspreadsheets.NewWidget(app)) + widget = gspreadsheets.NewWidget(app) case "hackernews": - widgets = append(widgets, hackernews.NewWidget(app, pages)) + widget = hackernews.NewWidget(app, pages) case "ipapi": - widgets = append(widgets, ipapi.NewWidget(app)) + widget = ipapi.NewWidget(app) case "ipinfo": - widgets = append(widgets, ipinfo.NewWidget(app)) + widget = ipinfo.NewWidget(app) case "jenkins": - widgets = append(widgets, jenkins.NewWidget(app, pages)) + widget = jenkins.NewWidget(app, pages) case "jira": - widgets = append(widgets, jira.NewWidget(app, pages)) + widget = jira.NewWidget(app, pages) case "logger": - widgets = append(widgets, logger.NewWidget(app)) + widget = logger.NewWidget(app) case "mercurial": - widgets = append(widgets, mercurial.NewWidget(app, pages)) + widget = mercurial.NewWidget(app, pages) case "nbascore": - widgets = append(widgets, nbascore.NewWidget(app, pages)) + widget = nbascore.NewWidget(app, pages) case "newrelic": - widgets = append(widgets, newrelic.NewWidget(app)) + widget = newrelic.NewWidget(app) case "opsgenie": - widgets = append(widgets, opsgenie.NewWidget(app)) + widget = opsgenie.NewWidget(app) case "pagerduty": - widgets = append(widgets, pagerduty.NewWidget(app)) + widget = pagerduty.NewWidget(app) case "power": - widgets = append(widgets, power.NewWidget(app)) + widget = power.NewWidget(app) case "prettyweather": - widgets = append(widgets, prettyweather.NewWidget(app)) + widget = prettyweather.NewWidget(app) + case "resourceusage": + widget = resourceusage.NewWidget(app) case "security": - widgets = append(widgets, security.NewWidget(app)) + widget = security.NewWidget(app) case "status": - widgets = append(widgets, status.NewWidget(app)) + widget = status.NewWidget(app) case "system": - widgets = append(widgets, system.NewWidget(app, date, version)) + widget = system.NewWidget(app, date, version) case "spotify": - widgets = append(widgets, spotify.NewWidget(app, pages)) + widget = spotify.NewWidget(app, pages) case "spotifyweb": - widgets = append(widgets, spotifyweb.NewWidget(app, pages)) + widget = spotifyweb.NewWidget(app, pages) case "textfile": - widgets = append(widgets, textfile.NewWidget(app, pages)) + widget = textfile.NewWidget(app, pages) case "todo": - widgets = append(widgets, todo.NewWidget(app, pages)) + widget = todo.NewWidget(app, pages) case "todoist": - widgets = append(widgets, todoist.NewWidget(app, pages)) + widget = todoist.NewWidget(app, pages) case "travisci": - widgets = append(widgets, travisci.NewWidget(app, pages)) + widget = travisci.NewWidget(app, pages) case "rollbar": - widgets = append(widgets, rollbar.NewWidget(app, pages)) + widget = rollbar.NewWidget(app, pages) case "trello": - widgets = append(widgets, trello.NewWidget(app)) + widget = trello.NewWidget(app) case "twitter": - widgets = append(widgets, twitter.NewWidget(app, pages)) + widget = twitter.NewWidget(app, pages) case "victorops": - widgets = append(widgets, victorops.NewWidget(app)) + widget = victorops.NewWidget(app) case "weather": - widgets = append(widgets, weather.NewWidget(app, pages)) + widget = weather.NewWidget(app, pages) case "zendesk": - widgets = append(widgets, zendesk.NewWidget(app)) + widget = zendesk.NewWidget(app) 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") for mod := range mods { 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() pages := tview.NewPages() - makeWidgets(app, pages) - initializeFocusTracker(app) + widgets := makeWidgets(app, pages) + validateWidgets(widgets) + + initializeFocusTracker(app, widgets) display := wtf.NewDisplay(widgets) pages.AddPage("grid", display.Grid, true, true) + app.SetInputCapture(keyboardIntercept) go watchForConfigChanges(app, flags.Config, display.Grid, pages) diff --git a/modules/bamboohr/widget.go b/modules/bamboohr/widget.go index 464c06cd..a757e40a 100644 --- a/modules/bamboohr/widget.go +++ b/modules/bamboohr/widget.go @@ -40,7 +40,7 @@ func (widget *Widget) Refresh() { 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)) } diff --git a/modules/circleci/widget.go b/modules/circleci/widget.go index 62c4210e..7806d074 100644 --- a/modules/circleci/widget.go +++ b/modules/circleci/widget.go @@ -38,7 +38,7 @@ func (widget *Widget) Refresh() { 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 if err != nil { diff --git a/modules/datadog/widget.go b/modules/datadog/widget.go index 2d5d97f7..5ed2f9b9 100644 --- a/modules/datadog/widget.go +++ b/modules/datadog/widget.go @@ -25,7 +25,7 @@ func NewWidget(app *tview.Application) *Widget { func (widget *Widget) Refresh() { 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() var content string diff --git a/modules/gcal/display.go b/modules/gcal/display.go index f1157b19..af2b34c2 100644 --- a/modules/gcal/display.go +++ b/modules/gcal/display.go @@ -32,7 +32,7 @@ func (widget *Widget) display() { widget.mutex.Lock() 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)) } diff --git a/modules/gerrit/display.go b/modules/gerrit/display.go index db704e12..770c3231 100644 --- a/modules/gerrit/display.go +++ b/modules/gerrit/display.go @@ -14,7 +14,7 @@ func (widget *Widget) display() { 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 = str + " [red]Stats[white]\n" diff --git a/modules/gerrit/widget.go b/modules/gerrit/widget.go index 051c7f02..6fcdaee9 100644 --- a/modules/gerrit/widget.go +++ b/modules/gerrit/widget.go @@ -94,7 +94,7 @@ func (widget *Widget) Refresh() { gerrit, err := glb.NewClient(gerritUrl, httpClient) if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) widget.View.SetText(err.Error()) return } diff --git a/modules/git/display.go b/modules/git/display.go index 1086d081..546b3f6e 100644 --- a/modules/git/display.go +++ b/modules/git/display.go @@ -15,7 +15,7 @@ func (widget *Widget) display() { 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)) str := wtf.SigilStr(len(widget.GitRepos), widget.Idx, widget.View) + "\n" diff --git a/modules/github/display.go b/modules/github/display.go index 940e12fc..556f38a3 100644 --- a/modules/github/display.go +++ b/modules/github/display.go @@ -14,7 +14,7 @@ func (widget *Widget) display() { 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 = str + " [red]Stats[white]\n" diff --git a/modules/gitlab/display.go b/modules/gitlab/display.go index 0c8028cf..3899d7f2 100644 --- a/modules/gitlab/display.go +++ b/modules/gitlab/display.go @@ -14,7 +14,7 @@ func (widget *Widget) display() { 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 = str + " [red]Stats[white]\n" diff --git a/modules/gitter/widget.go b/modules/gitter/widget.go index cb15cd0b..89dbb03a 100644 --- a/modules/gitter/widget.go +++ b/modules/gitter/widget.go @@ -54,7 +54,7 @@ func (widget *Widget) Refresh() { room, err := GetRoom(wtf.Config.UString("wtf.mods.gitter.roomUri", "wtfutil/Lobby")) if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) widget.View.SetText(err.Error()) return } @@ -67,7 +67,7 @@ func (widget *Widget) Refresh() { if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) widget.View.SetText(err.Error()) } else { widget.messages = messages @@ -86,7 +86,7 @@ func (widget *Widget) display() { widget.View.SetWrap(true) 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.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight() } diff --git a/modules/hackernews/widget.go b/modules/hackernews/widget.go index 8600e5c4..be19ab36 100644 --- a/modules/hackernews/widget.go +++ b/modules/hackernews/widget.go @@ -64,7 +64,7 @@ func (widget *Widget) Refresh() { if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) widget.View.SetText(err.Error()) } else { var stories []Story @@ -94,7 +94,7 @@ func (widget *Widget) display() { widget.View.SetWrap(false) 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.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight() } diff --git a/modules/jenkins/widget.go b/modules/jenkins/widget.go index 9aa70824..23e6d16e 100644 --- a/modules/jenkins/widget.go +++ b/modules/jenkins/widget.go @@ -63,7 +63,7 @@ func (widget *Widget) Refresh() { if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.ContextualTitle(widget.Name)) + widget.View.SetTitle(widget.ContextualTitle(widget.Name())) widget.View.SetText(err.Error()) } @@ -80,7 +80,7 @@ func (widget *Widget) display() { widget.View.SetWrap(false) 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.Highlight(strconv.Itoa(widget.selected)).ScrollToHighlight() } diff --git a/modules/jira/widget.go b/modules/jira/widget.go index cd9f80f2..ef260a12 100644 --- a/modules/jira/widget.go +++ b/modules/jira/widget.go @@ -57,7 +57,7 @@ func (widget *Widget) Refresh() { if err != nil { widget.result = nil widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) widget.View.SetText(err.Error()) } else { widget.result = searchResult @@ -74,7 +74,7 @@ func (widget *Widget) display() { } 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.SetTitle(widget.ContextualTitle(str)) diff --git a/modules/mercurial/display.go b/modules/mercurial/display.go index 87f287ed..724baddb 100644 --- a/modules/mercurial/display.go +++ b/modules/mercurial/display.go @@ -15,7 +15,7 @@ func (widget *Widget) display() { 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)) str := wtf.SigilStr(len(widget.Data), widget.Idx, widget.View) + "\n" diff --git a/modules/nbascore/widget.go b/modules/nbascore/widget.go index 4231fcc1..242decb9 100644 --- a/modules/nbascore/widget.go +++ b/modules/nbascore/widget.go @@ -47,7 +47,7 @@ func NewWidget(app *tview.Application, pages *tview.Pages) *Widget { func (widget *Widget) Refresh() { widget.nbascore() - widget.View.SetTitle(widget.ContextualTitle(widget.Name)) + widget.View.SetTitle(widget.ContextualTitle(widget.Name())) } func (widget *Widget) nbascore() { diff --git a/modules/newrelic/widget.go b/modules/newrelic/widget.go index a8ee6950..591426c5 100644 --- a/modules/newrelic/widget.go +++ b/modules/newrelic/widget.go @@ -34,7 +34,7 @@ func (widget *Widget) Refresh() { 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() var content string diff --git a/modules/opsgenie/widget.go b/modules/opsgenie/widget.go index 50f509f8..717c5f34 100644 --- a/modules/opsgenie/widget.go +++ b/modules/opsgenie/widget.go @@ -27,7 +27,7 @@ func (widget *Widget) Refresh() { wtf.Config.UString("wtf.mods.opsgenie.scheduleIdentifierType"), getSchedules(), ) - widget.View.SetTitle(widget.ContextualTitle(widget.Name)) + widget.View.SetTitle(widget.ContextualTitle(widget.Name())) var content string if err != nil { diff --git a/modules/pagerduty/widget.go b/modules/pagerduty/widget.go index 5bfea9a5..469abbdb 100644 --- a/modules/pagerduty/widget.go +++ b/modules/pagerduty/widget.go @@ -38,7 +38,7 @@ func (widget *Widget) Refresh() { 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() var content string diff --git a/modules/rollbar/widget.go b/modules/rollbar/widget.go index 0e836408..e1f34204 100644 --- a/modules/rollbar/widget.go +++ b/modules/rollbar/widget.go @@ -55,7 +55,7 @@ func (widget *Widget) Refresh() { if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) widget.View.SetText(err.Error()) } else { widget.items = &items.Results @@ -73,7 +73,7 @@ func (widget *Widget) display() { widget.View.SetWrap(false) 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)) } diff --git a/modules/todo/widget.go b/modules/todo/widget.go index 1553921b..5f0abeba 100644 --- a/modules/todo/widget.go +++ b/modules/todo/widget.go @@ -72,7 +72,7 @@ func (widget *Widget) Refresh() { widget.load() widget.display() - widget.View.SetTitle(widget.ContextualTitle(widget.Name)) + widget.View.SetTitle(widget.ContextualTitle(widget.Name())) } func (widget *Widget) SetList(newList checklist.Checklist) { diff --git a/modules/travisci/widget.go b/modules/travisci/widget.go index 9ab5ecc8..8844fcaf 100644 --- a/modules/travisci/widget.go +++ b/modules/travisci/widget.go @@ -55,7 +55,7 @@ func (widget *Widget) Refresh() { if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) widget.View.SetText(err.Error()) } else { widget.builds = builds @@ -73,7 +73,7 @@ func (widget *Widget) display() { 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)) } diff --git a/modules/trello/widget.go b/modules/trello/widget.go index 96b017d8..61ddf0cc 100644 --- a/modules/trello/widget.go +++ b/modules/trello/widget.go @@ -35,14 +35,14 @@ func (widget *Widget) Refresh() { var content string if err != nil { widget.View.SetWrap(true) - widget.View.SetTitle(widget.Name) + widget.View.SetTitle(widget.Name()) content = err.Error() } else { widget.View.SetWrap(false) widget.View.SetTitle( fmt.Sprintf( "[white]%s: [green]%s ", - widget.Name, + widget.Name(), wtf.Config.UString("wtf.mods.trello.board"), ), ) diff --git a/modules/unknown/widget.go b/modules/unknown/widget.go index 76ffe6b1..88653d90 100644 --- a/modules/unknown/widget.go +++ b/modules/unknown/widget.go @@ -23,9 +23,9 @@ func NewWidget(app *tview.Application, name string) *Widget { 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() - content := fmt.Sprintf("Widget %s does not exist", widget.Name) + content := fmt.Sprintf("Widget %s does not exist", widget.Name()) widget.View.SetText(content) } diff --git a/modules/victorops/widget.go b/modules/victorops/widget.go index 0a9dac06..a4de256f 100644 --- a/modules/victorops/widget.go +++ b/modules/victorops/widget.go @@ -41,7 +41,7 @@ func (widget *Widget) Refresh() { } teams, err := Fetch() - widget.View.SetTitle(widget.ContextualTitle(widget.Name)) + widget.View.SetTitle(widget.ContextualTitle(widget.Name())) if err != nil { widget.View.SetWrap(true) diff --git a/modules/zendesk/widget.go b/modules/zendesk/widget.go index 7d1b08ab..153a954f 100644 --- a/modules/zendesk/widget.go +++ b/modules/zendesk/widget.go @@ -43,7 +43,7 @@ func (widget *Widget) Refresh() { /* -------------------- Unexported Functions -------------------- */ 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)) } diff --git a/wtf/bargraph.go b/wtf/bargraph.go index 8642ea20..cc00887e 100644 --- a/wtf/bargraph.go +++ b/wtf/bargraph.go @@ -9,16 +9,17 @@ import ( //BarGraph lets make graphs type BarGraph struct { - enabled bool - focusable bool - starChar string - maxStars int - Name string + enabled bool + focusable bool + key string + maxStars int + name string + starChar string + RefreshInt int View *tview.TextView Position - } type Bar struct { @@ -32,9 +33,10 @@ func NewBarGraph(app *tview.Application, name string, configKey string, focusabl widget := BarGraph{ enabled: Config.UBool(fmt.Sprintf("wtf.mods.%s.enabled", configKey), false), 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), - 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), } @@ -78,6 +80,20 @@ func (widget *BarGraph) FocusChar() string { 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 { return widget.RefreshInt } @@ -99,7 +115,7 @@ func (widget *BarGraph) addView(app *tview.Application, configKey string) { view.SetBorder(true) view.SetBorderColor(ColorFor(widget.BorderColor())) view.SetDynamicColors(true) - view.SetTitle(widget.Name) + view.SetTitle(widget.Name()) view.SetTitleColor(ColorFor( Config.UString( fmt.Sprintf("wtf.mods.%s.colors.title", configKey), @@ -154,11 +170,11 @@ func BuildStars(data []Bar, maxStars int, starChar string) string { fmt.Sprintf( "%s%s[[red]%s[white]%s] %s\n", bar.Label, - strings.Repeat(" ", longestLabel - len(bar.Label)), + strings.Repeat(" ", longestLabel-len(bar.Label)), strings.Repeat(starChar, starCount), - strings.Repeat(" ", maxStars - starCount), + strings.Repeat(" ", maxStars-starCount), label, - ), + ), ) } diff --git a/wtf/display.go b/wtf/display.go index 7779cb5b..431e36d4 100644 --- a/wtf/display.go +++ b/wtf/display.go @@ -26,6 +26,10 @@ func (display *Display) add(widget Wtfable) { return } + if !widget.IsPositionable() { + return + } + display.Grid.AddItem( widget.TextView(), widget.Top(), diff --git a/wtf/enabler.go b/wtf/enabler.go index c7a5b973..cdf2894d 100644 --- a/wtf/enabler.go +++ b/wtf/enabler.go @@ -3,5 +3,7 @@ package wtf type Enabler interface { Disabled() bool Enabled() bool + IsPositionable() bool + Disable() } diff --git a/wtf/position.go b/wtf/position.go index 521a93b3..18e8fc9e 100644 --- a/wtf/position.go +++ b/wtf/position.go @@ -18,18 +18,26 @@ func NewPosition(top, left, width, height int) Position { return pos } -func (pos *Position) Top() int { - return pos.top +func (pos *Position) IsValid() bool { + 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 { return pos.left } +func (pos *Position) Top() int { + return pos.top +} + func (pos *Position) Width() int { return pos.width } - -func (pos *Position) Height() int { - return pos.height -} diff --git a/wtf/position_test.go b/wtf/position_test.go new file mode 100644 index 00000000..0e8edabd --- /dev/null +++ b/wtf/position_test.go @@ -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) + } + } +} diff --git a/wtf/text_widget.go b/wtf/text_widget.go index 1e661e9b..74ead21f 100644 --- a/wtf/text_widget.go +++ b/wtf/text_widget.go @@ -13,8 +13,9 @@ type TextWidget struct { enabled bool focusable bool focusChar string + key string + name string - Name string RefreshInt int 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), focusable: focusable, 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)), } @@ -86,6 +88,20 @@ func (widget *TextWidget) FocusChar() string { 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 { return widget.RefreshInt } @@ -129,7 +145,7 @@ func (widget *TextWidget) addView(app *tview.Application, configKey string) { app.Draw() }) view.SetDynamicColors(true) - view.SetTitle(widget.ContextualTitle(widget.Name)) + view.SetTitle(widget.ContextualTitle(widget.name)) view.SetWrap(false) widget.View = view diff --git a/wtf/wtfable.go b/wtf/wtfable.go index 973db6c6..86e33121 100644 --- a/wtf/wtfable.go +++ b/wtf/wtfable.go @@ -11,6 +11,8 @@ type Wtfable interface { BorderColor() string Focusable() bool FocusChar() string + Key() string + Name() string SetFocusChar(string) TextView() *tview.TextView diff --git a/wtf_tests/position_test.go b/wtf_tests/position_test.go deleted file mode 100644 index ed5cbd4c..00000000 --- a/wtf_tests/position_test.go +++ /dev/null @@ -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()) - } -}