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  }