diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/state/renderer.go | 205 | ||||
-rw-r--r-- | lib/state/state.go | 86 | ||||
-rw-r--r-- | lib/state/templates.go | 78 | ||||
-rw-r--r-- | lib/state/texter.go | 21 |
4 files changed, 121 insertions, 269 deletions
diff --git a/lib/state/renderer.go b/lib/state/renderer.go deleted file mode 100644 index 13e593fe..00000000 --- a/lib/state/renderer.go +++ /dev/null @@ -1,205 +0,0 @@ -package state - -import ( - "errors" - "fmt" - "os" - "strings" - "unicode" - - "git.sr.ht/~rjarry/aerc/config" - "github.com/mattn/go-runewidth" -) - -type renderParams struct { - width int - sep string - acct *accountState - fldr *folderState -} - -type renderFunc func(r renderParams) string - -func newRenderer() renderFunc { - var texter Texter - switch strings.ToLower(config.Statusline.DisplayMode) { - case "icon": - texter = &icon{} - default: - texter = &text{} - } - - return renderer(texter) -} - -func renderer(texter Texter) renderFunc { - var leftFmt, rightFmt string - if idx := strings.Index(config.Statusline.RenderFormat, "%>"); idx < 0 { - leftFmt = config.Statusline.RenderFormat - } else { - leftFmt = config.Statusline.RenderFormat[:idx] - rightFmt = strings.Replace(config.Statusline.RenderFormat[idx:], "%>", "", 1) - } - - return func(r renderParams) string { - lfmtStr, largs, err := parseStatuslineFormat(leftFmt, texter, r) - if err != nil { - return err.Error() - } - rfmtStr, rargs, err := parseStatuslineFormat(rightFmt, texter, r) - if err != nil { - return err.Error() - } - leftText, rightText := fmt.Sprintf(lfmtStr, largs...), fmt.Sprintf(rfmtStr, rargs...) - return runewidth.FillRight(leftText, r.width-len(rightText)-1) + rightText - } -} - -func connectionInfo(acct *accountState, texter Texter) (conn string) { - if acct.ConnActivity != "" { - conn += acct.ConnActivity - } else { - if acct.Connected { - conn += texter.Connected() - } else { - conn += texter.Disconnected() - } - } - return -} - -func contentInfo(acct *accountState, fldr *folderState, texter Texter) []string { - var status []string - if fldr.FilterActivity != "" { - status = append(status, fldr.FilterActivity) - } else if fldr.Filter != "" { - status = append(status, texter.FormatFilter(fldr.Filter)) - } - if fldr.Search != "" { - status = append(status, texter.FormatSearch(fldr.Search)) - } - return status -} - -func trayInfo(acct *accountState, fldr *folderState, texter Texter) []string { - var tray []string - if fldr.Sorting { - tray = append(tray, texter.Sorting()) - } - if fldr.Threading { - tray = append(tray, texter.Threading()) - } - if acct.Passthrough { - tray = append(tray, texter.Passthrough()) - } - return tray -} - -func parseStatuslineFormat(format string, texter Texter, r renderParams) (string, []interface{}, error) { - retval := make([]byte, 0, len(format)) - var args []interface{} - mute := false - - var c rune - for i, ni := 0, 0; i < len(format); { - ni = strings.IndexByte(format[i:], '%') - if ni < 0 { - ni = len(format) - retval = append(retval, []byte(format[i:ni])...) - break - } - ni += i + 1 - // Check for fmt flags - if ni == len(format) { - goto handle_end_error - } - c = rune(format[ni]) - if c == '+' || c == '-' || c == '#' || c == ' ' || c == '0' { - ni++ - } - - // Check for precision and width - if ni == len(format) { - goto handle_end_error - } - c = rune(format[ni]) - for unicode.IsDigit(c) { - ni++ - c = rune(format[ni]) - } - if c == '.' { - ni++ - c = rune(format[ni]) - for unicode.IsDigit(c) { - ni++ - c = rune(format[ni]) - } - } - - retval = append(retval, []byte(format[i:ni])...) - // Get final format verb - if ni == len(format) { - goto handle_end_error - } - c = rune(format[ni]) - switch c { - case '%': - retval = append(retval, '%') - case 'a': - retval = append(retval, 's') - args = append(args, r.acct.Name) - case 'c': - retval = append(retval, 's') - args = append(args, connectionInfo(r.acct, texter)) - case 'd': - retval = append(retval, 's') - args = append(args, r.fldr.Name) - case 'm': - mute = true - case 'S': - var status []string - if conn := connectionInfo(r.acct, texter); conn != "" { - status = append(status, conn) - } - - if r.acct.Connected { - status = append(status, contentInfo(r.acct, r.fldr, texter)...) - } - retval = append(retval, 's') - args = append(args, strings.Join(status, r.sep)) - case 'T': - var tray []string - if r.acct.Connected { - tray = trayInfo(r.acct, r.fldr, texter) - } - retval = append(retval, 's') - args = append(args, strings.Join(tray, r.sep)) - case 'p': - path, err := os.Getwd() - if err == nil { - home, _ := os.UserHomeDir() - if strings.HasPrefix(path, home) { - path = strings.Replace(path, home, "~", 1) - } - retval = append(retval, 's') - args = append(args, path) - } - default: - // Just ignore it and print as is - // so %k in index format becomes %%k to Printf - retval = append(retval, '%') - retval = append(retval, byte(c)) - } - i = ni + 1 - } - - if mute { - return "", nil, nil - } - - return string(retval), args, nil - -handle_end_error: - return "", nil, - errors.New("reached end of string while parsing statusline format") -} diff --git a/lib/state/state.go b/lib/state/state.go index b5f925ac..49431029 100644 --- a/lib/state/state.go +++ b/lib/state/state.go @@ -2,27 +2,16 @@ package state import ( "fmt" - - "git.sr.ht/~rjarry/aerc/config" ) -type State struct { - renderer renderFunc - acct *accountState - fldr map[string]*folderState - width int -} - -type accountState struct { - Name string - Multiple bool - ConnActivity string +type AccountState struct { Connected bool - Passthrough bool + connActivity string + passthrough bool + folders map[string]*folderState } type folderState struct { - Name string Search string Filter string FilterActivity string @@ -30,60 +19,33 @@ type folderState struct { Threading bool } -func NewState(name string, multipleAccts bool) *State { - return &State{ - renderer: newRenderer(), - acct: &accountState{Name: name, Multiple: multipleAccts}, - fldr: make(map[string]*folderState), - } -} - -func (s *State) StatusLine(folder string) string { - return s.renderer(renderParams{ - width: s.width, - sep: config.Statusline.Separator, - acct: s.acct, - fldr: s.folderState(folder), - }) -} - -func (s *State) folderState(folder string) *folderState { - if _, ok := s.fldr[folder]; !ok { - s.fldr[folder] = &folderState{Name: folder} +func (s *AccountState) folderState(folder string) *folderState { + if s.folders == nil { + s.folders = make(map[string]*folderState) } - return s.fldr[folder] -} - -func (s *State) SetWidth(w int) bool { - changeState := false - if s.width != w { - s.width = w - changeState = true + if _, ok := s.folders[folder]; !ok { + s.folders[folder] = &folderState{} } - return changeState -} - -func (s *State) Connected() bool { - return s.acct.Connected + return s.folders[folder] } -type SetStateFunc func(s *State, folder string) +type SetStateFunc func(s *AccountState, folder string) func SetConnected(state bool) SetStateFunc { - return func(s *State, folder string) { - s.acct.ConnActivity = "" - s.acct.Connected = state + return func(s *AccountState, folder string) { + s.connActivity = "" + s.Connected = state } } func ConnectionActivity(desc string) SetStateFunc { - return func(s *State, folder string) { - s.acct.ConnActivity = desc + return func(s *AccountState, folder string) { + s.connActivity = desc } } func SearchFilterClear() SetStateFunc { - return func(s *State, folder string) { + return func(s *AccountState, folder string) { s.folderState(folder).Search = "" s.folderState(folder).FilterActivity = "" s.folderState(folder).Filter = "" @@ -91,13 +53,13 @@ func SearchFilterClear() SetStateFunc { } func FilterActivity(str string) SetStateFunc { - return func(s *State, folder string) { + return func(s *AccountState, folder string) { s.folderState(folder).FilterActivity = str } } func FilterResult(str string) SetStateFunc { - return func(s *State, folder string) { + return func(s *AccountState, folder string) { s.folderState(folder).FilterActivity = "" s.folderState(folder).Filter = concatFilters(s.folderState(folder).Filter, str) } @@ -111,25 +73,25 @@ func concatFilters(existing, next string) string { } func Search(desc string) SetStateFunc { - return func(s *State, folder string) { + return func(s *AccountState, folder string) { s.folderState(folder).Search = desc } } func Sorting(on bool) SetStateFunc { - return func(s *State, folder string) { + return func(s *AccountState, folder string) { s.folderState(folder).Sorting = on } } func Threading(on bool) SetStateFunc { - return func(s *State, folder string) { + return func(s *AccountState, folder string) { s.folderState(folder).Threading = on } } func Passthrough(on bool) SetStateFunc { - return func(s *State, folder string) { - s.acct.Passthrough = on + return func(s *AccountState, folder string) { + s.passthrough = on } } diff --git a/lib/state/templates.go b/lib/state/templates.go index 48106295..f37c4865 100644 --- a/lib/state/templates.go +++ b/lib/state/templates.go @@ -30,6 +30,9 @@ type TemplateData struct { folder string // selected folder name folders []string getRUEcount func(string) (int, int, int) + + state *AccountState + pendingKeys []config.KeyStroke } // only used for compose/reply/forward @@ -65,6 +68,14 @@ func (d *TemplateData) SetRUE(folders []string, cb func(string) (int, int, int)) d.getRUEcount = cb } +func (d *TemplateData) SetState(state *AccountState) { + d.state = state +} + +func (d *TemplateData) SetPendingKeys(keys []config.KeyStroke) { + d.pendingKeys = keys +} + func (d *TemplateData) Account() string { if d.account != nil { return d.account.Name @@ -357,3 +368,70 @@ func (d *TemplateData) Exists(folders ...string) int { _, _, e := d.rue(folders...) return e } + +func (d *TemplateData) Connected() bool { + if d.state != nil { + return d.state.Connected + } + return false +} + +func (d *TemplateData) ConnectionInfo() string { + switch { + case d.state == nil: + return "" + case d.state.connActivity != "": + return d.state.connActivity + case d.state.Connected: + return texter().Connected() + default: + return texter().Disconnected() + } +} + +func (d *TemplateData) ContentInfo() string { + if d.state == nil { + return "" + } + var content []string + fldr := d.state.folderState(d.folder) + if fldr.FilterActivity != "" { + content = append(content, fldr.FilterActivity) + } else if fldr.Filter != "" { + content = append(content, texter().FormatFilter(fldr.Filter)) + } + if fldr.Search != "" { + content = append(content, texter().FormatSearch(fldr.Search)) + } + return strings.Join(content, config.Statusline.Separator) +} + +func (d *TemplateData) StatusInfo() string { + stat := d.ConnectionInfo() + if content := d.ContentInfo(); content != "" { + stat += config.Statusline.Separator + content + } + return stat +} + +func (d *TemplateData) TrayInfo() string { + if d.state == nil { + return "" + } + var tray []string + fldr := d.state.folderState(d.folder) + if fldr.Sorting { + tray = append(tray, texter().Sorting()) + } + if fldr.Threading { + tray = append(tray, texter().Threading()) + } + if d.state.passthrough { + tray = append(tray, texter().Passthrough()) + } + return strings.Join(tray, config.Statusline.Separator) +} + +func (d *TemplateData) PendingKeys() string { + return config.FormatKeyStrokes(d.pendingKeys) +} diff --git a/lib/state/texter.go b/lib/state/texter.go index 21cf3627..9212108d 100644 --- a/lib/state/texter.go +++ b/lib/state/texter.go @@ -1,8 +1,12 @@ package state -import "strings" +import ( + "strings" -type Texter interface { + "git.sr.ht/~rjarry/aerc/config" +) + +type texterInterface interface { Connected() string Disconnected() string Passthrough() string @@ -14,6 +18,8 @@ type Texter interface { type text struct{} +var txt text + func (t text) Connected() string { return "Connected" } @@ -44,6 +50,8 @@ func (t text) FormatSearch(s string) string { type icon struct{} +var icn icon + func (i icon) Connected() string { return "✓" } @@ -71,3 +79,12 @@ func (i icon) FormatFilter(s string) string { func (i icon) FormatSearch(s string) string { return strings.ReplaceAll(s, "search", "🔎") } + +func texter() texterInterface { + switch strings.ToLower(config.Statusline.DisplayMode) { + case "icon": + return &icn + default: + return &txt + } +} |