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§

Modules§

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

Functions§

  • Get the current version of the client