Coder Social home page Coder Social logo

tcr / edit-text Goto Github PK

View Code? Open in Web Editor NEW
233.0 9.0 22.0 25.68 MB

Collaborative rich text editor for the web. Written in Rust + WebAssembly.

Home Page: http://edit.io/

License: MIT License

JavaScript 0.27% Rust 86.27% HTML 0.83% CSS 2.57% TypeScript 9.94% Shell 0.06% Batchfile 0.06%
rust wasm webassembly editor rtf docs

edit-text's Introduction

edit-text's People

Contributors

bors[bot] avatar briankabiro avatar greenkeeper[bot] avatar tcr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

edit-text's Issues

Have mercutio-sync hot-reload from the dist folder unless otherwise specified

Right now, mercutio-sync compiles all support files into its binary when cargo build is run. Another way to do this would be only in release mode are the support files compiled in, and outside release mode it loads on-demand from the frontend/dist/ directory.

This allows x.rs js-watch to be run in parallel without having to restart the server.

Todo

  • Backspace in lists to join bullet groups to match splitting them
  • The monkey test that working
  • Then fixing the phantom empty skip group thing on multi when you start stop monkey
  • Then monkey test that thing
  • Then adding random click back in and debugging it, including using mercutio-replay to do so
  • Then having random click fix more bugs around multiple people using Mercutio
  • Then you have it resilient for launch
  • Add pages?
  • Add warning about this being demo software
  • Write a talk.
  • Test more usability fixes when testing out how to give a demo.
  • Add export
  • Add custom page names
  • Add bottom of page warning
  • Add import(?)
  • Remove carets from terminated clients(?)

Audit use of supports_text()

This is used as a hack to support carets, but shouldn't be used that way (instead, use the actual parents() operators)

Support a flatfile backing store

This would allow you to run edit-text locally (for example) and store .ron files inside of Dropbox or a git repository. Not perfect (will Dropbox automatically try to do conflict resolution on utf-8 text?) but gives an alternative to storing an Sqlite database.

This would require abstracting out the storage component and making sure it works when shared across sync and server threads.

Some notes about fs flushing though: https://news.ycombinator.com/item?id=16573487

Support H4-H6 as well

Since the goal of the editor is to be compatible with Markdown, this means we'll need to support H1-H6 (the editor currently supports H1, H2, and H3).

This should be straightforward, as in just duplicating the code for H1 H2 and H3 that lives in mercutio-client.

Enforce consistent naming: Sync, User, and Frontend

(TODO expand this)

Right now "client" is used to mean many different things, and this becomes confusing for commands etc. It would be good to redo this naming so we have the following:

enum SyncToUserCommand { ... }
enum UserToSyncCommand { ... }
enum UserToFrontendCommand { ... }
enum FrontendToUserCommand { ... }

Also the book should be updated with info on this.

Button header should be sticky

Otherwise when you're scrolling a long document, you have to scroll all the way up in order to change any of the settings.

Start an editor book.

High level concepts (sync server / client server / wasm proxy) about the system and details of how the operational transform mechanism works are solidified enough by now it's worth writing out a guide to them.

Add GraphQL endpoint to Sync

Right now the Sync server (mercutio-server/src/sync.rs) and the file server (mercutio-server/src/bin/mercutio-server.rs) both share access to the database, which can result in spurious "database is locked" errors from SQLite. One solution to this problem is to make Sync have a GraphQL endpoint, and have the file server make modifications through this API.

As a result, we can also support a number of other features that fit an out-of-band request/response model:

  • Downloading the raw Markdown or raw HTML for a file
  • Overwriting a page with new Markdown contents
  • Downloading an archive of all data
  • Searching all documents for a string (full text search)
  • Github or Dropbox login/logout

I played around with Juniper and think it should be a great fit here.

Support selecting spans of text

Initial design: similar to carets, we can add an "anchor" caret at the target of what you're selecting to match the "end" caret that usually appears where you are writing. So both are tracked inline with the document:

This is some text <caret client-id=... />selected from here<anchor-caret client-id=... /> until here.

The selected text would lie between <caret> and <anchor-caret>, and be "selected from here".

  • Server would need to be able to evict abandoned anchor carets wherever it evicts regular carets: when a client disconnects, at the end of each operation checking for a missing client.
  • The client would need to be able to render a span from an anchor to its selection point.
  • The client would need to be able to author operations that operate on the span (delete selection, copy, etc.)

Test Markdown sanitizer thoroughly

Relevant: a development diary about documents and Markdown.

If the Markdown sanitizer can be thoroughly proven to make validatible documents when inputted into edit-text, then we can enable 1) importing Markdown files and 2) possible flatfile storage with Markdown support (like storing directly to Dropbox).

  1. Is there an independent Markdown test suite of documents?
  2. Can this be fed into a test suite for making sure the sanitizer can always produce a valid Mercutio document as an output?

Support option backspace to delete whole words (macOS)

Similar to how option left and right to move the cursor was implemented in 482a678, it'd be awesome to support option backspace to delete whole words quickly (a holdover until actual caret selections are supported and deleting text is made even simpler.)

Support an -r shortcut for --release in ./x.rs

It's a lot of work to type ./x.rs server --client-proxy --release in one window and ./x.rs client-proxy --release in another!

-r would allow this to shorten to ./x.rs server -cr and ./x.rs client-proxy -r.

Because this has to be handled at the x.rs (not the shelled out binary) level, this needs special logic to detect the short argument.

Remove carets from terminated clients

After 30s of inactivity (including a lack of a heartbeat ping), clients should be considered "terminated" and then their caret removed from the server state.

Move oatie/src/schema.rs to mercutio/

