aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Ovchinnikov <v@postbox.nz>2023-09-04 18:39:41 +0300
committerRobin Jarry <robin@jarry.cc>2023-09-05 20:46:57 +0200
commit389d89a9362e2e782f17074331bf85bb579d7466 (patch)
tree94713f6ea625f1b02014516ee8216510cf3b0580
parent39fee6ca17fa0df8ecc25925659c4f9785c769fc (diff)
downloadaerc-389d89a9362e2e782f17074331bf85bb579d7466.tar.gz
aerc-389d89a9362e2e782f17074331bf85bb579d7466.zip
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>
-rw-r--r--widgets/msgviewer.go37
-rw-r--r--widgets/msgviewer_test.go68
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))
+}