diff options
Diffstat (limited to 'config')
-rw-r--r-- | config/config.go | 321 | ||||
-rw-r--r-- | config/ui.go | 340 |
2 files changed, 345 insertions, 316 deletions
diff --git a/config/config.go b/config/config.go index 7a880b6d..91fd99a2 100644 --- a/config/config.go +++ b/config/config.go @@ -8,13 +8,10 @@ import ( "path" "regexp" "strings" - "time" "unicode" - "github.com/gdamore/tcell/v2" "github.com/go-ini/ini" "github.com/google/shlex" - "github.com/imdario/mergo" "github.com/kyoh86/xdg" "github.com/mitchellh/go-homedir" @@ -28,75 +25,6 @@ type GeneralConfig struct { UnsafeAccountsConf bool `ini:"unsafe-accounts-conf"` } -type UIConfig struct { - AutoMarkRead bool `ini:"auto-mark-read"` - IndexFormat string `ini:"index-format"` - TimestampFormat string `ini:"timestamp-format"` - ThisDayTimeFormat string `ini:"this-day-time-format"` - ThisWeekTimeFormat string `ini:"this-week-time-format"` - ThisYearTimeFormat string `ini:"this-year-time-format"` - MessageViewTimestampFormat string `ini:"message-view-timestamp-format"` - MessageViewThisDayTimeFormat string `ini:"message-view-this-day-time-format"` - MessageViewThisWeekTimeFormat string `ini:"message-view-this-week-time-format"` - MessageViewThisYearTimeFormat string `ini:"message-view-this-year-time-format"` - ShowHeaders []string `delim:","` - RenderAccountTabs string `ini:"render-account-tabs"` - PinnedTabMarker string `ini:"pinned-tab-marker"` - SidebarWidth int `ini:"sidebar-width"` - PreviewHeight int `ini:"preview-height"` - EmptyMessage string `ini:"empty-message"` - EmptyDirlist string `ini:"empty-dirlist"` - MouseEnabled bool `ini:"mouse-enabled"` - ThreadingEnabled bool `ini:"threading-enabled"` - ForceClientThreads bool `ini:"force-client-threads"` - ClientThreadsDelay time.Duration `ini:"client-threads-delay"` - FuzzyComplete bool `ini:"fuzzy-complete"` - NewMessageBell bool `ini:"new-message-bell"` - Spinner string `ini:"spinner"` - SpinnerDelimiter string `ini:"spinner-delimiter"` - IconUnencrypted string `ini:"icon-unencrypted"` - IconEncrypted string `ini:"icon-encrypted"` - IconSigned string `ini:"icon-signed"` - IconSignedEncrypted string `ini:"icon-signed-encrypted"` - IconUnknown string `ini:"icon-unknown"` - IconInvalid string `ini:"icon-invalid"` - DirListFormat string `ini:"dirlist-format"` - DirListDelay time.Duration `ini:"dirlist-delay"` - DirListTree bool `ini:"dirlist-tree"` - DirListCollapse int `ini:"dirlist-collapse"` - Sort []string `delim:" "` - NextMessageOnDelete bool `ini:"next-message-on-delete"` - CompletionDelay time.Duration `ini:"completion-delay"` - CompletionMinChars int `ini:"completion-min-chars"` - CompletionPopovers bool `ini:"completion-popovers"` - StyleSetDirs []string `ini:"stylesets-dirs" delim:":"` - StyleSetName string `ini:"styleset-name"` - style StyleSet - // customize border appearance - BorderCharVertical rune `ini:"-"` - BorderCharHorizontal rune `ini:"-"` - - ReverseOrder bool `ini:"reverse-msglist-order"` - ReverseThreadOrder bool `ini:"reverse-thread-order"` - SortThreadSiblings bool `ini:"sort-thread-siblings"` -} - -type ContextType int - -const ( - UI_CONTEXT_FOLDER ContextType = iota - UI_CONTEXT_ACCOUNT - UI_CONTEXT_SUBJECT - BIND_CONTEXT_ACCOUNT - BIND_CONTEXT_FOLDER -) - -type UIConfigContext struct { - ContextType ContextType - Regex *regexp.Regexp - UiConfig UIConfig -} - const ( FILTER_MIMETYPE = iota FILTER_HEADER @@ -326,61 +254,6 @@ func (config *AercConfig) LoadConfig(file *ini.File) error { } } - if ui, err := file.GetSection("ui"); err == nil { - if err := parseUiConfig(ui, &config.Ui); err != nil { - return err - } - } - - for _, sectionName := range file.SectionStrings() { - if !strings.Contains(sectionName, "ui:") { - continue - } - - uiSection, err := file.GetSection(sectionName) - if err != nil { - return err - } - uiSubConfig := UIConfig{} - if err := parseUiConfig(uiSection, &uiSubConfig); err != nil { - return err - } - contextualUi := UIConfigContext{ - UiConfig: uiSubConfig, - } - - var index int - switch { - case strings.Contains(sectionName, "~"): - index = strings.Index(sectionName, "~") - regex := string(sectionName[index+1:]) - contextualUi.Regex, err = regexp.Compile(regex) - if err != nil { - return err - } - case strings.Contains(sectionName, "="): - index = strings.Index(sectionName, "=") - value := string(sectionName[index+1:]) - contextualUi.Regex, err = regexp.Compile(regexp.QuoteMeta(value)) - if err != nil { - return err - } - default: - return fmt.Errorf("Invalid Ui Context regex in %s", sectionName) - } - - switch sectionName[3:index] { - case "account": - contextualUi.ContextType = UI_CONTEXT_ACCOUNT - case "folder": - contextualUi.ContextType = UI_CONTEXT_FOLDER - case "subject": - contextualUi.ContextType = UI_CONTEXT_SUBJECT - default: - return fmt.Errorf("Unknown Contextual Ui Section: %s", sectionName) - } - config.ContextualUis = append(config.ContextualUis, contextualUi) - } if triggers, err := file.GetSection("triggers"); err == nil { if err := triggers.MapTo(&config.Triggers); err != nil { return err @@ -396,11 +269,8 @@ func (config *AercConfig) LoadConfig(file *ini.File) error { } } - // append default paths to template-dirs and styleset-dirs + // append default paths to template-dirs for _, dir := range SearchDirs { - config.Ui.StyleSetDirs = append( - config.Ui.StyleSetDirs, path.Join(dir, "stylesets"), - ) config.Templates.TemplateDirs = append( config.Templates.TemplateDirs, path.Join(dir, "templates"), ) @@ -418,82 +288,6 @@ func (config *AercConfig) LoadConfig(file *ini.File) error { if err := templates.CheckTemplate(t.Forwards, t.TemplateDirs); err != nil { return err } - if err := config.Ui.loadStyleSet( - config.Ui.StyleSetDirs); err != nil { - return err - } - - for idx, contextualUi := range config.ContextualUis { - if contextualUi.UiConfig.StyleSetName == "" && - len(contextualUi.UiConfig.StyleSetDirs) == 0 { - continue // no need to do anything if nothing is overridden - } - // fill in the missing part from the base - if contextualUi.UiConfig.StyleSetName == "" { - config.ContextualUis[idx].UiConfig.StyleSetName = config.Ui.StyleSetName - } else if len(contextualUi.UiConfig.StyleSetDirs) == 0 { - config.ContextualUis[idx].UiConfig.StyleSetDirs = config.Ui.StyleSetDirs - } - // since at least one of them has changed, load the styleset - if err := config.ContextualUis[idx].UiConfig.loadStyleSet( - config.ContextualUis[idx].UiConfig.StyleSetDirs); err != nil { - return err - } - } - - return nil -} - -func parseUiConfig(section *ini.Section, config *UIConfig) error { - if err := section.MapTo(config); err != nil { - return err - } - - if key, err := section.GetKey("border-char-vertical"); err == nil { - chars := []rune(key.String()) - if len(chars) != 1 { - return fmt.Errorf("%v must be one and only one character", key) - } - config.BorderCharVertical = chars[0] - } - if key, err := section.GetKey("border-char-horizontal"); err == nil { - chars := []rune(key.String()) - if len(chars) != 1 { - return fmt.Errorf("%v must be one and only one character", key) - } - config.BorderCharHorizontal = chars[0] - } - - // Values with type=time.Duration must be explicitly set. If these - // values are given a default in the struct passed to ui.MapTo, which - // they are, a zero-value in the config won't overwrite the default. - if key, err := section.GetKey("dirlist-delay"); err == nil { - dur, err := key.Duration() - if err != nil { - return err - } - config.DirListDelay = dur - } - if key, err := section.GetKey("completion-delay"); err == nil { - dur, err := key.Duration() - if err != nil { - return err - } - config.CompletionDelay = dur - } - - if config.MessageViewTimestampFormat == "" { - config.MessageViewTimestampFormat = config.TimestampFormat - } - if config.MessageViewThisDayTimeFormat == "" { - config.MessageViewThisDayTimeFormat = config.TimestampFormat - } - if config.MessageViewThisWeekTimeFormat == "" { - config.MessageViewThisWeekTimeFormat = config.TimestampFormat - } - if config.MessageViewThisDayTimeFormat == "" { - config.MessageViewThisDayTimeFormat = config.TimestampFormat - } return nil } @@ -547,47 +341,7 @@ func LoadConfigFromFile(root *string, accts []string) (*AercConfig, error) { UnsafeAccountsConf: false, }, - Ui: UIConfig{ - AutoMarkRead: true, - IndexFormat: "%-20.20D %-17.17n %Z %s", - TimestampFormat: "2006-01-02 03:04 PM", - ThisDayTimeFormat: "", - ThisWeekTimeFormat: "", - ThisYearTimeFormat: "", - ShowHeaders: []string{ - "From", "To", "Cc", "Bcc", "Subject", "Date", - }, - RenderAccountTabs: "auto", - PinnedTabMarker: "`", - SidebarWidth: 20, - PreviewHeight: 12, - EmptyMessage: "(no messages)", - EmptyDirlist: "(no folders)", - MouseEnabled: false, - ClientThreadsDelay: 50 * time.Millisecond, - NewMessageBell: true, - FuzzyComplete: false, - Spinner: "[..] , [..] , [..] , [..] , [..], [..] , [..] , [..] ", - SpinnerDelimiter: ",", - IconUnencrypted: "", - IconSigned: "[s]", - IconEncrypted: "[e]", - IconSignedEncrypted: "", - IconUnknown: "[s?]", - IconInvalid: "[s!]", - DirListFormat: "%n %>r", - DirListDelay: 200 * time.Millisecond, - NextMessageOnDelete: true, - CompletionDelay: 250 * time.Millisecond, - CompletionMinChars: 1, - CompletionPopovers: true, - StyleSetDirs: []string{}, - StyleSetName: "default", - // border defaults - BorderCharVertical: ' ', - BorderCharHorizontal: ' ', - }, - + Ui: defaultUiConfig(), ContextualUis: []UIConfigContext{}, Viewer: ViewerConfig{ @@ -630,6 +384,9 @@ func LoadConfigFromFile(root *string, accts []string) (*AercConfig, error) { if err = config.LoadConfig(file); err != nil { return nil, err } + if err := config.parseUi(file); err != nil { + return nil, err + } if ui, err := file.GetSection("general"); err == nil { if err := ui.MapTo(&config.General); err != nil { @@ -641,7 +398,6 @@ func LoadConfigFromFile(root *string, accts []string) (*AercConfig, error) { } logging.Debugf("aerc.conf: [general] %#v", config.General) - logging.Debugf("aerc.conf: [ui] %#v", config.Ui) logging.Debugf("aerc.conf: [statusline] %#v", config.Statusline) logging.Debugf("aerc.conf: [viewer] %#v", config.Viewer) logging.Debugf("aerc.conf: [compose] %#v", config.Compose) @@ -669,73 +425,6 @@ func parseLayout(layout string) [][]string { return l } -func (ui *UIConfig) loadStyleSet(styleSetDirs []string) error { - ui.style = NewStyleSet() - err := ui.style.LoadStyleSet(ui.StyleSetName, styleSetDirs) - if err != nil { - return fmt.Errorf("Unable to load default styleset: %w", err) - } - - return nil -} - -func (config AercConfig) mergeContextualUi(baseUi UIConfig, - contextType ContextType, s string, -) UIConfig { - for _, contextualUi := range config.ContextualUis { - if contextualUi.ContextType != contextType { - continue - } - - if !contextualUi.Regex.Match([]byte(s)) { - continue - } - - err := mergo.Merge(&baseUi, contextualUi.UiConfig, mergo.WithOverride) - if err != nil { - logging.Warnf("merge ui failed: %v", err) - } - if contextualUi.UiConfig.StyleSetName != "" { - baseUi.style = contextualUi.UiConfig.style - } - return baseUi - } - - return baseUi -} - -func (config AercConfig) GetUiConfig(params map[ContextType]string) *UIConfig { - baseUi := config.Ui - - for k, v := range params { - baseUi = config.mergeContextualUi(baseUi, k, v) - } - - return &baseUi -} - -func (config *AercConfig) GetContextualUIConfigs() []UIConfigContext { - return config.ContextualUis -} - -func (uiConfig UIConfig) GetStyle(so StyleObject) tcell.Style { - return uiConfig.style.Get(so) -} - -func (uiConfig UIConfig) GetStyleSelected(so StyleObject) tcell.Style { - return uiConfig.style.Selected(so) -} - -func (uiConfig UIConfig) GetComposedStyle(base StyleObject, - styles []StyleObject, -) tcell.Style { - return uiConfig.style.Compose(base, styles) -} - -func (uiConfig UIConfig) GetComposedStyleSelected(base StyleObject, styles []StyleObject) tcell.Style { - return uiConfig.style.ComposeSelected(base, styles) -} - func contains(list []string, v string) bool { for _, item := range list { if item == v { diff --git a/config/ui.go b/config/ui.go new file mode 100644 index 00000000..16a296df --- /dev/null +++ b/config/ui.go @@ -0,0 +1,340 @@ +package config + +import ( + "fmt" + "path" + "regexp" + "strings" + "time" + + "git.sr.ht/~rjarry/aerc/logging" + "github.com/gdamore/tcell/v2" + "github.com/go-ini/ini" + "github.com/imdario/mergo" +) + +type UIConfig struct { + AutoMarkRead bool `ini:"auto-mark-read"` + IndexFormat string `ini:"index-format"` + TimestampFormat string `ini:"timestamp-format"` + ThisDayTimeFormat string `ini:"this-day-time-format"` + ThisWeekTimeFormat string `ini:"this-week-time-format"` + ThisYearTimeFormat string `ini:"this-year-time-format"` + MessageViewTimestampFormat string `ini:"message-view-timestamp-format"` + MessageViewThisDayTimeFormat string `ini:"message-view-this-day-time-format"` + MessageViewThisWeekTimeFormat string `ini:"message-view-this-week-time-format"` + MessageViewThisYearTimeFormat string `ini:"message-view-this-year-time-format"` + ShowHeaders []string `delim:","` + RenderAccountTabs string `ini:"render-account-tabs"` + PinnedTabMarker string `ini:"pinned-tab-marker"` + SidebarWidth int `ini:"sidebar-width"` + PreviewHeight int `ini:"preview-height"` + EmptyMessage string `ini:"empty-message"` + EmptyDirlist string `ini:"empty-dirlist"` + MouseEnabled bool `ini:"mouse-enabled"` + ThreadingEnabled bool `ini:"threading-enabled"` + ForceClientThreads bool `ini:"force-client-threads"` + ClientThreadsDelay time.Duration `ini:"client-threads-delay"` + FuzzyComplete bool `ini:"fuzzy-complete"` + NewMessageBell bool `ini:"new-message-bell"` + Spinner string `ini:"spinner"` + SpinnerDelimiter string `ini:"spinner-delimiter"` + IconUnencrypted string `ini:"icon-unencrypted"` + IconEncrypted string `ini:"icon-encrypted"` + IconSigned string `ini:"icon-signed"` + IconSignedEncrypted string `ini:"icon-signed-encrypted"` + IconUnknown string `ini:"icon-unknown"` + IconInvalid string `ini:"icon-invalid"` + DirListFormat string `ini:"dirlist-format"` + DirListDelay time.Duration `ini:"dirlist-delay"` + DirListTree bool `ini:"dirlist-tree"` + DirListCollapse int `ini:"dirlist-collapse"` + Sort []string `delim:" "` + NextMessageOnDelete bool `ini:"next-message-on-delete"` + CompletionDelay time.Duration `ini:"completion-delay"` + CompletionMinChars int `ini:"completion-min-chars"` + CompletionPopovers bool `ini:"completion-popovers"` + StyleSetDirs []string `ini:"stylesets-dirs" delim:":"` + StyleSetName string `ini:"styleset-name"` + style StyleSet + // customize border appearance + BorderCharVertical rune `ini:"-"` + BorderCharHorizontal rune `ini:"-"` + + ReverseOrder bool `ini:"reverse-msglist-order"` + ReverseThreadOrder bool `ini:"reverse-thread-order"` + SortThreadSiblings bool `ini:"sort-thread-siblings"` +} + +type ContextType int + +const ( + UI_CONTEXT_FOLDER ContextType = iota + UI_CONTEXT_ACCOUNT + UI_CONTEXT_SUBJECT + BIND_CONTEXT_ACCOUNT + BIND_CONTEXT_FOLDER +) + +type UIConfigContext struct { + ContextType ContextType + Regex *regexp.Regexp + UiConfig UIConfig +} + +func defaultUiConfig() UIConfig { + return UIConfig{ + AutoMarkRead: true, + IndexFormat: "%-20.20D %-17.17n %Z %s", + TimestampFormat: "2006-01-02 03:04 PM", + ThisDayTimeFormat: "", + ThisWeekTimeFormat: "", + ThisYearTimeFormat: "", + ShowHeaders: []string{ + "From", "To", "Cc", "Bcc", "Subject", "Date", + }, + RenderAccountTabs: "auto", + PinnedTabMarker: "`", + SidebarWidth: 20, + PreviewHeight: 12, + EmptyMessage: "(no messages)", + EmptyDirlist: "(no folders)", + MouseEnabled: false, + ClientThreadsDelay: 50 * time.Millisecond, + NewMessageBell: true, + FuzzyComplete: false, + Spinner: "[..] , [..] , [..] , [..] , [..], [..] , [..] , [..] ", + SpinnerDelimiter: ",", + IconUnencrypted: "", + IconSigned: "[s]", + IconEncrypted: "[e]", + IconSignedEncrypted: "", + IconUnknown: "[s?]", + IconInvalid: "[s!]", + DirListFormat: "%n %>r", + DirListDelay: 200 * time.Millisecond, + NextMessageOnDelete: true, + CompletionDelay: 250 * time.Millisecond, + CompletionMinChars: 1, + CompletionPopovers: true, + StyleSetDirs: []string{}, + StyleSetName: "default", + // border defaults + BorderCharVertical: ' ', + BorderCharHorizontal: ' ', + } +} + +func (config *AercConfig) parseUi(file *ini.File) error { + if ui, err := file.GetSection("ui"); err == nil { + if err := config.Ui.parse(ui); err != nil { + return err + } + } + + for _, sectionName := range file.SectionStrings() { + if !strings.Contains(sectionName, "ui:") { + continue + } + + uiSection, err := file.GetSection(sectionName) + if err != nil { + return err + } + uiSubConfig := UIConfig{} + if err := uiSubConfig.parse(uiSection); err != nil { + return err + } + contextualUi := UIConfigContext{ + UiConfig: uiSubConfig, + } + + var index int + switch { + case strings.Contains(sectionName, "~"): + index = strings.Index(sectionName, "~") + regex := string(sectionName[index+1:]) + contextualUi.Regex, err = regexp.Compile(regex) + if err != nil { + return err + } + case strings.Contains(sectionName, "="): + index = strings.Index(sectionName, "=") + value := string(sectionName[index+1:]) + contextualUi.Regex, err = regexp.Compile(regexp.QuoteMeta(value)) + if err != nil { + return err + } + default: + return fmt.Errorf("Invalid Ui Context regex in %s", sectionName) + } + + switch sectionName[3:index] { + case "account": + contextualUi.ContextType = UI_CONTEXT_ACCOUNT + case "folder": + contextualUi.ContextType = UI_CONTEXT_FOLDER + case "subject": + contextualUi.ContextType = UI_CONTEXT_SUBJECT + default: + return fmt.Errorf("Unknown Contextual Ui Section: %s", sectionName) + } + config.ContextualUis = append(config.ContextualUis, contextualUi) + } + + // append default paths to styleset-dirs + for _, dir := range SearchDirs { + config.Ui.StyleSetDirs = append( + config.Ui.StyleSetDirs, path.Join(dir, "stylesets"), + ) + } + + if err := config.Ui.loadStyleSet(config.Ui.StyleSetDirs); err != nil { + return err + } + + for idx, contextualUi := range config.ContextualUis { + if contextualUi.UiConfig.StyleSetName == "" && + len(contextualUi.UiConfig.StyleSetDirs) == 0 { + continue // no need to do anything if nothing is overridden + } + // fill in the missing part from the base + if contextualUi.UiConfig.StyleSetName == "" { + config.ContextualUis[idx].UiConfig.StyleSetName = config.Ui.StyleSetName + } else if len(contextualUi.UiConfig.StyleSetDirs) == 0 { + config.ContextualUis[idx].UiConfig.StyleSetDirs = config.Ui.StyleSetDirs + } + // since at least one of them has changed, load the styleset + if err := config.ContextualUis[idx].UiConfig.loadStyleSet( + config.ContextualUis[idx].UiConfig.StyleSetDirs); err != nil { + return err + } + } + + logging.Debugf("aerc.conf: [ui] %#v", config.Ui) + + return nil +} + +func (config *UIConfig) parse(section *ini.Section) error { + if err := section.MapTo(config); err != nil { + return err + } + + if key, err := section.GetKey("border-char-vertical"); err == nil { + chars := []rune(key.String()) + if len(chars) != 1 { + return fmt.Errorf("%v must be one and only one character", key) + } + config.BorderCharVertical = chars[0] + } + if key, err := section.GetKey("border-char-horizontal"); err == nil { + chars := []rune(key.String()) + if len(chars) != 1 { + return fmt.Errorf("%v must be one and only one character", key) + } + config.BorderCharHorizontal = chars[0] + } + + // Values with type=time.Duration must be explicitly set. If these + // values are given a default in the struct passed to ui.MapTo, which + // they are, a zero-value in the config won't overwrite the default. + if key, err := section.GetKey("dirlist-delay"); err == nil { + dur, err := key.Duration() + if err != nil { + return err + } + config.DirListDelay = dur + } + if key, err := section.GetKey("completion-delay"); err == nil { + dur, err := key.Duration() + if err != nil { + return err + } + config.CompletionDelay = dur + } + + if config.MessageViewTimestampFormat == "" { + config.MessageViewTimestampFormat = config.TimestampFormat + } + if config.MessageViewThisDayTimeFormat == "" { + config.MessageViewThisDayTimeFormat = config.TimestampFormat + } + if config.MessageViewThisWeekTimeFormat == "" { + config.MessageViewThisWeekTimeFormat = config.TimestampFormat + } + if config.MessageViewThisDayTimeFormat == "" { + config.MessageViewThisDayTimeFormat = config.TimestampFormat + } + + return nil +} + +func (ui *UIConfig) loadStyleSet(styleSetDirs []string) error { + ui.style = NewStyleSet() + err := ui.style.LoadStyleSet(ui.StyleSetName, styleSetDirs) + if err != nil { + return fmt.Errorf("Unable to load default styleset: %w", err) + } + + return nil +} + +func (config *AercConfig) mergeContextualUi(baseUi UIConfig, + contextType ContextType, s string, +) UIConfig { + for _, contextualUi := range config.ContextualUis { + if contextualUi.ContextType != contextType { + continue + } + + if !contextualUi.Regex.Match([]byte(s)) { + continue + } + + err := mergo.Merge(&baseUi, contextualUi.UiConfig, mergo.WithOverride) + if err != nil { + logging.Warnf("merge ui failed: %v", err) + } + if contextualUi.UiConfig.StyleSetName != "" { + baseUi.style = contextualUi.UiConfig.style + } + return baseUi + } + + return baseUi +} + +func (uiConfig *UIConfig) GetStyle(so StyleObject) tcell.Style { + return uiConfig.style.Get(so) +} + +func (uiConfig *UIConfig) GetStyleSelected(so StyleObject) tcell.Style { + return uiConfig.style.Selected(so) +} + +func (uiConfig *UIConfig) GetComposedStyle(base StyleObject, + styles []StyleObject, +) tcell.Style { + return uiConfig.style.Compose(base, styles) +} + +func (uiConfig *UIConfig) GetComposedStyleSelected( + base StyleObject, styles []StyleObject, +) tcell.Style { + return uiConfig.style.ComposeSelected(base, styles) +} + +func (config *AercConfig) GetUiConfig(params map[ContextType]string) *UIConfig { + baseUi := config.Ui + + for k, v := range params { + baseUi = config.mergeContextualUi(baseUi, k, v) + } + + return &baseUi +} + +func (config *AercConfig) GetContextualUIConfigs() []UIConfigContext { + return config.ContextualUis +} |