One of the oldest sins of the codebase is although it abstracted out the logic for how HTML should be transformed, it can't test itself effectively without a schema. There should be some pragmatic way to move oatie/src/schema.rs to mercutio/src/ so that oatie can be an actually independent library for operational transform logic.

This might require refining the Schema/Track traits and making them more internally consistent.

Cache results of setup_controls so we don't send redundant controls setup to the client

The ClientImpl::setup_controls method in mercutio-client/src/client.rs will send a new "controls" payload to the client with the following info:

  1. Which key combinations the Frontend should listen to
  2. Which buttons the Frontend should display
  3. Which buttons are highlighted (i.e. representing the result of the latest action).

Because we already know the previous ClientCommand::Controls we sent to the client, it would be helpful if we could

  1. Cache the most recently sent ClientCommand::Controls data in pub struct Client, and
  2. Not send a new payload if this structure hasn't changed.

There's a few ways to do it, but the trivial way would be to just track the previously sent information and then compare it with the new packet.

One option here is to extract the "keys" and "buttons" fields of ClientCommand::Controls into a "ControlState" struct, so we don't have to match against the ClientCommand enum to compare these values. Then we can change ClientCommand::Controls to ClientCommand::Controls(ControlState) rather than imbedding the data directly.

No end-to-end test for Mercutio

There's no end-to-end test showing that edit-text can launch successfully and perform live edits in HTML. There should be one that we can gate issues or PRs on, or test locally for radical changes. This is part of a much longer trajectory for how frequently the sandbox should be updated.

The only tests that exist at the moment are for Oatie's transform logic and some Operation APIs.

Refactor the X-Ray feature to be more maintainable

The X-Ray feature is old, from when the frontend was a generic "tree editor" and you could interact with any element directly. Now the text editor is the default, and most of the actions you could perform directly on the X-Ray aren't enabled. But there's a lot of vestigal code here, and even more vestigal Sass.

  • Replace in the SASS file the terms "style-mock" => "edit-text" and "style-block" => "xray", since the "mock" and "block" nomenclature is super old
  • Remove unused xray styles from Sass code
  • Replace mentions of the term "mote" in CSS and JS with "mercutio" (mote being the much earlier prototype for the frontend)

Support text spans (bold, inline, underline, links, etc.)

What if we styled Characters, in addition to having operations on tree structures made from Characters + Groups? Individual characters would be styled, allowing spans to be implemented easily, but also there would be an easy integration point for having text selections work. This also gets us closer to CRDT algorithms which operate on spans and which might play a future role in the editor.

The other option is to do full-fledged span elements which have specialty merging logic. This is similar to styling characters and possibly more generic, but at the cost of preserving more complexity than maybe it's worth. This is how spans were implemented in earlier attempts at Oatie.

Support images

At a minimum, edit-text should support block-level images.

It could work similar to how <hr> was implemented. 9cd29f4 Only caveat being, it needs to support inputting a URL at creation time, which stretches the limits of what the client controlling the button array can support.

This might just require the button_handlers input on the TypeScript side to accept a "prompt: bool" argument.

Monkey fails when editing a document with a unicode character in it.

The πŸ‘Ό emoji was added to the front page, but a multimonkey client soon failed with an AddWithGroup is malformed error. We should be supporting unicode input and transform out of the box. It's possible the DocString abstraction isn't comprehensive enough, or that the JavaScript frontend has issues counting characters (UCS-2 vs UTF-8).

Why isn't mercutio.js not being served with etags?

Something is up with the deployment configuration with the nginx Docker that prevents mercutio.js (the single JS bundle) from being served with e-tags, thus only requiring a 304 response instead of a 2mb bundle download with each page load.

Better method definitions for OT and Schema

At a recent talk I presented a simpler API (for purposes of explanation) and noticed that RtfSchema and TrackType could be unified. With some normalizing, this makes the trait API oatie into the following:

/// impl on the Operation
pub trait OT where Self: Sized {
    type Doc;

    fn apply(&Self::Doc, &Self) -> Self::Doc; // should reverse args?
    fn compose(&Self, &Self) -> Self;
    fn transform<S: Schema>(&Self, &Self) -> (Self, Self);
    fn transform_advance<S: Schema>(a: &Self, b: &Self) -> Self;

    fn empty() -> Self;
    fn compose_iter<'a, I>(iter: I) -> Self where I: Iterator<Item=&'a Self>, Self: 'a;
}

/// impl on an enum of types
pub trait Schema: Copy {
    type Attrs = HashMap<String, String>; // overloadable?

    fn allowed_in_root(&self) -> bool;
    fn contains_text(&self) -> bool;
    fn contains_children(&self) -> Vec<Self>;

    fn validate(&Doc) -> Result<(), Error>;
    fn identify(&Self::Attrs) -> Option<Schema>;
}

enum RtfSchema {
    ListItems,      // bullet
    BlockQuotes,    // blockquote
    Blocks,         // h1, h2, h3, h4, h5, h6, p, pre
    BlockObjects,   // hr
    Inlines,        // span
    InlineObjects,  // caret
}

Support ordered lists

This is slightly different than just duplicating the "bullet" tag to be something new, because it actually should change all adjacent tags to be a series of "enumerated" tags. But that would conflict with the transform logic, which would want to preserve intermediary insertions or joining of bullets into being bullet tags.

Changing a single parent tag at once (like a <ul> or <ol>) would be a more correct way to do this. I forget why that wasn't chosen except to avoid the problem of disjoint transforms not supporting being merged. But actually... that's the reason.

Also there has to be successive bullet information preserved anyway, such as when a list starts with a numeral other than 1. So it's either first bullet + all successive bullets being rendered as if they were joined on the client, or 2. supporting <ul> and <ol> and figuring out a disjoint transform fix.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.