diff options
48 files changed, 318 insertions, 1079 deletions
diff --git a/Makefile b/Makefile index aa60e95..59e066d 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,7 @@ DOCS := \ aerc-notmuch.5 \ aerc-smtp.5 \ aerc-tutorial.7 \ - aerc-templates.7 \ - aerc-stylesets.7 + aerc-templates.7 .1.scd.1: scdoc < $< > $@ @@ -60,7 +59,7 @@ clean: install: all mkdir -m755 -p $(BINDIR) $(MANDIR)/man1 $(MANDIR)/man5 $(MANDIR)/man7 \ - $(SHAREDIR) $(SHAREDIR)/filters $(SHAREDIR)/templates $(SHAREDIR)/stylesets + $(SHAREDIR) $(SHAREDIR)/filters $(SHAREDIR)/templates install -m755 aerc $(BINDIR)/aerc install -m644 aerc.1 $(MANDIR)/man1/aerc.1 install -m644 aerc-search.1 $(MANDIR)/man1/aerc-search.1 @@ -72,7 +71,6 @@ install: all install -m644 aerc-smtp.5 $(MANDIR)/man5/aerc-smtp.5 install -m644 aerc-tutorial.7 $(MANDIR)/man7/aerc-tutorial.7 install -m644 aerc-templates.7 $(MANDIR)/man7/aerc-templates.7 - install -m644 aerc-stylesets.7 $(MANDIR)/man7/aerc-stylesets.7 install -m644 config/accounts.conf $(SHAREDIR)/accounts.conf install -m644 aerc.conf $(SHAREDIR)/aerc.conf install -m644 config/binds.conf $(SHAREDIR)/binds.conf @@ -81,7 +79,6 @@ install: all install -m755 filters/plaintext $(SHAREDIR)/filters/plaintext install -m644 templates/quoted_reply $(SHAREDIR)/templates/quoted_reply install -m644 templates/forward_as_body $(SHAREDIR)/templates/forward_as_body - install -m644 config/default_styleset $(SHAREDIR)/stylesets/default RMDIR_IF_EMPTY:=sh -c '\ if test -d $$0 && ! ls -1qA $$0 | grep -q . ; then \ diff --git a/commands/account/mkdir.go b/commands/account/mkdir.go index f99fc01..4352a42 100644 --- a/commands/account/mkdir.go +++ b/commands/account/mkdir.go @@ -40,7 +40,7 @@ func (MakeDir) Execute(aerc *widgets.Aerc, args []string) error { aerc.PushStatus("Directory created.", 10*time.Second) acct.Directories().Select(name) case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) } }) return nil diff --git a/commands/account/view.go b/commands/account/view.go index d4653be..b421666 100644 --- a/commands/account/view.go +++ b/commands/account/view.go @@ -2,7 +2,6 @@ package account import ( "errors" - "time" "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/widgets" @@ -42,7 +41,7 @@ func (ViewMessage) Execute(aerc *widgets.Aerc, args []string) error { lib.NewMessageStoreView(msg, store, aerc.DecryptKeys, func(view lib.MessageView, err error) { if err != nil { - aerc.PushError(err.Error(), 10*time.Second) + aerc.PushError(err.Error()) return } viewer := widgets.NewMessageViewer(acct, aerc.Config(), view) diff --git a/commands/compose/attach.go b/commands/compose/attach.go index 6b8d72f..2b633dc 100644 --- a/commands/compose/attach.go +++ b/commands/compose/attach.go @@ -8,6 +8,7 @@ import ( "git.sr.ht/~sircmpwn/aerc/commands" "git.sr.ht/~sircmpwn/aerc/widgets" + "github.com/gdamore/tcell" "github.com/mitchellh/go-homedir" ) @@ -35,23 +36,24 @@ func (Attach) Execute(aerc *widgets.Aerc, args []string) error { path, err := homedir.Expand(path) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) return err } pathinfo, err := os.Stat(path) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) return err } else if pathinfo.IsDir() { - aerc.PushError("Attachment must be a file, not a directory", 10*time.Second) + aerc.PushError("Attachment must be a file, not a directory") return nil } composer, _ := aerc.SelectedTab().(*widgets.Composer) composer.AddAttachment(path) - aerc.PushSuccess(fmt.Sprintf("Attached %s", pathinfo.Name()), 10*time.Second) + aerc.PushStatus(fmt.Sprintf("Attached %s", pathinfo.Name()), 10*time.Second). + Color(tcell.ColorDefault, tcell.ColorGreen) return nil } diff --git a/commands/compose/detach.go b/commands/compose/detach.go index 8bc0e88..e8b07ed 100644 --- a/commands/compose/detach.go +++ b/commands/compose/detach.go @@ -6,6 +6,7 @@ import ( "time" "git.sr.ht/~sircmpwn/aerc/widgets" + "github.com/gdamore/tcell" ) type Detach struct{} @@ -43,7 +44,8 @@ func (Detach) Execute(aerc *widgets.Aerc, args []string) error { return err } - aerc.PushSuccess(fmt.Sprintf("Detached %s", path), 10*time.Second) + aerc.PushStatus(fmt.Sprintf("Detached %s", path), 10*time.Second). + Color(tcell.ColorDefault, tcell.ColorGreen) return nil } diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go index 90b6134..60c9df1 100644 --- a/commands/compose/postpone.go +++ b/commands/compose/postpone.go @@ -63,7 +63,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error { go func() { errStr := <-errChan if errStr != "" { - aerc.PushError(" "+errStr, 10*time.Second) + aerc.PushError(" " + errStr) return } @@ -71,7 +71,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error { ctr := datacounter.NewWriterCounter(ioutil.Discard) err = composer.WriteMessage(header, ctr) if err != nil { - aerc.PushError(errors.Wrap(err, "WriteMessage").Error(), 10*time.Second) + aerc.PushError(errors.Wrap(err, "WriteMessage").Error()) composer.Close() return } @@ -90,7 +90,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error { r.Close() composer.Close() case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) r.Close() composer.Close() } diff --git a/commands/compose/send.go b/commands/compose/send.go index a22be8f..59ae5d0 100644 --- a/commands/compose/send.go +++ b/commands/compose/send.go @@ -12,6 +12,7 @@ import ( "github.com/emersion/go-sasl" "github.com/emersion/go-smtp" + "github.com/gdamore/tcell" "github.com/google/shlex" "github.com/miolini/datacounter" "github.com/pkg/errors" @@ -224,7 +225,8 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error { aerc.PushStatus("Sending...", 10*time.Second) nbytes, err := sendAsync() if err != nil { - aerc.SetError(" " + err.Error()) + aerc.SetStatus(" "+err.Error()). + Color(tcell.ColorDefault, tcell.ColorRed) return } if config.CopyTo != "" { @@ -245,7 +247,7 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error { composer.SetSent() composer.Close() case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) r.Close() composer.Close() } diff --git a/commands/exec.go b/commands/exec.go index 0a5470d..e15afbe 100644 --- a/commands/exec.go +++ b/commands/exec.go @@ -7,6 +7,8 @@ import ( "time" "git.sr.ht/~sircmpwn/aerc/widgets" + + "github.com/gdamore/tcell" ) type ExecCmd struct{} @@ -31,17 +33,16 @@ func (ExecCmd) Execute(aerc *widgets.Aerc, args []string) error { go func() { err := cmd.Run() if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } else { + color := tcell.ColorDefault if cmd.ProcessState.ExitCode() != 0 { - aerc.PushError(fmt.Sprintf( - "%s: completed with status %d", args[0], - cmd.ProcessState.ExitCode()), 10*time.Second) - } else { - aerc.PushStatus(fmt.Sprintf( - "%s: completed with status %d", args[0], - cmd.ProcessState.ExitCode()), 10*time.Second) + color = tcell.ColorRed } + aerc.PushStatus(fmt.Sprintf( + "%s: completed with status %d", args[0], + cmd.ProcessState.ExitCode()), 10*time.Second). + Color(tcell.ColorDefault, color) } }() return nil diff --git a/commands/msg/archive.go b/commands/msg/archive.go index ba7e1f7..5561674 100644 --- a/commands/msg/archive.go +++ b/commands/msg/archive.go @@ -86,7 +86,7 @@ func (Archive) Execute(aerc *widgets.Aerc, args []string) error { case *types.Done: wg.Done() case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) success = false wg.Done() } diff --git a/commands/msg/copy.go b/commands/msg/copy.go index e822c5c..f3d4030 100644 --- a/commands/msg/copy.go +++ b/commands/msg/copy.go @@ -60,7 +60,7 @@ func (Copy) Execute(aerc *widgets.Aerc, args []string) error { case *types.Done: aerc.PushStatus("Messages copied.", 10*time.Second) case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) } }) return nil diff --git a/commands/msg/delete.go b/commands/msg/delete.go index 482b60c..4bda8b9 100644 --- a/commands/msg/delete.go +++ b/commands/msg/delete.go @@ -47,7 +47,7 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error { case *types.Done: aerc.PushStatus("Messages deleted.", 10*time.Second) case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) } }) @@ -68,7 +68,7 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error { lib.NewMessageStoreView(next, store, aerc.DecryptKeys, func(view lib.MessageView, err error) { if err != nil { - aerc.PushError(err.Error(), 10*time.Second) + aerc.PushError(err.Error()) return } nextMv := widgets.NewMessageViewer(acct, aerc.Config(), view) diff --git a/commands/msg/forward.go b/commands/msg/forward.go index 5dd51b2..28abbed 100644 --- a/commands/msg/forward.go +++ b/commands/msg/forward.go @@ -9,7 +9,6 @@ import ( "os" "path" "strings" - "time" "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/widgets" @@ -84,7 +83,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error { composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), acct.AccountConfig(), acct.Worker(), template, defaults, original) if err != nil { - aerc.PushError("Error: "+err.Error(), 10*time.Second) + aerc.PushError("Error: " + err.Error()) return nil, err } diff --git a/commands/msg/modify-labels.go b/commands/msg/modify-labels.go index d74aece..f91075a 100644 --- a/commands/msg/modify-labels.go +++ b/commands/msg/modify-labels.go @@ -58,7 +58,7 @@ func (ModifyLabels) Execute(aerc *widgets.Aerc, args []string) error { case *types.Done: aerc.PushStatus("labels updated", 10*time.Second) case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) } }) return nil diff --git a/commands/msg/move.go b/commands/msg/move.go index a19194e..830e752 100644 --- a/commands/msg/move.go +++ b/commands/msg/move.go @@ -71,7 +71,7 @@ func (Move) Execute(aerc *widgets.Aerc, args []string) error { case *types.Done: aerc.PushStatus("Message moved to "+joinedArgs, 10*time.Second) case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) } }) return nil diff --git a/commands/msg/pipe.go b/commands/msg/pipe.go index 15b8c52..c88d61f 100644 --- a/commands/msg/pipe.go +++ b/commands/msg/pipe.go @@ -12,6 +12,7 @@ import ( "git.sr.ht/~sircmpwn/aerc/worker/types" "git.sr.ht/~sircmpwn/getopt" + "github.com/gdamore/tcell" ) type Pipe struct{} @@ -75,7 +76,7 @@ func (Pipe) Execute(aerc *widgets.Aerc, args []string) error { doTerm := func(reader io.Reader, name string) { term, err := commands.QuickTerm(aerc, cmd, reader) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) return } aerc.NewTab(term, name) @@ -93,17 +94,16 @@ func (Pipe) Execute(aerc *widgets.Aerc, args []string) error { }() err = ecmd.Run() if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } else { + color := tcell.ColorDefault if ecmd.ProcessState.ExitCode() != 0 { - aerc.PushError(fmt.Sprintf( - "%s: completed with status %d", cmd[0], - ecmd.ProcessState.ExitCode()), 10*time.Second) - } else { - aerc.PushStatus(fmt.Sprintf( - "%s: completed with status %d", cmd[0], - ecmd.ProcessState.ExitCode()), 10*time.Second) + color = tcell.ColorRed } + aerc.PushStatus(fmt.Sprintf( + "%s: completed with status %d", cmd[0], + ecmd.ProcessState.ExitCode()), 10*time.Second). + Color(tcell.ColorDefault, color) } } diff --git a/commands/msg/read.go b/commands/msg/read.go index e27f743..1e264c2 100644 --- a/commands/msg/read.go +++ b/commands/msg/read.go @@ -93,7 +93,7 @@ func submitReadChange(aerc *widgets.Aerc, store *lib.MessageStore, case *types.Done: aerc.PushStatus(msg_success, 10*time.Second) case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) } }) } @@ -106,7 +106,7 @@ func submitReadChangeWg(aerc *widgets.Aerc, store *lib.MessageStore, case *types.Done: wg.Done() case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) *success = false wg.Done() } diff --git a/commands/msg/recall.go b/commands/msg/recall.go index 6c5e973..7c9ac19 100644 --- a/commands/msg/recall.go +++ b/commands/msg/recall.go @@ -2,7 +2,6 @@ package msg import ( "io" - "time" "github.com/emersion/go-message" _ "github.com/emersion/go-message/charset" @@ -92,7 +91,7 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error { }, func(msg types.WorkerMessage) { switch msg := msg.(type) { case *types.Error: - aerc.PushError(" "+msg.Error.Error(), 10*time.Second) + aerc.PushError(" " + msg.Error.Error()) composer.Close() } }) diff --git a/commands/msg/reply.go b/commands/msg/reply.go index 455c7ca..28ce245 100644 --- a/commands/msg/reply.go +++ b/commands/msg/reply.go @@ -7,7 +7,6 @@ import ( "io" gomail "net/mail" "strings" - "time" "git.sr.ht/~sircmpwn/getopt" @@ -140,7 +139,7 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error { composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), acct.AccountConfig(), acct.Worker(), template, defaults, original) if err != nil { - aerc.PushError("Error: "+err.Error(), 10*time.Second) + aerc.PushError("Error: " + err.Error()) return err } diff --git a/commands/msgview/next.go b/commands/msgview/next.go index f9fb3d7..978cf10 100644 --- a/commands/msgview/next.go +++ b/commands/msgview/next.go @@ -1,8 +1,6 @@ package msgview import ( - "time" - "git.sr.ht/~sircmpwn/aerc/commands/account" "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/widgets" @@ -42,7 +40,7 @@ func (NextPrevMsg) Execute(aerc *widgets.Aerc, args []string) error { lib.NewMessageStoreView(nextMsg, store, aerc.DecryptKeys, func(view lib.MessageView, err error) { if err != nil { - aerc.PushError(err.Error(), 10*time.Second) + aerc.PushError(err.Error()) return } nextMv := widgets.NewMessageViewer(acct, aerc.Config(), view) diff --git a/commands/msgview/open.go b/commands/msgview/open.go index 7f26542..f708b2d 100644 --- a/commands/msgview/open.go +++ b/commands/msgview/open.go @@ -49,20 +49,20 @@ func (Open) Execute(aerc *widgets.Aerc, args []string) error { tmpFile, err := ioutil.TempFile(os.TempDir(), "aerc-*"+extension) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) return } defer tmpFile.Close() _, err = io.Copy(tmpFile, reader) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) return } err = lib.OpenFile(tmpFile.Name()) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } aerc.PushStatus("Opened", 10*time.Second) diff --git a/commands/msgview/save.go b/commands/msgview/save.go index ea1b8f3..ef6bba8 100644 --- a/commands/msgview/save.go +++ b/commands/msgview/save.go @@ -128,7 +128,7 @@ func (Save) Execute(aerc *widgets.Aerc, args []string) error { go func() { err := <-ch if err != nil { - aerc.PushError(fmt.Sprintf("Save failed: %v", err), 10*time.Second) + aerc.PushError(fmt.Sprintf("Save failed: %v", err)) return } aerc.PushStatus("Saved to "+path, 10*time.Second) diff --git a/commands/term.go b/commands/term.go index 9023285..00f6937 100644 --- a/commands/term.go +++ b/commands/term.go @@ -2,7 +2,6 @@ package commands import ( "os/exec" - "time" "github.com/riywo/loginshell" @@ -47,7 +46,7 @@ func TermCore(aerc *widgets.Aerc, args []string) error { term.OnClose = func(err error) { aerc.RemoveTab(term) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } } return nil diff --git a/commands/util.go b/commands/util.go index 7c7b6ab..fdf20bd 100644 --- a/commands/util.go +++ b/commands/util.go @@ -32,7 +32,7 @@ func QuickTerm(aerc *widgets.Aerc, args []string, stdin io.Reader) (*widgets.Ter term.OnClose = func(err error) { if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) // remove the tab on error, otherwise it gets stuck aerc.RemoveTab(term) } else { @@ -56,7 +56,7 @@ func QuickTerm(aerc *widgets.Aerc, args []string, stdin io.Reader) (*widgets.Ter err := <-status if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } } diff --git a/config/aerc.conf.in b/config/aerc.conf.in index b9381a8..3348efa 100644 --- a/config/aerc.conf.in +++ b/config/aerc.conf.in @@ -67,17 +67,6 @@ sort= # Default: true next-message-on-delete=true -# The directories where the stylesets are stored. It takes a colon-separated -# list of directories. -# -# default: @SHAREDIR@/stylesets/ -stylesets-dirs=@SHAREDIR@/stylesets/ - -# Sets the styleset to use for the aerc ui elements. -# -# Default: default -styleset-name=default - [viewer] # # Specifies the pager to use when displaying emails. Note that some filters diff --git a/config/config.go b/config/config.go index c430724..8ebd69d 100644 --- a/config/config.go +++ b/config/config.go @@ -45,9 +45,6 @@ type UIConfig struct { NextMessageOnDelete bool `ini:"next-message-on-delete"` CompletionDelay time.Duration `ini:"completion-delay"` CompletionPopovers bool `ini:"completion-popovers"` - StyleSetDirs []string `ini:"stylesets-dirs", delim:":"` - StyleSetName string `ini:"styleset-name"` - style StyleSet } type ContextType int @@ -335,11 +332,6 @@ func (config *AercConfig) LoadConfig(file *ini.File) error { if err := ui.MapTo(&config.Ui); err != nil { return err } - - stylesetsDirs := ui.Key("stylesets-dirs").String() - if stylesetsDirs != "" { - config.Ui.StyleSetDirs = strings.Split(stylesetsDirs, ":") - } } for _, sectionName := range file.SectionStrings() { if !strings.Contains(sectionName, "ui:") { @@ -354,10 +346,6 @@ func (config *AercConfig) LoadConfig(file *ini.File) error { if err := uiSection.MapTo(&uiSubConfig); err != nil { return err } - stylesetsDirs := uiSection.Key("stylesets-dirs").String() - if stylesetsDirs != "" { - uiSubConfig.StyleSetDirs = strings.Split(stylesetsDirs, ":") - } contextualUi := UIConfigContext{ UiConfig: uiSubConfig, @@ -418,19 +406,6 @@ func (config *AercConfig) LoadConfig(file *ini.File) error { } } } - - if err := config.Ui.loadStyleSet( - config.Ui.StyleSetDirs); err != nil { - return err - } - - for idx, _ := range config.ContextualUis { - if err := config.ContextualUis[idx].UiConfig.loadStyleSet( - config.Ui.StyleSetDirs); err != nil { - return err - } - } - return nil } @@ -491,8 +466,6 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) { NextMessageOnDelete: true, CompletionDelay: 250 * time.Millisecond, CompletionPopovers: true, - StyleSetDirs: []string{path.Join(sharedir, "stylesets")}, - StyleSetName: "default", }, ContextualUis: []UIConfigContext{}, @@ -522,7 +495,6 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) { Forwards: "forward_as_body", }, } - // These bindings are not configurable config.Bindings.AccountWizard.ExKey = KeyStroke{ Key: tcell.KeyCtrlE, @@ -533,7 +505,6 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) { if err = config.LoadConfig(file); err != nil { return nil, err } - if ui, err := file.GetSection("general"); err == nil { if err := ui.MapTo(&config.General); err != nil { return nil, err @@ -641,17 +612,8 @@ func parseLayout(layout string) [][]string { return l } -func (ui *UIConfig) loadStyleSet(styleSetDirs []string) error { - ui.style = NewStyleSet() - if err := ui.style.ParseStyleSet(ui.StyleSetName, styleSetDirs); err != nil { - return fmt.Errorf("Error whie parsing styleset \"%s\": %s", ui.StyleSetName, err) - } - - return nil -} - -func (config AercConfig) mergeContextualUi(baseUi UIConfig, - contextType ContextType, s string) UIConfig { +func (config *AercConfig) mergeContextualUi(baseUi *UIConfig, + contextType ContextType, s string) { for _, contextualUi := range config.ContextualUis { if contextualUi.ContextType != contextType { continue @@ -661,30 +623,17 @@ func (config AercConfig) mergeContextualUi(baseUi UIConfig, continue } - mergo.Merge(&baseUi, contextualUi.UiConfig, mergo.WithOverride) - if contextualUi.UiConfig.StyleSetName != "" { - baseUi.style = contextualUi.UiConfig.style - } - return baseUi + mergo.MergeWithOverwrite(baseUi, contextualUi.UiConfig) + return } - - return baseUi } -func (config AercConfig) GetUiConfig(params map[ContextType]string) UIConfig { +func (config *AercConfig) GetUiConfig(params map[ContextType]string) UIConfig { baseUi := config.Ui for k, v := range params { - baseUi = config.mergeContextualUi(baseUi, k, v) + config.mergeContextualUi(&baseUi, k, v) } 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) -} diff --git a/config/default_styleset b/config/default_styleset deleted file mode 100644 index 9e918ae..0000000 --- a/config/default_styleset +++ /dev/null @@ -1,33 +0,0 @@ -# -# aerc default styleset -# -# This styleset uses the terminal defaults as its base. -# More information on how to configure the styleset can be found in -# the *aerc-styleset.7* manpage. Please read the manual before -# modifying or creating a styleset. - -*.default=true -*.selected.reverse=toggle - -title.reverse=true -header.bold=true - -error.fg=red -warning.fg=yellow -*error.bold=true -success.fg=green - -statusline*.default=true -statusline_default.reverse=true -statusline_error.fg=red -statusline_success.fg=green - -msglist_unread.bold=true - -completion_pill.reverse=true - -tab.reverse=true -border.reverse = true - -selecter_focused.reverse=true -selecter_chooser.bold=true diff --git a/config/style.go b/config/style.go deleted file mode 100644 index fb17d93..0000000 --- a/config/style.go +++ /dev/null @@ -1,372 +0,0 @@ -package config - -import ( - "errors" - "os" - "path" - "regexp" - "strings" - - "github.com/gdamore/tcell" - "github.com/go-ini/ini" - "github.com/mitchellh/go-homedir" -) - -type StyleObject int32 - -const ( - STYLE_DEFAULT StyleObject = iota - STYLE_ERROR - STYLE_WARNING - STYLE_SUCCESS - - STYLE_TITLE - STYLE_HEADER - - STYLE_STATUSLINE_DEFAULT - STYLE_STATUSLINE_ERROR - STYLE_STATUSLINE_SUCCESS - - STYLE_MSGLIST_DEFAULT - STYLE_MSGLIST_UNREAD - STYLE_MSGLIST_READ - STYLE_MSGLIST_DELETED - STYLE_MSGLIST_MARKED - STYLE_MSGLIST_FLAGGED - - STYLE_DIRLIST_DEFAULT - - STYLE_COMPLETION_DEFAULT - STYLE_COMPLETION_GUTTER - STYLE_COMPLETION_PILL - - STYLE_TAB - STYLE_STACK - STYLE_SPINNER - STYLE_BORDER - - STYLE_SELECTER_DEFAULT - STYLE_SELECTER_FOCUSED - STYLE_SELECTER_CHOOSER -) - -var StyleNames = map[string]StyleObject{ - "default": STYLE_DEFAULT, - "error": STYLE_ERROR, - "warning": STYLE_WARNING, - "success": STYLE_SUCCESS, - - "title": STYLE_TITLE, - "header": STYLE_HEADER, - - "statusline_default": STYLE_STATUSLINE_DEFAULT, - "statusline_error": STYLE_STATUSLINE_ERROR, - "statusline_success": STYLE_STATUSLINE_SUCCESS, - - "msglist_default": STYLE_MSGLIST_DEFAULT, - "msglist_unread": STYLE_MSGLIST_UNREAD, - "msglist_read": STYLE_MSGLIST_READ, - "msglist_deleted": STYLE_MSGLIST_DELETED, - "msglist_marked": STYLE_MSGLIST_MARKED, - "msglist_flagged": STYLE_MSGLIST_FLAGGED, - - "dirlist_default": STYLE_DIRLIST_DEFAULT, - - "completion_default": STYLE_COMPLETION_DEFAULT, - "completion_gutter": STYLE_COMPLETION_GUTTER, - "completion_pill": STYLE_COMPLETION_PILL, - - "tab": STYLE_TAB, - "stack": STYLE_STACK, - "spinner": STYLE_SPINNER, - "border": STYLE_BORDER, - - "selecter_default": STYLE_SELECTER_DEFAULT, - "selecter_focused": STYLE_SELECTER_FOCUSED, - "selecter_chooser": STYLE_SELECTER_CHOOSER, -} - -type Style struct { - Fg tcell.Color - Bg tcell.Color - Bold bool - Blink bool - Underline bool - Reverse bool -} - -func (s Style) Get() tcell.Style { - return tcell.StyleDefault. - Foreground(s.Fg). - Background(s.Bg). - Bold(s.Bold). - Blink(s.Blink). - Underline(s.Blink). - Reverse(s.Reverse) -} - -func (s *Style) Normal() { - s.Bold = false - s.Blink = false - s.Underline = false - s.Reverse = false -} - -func (s *Style) Default() *Style { - s.Fg = tcell.ColorDefault - s.Bg = tcell.ColorDefault - return s -} - -func (s *Style) Reset() *Style { - s.Default() - s.Normal() - return s -} - -func boolSwitch(val string, cur_val bool) (bool, error) { - switch val { - case "true": - return true, nil - case "false": - return false, nil - case "toggle": - return !cur_val, nil - default: - return cur_val, errors.New( - "Bool Switch attribute must be true, false, or toggle") - } -} - -func (s *Style) Set(attr, val string) error { - switch attr { - case "fg": - s.Fg = tcell.GetColor(val) - case "bg": - s.Bg = tcell.GetColor(val) - case "bold": - if state, err := boolSwitch(val, s.Bold); err != nil { - return err - } else { - s.Bold = state - } - case "blink": - if state, err := boolSwitch(val, s.Blink); err != nil { - return err - } else { - s.Blink = state - } - case "underline": - if state, err := boolSwitch(val, s.Underline); err != nil { - return err - } else { - s.Underline = state - } - case "reverse": - if state, err := boolSwitch(val, s.Reverse); err != nil { - return err - } else { - s.Reverse = state - } - case "default": - s.Default() - case "normal": - s.Normal() - default: - return errors.New("Unknown style attribute: " + attr) - } - - return nil -} - -type StyleSet struct { - objects map[StyleObject]*Style - selected map[StyleObject]*Style -} - -func NewStyleSet() StyleSet { - ss := StyleSet{ - objects: make(map[StyleObject]*Style), - selected: make(map[StyleObject]*Style), - } - for _, so := range StyleNames { - ss.objects[so] = new(Style) - ss.selected[so] = new(Style) - } - - return ss -} - -func (ss StyleSet) reset() { - for _, so := range StyleNames { - ss.objects[so].Reset() - ss.selected[so].Reset() - } -} - -func (ss StyleSet) Get(so StyleObject) tcell.Style { - return ss.objects[so].Get() -} - -func (ss StyleSet) Selected(so StyleObject) tcell.Style { - return ss.selected[so].Get() -} - -func findStyleSet(stylesetName string, stylesetsDir []string) (string, error) { - for _, dir := range stylesetsDir { - stylesetPath, err := homedir.Expand(path.Join(dir, stylesetName)) - if err != nil { - return "", err - } - - if _, err := os.Stat(stylesetPath); os.IsNotExist(err) { - continue - } - - return stylesetPath, nil - } - - return "", errors.New("Can't find styleset - " + stylesetName) -} -func (ss *StyleSet) ParseStyleSet(stylesetName string, stylesetDirs []string) error { - filepath, err := findStyleSet(stylesetName, stylesetDirs) - if err != nil { - return err - } - - file, err := ini.Load(filepath) - if err != nil { - return err - } - - ss.reset() - - defaultSection, err := file.GetSection(ini.DefaultSection) - if err != nil { - return err - } - - selectedKeys := []string{} - - for _, key := range defaultSection.KeyStrings() { - tokens := strings.Split(key, ".") - var styleName, attr string - switch len(tokens) { - case 2: - styleName, attr = tokens[0], tokens[1] - case 3: - if tokens[1] != "selected" { - return errors.New("Unknown modifier: " + tokens[1]) - } - selectedKeys = append(selectedKeys, key) - continue - default: - return errors.New("Style parsing error: " + key) - } - val := defaultSection.KeysHash()[key] - - if strings.ContainsAny(styleName, "*?") { - regex := fnmatchToRegex(styleName) - for sn, so := range StyleNames { - matched, err := regexp.MatchString(regex, sn) - if err != nil { - return err - } - - if !matched { - continue - } - - if err := ss.objects[so].Set(attr, val); err != nil { - return err - } - if err := ss.selected[so].Set(attr, val); err != nil { - return err - } - } - } else { - so, ok := StyleNames[styleName] - if !ok { - return errors.New("Unknown style object: " + styleName) - } - if err := ss.objects[so].Set(attr, val); err != nil { - return err - } - if err := ss.selected[so].Set(attr, val); err != nil { - return err - } - } - } - - for _, key := range selectedKeys { - tokens := strings.Split(key, ".") - styleName, modifier, attr := tokens[0], tokens[1], tokens[2] - if modifier != "selected" { - return errors.New("Unknown modifier: " + modifier) - } - - val := defaultSection.KeysHash()[key] - - if strings.ContainsAny(styleName, "*?") { - regex := fnmatchToRegex(styleName) - for sn, so := range StyleNames { - matched, err := regexp.MatchString(regex, sn) - if err != nil { - return err - } - - if !matched { - continue - } - - if err := ss.selected[so].Set(attr, val); err != nil { - return err - } - } - } else { - so, ok := StyleNames[styleName] - if !ok { - return errors.New("Unknown style object: " + styleName) - } - if err := ss.selected[so].Set(attr, val); err != nil { - return err - } - } - } - - for _, key := range defaultSection.KeyStrings() { - tokens := strings.Split(key, ".") - styleName, attr := tokens[0], tokens[1] - val := defaultSection.KeysHash()[key] - - if styleName != "selected" { - continue - } - - for _, so := range StyleNames { - if err := ss.selected[so].Set(attr, val); err != nil { - return err - } - } - } - - return nil -} - -func fnmatchToRegex(pattern string) string { - n := len(pattern) - var regex strings.Builder - - for i := 0; i < n; i++ { - switch pattern[i] { - case '*': - regex.WriteString(".*") - case '?': - regex.WriteByte('.') - default: - regex.WriteByte(pattern[i]) - } - } - - return regex.String() -} diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd index 3ff5177..eb88849 100644 --- a/doc/aerc-config.5.scd +++ b/doc/aerc-config.5.scd @@ -173,20 +173,6 @@ These options are configured in the *[ui]* section of aerc.conf. Default: 250ms -*stylesets-dirs* - The directories where the stylesets are stored. The config takes a - colon-seperated list of dirs. - - Default: "/usr/share/aerc/stylesets" - -*styleset-name* - The name of the styleset to be used to style the ui elements. The - stylesets are stored in the 'stylesets' directory in the config - directory. - - Default: default - - ## Contextual UI Configuration The UI configuration can be specialized for accounts, specific mail diff --git a/doc/aerc-stylesets.7.scd b/doc/aerc-stylesets.7.scd deleted file mode 100644 index 5b4cd37..0000000 --- a/doc/aerc-stylesets.7.scd +++ /dev/null @@ -1,189 +0,0 @@ -aerc-stylesets(7) - -# Name - -aerc-stylesets - styleset file specification for *aerc*(1) - -# SYNOPSIS - -aerc uses a simple configuration syntax to configure the styleset for -its ui. - -# Styleset Configuration - -Aerc uses a simple configuration file to describe a styleset. The -styleset is described as key, value pairs. In each line, the key -represents the style object it signifies and the color/atrribute of -that is modified. - -For example, in the line below, the foreground color of the -style object "msglist_unread" is set to "cornflowerblue" -``` -msglist_unread.fg=cornflowerblue -``` - -The configuration also allows wildcard matching of the style_objects -to configure multiple style objects at a time. - -## Style -The following options are available to be modified for each of the -style objects. - -*fg* - The foreground color of the style object is set. - - Syntax: `<style_object>.fg=<color>` - -*bg* - The background color of the style object is set. - - Syntax: `<style_object>.bg=<color>` - -*bold* - The bold attribute of the style object is set/unset. - - Syntax: `<style_object>.bold=<true|false|toggle>` - -*blink* - The blink attribute of the style object is set/unset. - _The terminal needs to support blinking text_ - - Syntax: `<style_object>.bold=<true|false|toggle>` - -*underline* - The underline attribute of the style object is set/unset. - _The terminal needs to support underline text_ - - Syntax: `<style_object>.underline=<true|false|toggle>` - -*reverse* - Reverses the color of the style object. Exchanges the foreground - and background colors. - - Syntax: `<style_object>.reverse=<true|false|toggle>` - _If the value is false, it doesn't change anything_ - -*normal* - All the attributes of the style object are unset. - - Syntax: `<style_object>.normal=<true>` - _The value doesn't matter_ - -*default* - Set the style object to the default style of the context. Usually - based on the terminal. - - Syntax: `<style_object>.default=<true>` - _The value doesn't matter_ - -## Style Objects -The style objects represent the various ui elements or ui instances for -styling. - -[[ *Style Object* -:[ *Description* -| default -: The default style object used for normal ui elements while not - using specialized configuration. -| error -: The style used to show errors. -| warning -: The style used when showing warnings. -| success -: The style used for success messages. -| title -: The style object used to style titles in ui elements. -| header -: The style object used to style headers in ui elements. -| statusline_default -: The default style applied to the statusline. -| statusline_error -: The style used for error messages in statusline. -| statusline_success -: The style used for success messages in statusline. -| msglist_default -: The default style for messages in a message list. -| msglist_unread -: Unread messages in a message list. -| msglist_read -: Read messages in a message list. -| msglist_deleted -: The messages marked as deleted. -| msglist_marked -: The messages with the marked flag. -| msglist_flagged -: The messages with the flagged flag. -| dirlist_default -: The default style for directories in the directory list. -| completion_default -: The default style for the completion engine. -| completion_gutter -: The completion gutter. -| completion_pill -: The completion pill. -| tab -: The style for the tab bar. -| stack -: The style for ui stack element. -| spinner -: The style for the loading spinner. -| border -: The style used to draw borders. *Only the background color is used*. -| selecter_default -: The default style for the selecter ui element. -| selecter_focused -: The focused item in a selecter ui element. -| selecter_chooser -: The item chooser in a selecter ui element. - -## fnmatch style wildcard matching -The styleset configuration can be made simpler by using the fnmatch -style wildcard matching for the style object. - -The special characters used in the fnmatch wildcards are: -[[ *Pattern* -:[ *Meaning* -| \* -: Matches everything -| \? -: Matches any single character - -For example, the following wildcards can be made using this syntax. -[[ *Example* -:[ Description -| \*.fg=blue -: Set the foreground color of all style objects to blue. -| \*list.bg=hotpink -: Set the background color of all style objects that end in list - to hotpink. - -## Selected modifier -Selected modifier can be applied to any style object. The style provided for -the selected modifier are applied on top of the style object it correspons to. - -If you would like to make sure message that are flagged as read in the msglist -appear in yellow foreground and black background. You can specify that with -this. - -\tmsglist_default.selected.fg=yellow -\tmsglist_default.selected.bg=black - -If we specify the global style selected modifer using fnmatch as below: - -\t\*.selected.reverse=toggle - -This toggles the reverse switch for selected version of all the style objects. - -## Colors -The color values are set using the values accepted by the tcell library. -The values can be one of the following. - - *default* - The color is set as per the system or terminal default. - - *<Color name>* - Any w3c approved color name is used to set colors for the style. - - *<Hex code>* - Hexcode for a color can be used. The format must be "\#XXXXXX" - diff --git a/lib/ui/borders.go b/lib/ui/borders.go index 99d6880..7a75759 100644 --- a/lib/ui/borders.go +++ b/lib/ui/borders.go @@ -2,8 +2,6 @@ package ui import ( "github.com/gdamore/tcell" - - "git.sr.ht/~sircmpwn/aerc/config" ) const ( @@ -18,15 +16,12 @@ type Bordered struct { borders uint content Drawable onInvalidate func(d Drawable) - uiConfig config.UIConfig } -func NewBordered( - content Drawable, borders uint, uiConfig config.UIConfig) *Bordered { +func NewBordered(content Drawable, borders uint) *Bordered { b := &Bordered{ - borders: borders, - content: content, - uiConfig: uiConfig, + borders: borders, + content: content, } content.OnInvalidate(b.contentInvalidated) return b @@ -49,7 +44,7 @@ func (bordered *Bordered) Draw(ctx *Context) { y := 0 width := ctx.Width() height := ctx.Height() - style := bordered.uiConfig.GetStyle(config.STYLE_BORDER) + style := tcell.StyleDefault.Reverse(true) if bordered.borders&BORDER_LEFT != 0 { ctx.Fill(0, 0, 1, ctx.Height(), ' ', style) x += 1 diff --git a/lib/ui/stack.go b/lib/ui/stack.go index c9004a0..690a869 100644 --- a/lib/ui/stack.go +++ b/lib/ui/stack.go @@ -3,19 +3,16 @@ package ui import ( "fmt" - "git.sr.ht/~sircmpwn/aerc/config" - "github.com/gdamore/tcell" ) type Stack struct { children []Drawable onInvalidate []func(d Drawable) - uiConfig config.UIConfig } -func NewStack(uiConfig config.UIConfig) *Stack { - return &Stack{uiConfig: uiConfig} +func NewStack() *Stack { + return &Stack{} } func (stack *Stack) Children() []Drawable { @@ -36,8 +33,7 @@ func (stack *Stack) Draw(ctx *Context) { if len(stack.children) > 0 { stack.Peek().Draw(ctx) } else { - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', - stack.uiConfig.GetStyle(config.STYLE_STACK)) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) } } diff --git a/lib/ui/tab.go b/lib/ui/tab.go index cd5f448..4b99e4b 100644 --- a/lib/ui/tab.go +++ b/lib/ui/tab.go @@ -283,9 +283,9 @@ func (tabs *Tabs) removeHistory(index int) { func (strip *TabStrip) Draw(ctx *Context) { x := 0 for i, tab := range strip.Tabs { - style := strip.uiConfig.GetStyle(config.STYLE_TAB) + style := tcell.StyleDefault.Reverse(true) if strip.Selected == i { - style = strip.uiConfig.GetStyleSelected(config.STYLE_TAB) + style = tcell.StyleDefault } tabWidth := 32 if ctx.Width()-x < tabWidth { @@ -301,8 +301,8 @@ func (strip *TabStrip) Draw(ctx *Context) { break } } - ctx.Fill(x, 0, ctx.Width()-x, 1, ' ', - strip.uiConfig.GetStyle(config.STYLE_TAB)) + style := tcell.StyleDefault.Reverse(true) + ctx.Fill(x, 0, ctx.Width()-x, 1, ' ', style) } func (strip *TabStrip) Invalidate() { @@ -386,8 +386,7 @@ func (content *TabContent) Draw(ctx *Context) { if content.Selected >= len(content.Tabs) { width := ctx.Width() height := ctx.Height() - ctx.Fill(0, 0, width, height, ' ', - content.uiConfig.GetStyle(config.STYLE_TAB)) + ctx.Fill(0, 0, width, height, ' ', tcell.StyleDefault) } tab := content.Tabs[content.Selected] diff --git a/lib/ui/text.go b/lib/ui/text.go index 455c2eb..2b82598 100644 --- a/lib/ui/text.go +++ b/lib/ui/text.go @@ -15,13 +15,17 @@ type Text struct { Invalidatable text string strategy uint - style tcell.Style + fg tcell.Color + bg tcell.Color + bold bool + reverse bool } -func NewText(text string, style tcell.Style) *Text { +func NewText(text string) *Text { return &Text{ - text: text, - style: style, + bg: tcell.ColorDefault, + fg: tcell.ColorDefault, + text: text, } } @@ -37,6 +41,25 @@ func (t *Text) Strategy(strategy uint) *Text { return t } +func (t *Text) Bold(bold bool) *Text { + t.bold = bold + t.Invalidate() + return t +} + +func (t *Text) Color(fg tcell.Color, bg tcell.Color) *Text { + t.fg = fg + t.bg = bg + t.Invalidate() + return t +} + +func (t *Text) Reverse(reverse bool) *Text { + t.reverse = reverse + t.Invalidate() + return t +} + func (t *Text) Draw(ctx *Context) { size := runewidth.StringWidth(t.text) x := 0 @@ -46,8 +69,15 @@ func (t *Text) Draw(ctx *Context) { if t.strategy == TEXT_RIGHT { x = ctx.Width() - size } - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', t.style) - ctx.Printf(x, 0, t.style, "%s", t.text) + style := tcell.StyleDefault.Background(t.bg).Foreground(t.fg) + if t.bold { + style = style.Bold(true) + } + if t.reverse { + style = style.Reverse(true) + } + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style) + ctx.Printf(x, 0, style, "%s", t.text) } func (t *Text) Invalidate() { diff --git a/lib/ui/textinput.go b/lib/ui/textinput.go index 2445065..f6b0c72 100644 --- a/lib/ui/textinput.go +++ b/lib/ui/textinput.go @@ -6,8 +6,6 @@ import ( "github.com/gdamore/tcell" "github.com/mattn/go-runewidth" - - "git.sr.ht/~sircmpwn/aerc/config" ) // TODO: Attach history providers @@ -29,18 +27,16 @@ type TextInput struct { completeIndex int completeDelay time.Duration completeDebouncer *time.Timer - uiConfig config.UIConfig } // Creates a new TextInput. TextInputs will render a "textbox" in the entire // context they're given, and process keypresses to build a string from user // input. -func NewTextInput(text string, ui config.UIConfig) *TextInput { +func NewTextInput(text string) *TextInput { return &TextInput{ - cells: -1, - text: []rune(text), - index: len([]rune(text)), - uiConfig: ui, + cells: -1, + text: []rune(text), + index: len([]rune(text)), } } @@ -91,18 +87,16 @@ func (ti *TextInput) Draw(ctx *Context) { ti.ensureScroll() } ti.ctx = ctx // gross - - defaultStyle := ti.uiConfig.GetStyle(config.STYLE_DEFAULT) - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', defaultStyle) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) text := ti.text[scroll:] sindex := ti.index - scroll if ti.password { - x := ctx.Printf(0, 0, defaultStyle, "%s", ti.prompt) + x := ctx.Printf(0, 0, tcell.StyleDefault, "%s", ti.prompt) cells := runewidth.StringWidth(string(text)) - ctx.Fill(x, 0, cells, 1, '*', defaultStyle) + ctx.Fill(x, 0, cells, 1, '*', tcell.StyleDefault) } else { - ctx.Printf(0, 0, defaultStyle, "%s%s", ti.prompt, string(text)) + ctx.Printf(0, 0, tcell.StyleDefault, "%s%s", ti.prompt, string(text)) } cells := runewidth.StringWidth(string(text[:sindex]) + ti.prompt) if ti.focus { @@ -132,7 +126,6 @@ func (ti *TextInput) drawPopover(ctx *Context) { ti.Set(stem + ti.StringRight()) ti.Invalidate() }, - uiConfig: ti.uiConfig, } width := maxLen(ti.completions) + 3 height := len(ti.completions) @@ -360,7 +353,6 @@ type completions struct { onSelect func(int) onExec func() onStem func(string) - uiConfig config.UIConfig } func maxLen(ss []string) int { @@ -375,10 +367,10 @@ func maxLen(ss []string) int { } func (c *completions) Draw(ctx *Context) { - bg := c.uiConfig.GetStyle(config.STYLE_COMPLETION_DEFAULT) - gutter := c.uiConfig.GetStyle(config.STYLE_COMPLETION_GUTTER) - pill := c.uiConfig.GetStyle(config.STYLE_COMPLETION_PILL) - sel := c.uiConfig.GetStyleSelected(config.STYLE_COMPLETION_DEFAULT) + bg := tcell.StyleDefault + sel := tcell.StyleDefault.Reverse(true) + gutter := tcell.StyleDefault + pill := tcell.StyleDefault.Reverse(true) ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', bg) diff --git a/widgets/account-wizard.go b/widgets/account-wizard.go index e247dd2..6f93367 100644 --- a/widgets/account-wizard.go +++ b/widgets/account-wizard.go @@ -10,7 +10,6 @@ import ( "path" "strconv" "strings" - "time" "github.com/gdamore/tcell" "github.com/go-ini/ini" @@ -76,21 +75,21 @@ type AccountWizard struct { func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { wizard := &AccountWizard{ - accountName: ui.NewTextInput("", conf.Ui).Prompt("> "), + accountName: ui.NewTextInput("").Prompt("> "), aerc: aerc, conf: conf, temporary: false, copySent: true, - email: ui.NewTextInput("", conf.Ui).Prompt("> "), - fullName: ui.NewTextInput("", conf.Ui).Prompt("> "), - imapPassword: ui.NewTextInput("", conf.Ui).Prompt("] ").Password(true), - imapServer: ui.NewTextInput("", conf.Ui).Prompt("> "), - imapStr: ui.NewText("imaps://", conf.Ui.GetStyle(config.STYLE_DEFAULT)), - imapUsername: ui.NewTextInput("", conf.Ui).Prompt("> "), - smtpPassword: ui.NewTextInput("", conf.Ui).Prompt("] ").Password(true), - smtpServer: ui.NewTextInput("", conf.Ui).Prompt("> "), - smtpStr: ui.NewText("smtps://", conf.Ui.GetStyle(config.STYLE_DEFAULT)), - smtpUsername: ui.NewTextInput("", conf.Ui).Prompt("> "), + email: ui.NewTextInput("").Prompt("> "), + fullName: ui.NewTextInput("").Prompt("> "), + imapPassword: ui.NewTextInput("").Prompt("] ").Password(true), + imapServer: ui.NewTextInput("").Prompt("> "), + imapStr: ui.NewText("imaps://"), + imapUsername: ui.NewTextInput("").Prompt("> "), + smtpPassword: ui.NewTextInput("").Prompt("] ").Password(true), + smtpServer: ui.NewTextInput("").Prompt("> "), + smtpStr: ui.NewText("smtps://"), + smtpUsername: ui.NewTextInput("").Prompt("> "), } // Autofill some stuff for the user @@ -151,36 +150,33 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { {ui.SIZE_WEIGHT, 1}, }) basics.AddChild( - ui.NewText("\nWelcome to aerc! Let's configure your account.\n\n"+ - "This wizard supports basic IMAP & SMTP configuration.\n"+ - "For other configurations, use <Ctrl+q> to exit and read the "+ - "aerc-config(5) man page.\n"+ - "Press <Tab> and <Shift+Tab> to cycle between each field in this form, "+ - "or <Ctrl+j> and <Ctrl+k>.", - conf.Ui.GetStyle(config.STYLE_DEFAULT))) + ui.NewText("\nWelcome to aerc! Let's configure your account.\n\n" + + "This wizard supports basic IMAP & SMTP configuration.\n" + + "For other configurations, use <Ctrl+q> to exit and read the " + + "aerc-config(5) man page.\n" + + "Press <Tab> and <Shift+Tab> to cycle between each field in this form, or <Ctrl+j> and <Ctrl+k>.")) basics.AddChild( - ui.NewText("Name for this account? (e.g. 'Personal' or 'Work')", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Name for this account? (e.g. 'Personal' or 'Work')"). + Bold(true)). At(1, 0) basics.AddChild(wizard.accountName). At(2, 0) basics.AddChild(ui.NewFill(' ')). At(3, 0) basics.AddChild( - ui.NewText("Full name for outgoing emails? (e.g. 'John Doe')", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Full name for outgoing emails? (e.g. 'John Doe')"). + Bold(true)). At(4, 0) basics.AddChild(wizard.fullName). At(5, 0) basics.AddChild(ui.NewFill(' ')). At(6, 0) basics.AddChild( - ui.NewText("Your email address? (e.g. 'john@example.org')", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Your email address? (e.g. 'john@example.org')").Bold(true)). At(7, 0) basics.AddChild(wizard.email). At(8, 0) - selecter := NewSelecter([]string{"Next"}, 0, conf.Ui). + selecter := NewSelecter([]string{"Next"}, 0). OnChoose(func(option string) { email := wizard.email.String() if strings.ContainsRune(email, '@') { @@ -231,19 +227,16 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { }).Columns([]ui.GridSpec{ {ui.SIZE_WEIGHT, 1}, }) - incoming.AddChild(ui.NewText("\nConfigure incoming mail (IMAP)", - conf.Ui.GetStyle(config.STYLE_DEFAULT))) + incoming.AddChild(ui.NewText("\nConfigure incoming mail (IMAP)")) incoming.AddChild( - ui.NewText("Username", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Username").Bold(true)). At(1, 0) incoming.AddChild(wizard.imapUsername). At(2, 0) incoming.AddChild(ui.NewFill(' ')). At(3, 0) incoming.AddChild( - ui.NewText("Password", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Password").Bold(true)). At(4, 0) incoming.AddChild(wizard.imapPassword). At(5, 0) @@ -251,22 +244,20 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { At(6, 0) incoming.AddChild( ui.NewText("Server address "+ - "(e.g. 'mail.example.org' or 'mail.example.org:1313')", - conf.Ui.GetStyle(config.STYLE_HEADER))). + "(e.g. 'mail.example.org' or 'mail.example.org:1313')").Bold(true)). At(7, 0) incoming.AddChild(wizard.imapServer). At(8, 0) incoming.AddChild(ui.NewFill(' ')). At(9, 0) incoming.AddChild( - ui.NewText("Connection mode", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Connection mode").Bold(true)). At(10, 0) imapMode := NewSelecter([]string{ "IMAP over SSL/TLS", "IMAP with STARTTLS", "Insecure IMAP", - }, 0, conf.Ui).Chooser(true).OnSelect(func(option string) { + }, 0).Chooser(true).OnSelect(func(option string) { switch option { case "IMAP over SSL/TLS": wizard.imapMode = IMAP_OVER_TLS @@ -278,7 +269,7 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { wizard.imapUri() }) incoming.AddChild(imapMode).At(11, 0) - selecter = NewSelecter([]string{"Previous", "Next"}, 1, conf.Ui). + selecter = NewSelecter([]string{"Previous", "Next"}, 1). OnChoose(wizard.advance) incoming.AddChild(ui.NewFill(' ')).At(12, 0) incoming.AddChild(wizard.imapStr).At(13, 0) @@ -313,19 +304,16 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { }).Columns([]ui.GridSpec{ {ui.SIZE_WEIGHT, 1}, }) - outgoing.AddChild(ui.NewText("\nConfigure outgoing mail (SMTP)", - conf.Ui.GetStyle(config.STYLE_DEFAULT))) + outgoing.AddChild(ui.NewText("\nConfigure outgoing mail (SMTP)")) outgoing.AddChild( - ui.NewText("Username", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Username").Bold(true)). At(1, 0) outgoing.AddChild(wizard.smtpUsername). At(2, 0) outgoing.AddChild(ui.NewFill(' ')). At(3, 0) outgoing.AddChild( - ui.NewText("Password", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Password").Bold(true)). At(4, 0) outgoing.AddChild(wizard.smtpPassword). At(5, 0) @@ -333,22 +321,20 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { At(6, 0) outgoing.AddChild( ui.NewText("Server address "+ - "(e.g. 'mail.example.org' or 'mail.example.org:1313')", - conf.Ui.GetStyle(config.STYLE_HEADER))). + "(e.g. 'mail.example.org' or 'mail.example.org:1313')").Bold(true)). At(7, 0) outgoing.AddChild(wizard.smtpServer). At(8, 0) outgoing.AddChild(ui.NewFill(' ')). At(9, 0) outgoing.AddChild( - ui.NewText("Connection mode", - conf.Ui.GetStyle(config.STYLE_HEADER))). + ui.NewText("Connection mode").Bold(true)). At(10, 0) smtpMode := NewSelecter([]string{ "SMTP over SSL/TLS", "SMTP with STARTTLS", "Insecure SMTP", - }, 0, conf.Ui).Chooser(true).OnSelect(func(option string) { + }, 0).Chooser(true).OnSelect(func(option string) { switch option { case "SMTP over SSL/TLS": wizard.smtpMode = SMTP_OVER_TLS @@ -360,15 +346,15 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { wizard.smtpUri() }) outgoing.AddChild(smtpMode).At(11, 0) - selecter = NewSelecter([]string{"Previous", "Next"}, 1, conf.Ui). + selecter = NewSelecter([]string{"Previous", "Next"}, 1). OnChoose(wizard.advance) outgoing.AddChild(ui.NewFill(' ')).At(12, 0) outgoing.AddChild(wizard.smtpStr).At(13, 0) outgoing.AddChild(ui.NewFill(' ')).At(14, 0) outgoing.AddChild( - ui.NewText("Copy sent messages to 'Sent' folder?", - conf.Ui.GetStyle(config.STYLE_HEADER))).At(15, 0) - copySent := NewSelecter([]string{"Yes", "No"}, 0, conf.Ui). + ui.NewText("Copy sent messages to 'Sent' folder?").Bold(true)). + At(15, 0) + copySent := NewSelecter([]string{"Yes", "No"}, 0). Chooser(true).OnChoose(func(option string) { switch option { case "Yes": @@ -394,16 +380,15 @@ func NewAccountWizard(conf *config.AercConfig, aerc *Aerc) *AccountWizard { {ui.SIZE_WEIGHT, 1}, }) complete.AddChild(ui.NewText( - "\nConfiguration complete!\n\n"+ - "You can go back and double check your settings, or choose 'Finish' to\n"+ - "save your settings to accounts.conf.\n\n"+ - "To add another account in the future, run ':new-account'.", - conf.Ui.GetStyle(config.STYLE_DEFAULT))) + "\nConfiguration complete!\n\n" + + "You can go back and double check your settings, or choose 'Finish' to\n" + + "save your settings to accounts.conf.\n\n" + + "To add another account in the future, run ':new-account'.")) selecter = NewSelecter([]string{ "Previous", "Finish & open tutorial", "Finish", - }, 1, conf.Ui).OnChoose(func(option string) { + }, 1).OnChoose(func(option string) { switch option { case "Previous": wizard.advance("Previous") @@ -429,7 +414,7 @@ func (wizard *AccountWizard) ConfigureTemporaryAccount(temporary bool) { func (wizard *AccountWizard) errorFor(d ui.Interactive, err error) { if d == nil { - wizard.aerc.PushError(" "+err.Error(), 10*time.Second) + wizard.aerc.PushError(" " + err.Error()) wizard.Invalidate() return } @@ -444,7 +429,7 @@ func (wizard *AccountWizard) errorFor(d ui.Interactive, err error) { wizard.step = step wizard.focus = focus wizard.Focus(true) - wizard.aerc.PushError(" "+err.Error(), 10*time.Second) + wizard.aerc.PushError(" " + err.Error()) wizard.Invalidate() return } @@ -555,7 +540,7 @@ func (wizard *AccountWizard) finish(tutorial bool) { term.OnClose = func(err error) { wizard.aerc.RemoveTab(term) if err != nil { - wizard.aerc.PushError(" "+err.Error(), 10*time.Second) + wizard.aerc.PushError(" " + err.Error()) } } } diff --git a/widgets/account.go b/widgets/account.go index 564a95d..20ed345 100644 --- a/widgets/account.go +++ b/widgets/account.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "log" - "time" "github.com/gdamore/tcell" @@ -55,7 +54,8 @@ func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountCon worker, err := worker.NewWorker(acct.Source, logger) if err != nil { - host.SetError(fmt.Sprintf("%s: %s", acct.Name, err)) + host.SetStatus(fmt.Sprintf("%s: %s", acct.Name, err)). + Color(tcell.ColorDefault, tcell.ColorRed) return &AccountView{ acct: acct, aerc: aerc, @@ -67,7 +67,7 @@ func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountCon dirlist := NewDirectoryList(conf, acct, logger, worker) if acctUiConf.SidebarWidth > 0 { - grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT, acctUiConf)) + grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT)) } msglist := NewMessageList(conf, logger, aerc) @@ -280,7 +280,8 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) { acct.labels = msg.Labels case *types.Error: acct.logger.Printf("%v", msg.Error) - acct.host.SetError(fmt.Sprintf("%v", msg.Error)) + acct.host.SetStatus(fmt.Sprintf("%v", msg.Error)). + Color(tcell.ColorDefault, tcell.ColorRed) } } @@ -290,7 +291,7 @@ func (acct *AccountView) getSortCriteria() []*types.SortCriterion { } criteria, err := sort.GetSortCriteria(acct.UiConfig().Sort) if err != nil { - acct.aerc.PushError(" ui.sort: "+err.Error(), 10*time.Second) + acct.aerc.PushError(" ui.sort: " + err.Error()) return nil } return criteria diff --git a/widgets/aerc.go b/widgets/aerc.go index 57d6cef..829873a 100644 --- a/widgets/aerc.go +++ b/widgets/aerc.go @@ -51,8 +51,8 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger, tabs := ui.NewTabs(&conf.Ui) - statusbar := ui.NewStack(conf.Ui) - statusline := NewStatusLine(conf.Ui) + statusbar := ui.NewStack() + statusline := NewStatusLine() statusbar.Push(statusline) grid := ui.NewGrid().Rows([]ui.GridSpec{ @@ -76,7 +76,7 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger, logger: logger, statusbar: statusbar, statusline: statusline, - prompts: ui.NewStack(conf.Ui), + prompts: ui.NewStack(), tabs: tabs, } @@ -382,20 +382,12 @@ func (aerc *Aerc) SetStatus(status string) *StatusMessage { return aerc.statusline.Set(status) } -func (aerc *Aerc) SetError(status string) *StatusMessage { - return aerc.statusline.SetError(status) -} - func (aerc *Aerc) PushStatus(text string, expiry time.Duration) *StatusMessage { return aerc.statusline.Push(text, expiry) } -func (aerc *Aerc) PushError(text string, expiry time.Duration) *StatusMessage { - return aerc.statusline.PushError(text, expiry) -} - -func (aerc *Aerc) PushSuccess(text string, expiry time.Duration) *StatusMessage { - return aerc.statusline.PushSuccess(text, expiry) +func (aerc *Aerc) PushError(text string) { + aerc.PushStatus(text, 10*time.Second).Color(tcell.ColorDefault, tcell.ColorRed) } func (aerc *Aerc) focus(item ui.Interactive) { @@ -424,11 +416,11 @@ func (aerc *Aerc) BeginExCommand(cmd string) { exline := NewExLine(aerc.conf, cmd, func(cmd string) { parts, err := shlex.Split(cmd) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } err = aerc.cmd(parts) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } // only add to history if this is an unsimulated command, // ie one not executed from a keybinding @@ -452,7 +444,7 @@ func (aerc *Aerc) RegisterPrompt(prompt string, cmd []string) { } err := aerc.cmd(cmd) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } }, func(cmd string) []string { return nil // TODO: completions @@ -479,7 +471,7 @@ func (aerc *Aerc) RegisterChoices(choices []Choice) { } err := aerc.cmd(cmd) if err != nil { - aerc.PushError(" "+err.Error(), 10*time.Second) + aerc.PushError(" " + err.Error()) } }, func(cmd string) []string { return nil // TODO: completions @@ -560,10 +552,11 @@ func (aerc *Aerc) CloseDialog() { return } + func (aerc *Aerc) GetPassword(title string, prompt string) (chText chan string, chErr chan error) { chText = make(chan string, 1) chErr = make(chan error, 1) - getPasswd := NewGetPasswd(title, prompt, aerc.conf, func(pw string, err error) { + getPasswd := NewGetPasswd(title, prompt, func(pw string, err error) { defer func() { close(chErr) close(chText) diff --git a/widgets/compose.go b/widgets/compose.go index f85e1f3..01b8dd8 100644 --- a/widgets/compose.go +++ b/widgets/compose.go @@ -72,11 +72,10 @@ func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig, templateData := templates.ParseTemplateData(defaults, original) cmpl := completer.New(conf.Compose.AddressBookCmd, func(err error) { - aerc.PushError( - fmt.Sprintf("could not complete header: %v", err), 10*time.Second) + aerc.PushError(fmt.Sprintf("could not complete header: %v", err)) worker.Logger.Printf("could not complete header: %v", err) }, aerc.Logger()) - layout, editors, focusable := buildComposeHeader(aerc, cmpl, defaults) + layout, editors, focusable := buildComposeHeader(conf, cmpl, defaults) email, err := ioutil.TempFile("", "aerc-compose-*.eml") if err != nil { @@ -113,21 +112,21 @@ func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig, return c, nil } -func buildComposeHeader(aerc *Aerc, cmpl *completer.Completer, +func buildComposeHeader(conf *config.AercConfig, cmpl *completer.Completer, defaults map[string]string) ( newLayout HeaderLayout, editors map[string]*headerEditor, focusable []ui.MouseableDrawableInteractive, ) { - layout := aerc.conf.Compose.HeaderLayout + layout := conf.Compose.HeaderLayout editors = make(map[string]*headerEditor) focusable = make([]ui.MouseableDrawableInteractive, 0) for _, row := range layout { for _, h := range row { - e := newHeaderEditor(h, "", aerc.SelectedAccount().UiConfig()) - if aerc.conf.Ui.CompletionPopovers { - e.input.TabComplete(cmpl.ForHeader(h), aerc.SelectedAccount().UiConfig().CompletionDelay) + e := newHeaderEditor(h, "") + if conf.Ui.CompletionPopovers { + e.input.TabComplete(cmpl.ForHeader(h), conf.Ui.CompletionDelay) } editors[h] = e switch h { @@ -144,9 +143,9 @@ func buildComposeHeader(aerc *Aerc, cmpl *completer.Completer, for _, h := range []string{"Cc", "Bcc"} { if val, ok := defaults[h]; ok && val != "" { if _, ok := editors[h]; !ok { - e := newHeaderEditor(h, "", aerc.SelectedAccount().UiConfig()) - if aerc.conf.Ui.CompletionPopovers { - e.input.TabComplete(cmpl.ForHeader(h), aerc.SelectedAccount().UiConfig().CompletionDelay) + e := newHeaderEditor(h, "") + if conf.Ui.CompletionPopovers { + e.input.TabComplete(cmpl.ForHeader(h), conf.Ui.CompletionDelay) } editors[h] = e focusable = append(focusable, e) @@ -260,9 +259,7 @@ func (c *Composer) readSignatureFromFile() []byte { } signature, err := ioutil.ReadFile(sigFile) if err != nil { - c.aerc.PushError( - fmt.Sprintf(" Error loading signature from file: %v", sigFile), - 10*time.Second) + c.aerc.PushError(fmt.Sprintf(" Error loading signature from file: %v", sigFile)) return nil } return signature @@ -651,7 +648,7 @@ func (c *Composer) AddEditor(header string, value string, appendHeader bool) { } return } - e := newHeaderEditor(header, value, c.aerc.SelectedAccount().UiConfig()) + e := newHeaderEditor(header, value) if c.config.Ui.CompletionPopovers { e.input.TabComplete(c.completer.ForHeader(header), c.config.Ui.CompletionDelay) } @@ -705,27 +702,23 @@ func (c *Composer) reloadEmail() error { } type headerEditor struct { - name string - focused bool - input *ui.TextInput - uiConfig config.UIConfig + name string + focused bool + input *ui.TextInput } -func newHeaderEditor(name string, value string, uiConfig config.UIConfig) *headerEditor { +func newHeaderEditor(name string, value string) *headerEditor { return &headerEditor{ - input: ui.NewTextInput(value, uiConfig), - name: name, - uiConfig: uiConfig, + input: ui.NewTextInput(value), + name: name, } } func (he *headerEditor) Draw(ctx *ui.Context) { name := he.name + " " size := runewidth.StringWidth(name) - defaultStyle := he.uiConfig.GetStyle(config.STYLE_DEFAULT) - headerStyle := he.uiConfig.GetStyle(config.STYLE_HEADER) - ctx.Fill(0, 0, size, ctx.Height(), ' ', defaultStyle) - ctx.Printf(0, 0, headerStyle, "%s", name) + ctx.Fill(0, 0, size, ctx.Height(), ' ', tcell.StyleDefault) + ctx.Printf(0, 0, tcell.StyleDefault.Bold(true), "%s", name) he.input.Draw(ctx.Subcontext(size, 0, ctx.Width()-size, 1)) } @@ -786,25 +779,21 @@ func newReviewMessage(composer *Composer, err error) *reviewMessage { {ui.SIZE_WEIGHT, 1}, }) - uiConfig := composer.config.Ui - if err != nil { - grid.AddChild(ui.NewText(err.Error(), uiConfig.GetStyle(config.STYLE_ERROR))) - grid.AddChild(ui.NewText("Press [q] to close this tab.", - uiConfig.GetStyle(config.STYLE_DEFAULT))).At(1, 0) + grid.AddChild(ui.NewText(err.Error()). + Color(tcell.ColorRed, tcell.ColorDefault)) + grid.AddChild(ui.NewText("Press [q] to close this tab.")).At(1, 0) } else { // TODO: source this from actual keybindings? - grid.AddChild(ui.NewText("Send this email? [y]es/[n]o/[e]dit/[a]ttach", - uiConfig.GetStyle(config.STYLE_DEFAULT))).At(0, 0) - grid.AddChild(ui.NewText("Attachments:", - uiConfig.GetStyle(config.STYLE_TITLE))).At(1, 0) + grid.AddChild(ui.NewText( + "Send this email? [y]es/[n]o/[p]ostpone/[e]dit/[a]ttach")).At(0, 0) + grid.AddChild(ui.NewText("Attachments:"). + Reverse(true)).At(1, 0) if len(composer.attachments) == 0 { - grid.AddChild(ui.NewText("(none)", - uiConfig.GetStyle(config.STYLE_DEFAULT))).At(2, 0) + grid.AddChild(ui.NewText("(none)")).At(2, 0) } else { for i, a := range composer.attachments { - grid.AddChild(ui.NewText(a, uiConfig.GetStyle(config.STYLE_DEFAULT))). - At(i+2, 0) + grid.AddChild(ui.NewText(a)).At(i+2, 0) } } } diff --git a/widgets/dirlist.go b/widgets/dirlist.go index 18072fa..600b38c 100644 --- a/widgets/dirlist.go +++ b/widgets/dirlist.go @@ -194,8 +194,7 @@ func (dirlist *DirectoryList) getRUEString(name string) string { } func (dirlist *DirectoryList) Draw(ctx *ui.Context) { - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', - dirlist.UiConfig().GetStyle(config.STYLE_DIRLIST_DEFAULT)) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) if dirlist.spinner.IsRunning() { dirlist.spinner.Draw(ctx) @@ -203,7 +202,7 @@ func (dirlist *DirectoryList) Draw(ctx *ui.Context) { } if len(dirlist.dirs) == 0 { - style := dirlist.UiConfig().GetStyle(config.STYLE_DIRLIST_DEFAULT) + style := tcell.StyleDefault ctx.Printf(0, 0, style, dirlist.UiConfig().EmptyDirlist) return } @@ -213,9 +212,12 @@ func (dirlist *DirectoryList) Draw(ctx *ui.Context) { if row >= ctx.Height() { break } - style := dirlist.UiConfig().GetStyle(config.STYLE_DIRLIST_DEFAULT) + style := tcell.StyleDefault if name == dirlist.selected { - style = dirlist.UiConfig().GetStyleSelected(config.STYLE_DIRLIST_DEFAULT) + style = style.Reverse(true) + } else if name == dirlist.selecting { + style = style.Reverse(true) + style = style.Foreground(tcell.ColorGray) } ctx.Fill(0, row, ctx.Width(), 1, ' ', style) diff --git a/widgets/exline.go b/widgets/exline.go index 692c8e2..6def938 100644 --- a/widgets/exline.go +++ b/widgets/exline.go @@ -15,14 +15,13 @@ type ExLine struct { tabcomplete func(cmd string) []string cmdHistory lib.History input *ui.TextInput - conf *config.AercConfig } func NewExLine(conf *config.AercConfig, cmd string, commit func(cmd string), finish func(), tabcomplete func(cmd string) []string, cmdHistory lib.History) *ExLine { - input := ui.NewTextInput("", conf.Ui).Prompt(":").Set(cmd) + input := ui.NewTextInput("").Prompt(":").Set(cmd) if conf.Ui.CompletionPopovers { input.TabComplete(tabcomplete, conf.Ui.CompletionDelay) } @@ -32,7 +31,6 @@ func NewExLine(conf *config.AercConfig, cmd string, commit func(cmd string), fin tabcomplete: tabcomplete, cmdHistory: cmdHistory, input: input, - conf: conf, } input.OnInvalidate(func(d ui.Drawable) { exline.Invalidate() @@ -43,7 +41,7 @@ func NewExLine(conf *config.AercConfig, cmd string, commit func(cmd string), fin func NewPrompt(conf *config.AercConfig, prompt string, commit func(text string), tabcomplete func(cmd string) []string) *ExLine { - input := ui.NewTextInput("", conf.Ui).Prompt(prompt) + input := ui.NewTextInput("").Prompt(prompt) if conf.Ui.CompletionPopovers { input.TabComplete(tabcomplete, conf.Ui.CompletionDelay) } diff --git a/widgets/getpasswd.go b/widgets/getpasswd.go index b3ea9e0..34f8b1f 100644 --- a/widgets/getpasswd.go +++ b/widgets/getpasswd.go @@ -5,7 +5,6 @@ import ( "github.com/gdamore/tcell" - "git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/lib/ui" ) @@ -15,16 +14,14 @@ type GetPasswd struct { title string prompt string input *ui.TextInput - conf *config.AercConfig } -func NewGetPasswd(title string, prompt string, conf *config.AercConfig, cb func(string, error)) *GetPasswd { +func NewGetPasswd(title string, prompt string, cb func(string, error)) *GetPasswd { getpasswd := &GetPasswd{ callback: cb, title: title, prompt: prompt, - conf: conf, - input: ui.NewTextInput("", conf.Ui).Password(true).Prompt("Password: "), + input: ui.NewTextInput("").Password(true).Prompt("Password: "), } getpasswd.input.OnInvalidate(func(_ ui.Drawable) { getpasswd.Invalidate() @@ -34,13 +31,10 @@ func NewGetPasswd(title string, prompt string, conf *config.AercConfig, cb func( } func (gp *GetPasswd) Draw(ctx *ui.Context) { - defaultStyle := gp.conf.Ui.GetStyle(config.STYLE_DEFAULT) - titleStyle := gp.conf.Ui.GetStyle(config.STYLE_TITLE) - - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', defaultStyle) - ctx.Fill(0, 0, ctx.Width(), 1, ' ', titleStyle) - ctx.Printf(1, 0, titleStyle, "%s", gp.title) - ctx.Printf(1, 1, defaultStyle, gp.prompt) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) + ctx.Fill(0, 0, ctx.Width(), 1, ' ', tcell.StyleDefault.Reverse(true)) + ctx.Printf(1, 0, tcell.StyleDefault.Reverse(true), "%s", gp.title) + ctx.Printf(1, 1, tcell.StyleDefault, gp.prompt) gp.input.Draw(ctx.Subcontext(1, 3, ctx.Width()-2, 1)) } diff --git a/widgets/msglist.go b/widgets/msglist.go index 5d12f8e..5aedb44 100644 --- a/widgets/msglist.go +++ b/widgets/msglist.go @@ -3,7 +3,6 @@ package widgets import ( "fmt" "log" - "time" "github.com/gdamore/tcell" "github.com/mattn/go-runewidth" @@ -50,8 +49,7 @@ func (ml *MessageList) Invalidate() { func (ml *MessageList) Draw(ctx *ui.Context) { ml.height = ctx.Height() - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', - ml.aerc.SelectedAccount().UiConfig().GetStyle(config.STYLE_MSGLIST_DEFAULT)) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) store := ml.Store() if store == nil { @@ -86,50 +84,34 @@ func (ml *MessageList) Draw(ctx *ui.Context) { continue } - uiConfig := ml.conf.GetUiConfig(map[config.ContextType]string{ - config.UI_CONTEXT_ACCOUNT: ml.aerc.SelectedAccount().AccountConfig().Name, - config.UI_CONTEXT_FOLDER: ml.aerc.SelectedAccount().Directories().Selected(), - config.UI_CONTEXT_SUBJECT: msg.Envelope.Subject, - }) - - so := config.STYLE_MSGLIST_DEFAULT + style := tcell.StyleDefault + // current row + if row == ml.store.SelectedIndex()-ml.scroll { + style = style.Reverse(true) + } // deleted message if _, ok := store.Deleted[msg.Uid]; ok { - so = config.STYLE_MSGLIST_DELETED + style = style.Foreground(tcell.ColorGray) } // unread message seen := false - flaged := false for _, flag := range msg.Flags { - switch flag { - case models.SeenFlag: + if flag == models.SeenFlag { seen = true - case models.FlaggedFlag: - flaged = true } } if !seen { - so = config.STYLE_MSGLIST_UNREAD - } - - if flaged { - so = config.STYLE_MSGLIST_FLAGGED - } - - // marked message - if store.IsMarked(msg.Uid) { - so = config.STYLE_MSGLIST_MARKED - } - - style := uiConfig.GetStyle(so) - - // current row - if row == ml.store.SelectedIndex()-ml.scroll { - style = uiConfig.GetStyleSelected(so) + style = style.Bold(true) } ctx.Fill(0, row, ctx.Width(), 1, ' ', style) + uiConfig := ml.conf.GetUiConfig(map[config.ContextType]string{ + config.UI_CONTEXT_ACCOUNT: ml.aerc.SelectedAccount().AccountConfig().Name, + config.UI_CONTEXT_FOLDER: ml.aerc.SelectedAccount().Directories().Selected(), + config.UI_CONTEXT_SUBJECT: msg.Envelope.Subject, + }) + fmtStr, args, err := format.ParseMessageFormat( ml.aerc.SelectedAccount().acct.From, uiConfig.IndexFormat, @@ -186,7 +168,7 @@ func (ml *MessageList) MouseEvent(localX int, localY int, event tcell.Event) { lib.NewMessageStoreView(msg, store, ml.aerc.DecryptKeys, func(view lib.MessageView, err error) { if err != nil { - ml.aerc.PushError(err.Error(), 10*time.Second) + ml.aerc.PushError(err.Error()) return } viewer := NewMessageViewer(acct, ml.aerc.Config(), view) @@ -306,8 +288,7 @@ func (ml *MessageList) Scroll() { } func (ml *MessageList) drawEmptyMessage(ctx *ui.Context) { - uiConfig := ml.aerc.SelectedAccount().UiConfig() - msg := uiConfig.EmptyMessage + msg := ml.aerc.SelectedAccount().UiConfig().EmptyMessage ctx.Printf((ctx.Width()/2)-(len(msg)/2), 0, - uiConfig.GetStyle(config.STYLE_MSGLIST_DEFAULT), "%s", msg) + tcell.StyleDefault, "%s", msg) } diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go index 6544ddd..ce85970 100644 --- a/widgets/msgviewer.go +++ b/widgets/msgviewer.go @@ -32,7 +32,6 @@ type MessageViewer struct { grid *ui.Grid switcher *PartSwitcher msg lib.MessageView - uiConfig config.UIConfig } type PartSwitcher struct { @@ -62,11 +61,9 @@ func NewMessageViewer(acct *AccountView, header, headerHeight := layout.grid( func(header string) ui.Drawable { return &HeaderView{ - conf: conf, Name: header, Value: fmtHeader(msg.MessageInfo(), header, acct.UiConfig().TimestampFormat), - uiConfig: acct.UiConfig(), } }, ) @@ -96,16 +93,15 @@ func NewMessageViewer(acct *AccountView, err := createSwitcher(acct, switcher, conf, msg) if err != nil { return &MessageViewer{ - err: err, - grid: grid, - msg: msg, - uiConfig: acct.UiConfig(), + err: err, + grid: grid, + msg: msg, } } grid.AddChild(header).At(0, 0) if msg.PGPDetails() != nil { - grid.AddChild(NewPGPInfo(msg.PGPDetails(), acct.UiConfig())).At(1, 0) + grid.AddChild(NewPGPInfo(msg.PGPDetails())).At(1, 0) grid.AddChild(ui.NewFill(' ')).At(2, 0) grid.AddChild(switcher).At(3, 0) } else { @@ -119,7 +115,6 @@ func NewMessageViewer(acct *AccountView, grid: grid, msg: msg, switcher: switcher, - uiConfig: acct.UiConfig(), } switcher.mv = mv @@ -228,9 +223,8 @@ func createSwitcher(acct *AccountView, switcher *PartSwitcher, func (mv *MessageViewer) Draw(ctx *ui.Context) { if mv.err != nil { - style := mv.acct.UiConfig().GetStyle(config.STYLE_DEFAULT) - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style) - ctx.Printf(0, 0, style, "%s", mv.err.Error()) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) + ctx.Printf(0, 0, tcell.StyleDefault, "%s", mv.err.Error()) return } mv.grid.Draw(ctx) @@ -352,10 +346,7 @@ func (ps *PartSwitcher) Draw(ctx *ui.Context) { ps.height = ctx.Height() y := ctx.Height() - height for i, part := range ps.parts { - style := ps.mv.uiConfig.GetStyle(config.STYLE_DEFAULT) - if ps.selected == i { - style = ps.mv.uiConfig.GetStyleSelected(config.STYLE_DEFAULT) - } + style := tcell.StyleDefault.Reverse(ps.selected == i) ctx.Fill(0, y+i, ctx.Width(), 1, ' ', style) name := fmt.Sprintf("%s/%s", strings.ToLower(part.part.MIMEType), @@ -444,7 +435,6 @@ func (mv *MessageViewer) Focus(focus bool) { type PartViewer struct { ui.Invalidatable - conf *config.AercConfig err error fetched bool filter *exec.Cmd @@ -459,7 +449,6 @@ type PartViewer struct { term *Terminal selecter *Selecter grid *ui.Grid - uiConfig config.UIConfig } func NewPartViewer(acct *AccountView, conf *config.AercConfig, @@ -529,8 +518,7 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig, {ui.SIZE_WEIGHT, 1}, }) - selecter := NewSelecter([]string{"Save message", "Pipe to command"}, - 0, acct.UiConfig()). + selecter := NewSelecter([]string{"Save message", "Pipe to command"}, 0). OnChoose(func(option string) { switch option { case "Save message": @@ -543,7 +531,6 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig, grid.AddChild(selecter).At(2, 0) pv := &PartViewer{ - conf: conf, filter: filter, index: index, msg: msg, @@ -555,7 +542,6 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig, term: term, selecter: selecter, grid: grid, - uiConfig: acct.UiConfig(), } if term != nil { @@ -653,16 +639,14 @@ func (pv *PartViewer) Invalidate() { } func (pv *PartViewer) Draw(ctx *ui.Context) { - style := pv.uiConfig.GetStyle(config.STYLE_DEFAULT) - styleError := pv.uiConfig.GetStyle(config.STYLE_ERROR) if pv.filter == nil { // TODO: Let them download it directly or something - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style) - ctx.Printf(0, 0, styleError, + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) + ctx.Printf(0, 0, tcell.StyleDefault.Foreground(tcell.ColorRed), "No filter configured for this mimetype ('%s/%s')", pv.part.MIMEType, pv.part.MIMESubType, ) - ctx.Printf(0, 2, style, + ctx.Printf(0, 2, tcell.StyleDefault, "You can still :save the message or :pipe it to an external command") pv.selecter.Focus(true) pv.grid.Draw(ctx) @@ -673,8 +657,8 @@ func (pv *PartViewer) Draw(ctx *ui.Context) { pv.fetched = true } if pv.err != nil { - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style) - ctx.Printf(0, 0, style, "%s", pv.err.Error()) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) + ctx.Printf(0, 0, tcell.StyleDefault, "%s", pv.err.Error()) return } pv.term.Draw(ctx) @@ -696,10 +680,8 @@ func (pv *PartViewer) Event(event tcell.Event) bool { type HeaderView struct { ui.Invalidatable - conf *config.AercConfig - Name string - Value string - uiConfig config.UIConfig + Name string + Value string } func (hv *HeaderView) Draw(ctx *ui.Context) { @@ -707,15 +689,18 @@ func (hv *HeaderView) Draw(ctx *ui.Context) { size := runewidth.StringWidth(name) lim := ctx.Width() - size - 1 value := runewidth.Truncate(" "+hv.Value, lim, "…") - - vstyle := hv.uiConfig.GetStyle(config.STYLE_DEFAULT) - hstyle := hv.uiConfig.GetStyle(config.STYLE_HEADER) - + var ( + hstyle tcell.Style + vstyle tcell.Style + ) // TODO: Make this more robust and less dumb if hv.Name == "PGP" { - vstyle = hv.uiConfig.GetStyle(config.STYLE_SUCCESS) + vstyle = tcell.StyleDefault.Foreground(tcell.ColorGreen) + hstyle = tcell.StyleDefault.Bold(true) + } else { + vstyle = tcell.StyleDefault + hstyle = tcell.StyleDefault.Bold(true) } - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', vstyle) ctx.Printf(0, 0, hstyle, "%s", name) ctx.Printf(size, 0, vstyle, "%s", value) diff --git a/widgets/pgpinfo.go b/widgets/pgpinfo.go index 94fb877..5da9141 100644 --- a/widgets/pgpinfo.go +++ b/widgets/pgpinfo.go @@ -3,40 +3,40 @@ package widgets import ( "errors" - "git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/lib/ui" + "github.com/gdamore/tcell" "golang.org/x/crypto/openpgp" pgperrors "golang.org/x/crypto/openpgp/errors" ) type PGPInfo struct { ui.Invalidatable - details *openpgp.MessageDetails - uiConfig config.UIConfig + details *openpgp.MessageDetails } -func NewPGPInfo(details *openpgp.MessageDetails, uiConfig config.UIConfig) *PGPInfo { - return &PGPInfo{details: details, uiConfig: uiConfig} +func NewPGPInfo(details *openpgp.MessageDetails) *PGPInfo { + return &PGPInfo{details: details} } func (p *PGPInfo) DrawSignature(ctx *ui.Context) { - errorStyle := p.uiConfig.GetStyle(config.STYLE_ERROR) - warningStyle := p.uiConfig.GetStyle(config.STYLE_WARNING) - validStyle := p.uiConfig.GetStyle(config.STYLE_SUCCESS) - defaultStyle := p.uiConfig.GetStyle(config.STYLE_DEFAULT) + errorStyle := tcell.StyleDefault.Background(tcell.ColorRed). + Foreground(tcell.ColorWhite).Bold(true) + softErrorStyle := tcell.StyleDefault.Foreground(tcell.ColorYellow).Bold(true) + validStyle := tcell.StyleDefault.Foreground(tcell.ColorGreen).Bold(true) // TODO: Nicer prompt for TOFU, fetch from keyserver, etc if errors.Is(p.details.SignatureError, pgperrors.ErrUnknownIssuer) || p.details.SignedBy == nil { - x := ctx.Printf(0, 0, warningStyle, "*") - x += ctx.Printf(x, 0, defaultStyle, + x := ctx.Printf(0, 0, softErrorStyle, "*") + x += ctx.Printf(x, 0, tcell.StyleDefault, " Signed with unknown key (%8X); authenticity unknown", p.details.SignedByKeyId) } else if p.details.SignatureError != nil { x := ctx.Printf(0, 0, errorStyle, "Invalid signature!") - x += ctx.Printf(x, 0, errorStyle, + x += ctx.Printf(x, 0, tcell.StyleDefault. + Foreground(tcell.ColorRed).Bold(true), " This message may have been tampered with! (%s)", p.details.SignatureError.Error()) } else { @@ -44,26 +44,24 @@ func (p *PGPInfo) DrawSignature(ctx *ui.Context) { ident := entity.PrimaryIdentity() x := ctx.Printf(0, 0, validStyle, "✓ Authentic ") - x += ctx.Printf(x, 0, defaultStyle, + x += ctx.Printf(x, 0, tcell.StyleDefault, "Signature from %s (%8X)", ident.Name, p.details.SignedByKeyId) } } func (p *PGPInfo) DrawEncryption(ctx *ui.Context, y int) { - validStyle := p.uiConfig.GetStyle(config.STYLE_SUCCESS) - defaultStyle := p.uiConfig.GetStyle(config.STYLE_DEFAULT) + validStyle := tcell.StyleDefault.Foreground(tcell.ColorGreen).Bold(true) entity := p.details.DecryptedWith.Entity ident := entity.PrimaryIdentity() x := ctx.Printf(0, y, validStyle, "✓ Encrypted ") - x += ctx.Printf(x, y, defaultStyle, + x += ctx.Printf(x, y, tcell.StyleDefault, "To %s (%8X) ", ident.Name, p.details.DecryptedWith.PublicKey.KeyId) } func (p *PGPInfo) Draw(ctx *ui.Context) { - defaultStyle := p.uiConfig.GetStyle(config.STYLE_DEFAULT) - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', defaultStyle) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) if p.details.IsSigned && p.details.IsEncrypted { p.DrawSignature(ctx) p.DrawEncryption(ctx, 1) diff --git a/widgets/selecter.go b/widgets/selecter.go index 0faf37e..7fae9cd 100644 --- a/widgets/selecter.go +++ b/widgets/selecter.go @@ -3,27 +3,24 @@ package widgets import ( "github.com/gdamore/tcell" - "git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/lib/ui" ) type Selecter struct { ui.Invalidatable - chooser bool - focused bool - focus int - options []string - uiConfig config.UIConfig + chooser bool + focused bool + focus int + options []string onChoose func(option string) onSelect func(option string) } -func NewSelecter(options []string, focus int, uiConfig config.UIConfig) *Selecter { +func NewSelecter(options []string, focus int) *Selecter { return &Selecter{ - focus: focus, - options: options, - uiConfig: uiConfig, + focus: focus, + options: options, } } @@ -37,16 +34,15 @@ func (sel *Selecter) Invalidate() { } func (sel *Selecter) Draw(ctx *ui.Context) { - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', - sel.uiConfig.GetStyle(config.STYLE_SELECTER_DEFAULT)) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) x := 2 for i, option := range sel.options { - style := sel.uiConfig.GetStyle(config.STYLE_SELECTER_DEFAULT) + style := tcell.StyleDefault if sel.focus == i { if sel.focused { - style = sel.uiConfig.GetStyle(config.STYLE_SELECTER_FOCUSED) + style = style.Reverse(true) } else if sel.chooser { - style = sel.uiConfig.GetStyle(config.STYLE_SELECTER_CHOOSER) + style = style.Bold(true) } } x += ctx.Printf(x, 1, style, "[%s]", option) diff --git a/widgets/spinner.go b/widgets/spinner.go index 0c72422..51b8c1b 100644 --- a/widgets/spinner.go +++ b/widgets/spinner.go @@ -16,7 +16,6 @@ type Spinner struct { frame int64 // access via atomic frames []string stop chan struct{} - style tcell.Style } func NewSpinner(uiConf *config.UIConfig) *Spinner { @@ -24,7 +23,6 @@ func NewSpinner(uiConf *config.UIConfig) *Spinner { stop: make(chan struct{}), frame: -1, frames: strings.Split(uiConf.Spinner, uiConf.SpinnerDelimiter), - style: uiConf.GetStyle(config.STYLE_SPINNER), } return &spinner } @@ -72,9 +70,9 @@ func (s *Spinner) Draw(ctx *ui.Context) { cur := int(atomic.LoadInt64(&s.frame) % int64(len(s.frames))) - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', s.style) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) col := ctx.Width()/2 - len(s.frames[0])/2 + 1 - ctx.Printf(col, 0, s.style, "%s", s.frames[cur]) + ctx.Printf(col, 0, tcell.StyleDefault, "%s", s.frames[cur]) } func (s *Spinner) Invalidate() { diff --git a/widgets/status.go b/widgets/status.go index d6d7761..8d0a1ae 100644 --- a/widgets/status.go +++ b/widgets/status.go @@ -6,7 +6,6 @@ import ( "github.com/gdamore/tcell" "github.com/mattn/go-runewidth" - "git.sr.ht/~sircmpwn/aerc/config" "git.sr.ht/~sircmpwn/aerc/lib/ui" ) @@ -15,21 +14,21 @@ type StatusLine struct { stack []*StatusMessage fallback StatusMessage aerc *Aerc - uiConfig config.UIConfig } type StatusMessage struct { - style tcell.Style + bg tcell.Color + fg tcell.Color message string } -func NewStatusLine(uiConfig config.UIConfig) *StatusLine { +func NewStatusLine() *StatusLine { return &StatusLine{ fallback: StatusMessage{ - style: uiConfig.GetStyle(config.STYLE_STATUSLINE_DEFAULT), + bg: tcell.ColorDefault, + fg: tcell.ColorDefault, message: "Idle", }, - uiConfig: uiConfig, } } @@ -42,7 +41,9 @@ func (status *StatusLine) Draw(ctx *ui.Context) { if len(status.stack) != 0 { line = status.stack[len(status.stack)-1] } - ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', line.style) + style := tcell.StyleDefault. + Background(line.bg).Foreground(line.fg).Reverse(true) + ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style) pendingKeys := "" if status.aerc != nil { for _, pendingKey := range status.aerc.pendingKeys { @@ -50,21 +51,13 @@ func (status *StatusLine) Draw(ctx *ui.Context) { } } message := runewidth.FillRight(line.message, ctx.Width()-len(pendingKeys)-5) - ctx.Printf(0, 0, line.style, "%s%s", message, pendingKeys) + ctx.Printf(0, 0, style, "%s%s", message, pendingKeys) } func (status *StatusLine) Set(text string) *StatusMessage { status.fallback = StatusMessage{ - style: status.uiConfig.GetStyle(config.STYLE_STATUSLINE_DEFAULT), - message: text, - } - status.Invalidate() - return &status.fallback -} - -func (status *StatusLine) SetError(text string) *StatusMessage { - status.fallback = StatusMessage{ - style: status.uiConfig.GetStyle(config.STYLE_STATUSLINE_ERROR), + bg: tcell.ColorDefault, + fg: tcell.ColorDefault, message: text, } status.Invalidate() @@ -73,7 +66,8 @@ func (status *StatusLine) SetError(text string) *StatusMessage { func (status *StatusLine) Push(text string, expiry time.Duration) *StatusMessage { msg := &StatusMessage{ - style: status.uiConfig.GetStyle(config.STYLE_STATUSLINE_DEFAULT), + bg: tcell.ColorDefault, + fg: tcell.ColorDefault, message: text, } status.stack = append(status.stack, msg) @@ -90,18 +84,6 @@ func (status *StatusLine) Push(text string, expiry time.Duration) *StatusMessage return msg } -func (status *StatusLine) PushError(text string, expiry time.Duration) *StatusMessage { - msg := status.Push(text, expiry) - msg.Color(status.uiConfig.GetStyle(config.STYLE_STATUSLINE_ERROR)) - return msg -} - -func (status *StatusLine) PushSuccess(text string, expiry time.Duration) *StatusMessage { - msg := status.Push(text, expiry) - msg.Color(status.uiConfig.GetStyle(config.STYLE_STATUSLINE_SUCCESS)) - return msg -} - func (status *StatusLine) Expire() { status.stack = nil } @@ -110,6 +92,7 @@ func (status *StatusLine) SetAerc(aerc *Aerc) { status.aerc = aerc } -func (msg *StatusMessage) Color(style tcell.Style) { - msg.style = style +func (msg *StatusMessage) Color(bg tcell.Color, fg tcell.Color) { + msg.bg = bg + msg.fg = fg } diff --git a/widgets/tabhost.go b/widgets/tabhost.go index 1322a0a..0ac67e5 100644 --- a/widgets/tabhost.go +++ b/widgets/tabhost.go @@ -7,9 +7,6 @@ import ( type TabHost interface { BeginExCommand(cmd string) SetStatus(status string) *StatusMessage - SetError(err string) *StatusMessage PushStatus(text string, expiry time.Duration) *StatusMessage - PushError(text string, expiry time.Duration) *StatusMessage - PushSuccess(text string, expiry time.Duration) *StatusMessage Beep() } |