mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Reimpliments the module configuration validation
Now supports displaying errors from multiple widgets.
This commit is contained in:
@@ -44,7 +44,7 @@ type Sigils struct {
|
||||
type Common struct {
|
||||
Colors
|
||||
Module
|
||||
Position `help:"Defines where in the grid this module’s widget will be displayed."`
|
||||
PositionSettings `help:"Defines where in the grid this module’s widget will be displayed."`
|
||||
Sigils
|
||||
|
||||
Enabled bool `help:"Determines whether or not this module is executed and if its data displayed onscreen." values:"true, false"`
|
||||
@@ -78,7 +78,7 @@ func NewCommonSettingsFromModule(name, defaultTitle string, moduleConfig *config
|
||||
Type: moduleConfig.UString("type", name),
|
||||
},
|
||||
|
||||
Position: NewPositionFromYAML(name, moduleConfig),
|
||||
PositionSettings: NewPositionSettingsFromYAML(name, moduleConfig),
|
||||
|
||||
Enabled: moduleConfig.UBool("enabled", false),
|
||||
RefreshInterval: moduleConfig.UInt("refreshInterval", 300),
|
||||
@@ -100,6 +100,8 @@ func NewCommonSettingsFromModule(name, defaultTitle string, moduleConfig *config
|
||||
return &common
|
||||
}
|
||||
|
||||
/* -------------------- Exported Functions -------------------- */
|
||||
|
||||
func (common *Common) DefaultFocusedRowColor() string {
|
||||
return fmt.Sprintf("%s:%s", common.Colors.HighlightFore, common.Colors.HighlightBack)
|
||||
}
|
||||
@@ -109,12 +111,11 @@ func (common *Common) DefaultRowColor() string {
|
||||
}
|
||||
|
||||
func (common *Common) FocusChar() string {
|
||||
focusChar := string('0' + common.focusChar)
|
||||
if common.focusChar == -1 {
|
||||
focusChar = ""
|
||||
if common.focusChar <= -1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return focusChar
|
||||
return string('0' + common.focusChar)
|
||||
}
|
||||
|
||||
func (common *Common) RowColor(idx int) string {
|
||||
@@ -143,3 +144,15 @@ func (common *Common) SigilStr(len, pos int, width int) string {
|
||||
|
||||
return sigils
|
||||
}
|
||||
|
||||
// Validations aggregates all the validations from all the sub-sections in Common into a
|
||||
// single array of validations
|
||||
func (common *Common) Validations() []Validatable {
|
||||
validatables := []Validatable{}
|
||||
|
||||
for _, validation := range common.PositionSettings.Validations.validations {
|
||||
validatables = append(validatables, validation)
|
||||
}
|
||||
|
||||
return validatables
|
||||
}
|
||||
|
||||
123
cfg/position.go
123
cfg/position.go
@@ -1,123 +0,0 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/olebedev/config"
|
||||
)
|
||||
|
||||
const (
|
||||
positionPath = "position"
|
||||
)
|
||||
|
||||
/* -------------------- Position Validation -------------------- */
|
||||
|
||||
type positionValidation struct {
|
||||
err error
|
||||
name string
|
||||
val int
|
||||
}
|
||||
|
||||
func (posVal *positionValidation) hasError() bool {
|
||||
return posVal.err != nil
|
||||
}
|
||||
|
||||
// String returns the Stringer representation of the positionValidation
|
||||
func (posVal *positionValidation) String() string {
|
||||
return fmt.Sprintf("Invalid value for %s:\t%d", posVal.name, posVal.val)
|
||||
}
|
||||
|
||||
func newPositionValidation(name string, val int, err error) *positionValidation {
|
||||
posVal := &positionValidation{
|
||||
err: err,
|
||||
name: name,
|
||||
val: val,
|
||||
}
|
||||
|
||||
return posVal
|
||||
}
|
||||
|
||||
/* -------------------- Position -------------------- */
|
||||
|
||||
// Position represents the onscreen location of a widget
|
||||
type Position struct {
|
||||
Height int
|
||||
Left int
|
||||
Top int
|
||||
Width int
|
||||
}
|
||||
|
||||
// NewPositionFromYAML creates and returns a new instance of Position
|
||||
func NewPositionFromYAML(moduleName string, moduleConfig *config.Config) Position {
|
||||
var val int
|
||||
var err error
|
||||
validations := make(map[string]*positionValidation)
|
||||
|
||||
// Parse the positional data from the config data
|
||||
val, err = moduleConfig.Int(positionPath + ".top")
|
||||
validations["top"] = newPositionValidation("top", val, err)
|
||||
|
||||
val, err = moduleConfig.Int(positionPath + ".left")
|
||||
validations["left"] = newPositionValidation("left", val, err)
|
||||
|
||||
val, err = moduleConfig.Int(positionPath + ".width")
|
||||
validations["width"] = newPositionValidation("width", val, err)
|
||||
|
||||
val, err = moduleConfig.Int(positionPath + ".height")
|
||||
validations["height"] = newPositionValidation("height", val, err)
|
||||
|
||||
validatePositions(moduleName, validations)
|
||||
|
||||
pos := Position{
|
||||
Top: validations["top"].val,
|
||||
Left: validations["left"].val,
|
||||
Width: validations["width"].val,
|
||||
Height: validations["height"].val,
|
||||
}
|
||||
|
||||
return pos
|
||||
}
|
||||
|
||||
/* -------------------- Unexported Functions -------------------- */
|
||||
|
||||
// If any of the position values have an error then we inform the user and exit the app
|
||||
// Common examples of invalid position configuration are:
|
||||
//
|
||||
// position:
|
||||
// top: 3
|
||||
// width: 2
|
||||
// height: 1
|
||||
//
|
||||
// position:
|
||||
// top: 3
|
||||
// # left: 2
|
||||
// width: 2
|
||||
// height: 1
|
||||
//
|
||||
// position:
|
||||
// top: 3
|
||||
// left: 2
|
||||
// width: 2
|
||||
// height: 1
|
||||
//
|
||||
func validatePositions(moduleName string, validations map[string]*positionValidation) {
|
||||
var errStr string
|
||||
|
||||
for _, posVal := range validations {
|
||||
if posVal.hasError() {
|
||||
errStr += fmt.Sprintf(" - %s.\t\033[0;31mError\033[0m %v\n", posVal, posVal.err)
|
||||
}
|
||||
}
|
||||
|
||||
if errStr != "" {
|
||||
fmt.Println()
|
||||
fmt.Printf("\033[0;1mErrors in %s position configuration\033[0m\n", strings.Title(moduleName))
|
||||
fmt.Println(errStr)
|
||||
fmt.Println("Please check your config.yml file.")
|
||||
fmt.Println()
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
51
cfg/position_settings.go
Normal file
51
cfg/position_settings.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"github.com/olebedev/config"
|
||||
)
|
||||
|
||||
const (
|
||||
positionPath = "position"
|
||||
)
|
||||
|
||||
// PositionSettings represents the onscreen location of a widget
|
||||
type PositionSettings struct {
|
||||
Validations *Validations
|
||||
|
||||
Height int
|
||||
Left int
|
||||
Top int
|
||||
Width int
|
||||
}
|
||||
|
||||
// NewPositionSettingsFromYAML creates and returns a new instance of cfg.Position
|
||||
func NewPositionSettingsFromYAML(moduleName string, moduleConfig *config.Config) PositionSettings {
|
||||
var currVal int
|
||||
var err error
|
||||
|
||||
validations := NewValidations()
|
||||
|
||||
// Parse the positional data from the config data
|
||||
currVal, err = moduleConfig.Int(positionPath + ".top")
|
||||
validations.append("top", newPositionValidation("top", currVal, err))
|
||||
|
||||
currVal, err = moduleConfig.Int(positionPath + ".left")
|
||||
validations.append("left", newPositionValidation("left", currVal, err))
|
||||
|
||||
currVal, err = moduleConfig.Int(positionPath + ".width")
|
||||
validations.append("width", newPositionValidation("width", currVal, err))
|
||||
|
||||
currVal, err = moduleConfig.Int(positionPath + ".height")
|
||||
validations.append("height", newPositionValidation("height", currVal, err))
|
||||
|
||||
pos := PositionSettings{
|
||||
Validations: validations,
|
||||
|
||||
Top: validations.valueFor("top"),
|
||||
Left: validations.valueFor("left"),
|
||||
Width: validations.valueFor("width"),
|
||||
Height: validations.valueFor("height"),
|
||||
}
|
||||
|
||||
return pos
|
||||
}
|
||||
65
cfg/position_validation.go
Normal file
65
cfg/position_validation.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
)
|
||||
|
||||
// Common examples of invalid position configuration are:
|
||||
//
|
||||
// position:
|
||||
// top: -3
|
||||
// left: 2
|
||||
// width: 0
|
||||
// height: 1
|
||||
//
|
||||
// position:
|
||||
// top: 3
|
||||
// width: 2
|
||||
// height: 1
|
||||
//
|
||||
// position:
|
||||
// top: 3
|
||||
// # left: 2
|
||||
// width: 2
|
||||
// height: 1
|
||||
//
|
||||
// position:
|
||||
// top: 3
|
||||
// left: 2
|
||||
// width: 2
|
||||
// height: 1
|
||||
//
|
||||
type positionValidation struct {
|
||||
err error
|
||||
name string
|
||||
intVal int
|
||||
}
|
||||
|
||||
func (posVal *positionValidation) Error() error {
|
||||
return posVal.err
|
||||
}
|
||||
|
||||
func (posVal *positionValidation) HasError() bool {
|
||||
return posVal.err != nil
|
||||
}
|
||||
|
||||
func (posVal *positionValidation) IntValue() int {
|
||||
return posVal.intVal
|
||||
}
|
||||
|
||||
// String returns the Stringer representation of the positionValidation
|
||||
func (posVal *positionValidation) String() string {
|
||||
return fmt.Sprintf("Invalid value for %s:\t%d", aurora.Yellow(posVal.name), posVal.intVal)
|
||||
}
|
||||
|
||||
func newPositionValidation(name string, intVal int, err error) *positionValidation {
|
||||
posVal := &positionValidation{
|
||||
err: err,
|
||||
name: name,
|
||||
intVal: intVal,
|
||||
}
|
||||
|
||||
return posVal
|
||||
}
|
||||
9
cfg/validatable.go
Normal file
9
cfg/validatable.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package cfg
|
||||
|
||||
// Validatable is implemented by any value that validates a configuration setting
|
||||
type Validatable interface {
|
||||
Error() error
|
||||
HasError() bool
|
||||
String() string
|
||||
IntValue() int
|
||||
}
|
||||
28
cfg/validations.go
Normal file
28
cfg/validations.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package cfg
|
||||
|
||||
// Validations represent a collection of config setting validations
|
||||
type Validations struct {
|
||||
validations map[string]Validatable
|
||||
}
|
||||
|
||||
// NewValidations creates and returns an instance of Validations
|
||||
func NewValidations() *Validations {
|
||||
vals := &Validations{
|
||||
validations: make(map[string]Validatable),
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
|
||||
func (vals *Validations) append(key string, posVal Validatable) {
|
||||
vals.validations[key] = posVal
|
||||
}
|
||||
|
||||
func (vals *Validations) valueFor(key string) int {
|
||||
val := vals.validations[key]
|
||||
if val != nil {
|
||||
return val.IntValue()
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user