Repository navigation
A pasted list of addresses becomes one chip per address - #89
Merged
Merged
Conversation
The address parser had one model: cut on `,`, `;` and new lines, then
read each entry as `Name <address>` or a bare address. A probe test
against it showed what that does to text people actually paste:
"a@x.fr b@y.fr" -> nothing (one entry, two @)
"a@x.fr<TAB>b@y.fr" -> nothing
"Jean Dupont <jd@x.fr> jo@jo.fr" -> nothing (fails ^(.*?)<([^>]+)>$)
"jo@jo.fr Jean Dupont <jd@x.fr>" -> one recipient, jd@x.fr, named
"jo@jo.fr Jean Dupont"
"mailto:jo@jo.fr" -> the address "mailto:jo@jo.fr"
"anna lists@example.org" -> one address with a space in it
Cutting on separators cannot be fixed by adding a space to the list:
a space must split `a@x.fr b@y.fr` and must not split `Jean Dupont`.
So `recipientPieces()` picks each recipient out instead, with the
web composer's own pattern (pl_mail#380):
(?:"[^"]*"|[^<>"@;,\r\n])*<[^<>]*>|[^\s<>;,"]+
A recipient is a name followed by `<address>`, or a run with no space
in it. A name may hold spaces, and commas inside quotes, but no `@`
outside quotes. That last rule is what keeps the address in front of a
spaced name from becoming part of the name. Each piece keeps its text
when it is not an address, so the field can hand it back rather than
drop it (next commit).
One validator for every entry, `asRecipient()`, used by both paths:
`mailto:` in front is dropped, and an address with whitespace in it is
refused. Deliberately no dot required in the domain, unlike the web's
check: plMail is self-hosted and `anna@nas` is a real address on a home
network. The server is the one that rejects what is wrong.
`parseAddresses()`, which reads share intents and mailto: links, keeps
cutting on `,`, `;` and new lines only. Those lists are written by
programs, one entry per comma, and a space inside an entry means the
entry is broken: splitting `anna lists@example.org` would write to
lists@example.org, a stranger. Now it refuses it, which is what the
comment in Mailto.kt already claimed happened. Mailto's own splitting
and decoding are untouched, and its 18 tests pass unchanged.
Three comments said the share path used "the same parser" as the field
for pasted text. It now shares the validator, not the splitting, and
they say so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CFCshXUp57k1yHeHy68JXy
Counterpart to pl_mail#379 / #380 on the web. What the field did with a paste: it committed only when the new text *ended* in `,`, `;` or a space. A list copied out of another client rarely ends in a separator, so it sat in the line as text until Enter or until focus left, and then went through the old parser (previous commit) that dropped most of it without a word. `recipientEdit()` now decides what a change to the line means, as a pure function so the JVM suite can hold it: - A typed character commits only when it ends a recipient, a separator or whitespace. Anything else would chip `jo@x` while the user is still typing `jo@x.fr`, because `jo@x` is already an address. - A paste commits at once. A text field reports values, not paste events, so a paste is "more than one character arrived at once". Deleting never commits. - An unclosed `<` or quote is somebody typing `Jean <jd@x.fr` by hand, and the space in it must not cut it into pieces. - Text with no address in it is never a commit: `Jean Dupont` pasted is a contact to look up. A single plain address pasted alone also stays text, as before, so suggestions still open on it. That last rule also fixes typing a two-word name. The old onValueChange handed "Jean " to commit(), which found no address and returned without updating the field: the space was swallowed and "Jean Dupont" could not be typed, let alone searched. What is not an address stays in the line, joined with "; " as on the web, and is reported. The rest of the list is still added, de-duplicated without regard to case against the chips already there and within the paste. Enter on text with no address reports it too. Leaving the line with a half-typed name does not: that is an abandoned search, not a mistake. The report is a snackbar through ComposeError, not a line under the field. Every composer error already goes that way, the text itself stays visible in the field for correcting, and the header is kept to one line per address field on purpose; an error row under To, Cc or Bcc would be the only one of its kind. The message names the first piece, as the web does: "“bob” is not an email address. Correct it in the field, or remove it." New string in values/ and values-de/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CFCshXUp57k1yHeHy68JXy
`Jane Doe (jane@doe.fr)` and `jo@x.fr.` at the end of a sentence each reached the validator as one run with no space in it, and became chips for "(jane@doe.fr)" and "jo@x.fr." that failed only at submission. Brackets, quotes and the other characters an unquoted address cannot hold are now refused, as is a dot at either end of either half or two in a row. Refused pieces stay in the field and are reported, as any other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXqu9W8fGcoAz9KCdCHwEG
…unts three languages Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXqu9W8fGcoAz9KCdCHwEG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXqu9W8fGcoAz9KCdCHwEG
5 of 7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #82.
#83 by @jo2904, with the review fixes on top, so it can merge after #75.
What changes
asRecipient).Jane Doe (jane@doe.fr)andjo@x.fr.at the end of a sentence used to become chips for(jane@doe.fr)andjo@x.fr., which failed only at submission. Brackets, quotes and the other characters an unquoted address cannot hold are now refused, as is a leading, trailing or doubled dot in either half. The refused pieces stay in the field and are reported. Two new cases inComposeInputTest.compose_error_not_an_address, now that French translation #75 is in. Without it, lint'sMissingTranslationfails.How it was checked
buildis the check. Key and placeholder coverage of everyvalues-fr/file againstvalues/was checked with a script.Generated by Claude Code