github.com/wtfutil/wtf@v0.43.0/cfg/common_settings.go (about) 1 package cfg 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "github.com/olebedev/config" 9 "golang.org/x/text/language" 10 "golang.org/x/text/message" 11 ) 12 13 const ( 14 defaultLanguageTag = "en-CA" 15 ) 16 17 type Module struct { 18 Name string 19 Type string 20 } 21 22 type Sigils struct { 23 Checkbox struct { 24 Checked string 25 Unchecked string 26 } 27 Paging struct { 28 Normal string 29 Selected string 30 } 31 } 32 33 // Common defines a set of common configuration settings applicable to all modules 34 type Common struct { 35 Module 36 PositionSettings `help:"Defines where in the grid this moduleâÂÂs widget will be displayed."` 37 Sigils 38 39 Colors ColorTheme 40 Config *config.Config 41 42 DocPath string 43 44 Bordered bool `help:"Whether or not the module should be displayed with a border." values:"true, false" optional:"true" default:"true"` 45 Enabled bool `help:"Whether or not this module is executed and if its data displayed onscreen." values:"true, false" optional:"true" default:"false"` 46 Focusable bool `help:"Whether or not this module is focusable." values:"true, false" optional:"true" default:"false"` 47 LanguageTag string `help:"The BCP 47 langauge tag to localize text to." values:"Any supported BCP 47 language tag." optional:"true" default:"en-CA"` 48 RefreshInterval time.Duration `help:"How often this module will update its data." values:"A positive integer followed by a time unit (ns, us or õs, ms, s, m, h, or nothing which defaults to s)" optional:"true"` 49 Title string `help:"The title string to show when displaying this module" optional:"true"` 50 51 focusChar int `help:"Define one of the number keys as a short cut key to access the widget." optional:"true"` 52 } 53 54 // NewCommonSettingsFromModule returns a common settings configuration tailed to the given module 55 func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable bool, moduleConfig *config.Config, globalConfig *config.Config) *Common { 56 baseColors := NewDefaultColorTheme() 57 58 colorsConfig, err := globalConfig.Get("wtf.colors") 59 if err != nil && strings.Contains(err.Error(), "Nonexistent map") { 60 // Create a default colors config to fill in for the missing one 61 // This comes into play when the configuration file does not contain a `colors:` key, i.e: 62 // 63 // wtf: 64 // # colors: <- missing 65 // refreshInterval: 1 66 // openFileUtil: "open" 67 // 68 colorsConfig, _ = NewDefaultColorConfig() 69 } 70 71 // And finally create a third instance to be the final default fallback in case there are empty or nil values in 72 // the colors extracted from the config file (aka colorsConfig) 73 defaultColorTheme := NewDefaultColorTheme() 74 75 baseColors.BorderTheme.Focusable = moduleConfig.UString("colors.border.focusable", colorsConfig.UString("border.focusable", defaultColorTheme.BorderTheme.Focusable)) 76 baseColors.BorderTheme.Focused = moduleConfig.UString("colors.border.focused", colorsConfig.UString("border.focused", defaultColorTheme.BorderTheme.Focused)) 77 baseColors.BorderTheme.Unfocusable = moduleConfig.UString("colors.border.normal", colorsConfig.UString("border.normal", defaultColorTheme.BorderTheme.Unfocusable)) 78 79 baseColors.CheckboxTheme.Checked = moduleConfig.UString("colors.checked", colorsConfig.UString("checked", defaultColorTheme.CheckboxTheme.Checked)) 80 81 baseColors.RowTheme.EvenForeground = moduleConfig.UString("colors.rows.even", colorsConfig.UString("rows.even", defaultColorTheme.RowTheme.EvenForeground)) 82 baseColors.RowTheme.OddForeground = moduleConfig.UString("colors.rows.odd", colorsConfig.UString("rows.odd", defaultColorTheme.RowTheme.OddForeground)) 83 84 baseColors.TextTheme.Label = moduleConfig.UString("colors.label", colorsConfig.UString("label", defaultColorTheme.TextTheme.Label)) 85 baseColors.TextTheme.Subheading = moduleConfig.UString("colors.subheading", colorsConfig.UString("subheading", defaultColorTheme.TextTheme.Subheading)) 86 baseColors.TextTheme.Text = moduleConfig.UString("colors.text", colorsConfig.UString("text", defaultColorTheme.TextTheme.Text)) 87 baseColors.TextTheme.Title = moduleConfig.UString("colors.title", colorsConfig.UString("title", defaultColorTheme.TextTheme.Title)) 88 89 baseColors.WidgetTheme.Background = moduleConfig.UString("colors.background", colorsConfig.UString("background", defaultColorTheme.WidgetTheme.Background)) 90 91 common := Common{ 92 Colors: baseColors, 93 94 Module: Module{ 95 Name: name, 96 Type: moduleConfig.UString("type", name), 97 }, 98 99 PositionSettings: NewPositionSettingsFromYAML(moduleConfig), 100 101 Bordered: moduleConfig.UBool("border", true), 102 Config: moduleConfig, 103 Enabled: moduleConfig.UBool("enabled", false), 104 Focusable: moduleConfig.UBool("focusable", defaultFocusable), 105 LanguageTag: globalConfig.UString("wtf.language", defaultLanguageTag), 106 RefreshInterval: ParseTimeString(moduleConfig, "refreshInterval", "300s"), 107 Title: moduleConfig.UString("title", defaultTitle), 108 109 focusChar: moduleConfig.UInt("focusChar", -1), 110 } 111 112 sigilsPath := "wtf.sigils" 113 common.Sigils.Checkbox.Checked = globalConfig.UString(sigilsPath+".checkbox.checked", "x") 114 common.Sigils.Checkbox.Unchecked = globalConfig.UString(sigilsPath+".checkbox.unchecked", " ") 115 common.Sigils.Paging.Normal = globalConfig.UString(sigilsPath+".paging.normal", globalConfig.UString("wtf.paging.pageSigil", "*")) 116 common.Sigils.Paging.Selected = globalConfig.UString(sigilsPath+".paging.select", globalConfig.UString("wtf.paging.selectedSigil", "_")) 117 118 return &common 119 } 120 121 /* -------------------- Exported Functions -------------------- */ 122 123 func (common *Common) DefaultFocusedRowColor() string { 124 return fmt.Sprintf( 125 "%s:%s", 126 common.Colors.RowTheme.HighlightedForeground, 127 common.Colors.RowTheme.HighlightedBackground, 128 ) 129 } 130 131 func (common *Common) DefaultRowColor() string { 132 return fmt.Sprintf( 133 "%s:%s", 134 common.Colors.RowTheme.EvenForeground, 135 common.Colors.RowTheme.EvenBackground, 136 ) 137 } 138 139 // FocusChar returns the keyboard number assigned to the widget used to give onscreen 140 // focus to this widget, as a string. Focus characters can be a range between 1 and 9 141 func (common *Common) FocusChar() string { 142 if common.focusChar <= 0 { 143 return "" 144 } 145 146 if common.focusChar > 9 { 147 return "" 148 } 149 150 return fmt.Sprint(common.focusChar) 151 } 152 153 // LocalizedPrinter returns a message.Printer instance localized to the BCP 47 language 154 // configuration value defined in 'wtf.language' config. If none exists, it defaults to 155 // 'en-CA'. Use this to format numbers, etc. 156 func (common *Common) LocalizedPrinter() (*message.Printer, error) { 157 langTag, err := language.Parse(common.LanguageTag) 158 if err != nil { 159 return nil, err 160 } 161 162 prntr := message.NewPrinter(langTag) 163 164 return prntr, nil 165 } 166 167 func (common *Common) RowColor(idx int) string { 168 if idx%2 == 0 { 169 return fmt.Sprintf( 170 "%s:%s", 171 common.Colors.RowTheme.EvenForeground, 172 common.Colors.RowTheme.EvenBackground, 173 ) 174 } 175 return fmt.Sprintf( 176 "%s:%s", 177 common.Colors.RowTheme.OddForeground, 178 common.Colors.RowTheme.OddBackground, 179 ) 180 } 181 182 func (common *Common) RightAlignFormat(width int) string { 183 borderOffset := 2 184 return fmt.Sprintf("%%%ds", width-borderOffset) 185 } 186 187 // PaginationMarker generates the pagination indicators that appear in the top-right corner 188 // of multisource widgets 189 func (common *Common) PaginationMarker(length, pos, width int) string { 190 sigils := "" 191 192 if length > 1 { 193 sigils = strings.Repeat(common.Sigils.Paging.Normal, pos) 194 sigils += common.Sigils.Paging.Selected 195 sigils += strings.Repeat(common.Sigils.Paging.Normal, length-1-pos) 196 197 sigils = "[lightblue]" + fmt.Sprintf(common.RightAlignFormat(width), sigils) + "[white]" 198 } 199 200 return sigils 201 } 202 203 // SetDocumentationPath is used to explicitly set the documentation path that should be opened 204 // when the key to open the documentation is pressed. 205 // Setting this is probably not necessary unless the module documentation is nested inside a 206 // documentation subdirectory in the /wtfutildocs repo, or the module here has a different 207 // name than the module's display name in the documentation (which ideally wouldn't be a thing). 208 func (common *Common) SetDocumentationPath(path string) { 209 common.DocPath = path 210 } 211 212 // Validations aggregates all the validations from all the sub-sections in Common into a 213 // single array of validations 214 func (common *Common) Validations() []Validatable { 215 validatables := []Validatable{} 216 217 for _, validation := range common.PositionSettings.Validations.validations { 218 validatables = append(validatables, validation) 219 } 220 221 return validatables 222 }