This started as a follow up on https://lists.sr.ht/~rjarry/aerc-devel/patches/44342 and grew out of hand pretty quickly. Patch 3/3 also contains a revert of the aforementioned patch since colors/style now allow differentiating MIME types from filenames without any alignment. Robin Jarry (3): config: add default values for empty stylesets colorize: support trailing comments after values msgviewer: add styles for part selector CHANGELOG.md | 9 ++ config/style.go | 108 +++++++++++++++++++---- doc/aerc-stylesets.7.scd | 48 ++++++++++ filters/colorize.c | 2 +- filters/test.sh | 8 +- filters/vectors/colorize-patch.expected | 18 ++-- filters/vectors/colorize-quotes.expected | 4 +- stylesets/blue | 9 ++ stylesets/default | 52 ++++++----- stylesets/dracula | 9 ++ stylesets/nord | 6 ++ stylesets/pink | 9 +- stylesets/solarized | 3 + widgets/msgviewer.go | 52 ++++------- widgets/msgviewer_test.go | 68 -------------- 15 files changed, 247 insertions(+), 158 deletions(-) delete mode 100644 widgets/msgviewer_test.go -- 2.41.0
aerc/patches: SUCCESS in 5m8s [Allow styling part selector MIME and filename][0] from [Robin Jarry][1] [0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/44854 [1]: mailto:robin@jarry.cc ✓ #1059559 SUCCESS aerc/patches/openbsd.yml https://builds.sr.ht/~rjarry/job/1059559 ✓ #1059558 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1059558
Beautiful! Tested-By: inwit <inwit@sindominio.net>
Applied. Thanks!
inwit, Sep 19, 2023 at 16:22:
Vitaly Ovchinnikov, Sep 19, 2023 at 23:04:
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~rjarry/aerc-devel/patches/44854/mbox | git am -3Learn more about email & git
When adding new style objects it is impossible to give them a default color nor attributes without modifying each existing user styleset. Also, if the user has an incomplete styleset, some parts of aerc will have no style at all. These quirks are not nice from a user experience point of view. Before parsing the user styleset, initialize aerc style with basic defaults. Reuse the exact same content than the actual "default" styleset provided in /usr/share/aerc/stylesets. Comment all of the default styleset to make it obvious that these are default values. This has some implications: * To reset these defaults, the user styleset must now start with these two lines: *.default = true *.normal = true If these two lines are not present, the default style will be kept and only changed if the user styleset explicitly sets them. * Empty stylesets no longer produce weird results. Signed-off-by: Robin Jarry <robin@jarry.cc> --- CHANGELOG.md | 9 ++++ config/style.go | 89 ++++++++++++++++++++++++++++++++-------- doc/aerc-stylesets.7.scd | 39 ++++++++++++++++++ stylesets/blue | 3 ++ stylesets/default | 49 +++++++++++----------- stylesets/dracula | 3 ++ stylesets/nord | 1 + stylesets/pink | 3 +- stylesets/solarized | 1 + 9 files changed, 156 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d138a8383026..4e9b3f2a9064 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). default. Legacy behaviour can be restored by setting `send-with-hostname = true` in `accounts.conf`. - The notmuch bindings were replaced with internal bindings +- Aerc now has a default style for most UI elements. The `default` styleset is + now empty. Existing stylesets will only override the default attributes if + they are set explicitly. To reset the default style and preserve existing + stylesets appearance, these two lines must be inserted **at the beginning**: + + ``` + *.default=true + *.normal=true + ``` ### Deprecated diff --git a/config/style.go b/config/style.go index 50c53de328b5..f50126bdb361 100644 --- a/config/style.go +++ b/config/style.go @@ -280,25 +280,82 @@ func NewStyleSet() StyleSet { user: make(map[string]*Style), } for _, so := range StyleNames { - ss.objects[so] = new(StyleConf) - ss.selected[so] = new(StyleConf) + conf := new(StyleConf) + + switch so { + case STYLE_ERROR: + // *error.bold=true + conf.base.Bold = true + // error.fg=red + conf.base.Fg = tcell.ColorRed + case STYLE_WARNING: + // warning.fg=yellow + conf.base.Fg = tcell.ColorYellow + case STYLE_SUCCESS: + // success.fg=green + conf.base.Fg = tcell.ColorGreen + case STYLE_TITLE: + // title.reverse=true + conf.base.Reverse = true + case STYLE_HEADER: + // header.bold=true + conf.base.Bold = true + case STYLE_STATUSLINE_DEFAULT: + // statusline_default.reverse=true + conf.base.Reverse = true + case STYLE_STATUSLINE_ERROR: + // *error.bold=true + conf.base.Fg = tcell.ColorRed + // statusline_error.fg=red + conf.base.Bold = true + // statusline_error.reverse=true + conf.base.Reverse = true + case STYLE_STATUSLINE_WARNING: + // statusline_warning.fg=yellow + conf.base.Fg = tcell.ColorYellow + // statusline_warning.reverse=true + conf.base.Reverse = true + case STYLE_STATUSLINE_SUCCESS: + conf.base.Fg = tcell.ColorGreen + conf.base.Reverse = true + case STYLE_MSGLIST_UNREAD: + // msglist_unread.bold=true + conf.base.Bold = true + case STYLE_MSGLIST_DELETED: + // msglist_deleted.fg=gray + conf.base.Fg = tcell.ColorGray + case STYLE_MSGLIST_RESULT: + // msglist_result.fg=green + conf.base.Fg = tcell.ColorGreen + case STYLE_MSGLIST_PILL: + // msglist_pill.reverse=true + conf.base.Reverse = true + case STYLE_COMPLETION_PILL: + // completion_pill.reverse=true + conf.base.Reverse = true + case STYLE_TAB: + // tab.reverse=true + conf.base.Reverse = true + case STYLE_BORDER: + // border.reverse = true + conf.base.Reverse = true + case STYLE_SELECTOR_FOCUSED: + // selector_focused.reverse=true + conf.base.Reverse = true + case STYLE_SELECTOR_CHOOSER: + // selector_chooser.bold=true + conf.base.Bold = true + } + + ss.objects[so] = conf + selected := *conf + // *.selected.reverse=toggle + selected.base.Reverse = !conf.base.Reverse + ss.selected[so] = &selected } return ss } -func (ss StyleSet) reset() { - for _, so := range StyleNames { - ss.objects[so].base.Reset() - for _, d := range ss.objects[so].dynamic { - d.Reset() - } - ss.selected[so].base.Reset() - for _, d := range ss.selected[so].dynamic { - d.Reset() - } - } -} - func (c *StyleConf) getStyle(h *mail.Header) *Style { if h == nil { return &c.base @@ -367,8 +424,6 @@ func findStyleSet(stylesetName string, stylesetsDir []string) (string, error) { } func (ss *StyleSet) ParseStyleSet(file *ini.File) error { - ss.reset() - defaultSection, err := file.GetSection(ini.DefaultSection) if err != nil { return err diff --git a/doc/aerc-stylesets.7.scd b/doc/aerc-stylesets.7.scd index 91b6e77aff82..4f43859b3d2d 100644 --- a/doc/aerc-stylesets.7.scd +++ b/doc/aerc-stylesets.7.scd @@ -334,6 +334,45 @@ _<Dec number>_ Color based on the terminal palette index. Valid numbers are between _0_ and _255_. +# DEFAULTS + +Before parsing a styleset, it is first initialized with the following defaults: + +``` +*.selected.reverse=toggle +title.reverse=true +header.bold=true +*error.bold=true +error.fg=red +warning.fg=yellow +success.fg=green +statusline*.default=true +statusline_default.reverse=true +statusline_error.fg=red +statusline_error.reverse=true +statusline_warning.fg=yellow +statusline_warning.reverse=true +msglist_unread.bold=true +msglist_deleted.fg=gray +msglist_result.fg=green +msglist_pill.reverse=true +completion_pill.reverse=true +tab.reverse=true +border.reverse = true +selector_focused.reverse=true +selector_chooser.bold=true +``` + +You can choose either to reset everything by starting your styleset with these +two lines: + +``` +*.default=true +*.normal=true +``` + +Or selectively override style object attributes. + # SEE ALSO *aerc*(1) *aerc-config*(5) diff --git a/stylesets/blue b/stylesets/blue index c598ef92da78..46e04b4604ff 100644 --- a/stylesets/blue +++ b/stylesets/blue @@ -1,5 +1,8 @@ # vim: ft=dosini +*.default=true +*.normal=true + border.bg=#005f87 title.bg=#005f87 diff --git a/stylesets/default b/stylesets/default index f3ea273396f7..c0d6f90919d1 100644 --- a/stylesets/default +++ b/stylesets/default @@ -6,36 +6,39 @@ # the aerc-stylesets(7) manpage. Please read the manual before # modifying or creating a styleset. -*.default=true -*.selected.reverse=toggle +# Uncomment these two lines to reset all attributes and start from scratch. +#*.default=true +#*.normal=true -title.reverse=true -header.bold=true +#*.selected.reverse=toggle +# +#title.reverse=true +#header.bold=true -*error.bold=true -error.fg=red -warning.fg=yellow -success.fg=green +#*error.bold=true +#error.fg=red +#warning.fg=yellow +#success.fg=green -statusline*.default=true -statusline_default.reverse=true -statusline_error.fg=red -statusline_error.reverse=true -statusline_warning.fg=yellow -statusline_warning.reverse=true +#statusline*.default=true +#statusline_default.reverse=true +#statusline_error.fg=red +#statusline_error.reverse=true +#statusline_warning.fg=yellow +#statusline_warning.reverse=true -msglist_unread.bold=true -msglist_deleted.fg=gray -msglist_result.fg=green -msglist_pill.reverse=true +#msglist_unread.bold=true +#msglist_deleted.fg=gray +#msglist_result.fg=green +#msglist_pill.reverse=true -completion_pill.reverse=true +#completion_pill.reverse=true -tab.reverse=true -border.reverse = true +#tab.reverse=true +#border.reverse = true -selector_focused.reverse=true -selector_chooser.bold=true +#selector_focused.reverse=true +#selector_chooser.bold=true #[viewer] #url.underline=true diff --git a/stylesets/dracula b/stylesets/dracula index 9e24f422af93..8b8788e9ce40 100644 --- a/stylesets/dracula +++ b/stylesets/dracula @@ -1,3 +1,6 @@ +*.default=true +*.normal=true + #border.bg=#BD93F9 title.bg=#BD93F9 diff --git a/stylesets/nord b/stylesets/nord index f099a43ffa3b..e9c7e853aa9f 100644 --- a/stylesets/nord +++ b/stylesets/nord @@ -3,6 +3,7 @@ # *.default=true +*.normal=true title.reverse=true header.bold=true diff --git a/stylesets/pink b/stylesets/pink index 1f73d0f78700..9fd8c213feb2 100644 --- a/stylesets/pink +++ b/stylesets/pink @@ -1,6 +1,7 @@ # vim: ft=dosini -#de4e85 +*.default=true +*.normal=true border.bg=#de4e85 title.bg=#de4e85 diff --git a/stylesets/solarized b/stylesets/solarized index 026c3755d162..dcd8606f7ce2 100644 --- a/stylesets/solarized +++ b/stylesets/solarized @@ -3,6 +3,7 @@ # *.default=true +*.normal=true *error.bold=true border.reverse=true completion_pill.reverse=true -- 2.41.0
Strip trailing comments after attribute values in stylesets. Update the test styleset to check it works. Signed-off-by: Robin Jarry <robin@jarry.cc> --- filters/colorize.c | 2 +- filters/test.sh | 8 ++++---- filters/vectors/colorize-patch.expected | 18 +++++++++--------- filters/vectors/colorize-quotes.expected | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/filters/colorize.c b/filters/colorize.c index d991cb7214b6..03f0fc75c6a2 100644 --- a/filters/colorize.c +++ b/filters/colorize.c @@ -337,7 +337,7 @@ static struct {const char *n; struct style *s;} ini_objects[] = { }; /* object attribute value */ -#define STYLE_LINE_FORMAT "%127[0-9A-Za-z_-].%127[0-9a-zA-Z_-] = %127s" +#define STYLE_LINE_FORMAT "%127[0-9A-Za-z_-].%127[0-9a-zA-Z_-] = %127[#a-zA-Z0-9]s" static int parse_styleset(void) { diff --git a/filters/test.sh b/filters/test.sh index c0d9e6cdff53..16d1438c6c98 100755 --- a/filters/test.sh +++ b/filters/test.sh @@ -12,15 +12,15 @@ cat >$style <<EOF url.fg = red [viewer] -url.underline = true -header.bold= true +url.underline = true # cxwlkj +header.bold= true # comment signature.dim=true diff_meta.bold =true diff_chunk.dim= true invalid . xxx = lkjfdslkjfdsqqqqqlkjdsq -diff_add.fg=2 +diff_add.fg= #00ff00 # comment # comment -diff_del.fg= 1 +diff_del.fg= 1 # comment2 quote_*.fg =6 quote_*.dim=true quote_1.dim=false diff --git a/filters/vectors/colorize-patch.expected b/filters/vectors/colorize-patch.expected index dd04c5b7d0bf..fe9209903223 100644 --- a/filters/vectors/colorize-patch.expected +++ b/filters/vectors/colorize-patch.expected @@ -24,12 +24,12 @@ According to scdoc(5), numbered lists start with a period. [31m-4. *msglist_flagged*[0m [31m-5. *msglist_deleted*[0m [31m-6. *msglist_marked*[0m -[32m+. *msglist_default*[0m -[32m+. *msglist_unread*[0m -[32m+. *msglist_read*[0m -[32m+. *msglist_flagged*[0m -[32m+. *msglist_deleted*[0m -[32m+. *msglist_marked*[0m +[38;2;0;255;0m+. *msglist_default*[0m +[38;2;0;255;0m+. *msglist_unread*[0m +[38;2;0;255;0m+. *msglist_read*[0m +[38;2;0;255;0m+. *msglist_flagged*[0m +[38;2;0;255;0m+. *msglist_deleted*[0m +[38;2;0;255;0m+. *msglist_marked*[0m So, the marked style will override all other msglist styles. @@ -38,9 +38,9 @@ According to scdoc(5), numbered lists start with a period. [31m-1. *dirlist_default*[0m [31m-2. *dirlist_unread*[0m [31m-3. *dirlist_recent*[0m -[32m+. *dirlist_default*[0m -[32m+. *dirlist_unread*[0m -[32m+. *dirlist_recent*[0m +[38;2;0;255;0m+. *dirlist_default*[0m +[38;2;0;255;0m+. *dirlist_unread*[0m +[38;2;0;255;0m+. *dirlist_recent*[0m ## COLORS diff --git a/filters/vectors/colorize-quotes.expected b/filters/vectors/colorize-quotes.expected index 4e1e643c22c6..a5d13e008c51 100644 --- a/filters/vectors/colorize-quotes.expected +++ b/filters/vectors/colorize-quotes.expected @@ -37,12 +37,12 @@ facilisi et pri http:// or https://! [0m> [1mdiff --git a/foo b/foo[0m [0m> [1mindex 4b0fe8dded3a..518b67134639 100644[0m [0m> [0m[31m--- a/foo[0m -[0m> [0m[32m+++ b/foo[0m +[0m> [0m[38;2;0;255;0m+++ b/foo[0m [0m> @@ -131,6 +131,83 @@ func pouet() int {[0m [0m> err := doThis()[0m [0m> [0m [0m> [0m[31m- err2 := doThat()[0m -[0m> [0m[32m+ err2 := notDoThat()[0m +[0m> [0m[38;2;0;255;0m+ err2 := notDoThat()[0m [0m> [0m [0m> if err != nil || err2 != nil {[0m -- 2.41.0
Allow styling the part selector mime type and (if any) attachment filename. Remove custom alignment code since now both can be differentiated easily with colors and/or attributes. Signed-off-by: Robin Jarry <robin@jarry.cc> --- config/style.go | 19 +++++++++++ doc/aerc-stylesets.7.scd | 9 ++++++ stylesets/blue | 6 ++++ stylesets/default | 3 ++ stylesets/dracula | 6 ++++ stylesets/nord | 5 +++ stylesets/pink | 6 ++++ stylesets/solarized | 2 ++ widgets/msgviewer.go | 52 +++++++++++------------------- widgets/msgviewer_test.go | 68 --------------------------------------- 10 files changed, 75 insertions(+), 101 deletions(-) delete mode 100644 widgets/msgviewer_test.go diff --git a/config/style.go b/config/style.go index f50126bdb361..3f117fc067d4 100644 --- a/config/style.go +++ b/config/style.go @@ -46,6 +46,10 @@ const ( STYLE_DIRLIST_UNREAD STYLE_DIRLIST_RECENT + STYLE_PART_SWITCHER + STYLE_PART_FILENAME + STYLE_PART_MIMETYPE + STYLE_COMPLETION_DEFAULT STYLE_COMPLETION_GUTTER STYLE_COMPLETION_PILL @@ -91,6 +95,10 @@ var StyleNames = map[string]StyleObject{ "dirlist_unread": STYLE_DIRLIST_UNREAD, "dirlist_recent": STYLE_DIRLIST_RECENT, + "part_switcher": STYLE_PART_SWITCHER, + "part_filename": STYLE_PART_FILENAME, + "part_mimetype": STYLE_PART_MIMETYPE, + "completion_default": STYLE_COMPLETION_DEFAULT, "completion_gutter": STYLE_COMPLETION_GUTTER, "completion_pill": STYLE_COMPLETION_PILL, @@ -330,6 +338,9 @@ func NewStyleSet() StyleSet { case STYLE_MSGLIST_PILL: // msglist_pill.reverse=true conf.base.Reverse = true + case STYLE_PART_MIMETYPE: + // part_mimetype.dim=true + conf.base.Dim = true case STYLE_COMPLETION_PILL: // completion_pill.reverse=true conf.base.Reverse = true @@ -351,6 +362,14 @@ func NewStyleSet() StyleSet { selected := *conf // *.selected.reverse=toggle selected.base.Reverse = !conf.base.Reverse + switch so { + case STYLE_PART_MIMETYPE: + // part_mimetype.selected.dim=false + selected.base.Dim = false + case STYLE_PART_FILENAME: + // part_filename.selected.bold=true + selected.base.Bold = true + } ss.selected[so] = &selected } return ss diff --git a/doc/aerc-stylesets.7.scd b/doc/aerc-stylesets.7.scd index 4f43859b3d2d..698ad6716abf 100644 --- a/doc/aerc-stylesets.7.scd +++ b/doc/aerc-stylesets.7.scd @@ -119,6 +119,12 @@ styling. : The style used for directories with unread messages | *dirlist_recent* : The style used for directories with recent messages +| *part_switcher* +: Background for the part switcher in the message viewer. +| *part_filename* +: Attachment file name in the part switcher. +| *part_mimetype* +: Attachment/part MIME type in the part switcher. | *completion_default* : The default style for the completion engine. | *completion_gutter* @@ -356,6 +362,9 @@ msglist_unread.bold=true msglist_deleted.fg=gray msglist_result.fg=green msglist_pill.reverse=true +part_mimetype.dim=true +part_mimetype.selected.dim=false +part_filename.selected.bold=true completion_pill.reverse=true tab.reverse=true border.reverse = true diff --git a/stylesets/blue b/stylesets/blue index 46e04b4604ff..4ffcbc876bf6 100644 --- a/stylesets/blue +++ b/stylesets/blue @@ -37,6 +37,12 @@ msglist_marked.bg=#005f87 msglist_marked.selected.bg=#005fff msglist_pill.reverse=true +part_*.fg=#ffffff +part_mimetype.fg=#005f87 +part_*.selected.fg=#ffffff +part_*.selected.bg=#005f87 +part_filename.selected.bold=true + completion_pill.reverse=true selector_focused.bold=true selector_focused.bg=#005f87 diff --git a/stylesets/default b/stylesets/default index c0d6f90919d1..74bbe97a068c 100644 --- a/stylesets/default +++ b/stylesets/default @@ -32,6 +32,9 @@ #msglist_result.fg=green #msglist_pill.reverse=true +#part_mimetype.dim=true +#part_mimetype.selected.dim=false +#part_filename.selected.bold=true #completion_pill.reverse=true #tab.reverse=true diff --git a/stylesets/dracula b/stylesets/dracula index 8b8788e9ce40..73623547d7ad 100644 --- a/stylesets/dracula +++ b/stylesets/dracula @@ -37,6 +37,12 @@ msglist_marked.bg=#BD93F9 msglist_marked.selected.bg=#9956f5 msglist_pill.reverse=true +part_*.fg=#ffffff +part_mimetype.fg=#44475A +part_*.selected.fg=#ffffff +part_*.selected.bg=#44475A +part_filename.selected.bold=true + completion_pill.reverse=false selector_focused.bold=false selector_focused.bg=#44475A diff --git a/stylesets/nord b/stylesets/nord index e9c7e853aa9f..a1fdf882e2d1 100644 --- a/stylesets/nord +++ b/stylesets/nord @@ -48,6 +48,11 @@ tab.selected.fg=#2c3441 dirlist_unread.fg=#64A6B3 dirlist_recent.fg=#64A6B3 +part_*.fg=#ffffff +part_mimetype.fg=#394353 +part_*.selected.fg=#ffffff +part_filename.selected.bold=true + [viewer] url.underline=true header.bold=true diff --git a/stylesets/pink b/stylesets/pink index 9fd8c213feb2..deaae5ac7079 100644 --- a/stylesets/pink +++ b/stylesets/pink @@ -37,6 +37,12 @@ msglist_marked.bg=#de4e85 msglist_marked.selected.bg=#c93687 msglist_pill.reverse=true +part_*.fg=#ffffff +part_mimetype.fg=#de4e85 +part_*.selected.fg=#ffffff +part_*.selected.bg=#de4e85 +part_filename.selected.bold=true + completion_pill.reverse=true selector_focused.bold=true selector_focused.bg=#de4e85 diff --git a/stylesets/solarized b/stylesets/solarized index dcd8606f7ce2..9874e2d8b098 100644 --- a/stylesets/solarized +++ b/stylesets/solarized @@ -33,6 +33,8 @@ tab.bg=#eee8d5 tab.fg=#586e75 tab.selected.bg=#b58900 tab.selected.fg=#002b36 +part_mimetype.fg=#b58900 +part_filename.selected.bold=true [viewer] diff_add.fg=#859900 # green diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go index c94d57a3f498..41cb639e34b6 100644 --- a/widgets/msgviewer.go +++ b/widgets/msgviewer.go @@ -422,18 +422,32 @@ func (ps *PartSwitcher) Draw(ctx *ui.Context) { ps.parts[ps.selected].Draw(ctx) return } + + var styleSwitcher, styleFile, styleMime tcell.Style + // TODO: cap height and add scrolling for messages with many parts 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) + styleSwitcher = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_SWITCHER) + styleFile = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_FILENAME) + styleMime = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_MIMETYPE) + } else { + styleSwitcher = ps.mv.uiConfig.GetStyle(config.STYLE_PART_SWITCHER) + styleFile = ps.mv.uiConfig.GetStyle(config.STYLE_PART_FILENAME) + styleMime = ps.mv.uiConfig.GetStyle(config.STYLE_PART_MIMETYPE) } - ctx.Fill(0, y+i, ctx.Width(), 1, ' ', style) + ctx.Fill(0, y+i, ctx.Width(), 1, ' ', styleSwitcher) left := len(part.index) * 2 - name := formatMessagePart(part.part.FullMIMEType(), part.part.FileName(), ctx.Width()-left) - ctx.Printf(left, y+i, style, "%s", name) + if part.part.FileName() != "" { + name := runewidth.Truncate(part.part.FileName(), + ctx.Width()-left-1, "…") + left += ctx.Printf(left, y+i, styleFile, "%s ", name) + } + t := "(" + part.part.FullMIMEType() + ")" + t = runewidth.Truncate(t, ctx.Width()-left, "…") + ctx.Printf(left, y+i, styleMime, "%s", t) } ps.parts[ps.selected].Draw(ctx.Subcontext( 0, 0, ctx.Width(), ctx.Height()-height)) @@ -500,34 +514,6 @@ func (ps *PartSwitcher) Cleanup() { } } -func formatMessagePart(mime, filename string, width int) string { - lname := runewidth.StringWidth(filename) - lmime := runewidth.StringWidth(mime) - - switch { - case width <= 0: - return "" - - case filename == "": - return runewidth.Truncate(mime, width, "…") - - case lname+lmime+3 <= width: - // simple scenario - everything fits - return fmt.Sprintf("%s (%s)", - runewidth.FillRight(filename, width-lmime-3), mime) - - case lname+3 < width: - // file name fits + we have space for parentheses and at least - // one symbol of mime - return fmt.Sprintf("%s (%s)", filename, - runewidth.Truncate(mime, width-lname-3, "…")) - - default: - // ok, we don't have space even for the file name - return runewidth.Truncate(filename, width, "…") - } -} - func (mv *MessageViewer) Event(event tcell.Event) bool { return mv.switcher.Event(event) } diff --git a/widgets/msgviewer_test.go b/widgets/msgviewer_test.go deleted file mode 100644 index f6d01edbdd09..000000000000 --- a/widgets/msgviewer_test.go @@ -1,68 +0,0 @@ -package widgets - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFormatMessageNoFilename(t *testing.T) { - assert.Equal(t, "mime/type", formatMessagePart("mime/type", "", 24)) - assert.Equal(t, "m/type", formatMessagePart("m/type", "", 24)) - assert.Equal(t, "2", formatMessagePart("2", "", 24)) - assert.Equal(t, "2", formatMessagePart("2", "", 20)) -} - -func TestFormatMessageNoFilenameNotEnoguhSpace(t *testing.T) { - assert.Equal(t, "mime/type", formatMessagePart("mime/type", "", 24)) - assert.Equal(t, "mime/type", formatMessagePart("mime/type", "", 9)) - assert.Equal(t, "mime/ty…", formatMessagePart("mime/type", "", 8)) - assert.Equal(t, "mime/…", formatMessagePart("mime/type", "", 6)) - assert.Equal(t, "m…", formatMessagePart("mime/type", "", 2)) - assert.Equal(t, "…", formatMessagePart("mime/type", "", 1)) - - assert.Equal(t, "", formatMessagePart("mime/type", "", 0)) - assert.Equal(t, "", formatMessagePart("mime/type", "", -1)) - assert.Equal(t, "", formatMessagePart("mime/type", "", -10)) -} - -func TestFormatMessagePartSimpleCases(t *testing.T) { - assert.Equal(t, "filename.doc (mime/type)", formatMessagePart("mime/type", "filename.doc", 24)) - assert.Equal(t, "имяфайла.док (mime/type)", formatMessagePart("mime/type", "имяфайла.док", 24)) - assert.Equal(t, "file.doc (m/type)", formatMessagePart("m/type", "file.doc", 24)) - assert.Equal(t, "1 (2)", formatMessagePart("2", "1", 24)) - assert.Equal(t, "1 (2)", formatMessagePart("2", "1", 20)) - assert.Equal(t, "1 (2)", formatMessagePart("2", "1", 5)) -} - -func TestFormatMessagePartNotEnoughSpaceForMime(t *testing.T) { - assert.Equal(t, "filename.doc (mime/type)", formatMessagePart("mime/type", "filename.doc", 30)) - assert.Equal(t, "filename.doc (mime/type)", formatMessagePart("mime/type", "filename.doc", 25)) - assert.Equal(t, "filename.doc (mime/type)", formatMessagePart("mime/type", "filename.doc", 24)) - assert.Equal(t, "filename.doc (mime/ty…)", formatMessagePart("mime/type", "filename.doc", 23)) - assert.Equal(t, "имяфайла.док (mime/ty…)", formatMessagePart("mime/type", "имяфайла.док", 23)) - assert.Equal(t, "filename.doc (m…)", formatMessagePart("mime/type", "filename.doc", 17)) - assert.Equal(t, "filename.doc (…)", formatMessagePart("mime/type", "filename.doc", 16)) - assert.Equal(t, "имяфайла.док (…)", formatMessagePart("mime/type", "имяфайла.док", 16)) - assert.Equal(t, "filename.doc", formatMessagePart("mime/type", "filename.doc", 15)) - assert.Equal(t, "filename.doc", formatMessagePart("mime/type", "filename.doc", 14)) - assert.Equal(t, "filename.doc", formatMessagePart("mime/type", "filename.doc", 13)) - assert.Equal(t, "filename.doc", formatMessagePart("mime/type", "filename.doc", 12)) - assert.Equal(t, "имяфайла.док", formatMessagePart("mime/type", "имяфайла.док", 12)) -} - -func TestFormatMessagePartNotEnoughSpaceForFilename(t *testing.T) { - assert.Equal(t, "filename.d…", formatMessagePart("mime/type", "filename.doc", 11)) - assert.Equal(t, "filename…", formatMessagePart("mime/type", "filename.doc", 9)) - assert.Equal(t, "f…", formatMessagePart("mime/type", "filename.doc", 2)) - assert.Equal(t, "…", formatMessagePart("mime/type", "filename.doc", 1)) - - assert.Equal(t, "", formatMessagePart("mime/type", "filename.doc", 0)) - assert.Equal(t, "", formatMessagePart("mime/type", "filename.doc", -1)) - assert.Equal(t, "", formatMessagePart("mime/type", "filename.doc", -10)) - - assert.Equal(t, "имяфайла.д…", formatMessagePart("mime/type", "имяфайла.док", 11)) - assert.Equal(t, "имяфайла…", formatMessagePart("mime/type", "имяфайла.док", 9)) - assert.Equal(t, "и…", formatMessagePart("mime/type", "имяфайла.док", 2)) - assert.Equal(t, "…", formatMessagePart("mime/type", "имяфайла.док", 1)) -} -- 2.41.0
builds.sr.ht <builds@sr.ht>aerc/patches: SUCCESS in 5m8s [Allow styling part selector MIME and filename][0] from [Robin Jarry][1] [0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/44854 [1]: mailto:robin@jarry.cc ✓ #1059559 SUCCESS aerc/patches/openbsd.yml https://builds.sr.ht/~rjarry/job/1059559 ✓ #1059558 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1059558
Beautiful! Tested-By: inwit <inwit@sindominio.net>