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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2026 Cyril Jacquet
//! A backend several documents can share.
//!
//! Every [`TextDocument`](crate::TextDocument) built by [`TextDocument::new`](crate::TextDocument::new)
//! owns a whole application context: a store, an undo manager, an event hub, and
//! an OS thread draining that hub. That is right for one document and wrong for
//! a hundred. A host that opens a document per scene of a manuscript pays a
//! hundred threads to display one book, and each thread reserves eight megabytes
//! of address space for a loop that is idle almost all of the time.
//!
//! # What can be shared, and what cannot
//!
//! Not the store, and not the undo stack. Every repository's `snapshot` and
//! `restore` take and put back the **whole** store (see
//! `Transaction::snapshot_store`), so two documents sharing one would undo and
//! roll each other back. Each document keeps its own.
//!
//! The event hub can be shared, and that is where the thread is. One hub means
//! one drain, so a backend holds one [`EventHubClient`] and one thread however
//! many documents are built in it.
//!
//! # Telling one document's events from another's
//!
//! With a shared hub, every document's long-operation subscription sees every
//! document's long-operation events. Each document therefore records the ids of
//! the operations it started and ignores an event carrying any other id. The
//! filter lives in the document, inside the lock the callback already takes, so
//! there is no second structure to keep in step and no second lock to order
//! against the first.
//!
//! # Lifetime
//!
//! The pump stops when the backend drops, not when a document does: a document
//! that shut the hub down on its own way out would stop delivery for every
//! sibling still open. Hold the backend for as long as any document built in it.
use Arc;
use AppContext;
use EventHubClient;
/// A shared document backend: one event hub, one pump thread, one
/// long-operation manager, for any number of documents.
///
/// Cheap to clone (an `Arc`), and every clone names the same backend. Build one
/// per project, or per whatever scope wants its documents to share a thread, and
/// create documents in it with
/// [`TextDocument::new_in`](crate::TextDocument::new_in).