codemp/
lib.rs

1//! # Code MultiPlexer - cooperative development
2//!
3//! `codemp` is an async client library to create cooperation tools for any text editor.
4//!
5//! It is built as a batteries-included client library managing an authenticated user, multiple
6//! workspaces each containing any number of buffers.
7//!
8//! The [`Client`] is completely managed by the library itself, making its use simple across async
9//! contexts and FFI boundaries. All memory is managed by the library itself, which gives out always
10//! atomic reference-counted pointers to internally mutable objects. Asynchronous actions are
11//! abstracted away by the [`api::Controller`], providing an unopinionated approach with both
12//! callback-based and blocking-based APIs.
13//!
14//! The library also provides ready-to-use bindings in a growing number of other programming languages,
15//! to support a potentially infinite number of editors.
16//!
17//! # Overview
18//! The main entrypoint is [`Client::connect`], which establishes an authenticated connection with
19//! a supported remote server and returns a [`Client`] handle to interact with it.
20//!
21//! ```no_run
22//! # async {
23//! let client = codemp::Client::connect(
24//!   codemp::api::Config::new(
25//!     "mail@example.net",
26//!     "dont-use-this-password"
27//!   )
28//! )
29//!   .await
30//!   .expect("failed to connect!");
31//! # };
32//! ```
33//!
34//! A [`Client`] can acquire a [`Workspace`] handle by joining an existing one it can access with
35//! [`Client::attach_workspace`] or create a new one with [`Client::create_workspace`].
36//!
37//! ```no_run
38//! # async {
39//! #  let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
40//! client.create_workspace("my-workspace").await.expect("failed to create workspace!");
41//! let workspace = client.attach_workspace("my-workspace").await.expect("failed to attach!");
42//! # };
43//! ```
44//!
45//! A [`Workspace`] handle can be used to acquire a [`cursor::Controller`] to track remote [`api::Cursor`]s
46//! and one or more [`buffer::Controller`] to send and receive [`api::TextChange`]s.
47//!
48//! ```no_run
49//! # async {
50//! #  let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
51//! # client.create_workspace("").await.unwrap();
52//! # let workspace = client.attach_workspace("").await.unwrap();
53//! use codemp::api::controller::{AsyncSender, AsyncReceiver}; // needed to access trait methods
54//! let cursor = workspace.cursor();
55//! let event = cursor.recv().await.expect("disconnected while waiting for event!");
56//! println!("user {} moved on buffer {}", event.user, event.sel.buffer);
57//! # };
58//! ```
59//!
60//! Internally, [`buffer::Controller`]s store the buffer state as a [diamond_types] CRDT, guaranteeing
61//! eventual consistency. Each [`api::TextChange`] is translated in a network counterpart that is
62//! guaranteed to converge.
63//!
64//! ```no_run
65//! # async {
66//! #  let client = codemp::Client::connect(codemp::api::Config::new("", "")).await.unwrap();
67//! # client.create_workspace("").await.unwrap();
68//! # let workspace = client.attach_workspace("").await.unwrap();
69//! # use codemp::api::controller::{AsyncSender, AsyncReceiver};
70//! let buffer = workspace.attach_buffer("/some/file.txt").await.expect("failed to attach");
71//! buffer.content(); // force-sync
72//! if let Some(mut update) = buffer.try_recv().await.unwrap() {
73//!   println!(
74//!     "content: {}, span: {}-{}",
75//!     update.change.content, update.change.start_idx, update.change.end_idx
76//!   );
77//!   buffer.ack(update.version);
78//! } // if None, no changes are currently available
79//! # };
80//! ```
81//!
82//! ## FFI
83//! As mentioned, we provide bindings in various programming languages. To obtain them, you can
84//! compile with the appropriate feature flag. Currently, the following are supported:
85//! * `lua`
86//! * `javascript`
87//! * `java` (requires additional build steps to be usable)
88//! * `python`
89//!
90//! For some of these, ready-to-use packages are available in various registries:
91//! * [npm (javascript)](https://www.npmjs.com/package/codemp)
92//! * [PyPI (python)](https://pypi.org/project/codemp)
93//! * [Maven Central (java)](https://central.sonatype.com/artifact/mp.code/codemp)
94//! * [LuaRocks (lua)](https://luarocks.org/modules/alemi/codemp)
95//!
96#![doc(html_logo_url = "https://code.mp/static/logo-round.png")]
97#![doc(html_favicon_url = "https://code.mp/static/favicon.ico")]
98
99/// core structs and traits
100pub mod api;
101
102/// cursor related types and controller
103pub mod cursor;
104
105/// buffer related types and controller
106pub mod buffer;
107
108/// workspace handle and operations
109pub mod workspace;
110pub use workspace::Workspace;
111
112/// client handle, containing all of the above
113pub mod client;
114pub use client::Client;
115
116/// crate error types
117pub mod errors;
118
119/// all-in-one imports : `use codemp::prelude::*;`
120pub mod prelude;
121
122/// common utils used in this library and re-exposed
123pub mod ext;
124
125/// language-specific ffi "glue"
126pub mod ffi;
127
128#[cfg(any(feature = "test-e2e", test))]
129pub mod tests;
130
131/// internal network services and interceptors
132pub(crate) mod network;
133
134/// Get the current version of the client
135pub fn version() -> &'static str {
136	env!("CARGO_PKG_VERSION")
137}