Skip to content

Commit

Permalink
Refactor revision IDs into RevId struct and u64 tokens
Browse files Browse the repository at this point in the history
The RevId struct is a delta-compressible representation used by Engine, the
RevToken is an alias for u64 that is used by plugins as a non-colliding
identifier for a revision to base their edits on.

The RevToken is currently just a DefaultHasher hashed version of RevId,
which since DefaultHasher is cryptographically-pseudorandom should never
really collide. The collision set is just concurrent revisions since it
searches for the corresponding revision from newest to oldest.

This refactor paves the way for different Fuchsia devices to have separate
device IDs on their Engine, allowing them to generate non-conflicting
revisions that can be merged using the Ledger syncing mechanics.
  • Loading branch information
trishume committed Jul 10, 2017
1 parent 09d8eef commit 1faa63c
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 83 deletions.
28 changes: 14 additions & 14 deletions rust/core-lib/src/editor.rs
Expand Up @@ -24,7 +24,7 @@ use serde_json::Value;
use xi_rope::rope::{LinesMetric, Rope, RopeInfo};
use xi_rope::interval::Interval;
use xi_rope::delta::{self, Delta, Transformer};
use xi_rope::engine::Engine;
use xi_rope::engine::{Engine, RevId, RevToken};
use xi_rope::spans::SpansBuilder;
use view::View;
use word_boundaries::WordCursor;
Expand Down Expand Up @@ -68,8 +68,8 @@ pub struct Editor<W: Write> {
/// different views arrive.
view: View,
engine: Engine,
last_rev_id: usize,
pristine_rev_id: usize,
last_rev_id: RevId,
pristine_rev_id: RevId,
undo_group_id: usize,
live_undos: Vec<usize>, //  undo groups that may still be toggled
cur_undo: usize, // index to live_undos, ones after this are undone
Expand All @@ -89,7 +89,7 @@ pub struct Editor<W: Write> {
#[allow(dead_code)]
sync_store: Option<SyncStore>,
#[allow(dead_code)]
last_synced_rev: usize,
last_synced_rev: RevId,
}

#[derive(PartialEq, Eq, Clone, Copy)]
Expand Down Expand Up @@ -239,7 +239,7 @@ impl<W: Write + Send + 'static> Editor<W> {
}

PluginBufferInfo::new(self.buffer_id, &views,
self.engine.get_head_rev_id(), self.text.len(),
self.engine.get_head_rev_id().token(), self.text.len(),
nb_lines, self.path.clone(), self.syntax.clone())
}

Expand Down Expand Up @@ -307,7 +307,7 @@ impl<W: Write + Send + 'static> Editor<W> {
}
self.last_edit_type = self.this_edit_type;
let priority = 0x10000;
self.engine.edit_rev(priority, undo_group, head_rev_id, delta);
self.engine.edit_rev(priority, undo_group, head_rev_id.token(), delta);
self.text = self.engine.get_head().clone();
}

Expand All @@ -322,10 +322,10 @@ impl<W: Write + Send + 'static> Editor<W> {
pub fn apply_plugin_edit(&mut self, edit: PluginEdit, undo_group: usize) {
let interval = Interval::new_closed_open(edit.start as usize, edit.end as usize);
let text = Rope::from(&edit.text);
let rev_len = self.engine.get_rev(edit.rev as usize).unwrap().len();
let rev_len = self.engine.get_rev(edit.rev).unwrap().len();
let delta = Delta::simple_edit(interval, text, rev_len);
//let prev_head_rev_id = self.engine.get_head_rev_id();
self.engine.edit_rev(edit.priority as usize, undo_group, edit.rev as usize, delta);
self.engine.edit_rev(edit.priority as usize, undo_group, edit.rev, delta);
self.text = self.engine.get_head().clone();

// TODO: actually implement priority, which makes the need for the following
Expand All @@ -349,7 +349,7 @@ impl<W: Write + Send + 'static> Editor<W> {
}

fn update_after_revision(&mut self, author: Option<&str>) {
let delta = self.engine.delta_rev_head(self.last_rev_id);
let delta = self.engine.delta_rev_head(self.last_rev_id.token());
let is_pristine = self.is_pristine();
self.scroll_to = self.view.after_edit(&self.text, &delta, is_pristine);
let (iv, new_len) = delta.summary();
Expand All @@ -375,7 +375,7 @@ impl<W: Write + Send + 'static> Editor<W> {
let update = PluginUpdate::new(
self.view.view_id.clone(),
iv.start(), iv.end(), new_len,
self.engine.get_head_rev_id(), text,
self.engine.get_head_rev_id().token(), text,
self.this_edit_type.json_string().to_owned(),
author.to_owned());

Expand Down Expand Up @@ -1004,7 +1004,7 @@ impl<W: Write + Send + 'static> Editor<W> {
}

