aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/state/renderer.go205
-rw-r--r--lib/state/state.go86
-rw-r--r--lib/state/templates.go78
-rw-r--r--lib/state/texter.go21
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
+ }
+}