Documentation
¶
Overview ¶
Package collabui holds the go-widgets bindings that need a live github.com/go-crdt/collab session — today CollabText.
They live outside package toolkit for the linker. go-crdt/collab carries its network transports (WebSocket over net/http, gRPC on native targets), and every package a program imports runs its init functions, which the Go linker treats as roots (cmd/link/internal/ld/deadcode.go floods from main.main and each imported package's init task). While CollabText sat in package toolkit, every toolkit program linked net/http, crypto/tls and their init-time self-tests whether or not it ever opened a session. Import collabui only in programs that do.
The CRDT-only bindings that need no session — toolkit.CollabSheet and toolkit.IsoCRDTDocument — stay in package toolkit: go-crdt/crdt links no transport.
Index ¶
Constants ¶
const ( // MetaName is the presence key carrying a participant's display name, shown // as the tag beside its remote caret. MetaName = "name" // MetaColor is the presence key carrying a participant's caret colour, as the // "#rrggbbaa" string [toolkit.Decoration] Color is painted in. MetaColor = "color" )
Presence metadata keys. A participant publishes its display name and caret colour under these keys, and a peer reads them back to paint a toolkit.Decoration. They are this binding's private contract with itself — the awareness core carries the map verbatim and interprets none of it.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CollabText ¶
type CollabText struct {
// Name is this participant's display name, published with every caret move so
// a peer can tag the remote caret. Set it before the first caret move; an
// empty name publishes no name key.
Name string
// Color is this participant's caret colour, published with every caret move.
// Its zero value (A == 0) publishes no colour key, and a peer paints the
// caret in the theme default.
Color toolkit.RGBA
// OnRemoteChange, when set, is called at the end of every remote application —
// a repaint seam for the host, the analogue of [toolkit.CollabSheet.Subscribe]. It
// runs on the UI goroutine, inside the apply closure the host ran.
OnRemoteChange func()
// contains filtered or unexported fields
}
CollabText is the live binding between a toolkit.CodeEditor (or its embedded toolkit.TextView) and one text part of a github.com/go-crdt/collab session: it turns the editor into one replica of a shared document, so any number of peers edit the same buffer at once and each sees the others' carets and selections painted in place. It is the text-editor analogue of toolkit.SyncSpreadsheet over a toolkit.CollabSheet and of an toolkit.IsoDiagram over an toolkit.IsoCRDTDocument — the reusable "CRDT ⇄ editor" glue, with no widget change: the toolkit.CodeEditor edits exactly as before, its edits now flow into the shared document, and a merged remote edit (text or presence) flows back into it.
It adds NO merge logic of its own. The convergence, commutativity, idempotence and associativity are the collab/crdt packages', inherited whole. This type is only the mapping between the editor's MVVM state and the session:
- Local → shared. A user edit ticks the editor's Text() [mvvm.Observable]; the binding diffs the previous buffer against the new one (crdt.ChangesFrom) and replays that one contiguous edit into the text part as rune-offset Insert/Delete. A caret or selection move ticks CursorLine()/CursorCol()/ Selection() and is published as an awareness.Cursor (anchor + head rune offsets) carrying this participant's CollabText.Name and CollabText.Color.
- Shared → local. A pump goroutine wakes on the session's coalesced change signal, loads the part's current text into the editor, and rebuilds the editor's toolkit.TextView Decorations from the session's peers — one Decoration per other participant, its caret and selection mapped from rune offsets to (line, col) and painted in the peer's own colour and name.
Threading model ¶
The editor's MVVM state is not safe for concurrent use — like the rest of the toolkit it must be driven from one goroutine (call it the UI goroutine). The binding owns a pump goroutine that consumes the session's asynchronous change signal, but it NEVER touches editor state from that goroutine. Instead it hands each remote application to the host over CollabText.Updates as a closure the host runs on its own UI goroutine — the same "the host calls back on its own UI thread" contract toolkit.Browser uses, marshalled here through a channel so there is a clean happens-before and no field to race on. A host drains it with
for apply := range ct.Updates() {
apply() // on the UI goroutine — applies remote text + rebuilds decorations
}
The channel closes when the pump stops (a CollabText.Close or the session ending), which ends the range. Local edits, that drain loop and CollabText.Close all run on the one UI goroutine.
CollabText.Close stops the pump, waits for it to exit and unsubscribes from the editor; it must be called on the UI goroutine and is idempotent. Because the pump selects on its stop signal even while offering an update, a host that has stopped draining never wedges Close.
func NewCollabText ¶
func NewCollabText(ed *toolkit.CodeEditor, client *collab.Client, textName string) (*CollabText, error)
NewCollabText binds ed to the text part named textName of client's session and returns the live binding. The part's current text is loaded into the editor at once, and from then on local edits flow into the session and remote edits flow back once the host drains CollabText.Updates. An invalid textName (empty or malformed; see crdt.Part) is returned as an error and nothing is wired.
The returned binding owns a pump goroutine; call CollabText.Close to stop it.
func (*CollabText) Close ¶
func (c *CollabText) Close() error
Close stops the pump goroutine, waits for it to exit, and unsubscribes from the editor. It must be called on the UI goroutine and is idempotent.
func (*CollabText) Updates ¶
func (c *CollabText) Updates() <-chan func()
Updates delivers remote-application closures for the host to run on its UI goroutine; see the threading model on CollabText. The channel closes when the pump stops.