pub fn plugin_update_spans(&mut self, plugin: PluginPid, start: usize, len: usize,
spans: Vec<ScopeSpan>, rev: usize) {
spans: Vec<ScopeSpan>, rev: RevToken) {
// TODO: more protection against invalid input
let mut start = start;
let mut end_offset = start + len;
Expand All @@ -1013,7 +1013,7 @@ impl<W: Write + Send + 'static> Editor<W> {
sb.add_span(Interval::new_open_open(span.start, span.end), span.scope_id);
}
let mut spans = sb.build();
if rev != self.engine.get_head_rev_id() {
if rev != self.engine.get_head_rev_id().token() {
let delta = self.engine.delta_rev_head(rev);
let mut transformer = Transformer::new(&delta);
let new_start = transformer.transform(start, false);
Expand All @@ -1030,8 +1030,8 @@ impl<W: Write + Send + 'static> Editor<W> {
self.render();
}

pub fn plugin_get_data(&self, offset: usize, max_size: usize, rev: usize) -> Option<String> {
let text_cow = if rev == self.engine.get_head_rev_id() {
pub fn plugin_get_data(&self, offset: usize, max_size: usize, rev: RevToken) -> Option<String> {
let text_cow = if rev == self.engine.get_head_rev_id().token() {
Cow::Borrowed(&self.text)
} else {
match self.engine.get_rev(rev) {
Expand Down
13 changes: 6 additions & 7 deletions rust/core-lib/src/plugins/rpc_types.rs
Expand Up @@ -34,7 +34,7 @@ pub struct PluginBufferInfo {
pub buffer_id: BufferIdentifier,
/// The buffer's current views.
pub views: Vec<ViewIdentifier>,
pub rev: usize,
pub rev: u64,
pub buf_size: usize,
pub nb_lines: usize,
#[serde(skip_serializing_if = "Option::is_none")]
Expand All @@ -60,7 +60,7 @@ pub struct PluginUpdate {
new_len: usize,
#[serde(skip_serializing_if = "Option::is_none")]
text: Option<String>,
rev: usize,
rev: u64,
edit_type: String,
author: String,
}
Expand Down Expand Up @@ -108,15 +108,15 @@ pub struct ScopeSpan {
/// RPC commands sent from plugins.
pub enum PluginCommand {
AddScopes { view_id: ViewIdentifier, scopes: Vec<Vec<String>> },
UpdateSpans { view_id: ViewIdentifier, start: usize, len: usize, spans: Vec<ScopeSpan>, rev: usize },
GetData { view_id: ViewIdentifier, offset: usize, max_size: usize, rev: usize },
UpdateSpans { view_id: ViewIdentifier, start: usize, len: usize, spans: Vec<ScopeSpan>, rev: u64 },
GetData { view_id: ViewIdentifier, offset: usize, max_size: usize, rev: u64 },
Alert { view_id: ViewIdentifier, msg: String },
LineCount { view_id: ViewIdentifier },
}

impl PluginBufferInfo {
pub fn new(buffer_id: BufferIdentifier, views: &[ViewIdentifier],
rev: usize, buf_size: usize, nb_lines: usize,
rev: u64, buf_size: usize, nb_lines: usize,
path: Option<PathBuf>, syntax: SyntaxDefinition) -> Self {
//TODO: do make any current assertions about paths being valid utf-8? do we want to?
let path = path.map(|p| p.to_str().unwrap().to_owned());
Expand All @@ -127,9 +127,8 @@ impl PluginBufferInfo {

impl PluginUpdate {
pub fn new(view_id: ViewIdentifier, start: usize, end: usize,
new_len: usize, rev: usize, text: Option<String>,
new_len: usize, rev: u64, text: Option<String>,
edit_type: String, author: String) -> Self {
PluginUpdate {
view_id: view_id,
start: start,
end: end,
Expand Down
2 changes: 1 addition & 1 deletion rust/plugin-lib/src/caching_plugin.rs
Expand Up @@ -38,7 +38,7 @@ pub trait Handler {
struct State {
buf_size: usize,
view_id: String,
rev: usize,
rev: u64,
cache: Option<String>,
cache_offset: usize,

Expand Down
10 changes: 5 additions & 5 deletions rust/plugin-lib/src/plugin_base.rs
Expand Up @@ -68,7 +68,7 @@ pub struct PluginCtx<'a>(RpcCtx<'a, io::Stdout>);

impl<'a> PluginCtx<'a> {
pub fn get_data(&self, view_id: &str, offset: usize,
max_size: usize, rev: usize) -> Result<String, Error> {
max_size: usize, rev: u64) -> Result<String, Error> {
let params = json!({
"view_id": view_id,
"offset": offset,
Expand All @@ -91,7 +91,7 @@ impl<'a> PluginCtx<'a> {
self.send_rpc_notification("add_scopes", &params);
}

pub fn update_spans(&self, view_id: &str, start: usize, len: usize, rev: usize, spans: &[ScopeSpan]) {
pub fn update_spans(&self, view_id: &str, start: usize, len: usize, rev: u64, spans: &[ScopeSpan]) {
let params = json!({
"view_id": view_id,
"start": start,
Expand Down Expand Up @@ -150,7 +150,7 @@ pub enum PluginRequest<'a> {
start: usize,
end: usize,
new_len: usize,
rev: usize,
rev: u64,
edit_type: EditType,
author: &'a str,
text: Option<&'a str>,
Expand All @@ -168,7 +168,7 @@ pub enum PluginRequest<'a> {
pub struct PluginBufferInfo {
pub buffer_id: usize,
pub views: Vec<String>,
pub rev: usize,
pub rev: u64,
pub buf_size: usize,
pub nb_lines: usize,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -235,7 +235,7 @@ fn parse_plugin_request<'a>(method: &str, params: &'a Value) ->
start: start as usize,
end: end as usize,
new_len: new_len as usize,
rev: rev as usize,
rev: rev,
edit_type: EditType::from_str(edit_type),
author: author,
text: dict_get_string(dict, "text"),
Expand Down

0 comments on commit 1faa63c

Please sign in to comment.