mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
when making a message preview, also recognize []-enclosed "horizontal ellipsis" unicode character as a snip
This commit is contained in:
parent
fc7b0cc71e
commit
4a4ccb83a3
2 changed files with 39 additions and 6 deletions
|
@ -45,7 +45,7 @@ func formatFirstLine(r io.Reader) (string, error) {
|
||||||
ensureLines()
|
ensureLines()
|
||||||
|
|
||||||
isSnipped := func(s string) bool {
|
isSnipped := func(s string) bool {
|
||||||
return s == "[...]" || s == "..."
|
return s == "[...]" || s == "[…]" || s == "..."
|
||||||
}
|
}
|
||||||
|
|
||||||
nextLineQuoted := func(i int) bool {
|
nextLineQuoted := func(i int) bool {
|
||||||
|
@ -55,7 +55,8 @@ func formatFirstLine(r io.Reader) (string, error) {
|
||||||
return i+1 < len(lines) && (strings.HasPrefix(lines[i+1], ">") || isSnipped(lines[i+1]))
|
return i+1 < len(lines) && (strings.HasPrefix(lines[i+1], ">") || isSnipped(lines[i+1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// remainder is signature if we see a line with only and minimum 2 dashes, and there are no more empty lines, and there aren't more than 5 lines left
|
// Remainder is signature if we see a line with only and minimum 2 dashes, and
|
||||||
|
// there are no more empty lines, and there aren't more than 5 lines left.
|
||||||
isSignature := func() bool {
|
isSignature := func() bool {
|
||||||
if len(lines) == 0 || !strings.HasPrefix(lines[0], "--") || strings.Trim(strings.TrimSpace(lines[0]), "-") != "" {
|
if len(lines) == 0 || !strings.HasPrefix(lines[0], "--") || strings.Trim(strings.TrimSpace(lines[0]), "-") != "" {
|
||||||
return false
|
return false
|
||||||
|
@ -77,6 +78,10 @@ func formatFirstLine(r io.Reader) (string, error) {
|
||||||
|
|
||||||
result := ""
|
result := ""
|
||||||
|
|
||||||
|
resultSnipped := func() bool {
|
||||||
|
return strings.HasSuffix(result, "[...]\n") || strings.HasSuffix(result, "[…]")
|
||||||
|
}
|
||||||
|
|
||||||
// Quick check for initial wrapped "On ... wrote:" line.
|
// Quick check for initial wrapped "On ... wrote:" line.
|
||||||
if len(lines) > 3 && strings.HasPrefix(lines[0], "On ") && !strings.HasSuffix(lines[0], "wrote:") && strings.HasSuffix(lines[1], ":") && nextLineQuoted(1) {
|
if len(lines) > 3 && strings.HasPrefix(lines[0], "On ") && !strings.HasSuffix(lines[0], "wrote:") && strings.HasSuffix(lines[1], ":") && nextLineQuoted(1) {
|
||||||
result = "[...]\n"
|
result = "[...]\n"
|
||||||
|
@ -87,7 +92,7 @@ func formatFirstLine(r io.Reader) (string, error) {
|
||||||
for ; len(lines) > 0 && !isSignature(); ensureLines() {
|
for ; len(lines) > 0 && !isSignature(); ensureLines() {
|
||||||
line := lines[0]
|
line := lines[0]
|
||||||
if strings.HasPrefix(line, ">") {
|
if strings.HasPrefix(line, ">") {
|
||||||
if !strings.HasSuffix(result, "[...]\n") {
|
if !resultSnipped() {
|
||||||
result += "[...]\n"
|
result += "[...]\n"
|
||||||
}
|
}
|
||||||
lines = lines[1:]
|
lines = lines[1:]
|
||||||
|
@ -101,14 +106,14 @@ func formatFirstLine(r io.Reader) (string, error) {
|
||||||
// line, with an optional empty line in between. If we don't have any text yet, we
|
// line, with an optional empty line in between. If we don't have any text yet, we
|
||||||
// don't require the digits.
|
// don't require the digits.
|
||||||
if strings.HasSuffix(line, ":") && (strings.ContainsAny(line, "0123456789") || result == "") && nextLineQuoted(0) {
|
if strings.HasSuffix(line, ":") && (strings.ContainsAny(line, "0123456789") || result == "") && nextLineQuoted(0) {
|
||||||
if !strings.HasSuffix(result, "[...]\n") {
|
if !resultSnipped() {
|
||||||
result += "[...]\n"
|
result += "[...]\n"
|
||||||
}
|
}
|
||||||
lines = lines[1:]
|
lines = lines[1:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Skip snipping by author.
|
// Skip possibly duplicate snipping by author.
|
||||||
if !(isSnipped(line) && strings.HasSuffix(result, "[...]\n")) {
|
if !isSnipped(line) || !resultSnipped() {
|
||||||
result += line + "\n"
|
result += line + "\n"
|
||||||
}
|
}
|
||||||
lines = lines[1:]
|
lines = lines[1:]
|
||||||
|
|
|
@ -1,11 +1,39 @@
|
||||||
package webmail
|
package webmail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mjl-/mox/dns"
|
"github.com/mjl-/mox/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestFormatFirstLine(t *testing.T) {
|
||||||
|
check := func(body, expLine string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
line, err := formatFirstLine(strings.NewReader(body))
|
||||||
|
tcompare(t, err, nil)
|
||||||
|
if line != expLine {
|
||||||
|
t.Fatalf("got %q, expected %q, for body %q", line, expLine, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check("", "")
|
||||||
|
check("single line", "single line\n")
|
||||||
|
check("single line\n", "single line\n")
|
||||||
|
check("> quoted\n", "[...]\n")
|
||||||
|
check("> quoted\nresponse\n", "[...]\nresponse\n")
|
||||||
|
check("> quoted\n[...]\nresponse after author snip\n", "[...]\nresponse after author snip\n")
|
||||||
|
check("[...]\nresponse after author snip\n", "[...]\nresponse after author snip\n")
|
||||||
|
check("[…]\nresponse after author snip\n", "[…]\nresponse after author snip\n")
|
||||||
|
check(">> quoted0\n> quoted1\n>quoted2\n[...]\nresponse after author snip\n", "[...]\nresponse after author snip\n")
|
||||||
|
check(">quoted\n\n>quoted\ncoalesce line-separated quotes\n", "[...]\ncoalesce line-separated quotes\n")
|
||||||
|
check("On <date> <user> wrote:\n> hi\nresponse", "[...]\nresponse\n")
|
||||||
|
check("On <longdate>\n<user> wrote:\n> hi\nresponse", "[...]\nresponse\n")
|
||||||
|
check("> quote\nresponse\n--\nsignature\n", "[...]\nresponse\n")
|
||||||
|
check("> quote\nline1\nline2\nline3\n", "[...]\nline1\nline2\nline3\n")
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseListPostAddress(t *testing.T) {
|
func TestParseListPostAddress(t *testing.T) {
|
||||||
check := func(s string, exp *MessageAddress) {
|
check := func(s string, exp *MessageAddress) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
Loading…
Reference in a new issue