diff options
author | Vitaly Ovchinnikov <v@postbox.nz> | 2023-09-04 18:39:41 +0300 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2023-09-05 20:46:57 +0200 |
commit | 389d89a9362e2e782f17074331bf85bb579d7466 (patch) | |
tree | 94713f6ea625f1b02014516ee8216510cf3b0580 /widgets | |
parent | 39fee6ca17fa0df8ecc25925659c4f9785c769fc (diff) | |
download | aerc-389d89a9362e2e782f17074331bf85bb579d7466.tar.gz |
msgviewer: show attachment file names first if possible
Change the parts switcher so it displays the file names first (if any)
and then the mime types. The mime types are aligned to the right to help
the file names to be more visible. If there is no file name - the mime
type is displayed on the left, as usual.
The idea is that the file name (if present) is more important than the
mime type. Especially when both file names and mime types are long -
this quickly becomes a mess.
If there is no space for both file name and mime, the mime type is
truncated with ellipsis. If there is no space for mime at all - it is
dropped completely. If then there is no space for the file name, it is
also truncated with ellipsis.
Signed-off-by: Vitaly Ovchinnikov <v@postbox.nz>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Inwit <inwit@sindominio.net>
Diffstat (limited to 'widgets')
-rw-r--r-- | widgets/msgviewer.go | 37 | ||||
-rw-r--r-- | widgets/msgviewer_test.go | 68 |
2 files changed, 99 insertions, 6 deletions
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go index 0908417d..c94d57a3 100644 --- a/widgets/msgviewer.go +++ b/widgets/msgviewer.go @@ -431,12 +431,9 @@ func (ps *PartSwitcher) Draw(ctx *ui.Context) { style = ps.mv.uiConfig.GetStyleSelected(config.STYLE_DEFAULT) } ctx.Fill(0, y+i, ctx.Width(), 1, ' ', style) - name := part.part.FullMIMEType() - filename := part.part.FileName() - if filename != "" { - name += fmt.Sprintf(" (%s)", filename) - } - ctx.Printf(len(part.index)*2, y+i, style, "%s", name) + left := len(part.index) * 2 + name := formatMessagePart(part.part.FullMIMEType(), part.part.FileName(), ctx.Width()-left) + ctx.Printf(left, y+i, style, "%s", name) } ps.parts[ps.selected].Draw(ctx.Subcontext( 0, 0, ctx.Width(), ctx.Height()-height)) @@ -503,6 +500,34 @@ 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 new file mode 100644 index 00000000..f6d01edb --- /dev/null +++ b/widgets/msgviewer_test.go @@ -0,0 +1,68 @@ +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)) +} |