statusline: refactor to make it more customizable
Refactor statusline by clearly separating the rendering part from the text display. Use printf-like format string for statusline customization. Document printf-like format string to customize the statusline. Allow to completely mute the statusline (except for push notifications) with a format specifier. Provide a display mode with unicode icons for the status elements. Implements: https://todo.sr.ht/~rjarry/aerc/34 Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
eb7e45d43b
commit
ce18e92881
|
@ -139,6 +139,23 @@ styleset-name=default
|
||||||
# Default: false
|
# Default: false
|
||||||
#threading-enabled=false
|
#threading-enabled=false
|
||||||
|
|
||||||
|
[statusline]
|
||||||
|
# Describes the format string for the statusline.
|
||||||
|
#
|
||||||
|
# Default: [%a] %S %>%T
|
||||||
|
render-format=[%a] %S %>%T
|
||||||
|
|
||||||
|
# Specifies the separator between grouped statusline elements.
|
||||||
|
#
|
||||||
|
# Default: " | "
|
||||||
|
# separator=
|
||||||
|
|
||||||
|
# Defines the mode for displaying the status elements.
|
||||||
|
# Options: text, icon
|
||||||
|
#
|
||||||
|
# Default: text
|
||||||
|
# display-mode=
|
||||||
|
|
||||||
[viewer]
|
[viewer]
|
||||||
#
|
#
|
||||||
# Specifies the pager to use when displaying emails. Note that some filters
|
# Specifies the pager to use when displaying emails. Note that some filters
|
||||||
|
|
|
@ -147,6 +147,12 @@ type ViewerConfig struct {
|
||||||
KeyPassthrough bool `ini:"-"`
|
KeyPassthrough bool `ini:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StatuslineConfig struct {
|
||||||
|
RenderFormat string `ini:"render-format"`
|
||||||
|
Separator string
|
||||||
|
DisplayMode string `ini:"display-mode"`
|
||||||
|
}
|
||||||
|
|
||||||
type TriggersConfig struct {
|
type TriggersConfig struct {
|
||||||
NewEmail string `ini:"new-email"`
|
NewEmail string `ini:"new-email"`
|
||||||
ExecuteCommand func(command []string) error
|
ExecuteCommand func(command []string) error
|
||||||
|
@ -163,11 +169,12 @@ type AercConfig struct {
|
||||||
Bindings BindingConfig
|
Bindings BindingConfig
|
||||||
ContextualBinds []BindingConfigContext
|
ContextualBinds []BindingConfigContext
|
||||||
Compose ComposeConfig
|
Compose ComposeConfig
|
||||||
Ini *ini.File `ini:"-"`
|
Ini *ini.File `ini:"-"`
|
||||||
Accounts []AccountConfig `ini:"-"`
|
Accounts []AccountConfig `ini:"-"`
|
||||||
Filters []FilterConfig `ini:"-"`
|
Filters []FilterConfig `ini:"-"`
|
||||||
Viewer ViewerConfig `ini:"-"`
|
Viewer ViewerConfig `ini:"-"`
|
||||||
Triggers TriggersConfig `ini:"-"`
|
Statusline StatuslineConfig `ini:"-"`
|
||||||
|
Triggers TriggersConfig `ini:"-"`
|
||||||
Ui UIConfig
|
Ui UIConfig
|
||||||
ContextualUis []UIConfigContext
|
ContextualUis []UIConfigContext
|
||||||
General GeneralConfig
|
General GeneralConfig
|
||||||
|
@ -410,6 +417,11 @@ func (config *AercConfig) LoadConfig(file *ini.File) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if statusline, err := file.GetSection("statusline"); err == nil {
|
||||||
|
if err := statusline.MapTo(&config.Statusline); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if compose, err := file.GetSection("compose"); err == nil {
|
if compose, err := file.GetSection("compose"); err == nil {
|
||||||
if err := compose.MapTo(&config.Compose); err != nil {
|
if err := compose.MapTo(&config.Compose); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -654,6 +666,12 @@ func LoadConfigFromFile(root *string, logger *log.Logger) (*AercConfig, error) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Statusline: StatuslineConfig{
|
||||||
|
RenderFormat: "[%a] %S %>%T",
|
||||||
|
Separator: " | ",
|
||||||
|
DisplayMode: "",
|
||||||
|
},
|
||||||
|
|
||||||
Compose: ComposeConfig{
|
Compose: ComposeConfig{
|
||||||
HeaderLayout: [][]string{
|
HeaderLayout: [][]string{
|
||||||
{"To", "From"},
|
{"To", "From"},
|
||||||
|
|
|
@ -295,6 +295,52 @@ index-format=...
|
||||||
index-format=...
|
index-format=...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## STATUSLINE
|
||||||
|
|
||||||
|
These options are configured in the *[statusline]* section of aerc.conf.
|
||||||
|
|
||||||
|
*render-format*
|
||||||
|
Describes the format string for the statusline format.
|
||||||
|
|
||||||
|
For a minimal statusline that only shows the current account and
|
||||||
|
the connection information, use [%a] %c.
|
||||||
|
|
||||||
|
To completely mute the statusline (except for push notficiations), use
|
||||||
|
%m only.
|
||||||
|
|
||||||
|
Default: [%a] %S %>%T
|
||||||
|
|
||||||
|
[- *Format specifier*
|
||||||
|
:[ *Description*
|
||||||
|
| %%
|
||||||
|
: literal %
|
||||||
|
| %a
|
||||||
|
: active account name
|
||||||
|
| %d
|
||||||
|
: active directory name
|
||||||
|
| %c
|
||||||
|
: connection state
|
||||||
|
| %m
|
||||||
|
: mute statusline and show only push notifications
|
||||||
|
| %S
|
||||||
|
: general status information (e.g. connection state, filter, search)
|
||||||
|
| %T
|
||||||
|
: general on/off information (e.g. passthrough, threading, sorting)
|
||||||
|
| %>
|
||||||
|
: does not print anything but all format specifier that follow will be right justified.
|
||||||
|
|
||||||
|
*separator*
|
||||||
|
Specifies the separator between grouped statusline elements (e.g. for
|
||||||
|
the %S and %T specifiers in *render-format*).
|
||||||
|
|
||||||
|
Default: " | "
|
||||||
|
|
||||||
|
*display-mode*
|
||||||
|
Defines the mode for displaying the status elements.
|
||||||
|
Options: text, icon
|
||||||
|
|
||||||
|
Default: text
|
||||||
|
|
||||||
|
|
||||||
## VIEWER
|
## VIEWER
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package statusline
|
|
||||||
|
|
||||||
type folderState struct {
|
|
||||||
Search string
|
|
||||||
Filter string
|
|
||||||
FilterActivity string
|
|
||||||
Sorting string
|
|
||||||
|
|
||||||
Threading string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fs *folderState) State() []string {
|
|
||||||
var line []string
|
|
||||||
|
|
||||||
if fs.FilterActivity != "" {
|
|
||||||
line = append(line, fs.FilterActivity)
|
|
||||||
} else {
|
|
||||||
if fs.Filter != "" {
|
|
||||||
line = append(line, fs.Filter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fs.Search != "" {
|
|
||||||
line = append(line, fs.Search)
|
|
||||||
}
|
|
||||||
if fs.Sorting != "" {
|
|
||||||
line = append(line, fs.Sorting)
|
|
||||||
}
|
|
||||||
if fs.Threading != "" {
|
|
||||||
line = append(line, fs.Threading)
|
|
||||||
}
|
|
||||||
return line
|
|
||||||
}
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
package statusline
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/mattn/go-runewidth"
|
||||||
|
)
|
||||||
|
|
||||||
|
type renderParams struct {
|
||||||
|
width int
|
||||||
|
sep string
|
||||||
|
acct *accountState
|
||||||
|
fldr *folderState
|
||||||
|
}
|
||||||
|
|
||||||
|
type renderFunc func(r renderParams) string
|
||||||
|
|
||||||
|
func newRenderer(renderFormat, textMode string) renderFunc {
|
||||||
|
var texter Texter
|
||||||
|
switch strings.ToLower(textMode) {
|
||||||
|
case "icon":
|
||||||
|
texter = &icon{}
|
||||||
|
default:
|
||||||
|
texter = &text{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderer(texter, renderFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderer(texter Texter, renderFormat string) renderFunc {
|
||||||
|
var leftFmt, rightFmt string
|
||||||
|
if idx := strings.Index(renderFormat, "%>"); idx < 0 {
|
||||||
|
leftFmt = renderFormat
|
||||||
|
} else {
|
||||||
|
leftFmt, rightFmt = renderFormat[:idx], strings.Replace(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))
|
||||||
|
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")
|
||||||
|
}
|
|
@ -2,76 +2,80 @@ package statusline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
"git.sr.ht/~rjarry/aerc/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
Name string
|
separator string
|
||||||
Multiple bool
|
renderer renderFunc
|
||||||
Separator string
|
acct *accountState
|
||||||
|
fldr map[string]*folderState
|
||||||
Connection string
|
width int
|
||||||
ConnActivity string
|
|
||||||
Connected bool
|
|
||||||
|
|
||||||
Passthrough string
|
|
||||||
|
|
||||||
fs map[string]*folderState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewState(name string, multipleAccts bool, sep string) *State {
|
type accountState struct {
|
||||||
return &State{Name: name, Multiple: multipleAccts, Separator: sep,
|
Name string
|
||||||
fs: make(map[string]*folderState)}
|
Multiple bool
|
||||||
|
ConnActivity string
|
||||||
|
Connected bool
|
||||||
|
Passthrough bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type folderState struct {
|
||||||
|
Name string
|
||||||
|
Search string
|
||||||
|
Filter string
|
||||||
|
FilterActivity string
|
||||||
|
Sorting bool
|
||||||
|
Threading bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewState(name string, multipleAccts bool, conf config.StatuslineConfig) *State {
|
||||||
|
return &State{separator: conf.Separator,
|
||||||
|
renderer: newRenderer(conf.RenderFormat, conf.DisplayMode),
|
||||||
|
acct: &accountState{Name: name, Multiple: multipleAccts},
|
||||||
|
fldr: make(map[string]*folderState),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) StatusLine(folder string) string {
|
func (s *State) StatusLine(folder string) string {
|
||||||
var line []string
|
return s.renderer(renderParams{
|
||||||
if s.Connection != "" || s.ConnActivity != "" {
|
width: s.width,
|
||||||
conn := s.Connection
|
sep: s.separator,
|
||||||
if s.ConnActivity != "" {
|
acct: s.acct,
|
||||||
conn = s.ConnActivity
|
fldr: s.folderState(folder),
|
||||||
}
|
})
|
||||||
if s.Multiple {
|
|
||||||
line = append(line, fmt.Sprintf("[%s] %s", s.Name, conn))
|
|
||||||
} else {
|
|
||||||
line = append(line, conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if s.Connected {
|
|
||||||
if s.Passthrough != "" {
|
|
||||||
line = append(line, s.Passthrough)
|
|
||||||
}
|
|
||||||
if folder != "" {
|
|
||||||
line = append(line, s.folderState(folder).State()...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(line, s.Separator)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) folderState(folder string) *folderState {
|
func (s *State) folderState(folder string) *folderState {
|
||||||
if _, ok := s.fs[folder]; !ok {
|
if _, ok := s.fldr[folder]; !ok {
|
||||||
s.fs[folder] = &folderState{}
|
s.fldr[folder] = &folderState{Name: folder}
|
||||||
}
|
}
|
||||||
return s.fs[folder]
|
return s.fldr[folder]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) SetWidth(w int) bool {
|
||||||
|
changeState := false
|
||||||
|
if s.width != w {
|
||||||
|
s.width = w
|
||||||
|
changeState = true
|
||||||
|
}
|
||||||
|
return changeState
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetStateFunc func(s *State, folder string)
|
type SetStateFunc func(s *State, folder string)
|
||||||
|
|
||||||
func Connected(state bool) SetStateFunc {
|
func Connected(state bool) SetStateFunc {
|
||||||
return func(s *State, folder string) {
|
return func(s *State, folder string) {
|
||||||
s.ConnActivity = ""
|
s.acct.ConnActivity = ""
|
||||||
s.Connected = state
|
s.acct.Connected = state
|
||||||
if state {
|
|
||||||
s.Connection = "Connected"
|
|
||||||
} else {
|
|
||||||
s.Connection = "Disconnected"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectionActivity(desc string) SetStateFunc {
|
func ConnectionActivity(desc string) SetStateFunc {
|
||||||
return func(s *State, folder string) {
|
return func(s *State, folder string) {
|
||||||
s.ConnActivity = desc
|
s.acct.ConnActivity = desc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,27 +115,18 @@ func Search(desc string) SetStateFunc {
|
||||||
|
|
||||||
func Sorting(on bool) SetStateFunc {
|
func Sorting(on bool) SetStateFunc {
|
||||||
return func(s *State, folder string) {
|
return func(s *State, folder string) {
|
||||||
s.folderState(folder).Sorting = ""
|
s.folderState(folder).Sorting = on
|
||||||
if on {
|
|
||||||
s.folderState(folder).Sorting = "sorting"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Threading(on bool) SetStateFunc {
|
func Threading(on bool) SetStateFunc {
|
||||||
return func(s *State, folder string) {
|
return func(s *State, folder string) {
|
||||||
s.folderState(folder).Threading = ""
|
s.folderState(folder).Threading = on
|
||||||
if on {
|
|
||||||
s.folderState(folder).Threading = "threading"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Passthrough(on bool) SetStateFunc {
|
func Passthrough(on bool) SetStateFunc {
|
||||||
return func(s *State, folder string) {
|
return func(s *State, folder string) {
|
||||||
s.Passthrough = ""
|
s.acct.Passthrough = on
|
||||||
if on {
|
|
||||||
s.Passthrough = "passthrough"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package statusline
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type Texter interface {
|
||||||
|
Connected() string
|
||||||
|
Disconnected() string
|
||||||
|
Passthrough() string
|
||||||
|
Sorting() string
|
||||||
|
Threading() string
|
||||||
|
FormatFilter(string) string
|
||||||
|
FormatSearch(string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type text struct{}
|
||||||
|
|
||||||
|
func (t text) Connected() string {
|
||||||
|
return "Connected"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t text) Disconnected() string {
|
||||||
|
return "Disconnected"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t text) Passthrough() string {
|
||||||
|
return "passthrough"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t text) Sorting() string {
|
||||||
|
return "sorting"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t text) Threading() string {
|
||||||
|
return "threading"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t text) FormatFilter(s string) string {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t text) FormatSearch(s string) string {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type icon struct{}
|
||||||
|
|
||||||
|
func (i icon) Connected() string {
|
||||||
|
return "✓"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i icon) Disconnected() string {
|
||||||
|
return "✘"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i icon) Passthrough() string {
|
||||||
|
return "➔"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i icon) Sorting() string {
|
||||||
|
return "⚙"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i icon) Threading() string {
|
||||||
|
return "🧵"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i icon) FormatFilter(s string) string {
|
||||||
|
return strings.ReplaceAll(s, "filter", "🔦")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i icon) FormatSearch(s string) string {
|
||||||
|
return strings.ReplaceAll(s, "search", "🔎")
|
||||||
|
}
|
|
@ -59,7 +59,7 @@ func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountCon
|
||||||
conf: conf,
|
conf: conf,
|
||||||
host: host,
|
host: host,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
state: statusline.NewState(acct.Name, len(conf.Accounts) > 1, " | "),
|
state: statusline.NewState(acct.Name, len(conf.Accounts) > 1, conf.Statusline),
|
||||||
}
|
}
|
||||||
|
|
||||||
view.grid = ui.NewGrid().Rows([]ui.GridSpec{
|
view.grid = ui.NewGrid().Rows([]ui.GridSpec{
|
||||||
|
@ -170,6 +170,9 @@ func (acct *AccountView) Invalidate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acct *AccountView) Draw(ctx *ui.Context) {
|
func (acct *AccountView) Draw(ctx *ui.Context) {
|
||||||
|
if acct.state.SetWidth(ctx.Width()) {
|
||||||
|
acct.UpdateStatus()
|
||||||
|
}
|
||||||
acct.grid.Draw(ctx)
|
acct.grid.Draw(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue