1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//! Composer drafts, **keyed by the target they were typed for** (§11, §5.3,
//! bl-a69a).
//!
//! One text box that re-labels its verb with the selection is not one draft: a
//! goal typed for a new conversation and a message typed to an agent are
//! different things said to different addressees, and a single buffer carried
//! the first into the second's box — where Enter would have deposited a fresh
//! start's text as a message to an unrelated agent. Every chat app answers this
//! the same way, and so does yog: a draft belongs to its target, switching the
//! selection shows that target's own, and switching back restores what was
//! there.
//!
//! Still RAM until sent (§5.3) — this is the *key*, not persistence. Nothing
//! here reaches disk, and the map dies with the process like the single buffer
//! it replaces. It is the same shape [`StartState::new_ball`] already uses for
//! the ball form's per-project drafts: the context is the key.
//!
//! **Absence is emptiness.** A key with no entry reads as `""` and writing `""`
//! removes the entry, so "no draft" has one representation rather than two, and
//! a send clears exactly its own key by writing the empty string.
use HashMap;
use PathBuf;
/// Which composer a draft belongs to — the target *and* the verb, which is one
/// fact: the composer's verb follows its target (§11).
/// Every in-flight composer draft, one per target (RAM, §5.3).