Crate codemp

Source
Expand description

§Code MultiPlexer - cooperative development

codemp is an async client library to create cooperation tools for any text editor.

It is built as a batteries-included client library managing an authenticated user, multiple workspaces each containing any number of buffers.

The Client is completely managed by the library itself, making its use simple across async contexts and FFI boundaries. All memory is managed by the library itself, which gives out always atomic reference-counted pointers to internally mutable objects. Asynchronous actions are abstracted away by the api::Controller, providing an unopinionated approach with both callback-based and blocking-based APIs.

The library also provides ready-to-use bindings in a growing number of other programming languages, to support a potentially infinite number of editors.

§Overview

The main entrypoint is Client::connect, which establishes an authenticated connection with a supported remote server and returns a Client handle to interact with it.

let client = codemp::Client::connect(
  codemp::api::Config::new(
    "mail@example.net",
    "dont-use-this-password"
  )
)
  .await
  .expect("failed to connect!");

A Client can acquire a Workspace handle by joining an existing one it can access with Client::attach_workspace or create a new one with Client::create_workspace.

client.create_workspace("my-workspace").await.expect("failed to create workspace!");
let workspace = client.attach_workspace("my-workspace").await.expect("failed to attach!");

A Workspace handle can be used to acquire a cursor::Controller to track remote api::Cursors and one or more buffer::Controller to send and receive api::TextChanges.

use codemp::api::controller::{AsyncSender, AsyncReceiver}; // needed to access trait methods
let cursor = workspace.cursor();
let event = cursor.recv().await.expect("disconnected while waiting for event!");
println!("user {} moved on buffer {}", event.user, event.sel.buffer);

Internally, buffer::Controllers store the buffer state as a diamond_types CRDT, guaranteeing eventual consistency. Each api::TextChange is translated in a network counterpart that is guaranteed to converge.

let buffer = workspace.attach_buffer("/some/file.txt").await.expect("failed to attach");
buffer.content(); // force-sync
if let Some(mut update) = buffer.try_recv().await.unwrap() {
  println!(
    "content: {}, span: {}-{}",
    update.change.content, update.change.start_idx, update.change.end_idx
  );
  buffer.ack(update.version);
} // if None, no changes are currently available

§FFI

As mentioned, we provide bindings in various programming languages. To obtain them, you can compile with the appropriate feature flag. Currently, the following are supported:

  • lua
  • javascript
  • java (requires additional build steps to be usable)
  • python

For some of these, ready-to-use packages are available in various registries:

Re-exports§

pub use workspace::Workspace;
pub use client::Client;

Modules§

api
core structs and traits
buffer
buffer related types and controller
client
client handle, containing all of the above
cursor
cursor related types and controller
errors
crate error types
ext
common utils used in this library and re-exposed
ffi
language-specific ffi “glue”
prelude
all-in-one imports : use codemp::prelude::*;
workspace
workspace handle and operations

Functions§

version
Get the current version of the client