mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
WTF-389 Don't load widgets that have invalid position co-ordinates in their config
This commit is contained in:
parent
293e191f1e
commit
c9c7e124cc
145
main.go
145
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,21 @@ 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)
|
||||
initializeFocusTracker(app, widgets)
|
||||
|
||||
display := wtf.NewDisplay(widgets)
|
||||
pages.AddPage("grid", display.Grid, true, true)
|
||||
case err := <-watch.Error:
|
||||
@ -172,112 +174,128 @@ 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)
|
||||
|
||||
if widget.IsPositionable() {
|
||||
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
|
||||
}
|
||||
|
||||
/* -------------------- Main -------------------- */
|
||||
@ -303,11 +321,12 @@ func main() {
|
||||
app := tview.NewApplication()
|
||||
pages := tview.NewPages()
|
||||
|
||||
makeWidgets(app, pages)
|
||||
initializeFocusTracker(app)
|
||||
widgets := makeWidgets(app, pages)
|
||||
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)
|
||||
|
@ -18,7 +18,6 @@ type BarGraph struct {
|
||||
View *tview.TextView
|
||||
|
||||
Position
|
||||
|
||||
}
|
||||
|
||||
type Bar struct {
|
||||
@ -78,6 +77,12 @@ 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) RefreshInterval() int {
|
||||
return widget.RefreshInt
|
||||
}
|
||||
@ -154,11 +159,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,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,10 @@ func (display *Display) add(widget Wtfable) {
|
||||
return
|
||||
}
|
||||
|
||||
if !widget.IsPositionable() {
|
||||
return
|
||||
}
|
||||
|
||||
display.Grid.AddItem(
|
||||
widget.TextView(),
|
||||
widget.Top(),
|
||||
|
@ -3,5 +3,7 @@ package wtf
|
||||
type Enabler interface {
|
||||
Disabled() bool
|
||||
Enabled() bool
|
||||
IsPositionable() bool
|
||||
|
||||
Disable()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
86
wtf/position_test.go
Normal file
86
wtf/position_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -86,6 +86,12 @@ 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) RefreshInterval() int {
|
||||
return widget.RefreshInt
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user