mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-24 14:47:13 -04:00
refactor attribute key
This commit is contained in:
parent
26aa4e951e
commit
4d139b3f56
83 changed files with 480 additions and 1044 deletions
|
@ -2,5 +2,5 @@ mod doc;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
mod sql_builder;
|
mod sql_builder;
|
||||||
|
|
||||||
pub use doc::*;
|
pub(crate) use doc::*;
|
||||||
pub use router::*;
|
pub use router::*;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use flowy_workspace::protobuf::{App, CreateViewParams, View, ViewType, Workspace
|
||||||
use crate::{
|
use crate::{
|
||||||
service::workspace_service::{
|
service::workspace_service::{
|
||||||
app::sql_builder::NewAppSqlBuilder as AppBuilder,
|
app::sql_builder::NewAppSqlBuilder as AppBuilder,
|
||||||
view::{create_view_with_transaction, sql_builder::NewViewSqlBuilder as ViewBuilder},
|
view::create_view_with_transaction,
|
||||||
workspace::sql_builder::NewWorkspaceBuilder as WorkspaceBuilder,
|
workspace::sql_builder::NewWorkspaceBuilder as WorkspaceBuilder,
|
||||||
},
|
},
|
||||||
sqlx_ext::{map_sqlx_error, DBTransaction},
|
sqlx_ext::{map_sqlx_error, DBTransaction},
|
||||||
|
|
|
@ -156,13 +156,6 @@ impl TestServer {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_doc(&self, params: UpdateDocParams) {
|
|
||||||
let url = format!("{}/api/doc", self.address);
|
|
||||||
let _ = update_doc_request(self.user_token(), params, &url)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read_doc(&self, params: QueryDocParams) -> Option<Doc> {
|
pub async fn read_doc(&self, params: QueryDocParams) -> Option<Doc> {
|
||||||
let url = format!("{}/api/doc", self.address);
|
let url = format!("{}/api/doc", self.address);
|
||||||
let doc = read_doc_request(self.user_token(), params, &url)
|
let doc = read_doc_request(self.user_token(), params, &url)
|
||||||
|
|
|
@ -7,7 +7,6 @@ use flowy_workspace::entities::{
|
||||||
DeleteWorkspaceParams,
|
DeleteWorkspaceParams,
|
||||||
QueryWorkspaceParams,
|
QueryWorkspaceParams,
|
||||||
UpdateWorkspaceParams,
|
UpdateWorkspaceParams,
|
||||||
Workspace,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Auto-generated, do not edit
|
// Auto-generated, do not edit
|
||||||
|
|
||||||
mod ffi_response;
|
mod ffi_response;
|
||||||
pub use ffi_response::*;
|
pub use ffi_response::*;
|
||||||
|
|
||||||
mod ffi_request;
|
mod ffi_request;
|
||||||
pub use ffi_request::*;
|
pub use ffi_request::*;
|
||||||
|
|
|
@ -47,9 +47,7 @@ pub enum ASTData<'a> {
|
||||||
impl<'a> ASTData<'a> {
|
impl<'a> ASTData<'a> {
|
||||||
pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a ASTField<'a>> + 'a> {
|
pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a ASTField<'a>> + 'a> {
|
||||||
match self {
|
match self {
|
||||||
ASTData::Enum(variants) => {
|
ASTData::Enum(variants) => Box::new(variants.iter().flat_map(|variant| variant.fields.iter())),
|
||||||
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
|
|
||||||
},
|
|
||||||
ASTData::Struct(_, fields) => Box::new(fields.iter()),
|
ASTData::Struct(_, fields) => Box::new(fields.iter()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,10 +118,7 @@ impl<'a> ASTField<'a> {
|
||||||
Some(inner) => {
|
Some(inner) => {
|
||||||
match inner.primitive_ty {
|
match inner.primitive_ty {
|
||||||
PrimitiveTy::Map(map_info) => {
|
PrimitiveTy::Map(map_info) => {
|
||||||
bracket_category = Some(BracketCategory::Map((
|
bracket_category = Some(BracketCategory::Map((map_info.key.clone(), map_info.value.clone())))
|
||||||
map_info.key.clone(),
|
|
||||||
map_info.value.clone(),
|
|
||||||
)))
|
|
||||||
},
|
},
|
||||||
PrimitiveTy::Vec => {
|
PrimitiveTy::Vec => {
|
||||||
bracket_category = Some(BracketCategory::Vec);
|
bracket_category = Some(BracketCategory::Vec);
|
||||||
|
@ -198,9 +193,7 @@ pub enum ASTStyle {
|
||||||
pub fn struct_from_ast<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> (ASTStyle, Vec<ASTField<'a>>) {
|
pub fn struct_from_ast<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> (ASTStyle, Vec<ASTField<'a>>) {
|
||||||
match fields {
|
match fields {
|
||||||
syn::Fields::Named(fields) => (ASTStyle::Struct, fields_from_ast(cx, &fields.named)),
|
syn::Fields::Named(fields) => (ASTStyle::Struct, fields_from_ast(cx, &fields.named)),
|
||||||
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
|
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => (ASTStyle::NewType, fields_from_ast(cx, &fields.unnamed)),
|
||||||
(ASTStyle::NewType, fields_from_ast(cx, &fields.unnamed))
|
|
||||||
},
|
|
||||||
syn::Fields::Unnamed(fields) => (ASTStyle::Tuple, fields_from_ast(cx, &fields.unnamed)),
|
syn::Fields::Unnamed(fields) => (ASTStyle::Tuple, fields_from_ast(cx, &fields.unnamed)),
|
||||||
syn::Fields::Unit => (ASTStyle::Unit, Vec::new()),
|
syn::Fields::Unit => (ASTStyle::Unit, Vec::new()),
|
||||||
}
|
}
|
||||||
|
@ -228,10 +221,7 @@ pub fn enum_from_ast<'a>(
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fields_from_ast<'a>(
|
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a Punctuated<syn::Field, Token![,]>) -> Vec<ASTField<'a>> {
|
||||||
cx: &Ctxt,
|
|
||||||
fields: &'a Punctuated<syn::Field, Token![,]>,
|
|
||||||
) -> Vec<ASTField<'a>> {
|
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
|
|
@ -22,12 +22,7 @@ impl AttrsContainer {
|
||||||
pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self {
|
pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self {
|
||||||
let mut pb_struct_type = ASTAttr::none(cx, PB_STRUCT);
|
let mut pb_struct_type = ASTAttr::none(cx, PB_STRUCT);
|
||||||
let mut pb_enum_type = ASTAttr::none(cx, PB_ENUM);
|
let mut pb_enum_type = ASTAttr::none(cx, PB_ENUM);
|
||||||
for meta_item in item
|
for meta_item in item.attrs.iter().flat_map(|attr| get_meta_items(cx, attr)).flatten() {
|
||||||
.attrs
|
|
||||||
.iter()
|
|
||||||
.flat_map(|attr| get_meta_items(cx, attr))
|
|
||||||
.flatten()
|
|
||||||
{
|
|
||||||
match &meta_item {
|
match &meta_item {
|
||||||
// Parse `#[pb(struct = "Type")]
|
// Parse `#[pb(struct = "Type")]
|
||||||
Meta(NameValue(m)) if m.path == PB_STRUCT => {
|
Meta(NameValue(m)) if m.path == PB_STRUCT => {
|
||||||
|
@ -44,15 +39,8 @@ impl AttrsContainer {
|
||||||
},
|
},
|
||||||
|
|
||||||
Meta(meta_item) => {
|
Meta(meta_item) => {
|
||||||
let path = meta_item
|
let path = meta_item.path().into_token_stream().to_string().replace(' ', "");
|
||||||
.path()
|
cx.error_spanned_by(meta_item.path(), format!("unknown pb container attribute `{}`", path));
|
||||||
.into_token_stream()
|
|
||||||
.to_string()
|
|
||||||
.replace(' ', "");
|
|
||||||
cx.error_spanned_by(
|
|
||||||
meta_item.path(),
|
|
||||||
format!("unknown pb container attribute `{}`", path),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Lit(lit) => {
|
Lit(lit) => {
|
||||||
|
@ -103,8 +91,7 @@ impl<'c, T> ASTAttr<'c, T> {
|
||||||
let tokens = obj.into_token_stream();
|
let tokens = obj.into_token_stream();
|
||||||
|
|
||||||
if self.value.is_some() {
|
if self.value.is_some() {
|
||||||
self.cx
|
self.cx.error_spanned_by(tokens, format!("duplicate attribute `{}`", self.name));
|
||||||
.error_spanned_by(tokens, format!("duplicate attribute `{}`", self.name));
|
|
||||||
} else {
|
} else {
|
||||||
self.tokens = tokens;
|
self.tokens = tokens;
|
||||||
self.value = Some(value);
|
self.value = Some(value);
|
||||||
|
@ -160,12 +147,7 @@ impl ASTAttrField {
|
||||||
None => index.to_string(),
|
None => index.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for meta_item in field
|
for meta_item in field.attrs.iter().flat_map(|attr| get_meta_items(cx, attr)).flatten() {
|
||||||
.attrs
|
|
||||||
.iter()
|
|
||||||
.flat_map(|attr| get_meta_items(cx, attr))
|
|
||||||
.flatten()
|
|
||||||
{
|
|
||||||
match &meta_item {
|
match &meta_item {
|
||||||
// Parse `#[pb(skip)]`
|
// Parse `#[pb(skip)]`
|
||||||
Meta(Path(word)) if word == SKIP => {
|
Meta(Path(word)) if word == SKIP => {
|
||||||
|
@ -200,15 +182,8 @@ impl ASTAttrField {
|
||||||
},
|
},
|
||||||
|
|
||||||
Meta(meta_item) => {
|
Meta(meta_item) => {
|
||||||
let path = meta_item
|
let path = meta_item.path().into_token_stream().to_string().replace(' ', "");
|
||||||
.path()
|
cx.error_spanned_by(meta_item.path(), format!("unknown field attribute `{}`", path));
|
||||||
.into_token_stream()
|
|
||||||
.to_string()
|
|
||||||
.replace(' ', "");
|
|
||||||
cx.error_spanned_by(
|
|
||||||
meta_item.path(),
|
|
||||||
format!("unknown field attribute `{}`", path),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Lit(lit) => {
|
Lit(lit) => {
|
||||||
|
@ -273,12 +248,7 @@ pub struct ASTEnumAttrVariant {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ASTEnumAttrVariant {
|
impl ASTEnumAttrVariant {
|
||||||
pub fn from_ast(
|
pub fn from_ast(ctxt: &Ctxt, ident: &syn::Ident, variant: &syn::Variant, enum_attrs: &Vec<syn::Attribute>) -> Self {
|
||||||
ctxt: &Ctxt,
|
|
||||||
ident: &syn::Ident,
|
|
||||||
variant: &syn::Variant,
|
|
||||||
enum_attrs: &Vec<syn::Attribute>,
|
|
||||||
) -> Self {
|
|
||||||
let enum_item_name = variant.ident.to_string();
|
let enum_item_name = variant.ident.to_string();
|
||||||
let enum_name = ident.to_string();
|
let enum_name = ident.to_string();
|
||||||
let mut value = String::new();
|
let mut value = String::new();
|
||||||
|
@ -311,11 +281,7 @@ impl ASTEnumAttrVariant {
|
||||||
pub fn event_error(&self) -> String { self.event_attrs.error_ty.as_ref().unwrap().clone() }
|
pub fn event_error(&self) -> String { self.event_attrs.error_ty.as_ref().unwrap().clone() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_event_attrs_from(
|
fn get_event_attrs_from(ctxt: &Ctxt, variant_attrs: &Vec<syn::Attribute>, enum_attrs: &Vec<syn::Attribute>) -> EventAttrs {
|
||||||
ctxt: &Ctxt,
|
|
||||||
variant_attrs: &Vec<syn::Attribute>,
|
|
||||||
enum_attrs: &Vec<syn::Attribute>,
|
|
||||||
) -> EventAttrs {
|
|
||||||
let mut event_attrs = EventAttrs {
|
let mut event_attrs = EventAttrs {
|
||||||
input: None,
|
input: None,
|
||||||
output: None,
|
output: None,
|
||||||
|
@ -325,13 +291,7 @@ fn get_event_attrs_from(
|
||||||
|
|
||||||
enum_attrs
|
enum_attrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|attr| {
|
.filter(|attr| attr.path.segments.iter().find(|s| s.ident == EVENT_ERR).is_some())
|
||||||
attr.path
|
|
||||||
.segments
|
|
||||||
.iter()
|
|
||||||
.find(|s| s.ident == EVENT_ERR)
|
|
||||||
.is_some()
|
|
||||||
})
|
|
||||||
.for_each(|attr| {
|
.for_each(|attr| {
|
||||||
if let Ok(NameValue(named_value)) = attr.parse_meta() {
|
if let Ok(NameValue(named_value)) = attr.parse_meta() {
|
||||||
if let syn::Lit::Str(s) = named_value.lit {
|
if let syn::Lit::Str(s) = named_value.lit {
|
||||||
|
@ -344,48 +304,34 @@ fn get_event_attrs_from(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut extract_event_attr =
|
let mut extract_event_attr = |attr: &syn::Attribute, meta_item: &syn::NestedMeta| match &meta_item {
|
||||||
|attr: &syn::Attribute, meta_item: &syn::NestedMeta| match &meta_item {
|
Meta(NameValue(name_value)) => {
|
||||||
Meta(NameValue(name_value)) => {
|
if name_value.path == EVENT_INPUT {
|
||||||
if name_value.path == EVENT_INPUT {
|
if let syn::Lit::Str(s) = &name_value.lit {
|
||||||
if let syn::Lit::Str(s) = &name_value.lit {
|
let input_type = parse_lit_str(s)
|
||||||
let input_type = parse_lit_str(s)
|
.map_err(|_| ctxt.error_spanned_by(s, format!("failed to parse request deserializer {:?}", s.value())))
|
||||||
.map_err(|_| {
|
.unwrap();
|
||||||
ctxt.error_spanned_by(
|
event_attrs.input = Some(input_type);
|
||||||
s,
|
|
||||||
format!("failed to parse request deserializer {:?}", s.value()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
event_attrs.input = Some(input_type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if name_value.path == EVENT_OUTPUT {
|
if name_value.path == EVENT_OUTPUT {
|
||||||
if let syn::Lit::Str(s) = &name_value.lit {
|
if let syn::Lit::Str(s) = &name_value.lit {
|
||||||
let output_type = parse_lit_str(s)
|
let output_type = parse_lit_str(s)
|
||||||
.map_err(|_| {
|
.map_err(|_| ctxt.error_spanned_by(s, format!("failed to parse response deserializer {:?}", s.value())))
|
||||||
ctxt.error_spanned_by(
|
.unwrap();
|
||||||
s,
|
event_attrs.output = Some(output_type);
|
||||||
format!(
|
|
||||||
"failed to parse response deserializer {:?}",
|
|
||||||
s.value()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
event_attrs.output = Some(output_type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Meta(Path(word)) => {
|
},
|
||||||
if word == EVENT_IGNORE && attr.path == EVENT {
|
Meta(Path(word)) => {
|
||||||
event_attrs.ignore = true;
|
if word == EVENT_IGNORE && attr.path == EVENT {
|
||||||
}
|
event_attrs.ignore = true;
|
||||||
},
|
}
|
||||||
Lit(s) => ctxt.error_spanned_by(s, "unexpected attribute"),
|
},
|
||||||
_ => ctxt.error_spanned_by(meta_item, "unexpected attribute"),
|
Lit(s) => ctxt.error_spanned_by(s, "unexpected attribute"),
|
||||||
};
|
_ => ctxt.error_spanned_by(meta_item, "unexpected attribute"),
|
||||||
|
};
|
||||||
|
|
||||||
let attr_meta_items_info = variant_attrs
|
let attr_meta_items_info = variant_attrs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -396,9 +342,7 @@ fn get_event_attrs_from(
|
||||||
.collect::<Vec<(&syn::Attribute, Vec<syn::NestedMeta>)>>();
|
.collect::<Vec<(&syn::Attribute, Vec<syn::NestedMeta>)>>();
|
||||||
|
|
||||||
for (attr, nested_metas) in attr_meta_items_info {
|
for (attr, nested_metas) in attr_meta_items_info {
|
||||||
nested_metas
|
nested_metas.iter().for_each(|meta_item| extract_event_attr(attr, meta_item))
|
||||||
.iter()
|
|
||||||
.for_each(|meta_item| extract_event_attr(attr, meta_item))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eprintln!("😁{:#?}", event_attrs);
|
// eprintln!("😁{:#?}", event_attrs);
|
||||||
|
@ -426,15 +370,9 @@ pub fn get_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result<Vec<syn::Neste
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lit_into_expr_path(
|
fn parse_lit_into_expr_path(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result<syn::ExprPath, ()> {
|
||||||
cx: &Ctxt,
|
|
||||||
attr_name: Symbol,
|
|
||||||
lit: &syn::Lit,
|
|
||||||
) -> Result<syn::ExprPath, ()> {
|
|
||||||
let string = get_lit_str(cx, attr_name, lit)?;
|
let string = get_lit_str(cx, attr_name, lit)?;
|
||||||
parse_lit_str(string).map_err(|_| {
|
parse_lit_str(string).map_err(|_| cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())))
|
||||||
cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_lit_str<'a>(cx: &Ctxt, attr_name: Symbol, lit: &'a syn::Lit) -> Result<&'a syn::LitStr, ()> {
|
fn get_lit_str<'a>(cx: &Ctxt, attr_name: Symbol, lit: &'a syn::Lit) -> Result<&'a syn::LitStr, ()> {
|
||||||
|
@ -443,10 +381,7 @@ fn get_lit_str<'a>(cx: &Ctxt, attr_name: Symbol, lit: &'a syn::Lit) -> Result<&'
|
||||||
} else {
|
} else {
|
||||||
cx.error_spanned_by(
|
cx.error_spanned_by(
|
||||||
lit,
|
lit,
|
||||||
format!(
|
format!("expected pb {} attribute to be a string: `{} = \"...\"`", attr_name, attr_name),
|
||||||
"expected pb {} attribute to be a string: `{} = \"...\"`",
|
|
||||||
attr_name, attr_name
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
@ -455,12 +390,7 @@ fn get_lit_str<'a>(cx: &Ctxt, attr_name: Symbol, lit: &'a syn::Lit) -> Result<&'
|
||||||
fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result<syn::Type, ()> {
|
fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result<syn::Type, ()> {
|
||||||
let string = get_lit_str(cx, attr_name, lit)?;
|
let string = get_lit_str(cx, attr_name, lit)?;
|
||||||
|
|
||||||
parse_lit_str(string).map_err(|_| {
|
parse_lit_str(string).map_err(|_| cx.error_spanned_by(lit, format!("failed to parse type: {} = {:?}", attr_name, string.value())))
|
||||||
cx.error_spanned_by(
|
|
||||||
lit,
|
|
||||||
format!("failed to parse type: {} = {:?}", attr_name, string.value()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_lit_str<T>(s: &syn::LitStr) -> parse::Result<T>
|
pub fn parse_lit_str<T>(s: &syn::LitStr) -> parse::Result<T>
|
||||||
|
@ -477,10 +407,7 @@ fn spanned_tokens(s: &syn::LitStr) -> parse::Result<TokenStream> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
|
fn respan_token_stream(stream: TokenStream, span: Span) -> TokenStream {
|
||||||
stream
|
stream.into_iter().map(|token| respan_token_tree(token, span)).collect()
|
||||||
.into_iter()
|
|
||||||
.map(|token| respan_token_tree(token, span))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
|
fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
|
||||||
|
@ -499,10 +426,7 @@ fn default_pb_type(ctxt: &Ctxt, ident: &syn::Ident) -> syn::Type {
|
||||||
return pb_struct_ty;
|
return pb_struct_ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctxt.error_spanned_by(
|
ctxt.error_spanned_by(ident, format!("❌ Can't find {} protobuf struct", take_ident));
|
||||||
ident,
|
|
||||||
format!("❌ Can't find {} protobuf struct", take_ident),
|
|
||||||
);
|
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,7 @@ impl Ctxt {
|
||||||
.push(syn::Error::new_spanned(obj.into_token_stream(), msg));
|
.push(syn::Error::new_spanned(obj.into_token_stream(), msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syn_error(&self, err: syn::Error) {
|
pub fn syn_error(&self, err: syn::Error) { self.errors.borrow_mut().as_mut().unwrap().push(err); }
|
||||||
self.errors.borrow_mut().as_mut().unwrap().push(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check(self) -> Result<(), Vec<syn::Error>> {
|
pub fn check(self) -> Result<(), Vec<syn::Error>> {
|
||||||
let errors = self.errors.borrow_mut().take().unwrap();
|
let errors = self.errors.borrow_mut().take().unwrap();
|
||||||
|
|
|
@ -58,10 +58,4 @@ table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(
|
allow_tables_to_appear_in_same_query!(app_table, doc_table, user_table, view_table, workspace_table,);
|
||||||
app_table,
|
|
||||||
doc_table,
|
|
||||||
user_table,
|
|
||||||
view_table,
|
|
||||||
workspace_table,
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
|
||||||
// #[proc_macro_derive(DartEvent, attributes(event_ty))]
|
// #[proc_macro_derive(DartEvent, attributes(event_ty))]
|
||||||
pub fn expand_enum_derive(_input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
|
pub fn expand_enum_derive(_input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> { Ok(TokenStream::default()) }
|
||||||
Ok(TokenStream::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
// use flowy_ast::{ASTContainer, Ctxt};
|
// use flowy_ast::{ASTContainer, Ctxt};
|
||||||
// use proc_macro2::TokenStream;
|
// use proc_macro2::TokenStream;
|
||||||
|
|
|
@ -69,8 +69,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
|
||||||
| "UserProfile"
|
| "UserProfile"
|
||||||
| "UpdateUserRequest"
|
| "UpdateUserRequest"
|
||||||
| "UpdateUserParams"
|
| "UpdateUserParams"
|
||||||
| "UserError"
|
| "UserError" => TypeCategory::Protobuf,
|
||||||
=> TypeCategory::Protobuf,
|
|
||||||
"ViewType"
|
"ViewType"
|
||||||
| "WorkspaceEvent"
|
| "WorkspaceEvent"
|
||||||
| "ErrorCode"
|
| "ErrorCode"
|
||||||
|
@ -80,8 +79,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
|
||||||
| "FFIStatusCode"
|
| "FFIStatusCode"
|
||||||
| "UserStatus"
|
| "UserStatus"
|
||||||
| "UserEvent"
|
| "UserEvent"
|
||||||
| "UserObservable"
|
| "UserObservable" => TypeCategory::Enum,
|
||||||
=> TypeCategory::Enum,
|
|
||||||
|
|
||||||
"Option" => TypeCategory::Opt,
|
"Option" => TypeCategory::Opt,
|
||||||
_ => TypeCategory::Primitive,
|
_ => TypeCategory::Primitive,
|
||||||
|
|
|
@ -16,25 +16,19 @@ mod proto_buf;
|
||||||
#[proc_macro_derive(ProtoBuf, attributes(pb))]
|
#[proc_macro_derive(ProtoBuf, attributes(pb))]
|
||||||
pub fn derive_proto_buf(input: TokenStream) -> TokenStream {
|
pub fn derive_proto_buf(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
proto_buf::expand_derive(&input)
|
proto_buf::expand_derive(&input).unwrap_or_else(to_compile_errors).into()
|
||||||
.unwrap_or_else(to_compile_errors)
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(ProtoBuf_Enum, attributes(pb))]
|
#[proc_macro_derive(ProtoBuf_Enum, attributes(pb))]
|
||||||
pub fn derive_proto_buf_enum(input: TokenStream) -> TokenStream {
|
pub fn derive_proto_buf_enum(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
proto_buf::expand_enum_derive(&input)
|
proto_buf::expand_enum_derive(&input).unwrap_or_else(to_compile_errors).into()
|
||||||
.unwrap_or_else(to_compile_errors)
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Flowy_Event, attributes(event, event_err))]
|
#[proc_macro_derive(Flowy_Event, attributes(event, event_err))]
|
||||||
pub fn derive_dart_event(input: TokenStream) -> TokenStream {
|
pub fn derive_dart_event(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
dart_event::expand_enum_derive(&input)
|
dart_event::expand_enum_derive(&input).unwrap_or_else(to_compile_errors).into()
|
||||||
.unwrap_or_else(to_compile_errors)
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
|
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
|
||||||
|
|
|
@ -6,20 +6,16 @@ pub fn make_de_token_steam(ctxt: &Ctxt, ast: &ASTContainer) -> Option<TokenStrea
|
||||||
let pb_ty = ast.attrs.pb_struct_type()?;
|
let pb_ty = ast.attrs.pb_struct_type()?;
|
||||||
let struct_ident = &ast.ident;
|
let struct_ident = &ast.ident;
|
||||||
|
|
||||||
let build_take_fields = ast
|
let build_take_fields = ast.data.all_fields().filter(|f| !f.attrs.skip_deserializing()).flat_map(|field| {
|
||||||
.data
|
if let Some(func) = field.attrs.deserialize_with() {
|
||||||
.all_fields()
|
let member = &field.member;
|
||||||
.filter(|f| !f.attrs.skip_deserializing())
|
Some(quote! { o.#member=#struct_ident::#func(pb); })
|
||||||
.flat_map(|field| {
|
} else if field.attrs.is_one_of() {
|
||||||
if let Some(func) = field.attrs.deserialize_with() {
|
token_stream_for_one_of(ctxt, field)
|
||||||
let member = &field.member;
|
} else {
|
||||||
Some(quote! { o.#member=#struct_ident::#func(pb); })
|
token_stream_for_field(ctxt, &field.member, &field.ty, false)
|
||||||
} else if field.attrs.is_one_of() {
|
}
|
||||||
token_stream_for_one_of(ctxt, field)
|
});
|
||||||
} else {
|
|
||||||
token_stream_for_field(ctxt, &field.member, &field.ty, false)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let de_token_stream: TokenStream = quote! {
|
let de_token_stream: TokenStream = quote! {
|
||||||
impl std::convert::TryFrom<bytes::Bytes> for #struct_ident {
|
impl std::convert::TryFrom<bytes::Bytes> for #struct_ident {
|
||||||
|
@ -102,12 +98,7 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option<TokenStream>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_stream_for_field(
|
fn token_stream_for_field(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_option: bool) -> Option<TokenStream> {
|
||||||
ctxt: &Ctxt,
|
|
||||||
member: &syn::Member,
|
|
||||||
ty: &syn::Type,
|
|
||||||
is_option: bool,
|
|
||||||
) -> Option<TokenStream> {
|
|
||||||
let ident = get_member_ident(ctxt, member)?;
|
let ident = get_member_ident(ctxt, member)?;
|
||||||
let ty_info = parse_ty(ctxt, ty)?;
|
let ty_info = parse_ty(ctxt, ty)?;
|
||||||
match ident_category(ty_info.ident) {
|
match ident_category(ty_info.ident) {
|
||||||
|
@ -142,8 +133,7 @@ fn token_stream_for_field(
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
TypeCategory::Str => {
|
TypeCategory::Str => {
|
||||||
let take_ident =
|
let take_ident = syn::Ident::new(&format!("take_{}", ident.to_string()), Span::call_site());
|
||||||
syn::Ident::new(&format!("take_{}", ident.to_string()), Span::call_site());
|
|
||||||
if is_option {
|
if is_option {
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
if pb.#member.is_empty() {
|
if pb.#member.is_empty() {
|
||||||
|
@ -158,9 +148,7 @@ fn token_stream_for_field(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TypeCategory::Opt => {
|
TypeCategory::Opt => token_stream_for_field(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true),
|
||||||
token_stream_for_field(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true)
|
|
||||||
},
|
|
||||||
TypeCategory::Primitive | TypeCategory::Bytes => {
|
TypeCategory::Primitive | TypeCategory::Bytes => {
|
||||||
// eprintln!("😄 #{:?}", &field.name().unwrap());
|
// eprintln!("😄 #{:?}", &field.name().unwrap());
|
||||||
if is_option {
|
if is_option {
|
||||||
|
@ -172,11 +160,7 @@ fn token_stream_for_field(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_stream_for_vec(
|
fn token_stream_for_vec(ctxt: &Ctxt, member: &syn::Member, bracketed_type: &TyInfo) -> Option<TokenStream> {
|
||||||
ctxt: &Ctxt,
|
|
||||||
member: &syn::Member,
|
|
||||||
bracketed_type: &TyInfo,
|
|
||||||
) -> Option<TokenStream> {
|
|
||||||
let ident = get_member_ident(ctxt, member)?;
|
let ident = get_member_ident(ctxt, member)?;
|
||||||
|
|
||||||
match ident_category(bracketed_type.ident) {
|
match ident_category(bracketed_type.ident) {
|
||||||
|
@ -208,11 +192,7 @@ fn token_stream_for_vec(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_stream_for_map(
|
fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, bracketed_type: &TyInfo) -> Option<TokenStream> {
|
||||||
ctxt: &Ctxt,
|
|
||||||
member: &syn::Member,
|
|
||||||
bracketed_type: &TyInfo,
|
|
||||||
) -> Option<TokenStream> {
|
|
||||||
let ident = get_member_ident(ctxt, member)?;
|
let ident = get_member_ident(ctxt, member)?;
|
||||||
|
|
||||||
let take_ident = format_ident!("take_{}", ident.to_string());
|
let take_ident = format_ident!("take_{}", ident.to_string());
|
||||||
|
|
|
@ -3,11 +3,7 @@ mod enum_serde;
|
||||||
mod serialize;
|
mod serialize;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
use crate::proto_buf::{
|
use crate::proto_buf::{deserialize::make_de_token_steam, enum_serde::make_enum_token_stream, serialize::make_se_token_stream};
|
||||||
deserialize::make_de_token_steam,
|
|
||||||
enum_serde::make_enum_token_stream,
|
|
||||||
serialize::make_se_token_stream,
|
|
||||||
};
|
|
||||||
use flowy_ast::*;
|
use flowy_ast::*;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
|
||||||
|
|
|
@ -76,18 +76,11 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option<TokenStream>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_token_stream(
|
fn gen_token_stream(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_option: bool) -> Option<TokenStream> {
|
||||||
ctxt: &Ctxt,
|
|
||||||
member: &syn::Member,
|
|
||||||
ty: &syn::Type,
|
|
||||||
is_option: bool,
|
|
||||||
) -> Option<TokenStream> {
|
|
||||||
let ty_info = parse_ty(ctxt, ty)?;
|
let ty_info = parse_ty(ctxt, ty)?;
|
||||||
match ident_category(ty_info.ident) {
|
match ident_category(ty_info.ident) {
|
||||||
TypeCategory::Array => token_stream_for_vec(ctxt, &member, &ty_info.ty),
|
TypeCategory::Array => token_stream_for_vec(ctxt, &member, &ty_info.ty),
|
||||||
TypeCategory::Map => {
|
TypeCategory::Map => token_stream_for_map(ctxt, &member, &ty_info.bracket_ty_info.unwrap().ty),
|
||||||
token_stream_for_map(ctxt, &member, &ty_info.bracket_ty_info.unwrap().ty)
|
|
||||||
},
|
|
||||||
TypeCategory::Str => {
|
TypeCategory::Str => {
|
||||||
if is_option {
|
if is_option {
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
|
@ -100,12 +93,8 @@ fn gen_token_stream(
|
||||||
Some(quote! { pb.#member = self.#member.clone(); })
|
Some(quote! { pb.#member = self.#member.clone(); })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TypeCategory::Protobuf => Some(
|
TypeCategory::Protobuf => Some(quote! { pb.#member = ::protobuf::SingularPtrField::some(self.#member.try_into().unwrap()); }),
|
||||||
quote! { pb.#member = ::protobuf::SingularPtrField::some(self.#member.try_into().unwrap()); },
|
TypeCategory::Opt => gen_token_stream(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true),
|
||||||
),
|
|
||||||
TypeCategory::Opt => {
|
|
||||||
gen_token_stream(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true)
|
|
||||||
},
|
|
||||||
TypeCategory::Enum => {
|
TypeCategory::Enum => {
|
||||||
// let pb_enum_ident = format_ident!("{}", ty_info.ident.to_string());
|
// let pb_enum_ident = format_ident!("{}", ty_info.ident.to_string());
|
||||||
// Some(quote! {
|
// Some(quote! {
|
||||||
|
|
|
@ -17,9 +17,6 @@ pub(crate) fn get_member_ident<'a>(ctxt: &Ctxt, member: &'a syn::Member) -> Opti
|
||||||
|
|
||||||
pub fn assert_bracket_ty_is_some(ctxt: &Ctxt, ty_info: &TyInfo) {
|
pub fn assert_bracket_ty_is_some(ctxt: &Ctxt, ty_info: &TyInfo) {
|
||||||
if ty_info.bracket_ty_info.is_none() {
|
if ty_info.bracket_ty_info.is_none() {
|
||||||
ctxt.error_spanned_by(
|
ctxt.error_spanned_by(ty_info.ty, format!("Invalid bracketed type when gen de token steam"));
|
||||||
ty_info.ty,
|
|
||||||
format!("Invalid bracketed type when gen de token steam"),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,7 @@ where
|
||||||
Payload::None => ready(Err(unexpected_none_payload(req))),
|
Payload::None => ready(Err(unexpected_none_payload(req))),
|
||||||
Payload::Bytes(bytes) => match T::parse_from_bytes(bytes.clone()) {
|
Payload::Bytes(bytes) => match T::parse_from_bytes(bytes.clone()) {
|
||||||
Ok(data) => ready(Ok(Data(data))),
|
Ok(data) => ready(Ok(Data(data))),
|
||||||
Err(e) => ready(Err(
|
Err(e) => ready(Err(InternalError::DeserializeFromBytes(format!("{}", e)).into())),
|
||||||
InternalError::DeserializeFromBytes(format!("{}", e)).into()
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,9 +76,7 @@ where
|
||||||
T: FromBytes,
|
T: FromBytes,
|
||||||
{
|
{
|
||||||
match payload {
|
match payload {
|
||||||
Payload::None => {
|
Payload::None => Err(InternalError::UnexpectedNone(format!("Parse fail, expected payload")).into()),
|
||||||
Err(InternalError::UnexpectedNone(format!("Parse fail, expected payload")).into())
|
|
||||||
},
|
|
||||||
Payload::Bytes(bytes) => {
|
Payload::Bytes(bytes) => {
|
||||||
let data = T::parse_from_bytes(bytes.clone())?;
|
let data = T::parse_from_bytes(bytes.clone())?;
|
||||||
Ok(Data(data))
|
Ok(Data(data))
|
||||||
|
|
|
@ -16,13 +16,5 @@ pub mod macros;
|
||||||
pub use errors::Error;
|
pub use errors::Error;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{byte_trait::*, data::*, dispatch::*, errors::*, module::*, request::*, response::*};
|
||||||
byte_trait::*,
|
|
||||||
data::*,
|
|
||||||
dispatch::*,
|
|
||||||
errors::*,
|
|
||||||
module::*,
|
|
||||||
request::*,
|
|
||||||
response::*,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,19 +10,13 @@ pub struct ModuleDataMap {
|
||||||
|
|
||||||
impl ModuleDataMap {
|
impl ModuleDataMap {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> ModuleDataMap {
|
pub fn new() -> ModuleDataMap { ModuleDataMap { map: HashMap::default() } }
|
||||||
ModuleDataMap {
|
|
||||||
map: HashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert<T>(&mut self, val: T) -> Option<T>
|
pub fn insert<T>(&mut self, val: T) -> Option<T>
|
||||||
where
|
where
|
||||||
T: 'static + Send + Sync,
|
T: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
self.map
|
self.map.insert(TypeId::of::<T>(), Box::new(val)).and_then(downcast_owned)
|
||||||
.insert(TypeId::of::<T>(), Box::new(val))
|
|
||||||
.and_then(downcast_owned)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove<T>(&mut self) -> Option<T>
|
pub fn remove<T>(&mut self) -> Option<T>
|
||||||
|
@ -36,18 +30,14 @@ impl ModuleDataMap {
|
||||||
where
|
where
|
||||||
T: 'static + Send + Sync,
|
T: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
self.map
|
self.map.get(&TypeId::of::<T>()).and_then(|boxed| boxed.downcast_ref())
|
||||||
.get(&TypeId::of::<T>())
|
|
||||||
.and_then(|boxed| boxed.downcast_ref())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<T>(&mut self) -> Option<&mut T>
|
pub fn get_mut<T>(&mut self) -> Option<&mut T>
|
||||||
where
|
where
|
||||||
T: 'static + Send + Sync,
|
T: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
self.map
|
self.map.get_mut(&TypeId::of::<T>()).and_then(|boxed| boxed.downcast_mut())
|
||||||
.get_mut(&TypeId::of::<T>())
|
|
||||||
.and_then(|boxed| boxed.downcast_mut())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains<T>(&self) -> bool
|
pub fn contains<T>(&self) -> bool
|
||||||
|
@ -60,6 +50,4 @@ impl ModuleDataMap {
|
||||||
pub fn extend(&mut self, other: ModuleDataMap) { self.map.extend(other.map); }
|
pub fn extend(&mut self, other: ModuleDataMap) { self.map.extend(other.map); }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn downcast_owned<T: 'static + Send + Sync>(boxed: Box<dyn Any + Send + Sync>) -> Option<T> {
|
fn downcast_owned<T: 'static + Send + Sync>(boxed: Box<dyn Any + Send + Sync>) -> Option<T> { boxed.downcast().ok().map(|boxed| *boxed) }
|
||||||
boxed.downcast().ok().map(|boxed| *boxed)
|
|
||||||
}
|
|
||||||
|
|
|
@ -51,10 +51,7 @@ where
|
||||||
if let Some(data) = req.module_data::<Unit<T>>() {
|
if let Some(data) = req.module_data::<Unit<T>>() {
|
||||||
ready(Ok(data.clone()))
|
ready(Ok(data.clone()))
|
||||||
} else {
|
} else {
|
||||||
let msg = format!(
|
let msg = format!("Failed to get the module data of type: {}", type_name::<T>());
|
||||||
"Failed to get the module data of type: {}",
|
|
||||||
type_name::<T>()
|
|
||||||
);
|
|
||||||
log::error!("{}", msg,);
|
log::error!("{}", msg,);
|
||||||
ready(Err(InternalError::Other(msg).into()))
|
ready(Err(InternalError::Other(msg).into()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,7 @@ pub trait Responder {
|
||||||
macro_rules! impl_responder {
|
macro_rules! impl_responder {
|
||||||
($res: ty) => {
|
($res: ty) => {
|
||||||
impl Responder for $res {
|
impl Responder for $res {
|
||||||
fn respond_to(self, _: &EventRequest) -> EventResponse {
|
fn respond_to(self, _: &EventRequest) -> EventResponse { ResponseBuilder::Ok().data(self).build() }
|
||||||
ResponseBuilder::Ok().data(self).build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,11 +44,8 @@ where
|
||||||
fn new_service(&self, cfg: Cfg) -> Self::Future { self.0.new_service(cfg) }
|
fn new_service(&self, cfg: Cfg) -> Self::Future { self.0.new_service(cfg) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BoxService<Req, Res, Err> = Box<
|
pub type BoxService<Req, Res, Err> =
|
||||||
dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<'static, Result<Res, Err>>>
|
Box<dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<'static, Result<Res, Err>>> + Sync + Send>;
|
||||||
+ Sync
|
|
||||||
+ Send,
|
|
||||||
>;
|
|
||||||
|
|
||||||
// #[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
// pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
|
// pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
|
||||||
|
@ -112,9 +109,6 @@ where
|
||||||
|
|
||||||
fn new_service(&self, cfg: Cfg) -> Self::Future {
|
fn new_service(&self, cfg: Cfg) -> Self::Future {
|
||||||
let f = self.0.new_service(cfg);
|
let f = self.0.new_service(cfg);
|
||||||
Box::pin(async {
|
Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as Self::Service) })
|
||||||
f.await
|
|
||||||
.map(|s| Box::new(ServiceWrapper::new(s)) as Self::Service)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,9 +41,7 @@ pub struct ServiceResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceResponse {
|
impl ServiceResponse {
|
||||||
pub fn new(request: EventRequest, response: EventResponse) -> Self {
|
pub fn new(request: EventRequest, response: EventResponse) -> Self { ServiceResponse { request, response } }
|
||||||
ServiceResponse { request, response }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_parts(self) -> (EventRequest, EventResponse) { (self.request, self.response) }
|
pub fn into_parts(self) -> (EventRequest, EventResponse) { (self.request, self.response) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,7 @@ impl FlowySystem {
|
||||||
|
|
||||||
let system = Self { sys_cmd_tx };
|
let system = Self { sys_cmd_tx };
|
||||||
FlowySystem::set_current(system);
|
FlowySystem::set_current(system);
|
||||||
let runner = SystemRunner {
|
let runner = SystemRunner { rt: runtime, stop_rx };
|
||||||
rt: runtime,
|
|
||||||
stop_rx,
|
|
||||||
};
|
|
||||||
runner
|
runner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,10 +109,7 @@ impl SystemRunner {
|
||||||
match rt.block_on(stop_rx) {
|
match rt.block_on(stop_rx) {
|
||||||
Ok(code) => {
|
Ok(code) => {
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(io::ErrorKind::Other, format!("Non-zero exit code: {}", code)))
|
||||||
io::ErrorKind::Other,
|
|
||||||
format!("Non-zero exit code: {}", code),
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,18 +10,10 @@ pub(crate) fn tokio_default_runtime() -> io::Result<tokio::runtime::Runtime> {
|
||||||
.enable_io()
|
.enable_io()
|
||||||
.enable_time()
|
.enable_time()
|
||||||
.on_thread_start(move || {
|
.on_thread_start(move || {
|
||||||
log::trace!(
|
log::trace!("{:?} thread started: thread_id= {}", thread::current(), thread_id::get());
|
||||||
"{:?} thread started: thread_id= {}",
|
|
||||||
thread::current(),
|
|
||||||
thread_id::get()
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.on_thread_stop(move || {
|
.on_thread_stop(move || {
|
||||||
log::trace!(
|
log::trace!("{:?} thread stopping: thread_id= {}", thread::current(), thread_id::get(),);
|
||||||
"{:?} thread stopping: thread_id= {}",
|
|
||||||
thread::current(),
|
|
||||||
thread_id::get(),
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
#[rustfmt::skip]
|
||||||
use flowy_dispatch::prelude::*;
|
use flowy_dispatch::prelude::*;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn setup_env() {
|
pub fn setup_env() {
|
||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
std::env::);
|
|
||||||
INIT.call_once(|| env_logger::init());
|
INIT.call_once(|| env_logger::init());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Auto-generated, do not edit
|
// Auto-generated, do not edit
|
||||||
|
|
||||||
mod observable;
|
mod observable;
|
||||||
pub use observable::*;
|
pub use observable::*;
|
||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
pub use errors::*;
|
pub use errors::*;
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
|
|
||||||
mod doc;
|
mod doc;
|
||||||
pub use doc::*;
|
pub use doc::*;
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl DocController {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self, conn), err)]
|
#[tracing::instrument(level = "debug", skip(self, conn, params), err)]
|
||||||
pub fn update(&self, params: UpdateDocParams, conn: &SqliteConnection) -> Result<(), DocError> {
|
pub fn update(&self, params: UpdateDocParams, conn: &SqliteConnection) -> Result<(), DocError> {
|
||||||
let changeset = DocTableChangeset::new(params.clone());
|
let changeset = DocTableChangeset::new(params.clone());
|
||||||
let _ = self.sql.update_doc_table(changeset, &*conn)?;
|
let _ = self.sql.update_doc_table(changeset, &*conn)?;
|
||||||
|
@ -58,7 +58,7 @@ impl DocController {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocController {
|
impl DocController {
|
||||||
#[tracing::instrument(level = "debug", skip(self), err)]
|
#[tracing::instrument(level = "debug", skip(self, params), err)]
|
||||||
fn update_doc_on_server(&self, params: UpdateDocParams) -> Result<(), DocError> {
|
fn update_doc_on_server(&self, params: UpdateDocParams) -> Result<(), DocError> {
|
||||||
let token = self.user.token()?;
|
let token = self.user.token()?;
|
||||||
let server = self.server.clone();
|
let server = self.server.clone();
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Auto-generated, do not edit
|
// Auto-generated, do not edit
|
||||||
|
|
||||||
mod kv;
|
mod kv;
|
||||||
pub use kv::*;
|
pub use kv::*;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::{fmt, io::Write};
|
||||||
use tracing::{Event, Id, Subscriber};
|
use tracing::{Event, Id, Subscriber};
|
||||||
use tracing_bunyan_formatter::JsonStorage;
|
use tracing_bunyan_formatter::JsonStorage;
|
||||||
use tracing_core::{metadata::Level, span::Attributes};
|
use tracing_core::{metadata::Level, span::Attributes};
|
||||||
use tracing_log::AsLog;
|
|
||||||
use tracing_subscriber::{fmt::MakeWriter, layer::Context, registry::SpanRef, Layer};
|
use tracing_subscriber::{fmt::MakeWriter, layer::Context, registry::SpanRef, Layer};
|
||||||
const LEVEL: &str = "level";
|
const LEVEL: &str = "level";
|
||||||
const TIME: &str = "time";
|
const TIME: &str = "time";
|
||||||
|
|
|
@ -5,9 +5,9 @@ use std::path::Path;
|
||||||
use tracing::subscriber::set_global_default;
|
use tracing::subscriber::set_global_default;
|
||||||
|
|
||||||
use crate::layer::*;
|
use crate::layer::*;
|
||||||
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
|
use tracing_bunyan_formatter::JsonStorageLayer;
|
||||||
use tracing_log::LogTracer;
|
use tracing_log::LogTracer;
|
||||||
use tracing_subscriber::{fmt::format::FmtSpan, layer::SubscriberExt, EnvFilter};
|
use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
|
||||||
|
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
|
@ -16,10 +16,7 @@ impl FlowyResponse {
|
||||||
|
|
||||||
pub fn success() -> Self { Self::new(Bytes::new(), None) }
|
pub fn success() -> Self { Self::new(Bytes::new(), None) }
|
||||||
|
|
||||||
pub fn data<T: TryInto<Bytes, Error = protobuf::ProtobufError>>(
|
pub fn data<T: TryInto<Bytes, Error = protobuf::ProtobufError>>(mut self, data: T) -> Result<Self, ServerError> {
|
||||||
mut self,
|
|
||||||
data: T,
|
|
||||||
) -> Result<Self, ServerError> {
|
|
||||||
let bytes: Bytes = data.try_into()?;
|
let bytes: Bytes = data.try_into()?;
|
||||||
self.data = bytes;
|
self.data = bytes;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
// return
|
// return
|
||||||
// Err(de::Error::duplicate_field("data")); }
|
// Err(de::Error::duplicate_field("data")); }
|
||||||
// data = match
|
// data = match
|
||||||
// MapAccess::next_value::<DeserializeWith<T>>(&mut map) {
|
// MapAccess::next_value::<DeserializeWith<T>>(&mut map) {
|
||||||
// Ok(wrapper) => wrapper.value, Err(err) =>
|
// Ok(wrapper) => wrapper.value, Err(err) =>
|
||||||
// return Err(err), };
|
// return Err(err), };
|
||||||
// },
|
// },
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
// }
|
// }
|
||||||
// let msg = msg.ok_or_else(||
|
// let msg = msg.ok_or_else(||
|
||||||
// de::Error::missing_field("msg"))?; let code =
|
// de::Error::missing_field("msg"))?; let code =
|
||||||
// code.ok_or_else(|| de::Error::missing_field("code"))?;
|
// code.ok_or_else(|| de::Error::missing_field("code"))?;
|
||||||
// Ok(Self::Value::new(data, msg, code)) }
|
// Ok(Self::Value::new(data, msg, code)) }
|
||||||
// }
|
// }
|
||||||
// const FIELDS: &'static [&'static str] = &["msg", "code", "data"];
|
// const FIELDS: &'static [&'static str] = &["msg", "code", "data"];
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Auto-generated, do not edit
|
// Auto-generated, do not edit
|
||||||
|
|
||||||
mod subject;
|
mod subject;
|
||||||
pub use subject::*;
|
pub use subject::*;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -8,11 +8,6 @@ impl DeleteExt for DefaultDelete {
|
||||||
fn ext_name(&self) -> &str { "DefaultDelete" }
|
fn ext_name(&self) -> &str { "DefaultDelete" }
|
||||||
|
|
||||||
fn apply(&self, _delta: &Delta, interval: Interval) -> Option<Delta> {
|
fn apply(&self, _delta: &Delta, interval: Interval) -> Option<Delta> {
|
||||||
Some(
|
Some(DeltaBuilder::new().retain(interval.start).delete(interval.size()).build())
|
||||||
DeltaBuilder::new()
|
|
||||||
.retain(interval.start)
|
|
||||||
.delete(interval.size())
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{extensions::DeleteExt, util::is_newline},
|
client::{extensions::DeleteExt, util::is_newline},
|
||||||
core::{Attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, Interval, NEW_LINE},
|
core::{plain_attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, Interval, NEW_LINE},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct PreserveLineFormatOnMerge {}
|
pub struct PreserveLineFormatOnMerge {}
|
||||||
|
@ -22,10 +22,7 @@ impl DeleteExt for PreserveLineFormatOnMerge {
|
||||||
}
|
}
|
||||||
|
|
||||||
iter.seek::<CharMetric>(interval.size() - 1);
|
iter.seek::<CharMetric>(interval.size() - 1);
|
||||||
let mut new_delta = DeltaBuilder::new()
|
let mut new_delta = DeltaBuilder::new().retain(interval.start).delete(interval.size()).build();
|
||||||
.retain(interval.start)
|
|
||||||
.delete(interval.size())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
while iter.has_next() {
|
while iter.has_next() {
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
|
@ -34,7 +31,7 @@ impl DeleteExt for PreserveLineFormatOnMerge {
|
||||||
//
|
//
|
||||||
match op.get_data().find(NEW_LINE) {
|
match op.get_data().find(NEW_LINE) {
|
||||||
None => {
|
None => {
|
||||||
new_delta.retain(op.len(), Attributes::empty());
|
new_delta.retain(op.len(), plain_attributes());
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
Some(line_break) => {
|
Some(line_break) => {
|
||||||
|
@ -45,7 +42,7 @@ impl DeleteExt for PreserveLineFormatOnMerge {
|
||||||
attributes.extend(newline_op.get_attributes());
|
attributes.extend(newline_op.get_attributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
new_delta.retain(line_break, Attributes::empty());
|
new_delta.retain(line_break, plain_attributes());
|
||||||
new_delta.retain(1, attributes);
|
new_delta.retain(1, attributes);
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
client::util::find_newline,
|
client::util::find_newline,
|
||||||
core::{Attribute, AttributeScope, Attributes, Delta, Operation},
|
core::{plain_attributes, Attribute, AttributeScope, Delta, Operation},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn line_break(op: &Operation, attribute: &Attribute, scope: AttributeScope) -> Delta {
|
pub(crate) fn line_break(op: &Operation, attribute: &Attribute, scope: AttributeScope) -> Delta {
|
||||||
|
@ -13,10 +13,10 @@ pub(crate) fn line_break(op: &Operation, attribute: &Attribute, scope: Attribute
|
||||||
match scope {
|
match scope {
|
||||||
AttributeScope::Inline => {
|
AttributeScope::Inline => {
|
||||||
new_delta.retain(line_break - start, attribute.clone().into());
|
new_delta.retain(line_break - start, attribute.clone().into());
|
||||||
new_delta.retain(1, Attributes::empty());
|
new_delta.retain(1, plain_attributes());
|
||||||
},
|
},
|
||||||
AttributeScope::Block => {
|
AttributeScope::Block => {
|
||||||
new_delta.retain(line_break - start, Attributes::empty());
|
new_delta.retain(line_break - start, plain_attributes());
|
||||||
new_delta.retain(1, attribute.clone().into());
|
new_delta.retain(1, attribute.clone().into());
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -31,7 +31,7 @@ pub(crate) fn line_break(op: &Operation, attribute: &Attribute, scope: Attribute
|
||||||
if start < end {
|
if start < end {
|
||||||
match scope {
|
match scope {
|
||||||
AttributeScope::Inline => new_delta.retain(end - start, attribute.clone().into()),
|
AttributeScope::Inline => new_delta.retain(end - start, attribute.clone().into()),
|
||||||
AttributeScope::Block => new_delta.retain(end - start, Attributes::empty()),
|
AttributeScope::Block => new_delta.retain(end - start, plain_attributes()),
|
||||||
_ => log::error!("Unsupported parser line break for {:?}", scope),
|
_ => log::error!("Unsupported parser line break for {:?}", scope),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
extensions::{format::helper::line_break, FormatExt},
|
extensions::{format::helper::line_break, FormatExt},
|
||||||
util::find_newline,
|
util::find_newline,
|
||||||
},
|
},
|
||||||
core::{Attribute, AttributeScope, Attributes, Delta, DeltaBuilder, DeltaIter, Interval},
|
core::{plain_attributes, Attribute, AttributeScope, Delta, DeltaBuilder, DeltaIter, Interval},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ResolveBlockFormat {}
|
pub struct ResolveBlockFormat {}
|
||||||
|
@ -22,7 +22,7 @@ impl FormatExt for ResolveBlockFormat {
|
||||||
while start < end && iter.has_next() {
|
while start < end && iter.has_next() {
|
||||||
let next_op = iter.next_op_with_len(end - start).unwrap();
|
let next_op = iter.next_op_with_len(end - start).unwrap();
|
||||||
match find_newline(next_op.get_data()) {
|
match find_newline(next_op.get_data()) {
|
||||||
None => new_delta.retain(next_op.len(), Attributes::empty()),
|
None => new_delta.retain(next_op.len(), plain_attributes()),
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
let tmp_delta = line_break(&next_op, attribute, AttributeScope::Block);
|
let tmp_delta = line_break(&next_op, attribute, AttributeScope::Block);
|
||||||
new_delta.extend(tmp_delta);
|
new_delta.extend(tmp_delta);
|
||||||
|
@ -33,14 +33,12 @@ impl FormatExt for ResolveBlockFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
while iter.has_next() {
|
while iter.has_next() {
|
||||||
let op = iter
|
let op = iter.next_op().expect("Unexpected None, iter.has_next() must return op");
|
||||||
.next_op()
|
|
||||||
.expect("Unexpected None, iter.has_next() must return op");
|
|
||||||
|
|
||||||
match find_newline(op.get_data()) {
|
match find_newline(op.get_data()) {
|
||||||
None => new_delta.retain(op.len(), Attributes::empty()),
|
None => new_delta.retain(op.len(), plain_attributes()),
|
||||||
Some(line_break) => {
|
Some(line_break) => {
|
||||||
new_delta.retain(line_break, Attributes::empty());
|
new_delta.retain(line_break, plain_attributes());
|
||||||
new_delta.retain(1, attribute.clone().into());
|
new_delta.retain(1, attribute.clone().into());
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,7 +31,7 @@ impl InsertExt for AutoFormatExt {
|
||||||
});
|
});
|
||||||
|
|
||||||
let next_attributes = match iter.next_op() {
|
let next_attributes = match iter.next_op() {
|
||||||
None => Attributes::empty(),
|
None => plain_attributes(),
|
||||||
Some(op) => op.get_attributes(),
|
Some(op) => op.get_attributes(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ impl InsertExt for AutoFormatExt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::core::{AttributeBuilder, Attributes, DeltaBuilder};
|
use crate::core::{plain_attributes, Attribute, Attributes, DeltaBuilder};
|
||||||
use bytecount::num_chars;
|
use bytecount::num_chars;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -62,7 +62,7 @@ pub enum AutoFormatter {
|
||||||
impl AutoFormatter {
|
impl AutoFormatter {
|
||||||
pub fn to_attributes(&self) -> Attributes {
|
pub fn to_attributes(&self) -> Attributes {
|
||||||
match self {
|
match self {
|
||||||
AutoFormatter::Url(url) => AttributeBuilder::new().link(url.as_str(), true).build(),
|
AutoFormatter::Url(url) => Attribute::Link(url.as_str()).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,28 +18,12 @@ pub struct InsertEmbedsExt {}
|
||||||
impl InsertExt for InsertEmbedsExt {
|
impl InsertExt for InsertEmbedsExt {
|
||||||
fn ext_name(&self) -> &str { "InsertEmbedsExt" }
|
fn ext_name(&self) -> &str { "InsertEmbedsExt" }
|
||||||
|
|
||||||
fn apply(
|
fn apply(&self, _delta: &Delta, _replace_len: usize, _text: &str, _index: usize) -> Option<Delta> { None }
|
||||||
&self,
|
|
||||||
_delta: &Delta,
|
|
||||||
_replace_len: usize,
|
|
||||||
_text: &str,
|
|
||||||
_index: usize,
|
|
||||||
) -> Option<Delta> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ForceNewlineForInsertsAroundEmbedExt {}
|
pub struct ForceNewlineForInsertsAroundEmbedExt {}
|
||||||
impl InsertExt for ForceNewlineForInsertsAroundEmbedExt {
|
impl InsertExt for ForceNewlineForInsertsAroundEmbedExt {
|
||||||
fn ext_name(&self) -> &str { "ForceNewlineForInsertsAroundEmbedExt" }
|
fn ext_name(&self) -> &str { "ForceNewlineForInsertsAroundEmbedExt" }
|
||||||
|
|
||||||
fn apply(
|
fn apply(&self, _delta: &Delta, _replace_len: usize, _text: &str, _index: usize) -> Option<Delta> { None }
|
||||||
&self,
|
|
||||||
_delta: &Delta,
|
|
||||||
_replace_len: usize,
|
|
||||||
_text: &str,
|
|
||||||
_index: usize,
|
|
||||||
) -> Option<Delta> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{extensions::InsertExt, util::is_newline},
|
client::{extensions::InsertExt, util::is_newline},
|
||||||
core::{
|
core::{attributes_except_header, plain_attributes, Attribute, AttributeKey, Attributes, Delta, DeltaBuilder, DeltaIter, NEW_LINE},
|
||||||
attributes_except_header,
|
|
||||||
AttributeKey,
|
|
||||||
Attributes,
|
|
||||||
Delta,
|
|
||||||
DeltaBuilder,
|
|
||||||
DeltaIter,
|
|
||||||
NEW_LINE,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct PreserveBlockFormatOnInsert {}
|
pub struct PreserveBlockFormatOnInsert {}
|
||||||
|
@ -32,14 +24,14 @@ impl InsertExt for PreserveBlockFormatOnInsert {
|
||||||
|
|
||||||
let mut reset_attribute = Attributes::new();
|
let mut reset_attribute = Attributes::new();
|
||||||
if newline_attributes.contains_key(&AttributeKey::Header) {
|
if newline_attributes.contains_key(&AttributeKey::Header) {
|
||||||
reset_attribute.add(AttributeKey::Header.value(""));
|
reset_attribute.add(Attribute::Header(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
let lines: Vec<_> = text.split(NEW_LINE).collect();
|
let lines: Vec<_> = text.split(NEW_LINE).collect();
|
||||||
let mut new_delta = DeltaBuilder::new().retain(index + replace_len).build();
|
let mut new_delta = DeltaBuilder::new().retain(index + replace_len).build();
|
||||||
lines.iter().enumerate().for_each(|(i, line)| {
|
lines.iter().enumerate().for_each(|(i, line)| {
|
||||||
if !line.is_empty() {
|
if !line.is_empty() {
|
||||||
new_delta.insert(line, Attributes::empty());
|
new_delta.insert(line, plain_attributes());
|
||||||
}
|
}
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
@ -51,9 +43,9 @@ impl InsertExt for PreserveBlockFormatOnInsert {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if !reset_attribute.is_empty() {
|
if !reset_attribute.is_empty() {
|
||||||
new_delta.retain(offset, Attributes::empty());
|
new_delta.retain(offset, plain_attributes());
|
||||||
let len = newline_op.get_data().find(NEW_LINE).unwrap();
|
let len = newline_op.get_data().find(NEW_LINE).unwrap();
|
||||||
new_delta.retain(len, Attributes::empty());
|
new_delta.retain(len, plain_attributes());
|
||||||
new_delta.retain(1, reset_attribute.clone());
|
new_delta.retain(1, reset_attribute.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
extensions::InsertExt,
|
extensions::InsertExt,
|
||||||
util::{contain_newline, is_newline},
|
util::{contain_newline, is_newline},
|
||||||
},
|
},
|
||||||
core::{AttributeKey, Attributes, Delta, DeltaBuilder, DeltaIter, OpNewline, NEW_LINE},
|
core::{plain_attributes, AttributeKey, Delta, DeltaBuilder, DeltaIter, OpNewline, NEW_LINE},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct PreserveInlineFormat {}
|
pub struct PreserveInlineFormat {}
|
||||||
|
@ -33,10 +33,10 @@ impl InsertExt for PreserveInlineFormat {
|
||||||
|
|
||||||
let next = iter.next_op();
|
let next = iter.next_op();
|
||||||
match &next {
|
match &next {
|
||||||
None => attributes = Attributes::empty(),
|
None => attributes = plain_attributes(),
|
||||||
Some(next) => {
|
Some(next) => {
|
||||||
if OpNewline::parse(&next).is_equal() {
|
if OpNewline::parse(&next).is_equal() {
|
||||||
attributes = Attributes::empty();
|
attributes = plain_attributes();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -72,11 +72,11 @@ impl InsertExt for PreserveLineFormatOnSplit {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut new_delta = Delta::new();
|
let mut new_delta = Delta::new();
|
||||||
new_delta.retain(index + replace_len, Attributes::empty());
|
new_delta.retain(index + replace_len, plain_attributes());
|
||||||
|
|
||||||
if newline_status.is_contain() {
|
if newline_status.is_contain() {
|
||||||
debug_assert!(next.has_attribute() == false);
|
debug_assert!(next.has_attribute() == false);
|
||||||
new_delta.insert(NEW_LINE, Attributes::empty());
|
new_delta.insert(NEW_LINE, plain_attributes());
|
||||||
return Some(new_delta);
|
return Some(new_delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ impl InsertExt for ResetLineFormatOnNewLine {
|
||||||
|
|
||||||
let mut reset_attribute = Attributes::new();
|
let mut reset_attribute = Attributes::new();
|
||||||
if next_op.get_attributes().contains_key(&AttributeKey::Header) {
|
if next_op.get_attributes().contains_key(&AttributeKey::Header) {
|
||||||
reset_attribute.add(AttributeKey::Header.value(""));
|
reset_attribute.mark_as_removed(&AttributeKey::Header);
|
||||||
}
|
}
|
||||||
|
|
||||||
let len = index + replace_len;
|
let len = index + replace_len;
|
||||||
|
|
|
@ -22,12 +22,7 @@ pub struct UndoResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UndoResult {
|
impl UndoResult {
|
||||||
pub fn fail() -> Self {
|
pub fn fail() -> Self { UndoResult { success: false, len: 0 } }
|
||||||
UndoResult {
|
|
||||||
success: false,
|
|
||||||
len: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn success(len: usize) -> Self { UndoResult { success: true, len } }
|
pub fn success(len: usize) -> Self { UndoResult { success: true, len } }
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,7 @@ impl View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert(
|
pub(crate) fn insert(&self, delta: &Delta, text: &str, interval: Interval) -> Result<Delta, OTError> {
|
||||||
&self,
|
|
||||||
delta: &Delta,
|
|
||||||
text: &str,
|
|
||||||
interval: Interval,
|
|
||||||
) -> Result<Delta, OTError> {
|
|
||||||
let mut new_delta = None;
|
let mut new_delta = None;
|
||||||
for ext in &self.insert_exts {
|
for ext in &self.insert_exts {
|
||||||
if let Some(delta) = ext.apply(delta, interval.size(), text, interval.start) {
|
if let Some(delta) = ext.apply(delta, interval.size(), text, interval.start) {
|
||||||
|
@ -58,12 +53,7 @@ impl View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn format(
|
pub(crate) fn format(&self, delta: &Delta, attribute: Attribute, interval: Interval) -> Result<Delta, OTError> {
|
||||||
&self,
|
|
||||||
delta: &Delta,
|
|
||||||
attribute: Attribute,
|
|
||||||
interval: Interval,
|
|
||||||
) -> Result<Delta, OTError> {
|
|
||||||
let mut new_delta = None;
|
let mut new_delta = None;
|
||||||
for ext in &self.format_exts {
|
for ext in &self.format_exts {
|
||||||
if let Some(delta) = ext.apply(delta, interval, &attribute) {
|
if let Some(delta) = ext.apply(delta, interval, &attribute) {
|
||||||
|
@ -102,9 +92,4 @@ fn construct_format_exts() -> Vec<FormatExtension> {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_delete_exts() -> Vec<DeleteExtension> {
|
fn construct_delete_exts() -> Vec<DeleteExtension> { vec![Box::new(PreserveLineFormatOnMerge {}), Box::new(DefaultDelete {})] }
|
||||||
vec![
|
|
||||||
Box::new(PreserveLineFormatOnMerge {}),
|
|
||||||
Box::new(DefaultDelete {}),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(non_snake_case)]
|
||||||
use crate::core::{Attributes, REMOVE_FLAG};
|
use crate::core::{Attributes, REMOVE_FLAG};
|
||||||
use derive_more::Display;
|
use derive_more::Display;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
@ -31,8 +32,7 @@ lazy_static! {
|
||||||
AttributeKey::Size,
|
AttributeKey::Size,
|
||||||
AttributeKey::Background,
|
AttributeKey::Background,
|
||||||
]);
|
]);
|
||||||
static ref INGORE_KEYS: HashSet<AttributeKey> =
|
static ref INGORE_KEYS: HashSet<AttributeKey> = HashSet::from_iter(vec![AttributeKey::Width, AttributeKey::Height,]);
|
||||||
HashSet::from_iter(vec![AttributeKey::Width, AttributeKey::Height,]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
@ -43,6 +43,51 @@ pub enum AttributeScope {
|
||||||
Ignore,
|
Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! inline_attribute {
|
||||||
|
(
|
||||||
|
$key: ident,
|
||||||
|
$value: ty
|
||||||
|
) => {
|
||||||
|
pub fn $key(value: $value) -> Self {
|
||||||
|
Self {
|
||||||
|
key: AttributeKey::$key,
|
||||||
|
value: value.into(),
|
||||||
|
scope: AttributeScope::Inline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! block_attribute {
|
||||||
|
(
|
||||||
|
$key: ident,
|
||||||
|
$value: ident
|
||||||
|
) => {
|
||||||
|
pub fn $key(value: $value) -> Self {
|
||||||
|
Self {
|
||||||
|
key: AttributeKey::$key,
|
||||||
|
value: value.into(),
|
||||||
|
scope: AttributeScope::Block,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ignore_attribute {
|
||||||
|
(
|
||||||
|
$key: ident,
|
||||||
|
$value: ident
|
||||||
|
) => {
|
||||||
|
pub fn $key(value: $value) -> Self {
|
||||||
|
Self {
|
||||||
|
key: AttributeKey::$key,
|
||||||
|
value: value.into(),
|
||||||
|
scope: AttributeScope::Ignore,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Attribute {
|
pub struct Attribute {
|
||||||
pub key: AttributeKey,
|
pub key: AttributeKey,
|
||||||
|
@ -50,6 +95,36 @@ pub struct Attribute {
|
||||||
pub scope: AttributeScope,
|
pub scope: AttributeScope,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Attribute {
|
||||||
|
inline_attribute!(Bold, bool);
|
||||||
|
inline_attribute!(Italic, bool);
|
||||||
|
inline_attribute!(Underline, bool);
|
||||||
|
inline_attribute!(StrikeThrough, bool);
|
||||||
|
inline_attribute!(Link, &str);
|
||||||
|
inline_attribute!(Color, String);
|
||||||
|
inline_attribute!(Font, usize);
|
||||||
|
inline_attribute!(Size, usize);
|
||||||
|
inline_attribute!(Background, String);
|
||||||
|
|
||||||
|
block_attribute!(Header, usize);
|
||||||
|
block_attribute!(LeftAlignment, usize);
|
||||||
|
block_attribute!(CenterAlignment, usize);
|
||||||
|
block_attribute!(RightAlignment, usize);
|
||||||
|
block_attribute!(JustifyAlignment, bool);
|
||||||
|
block_attribute!(Indent, String);
|
||||||
|
block_attribute!(Align, String);
|
||||||
|
block_attribute!(CodeBlock, String);
|
||||||
|
block_attribute!(List, String);
|
||||||
|
block_attribute!(Bullet, bool);
|
||||||
|
block_attribute!(Ordered, bool);
|
||||||
|
block_attribute!(Checked, bool);
|
||||||
|
block_attribute!(UnChecked, bool);
|
||||||
|
block_attribute!(QuoteBlock, bool);
|
||||||
|
|
||||||
|
ignore_attribute!(Width, usize);
|
||||||
|
ignore_attribute!(Height, usize);
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Attribute {
|
impl fmt::Display for Attribute {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
let s = format!("{:?}:{} {:?}", self.key, self.value.as_ref(), self.scope);
|
let s = format!("{:?}:{} {:?}", self.key, self.value.as_ref(), self.scope);
|
||||||
|
@ -120,91 +195,6 @@ pub enum AttributeKey {
|
||||||
UnChecked,
|
UnChecked,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttributeKey {
|
|
||||||
pub fn remove(&self) -> Attribute { self.value(REMOVE_FLAG) }
|
|
||||||
|
|
||||||
pub fn value<T: Into<AttributeValue>>(&self, value: T) -> Attribute {
|
|
||||||
let key = self.clone();
|
|
||||||
let value: AttributeValue = value.into();
|
|
||||||
debug_assert_eq!(self.check_value(&value), true);
|
|
||||||
|
|
||||||
if INLINE_KEYS.contains(self) {
|
|
||||||
return Attribute {
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
scope: AttributeScope::Inline,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if BLOCK_KEYS.contains(self) {
|
|
||||||
return Attribute {
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
scope: AttributeScope::Block,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Attribute {
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
scope: AttributeScope::Ignore,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_value(&self, value: &AttributeValue) -> bool {
|
|
||||||
if value.0.is_empty() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self {
|
|
||||||
AttributeKey::Bold
|
|
||||||
| AttributeKey::Italic
|
|
||||||
| AttributeKey::Underline
|
|
||||||
| AttributeKey::StrikeThrough
|
|
||||||
| AttributeKey::Indent
|
|
||||||
| AttributeKey::Align
|
|
||||||
| AttributeKey::CodeBlock
|
|
||||||
| AttributeKey::List
|
|
||||||
| AttributeKey::QuoteBlock
|
|
||||||
| AttributeKey::JustifyAlignment
|
|
||||||
| AttributeKey::Bullet
|
|
||||||
| AttributeKey::Ordered
|
|
||||||
| AttributeKey::Checked
|
|
||||||
| AttributeKey::UnChecked => {
|
|
||||||
if let Err(e) = value.0.parse::<bool>() {
|
|
||||||
log::error!(
|
|
||||||
"Parser failed: {:?}. expected bool, but receive {}",
|
|
||||||
e,
|
|
||||||
value.0
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
AttributeKey::Link | AttributeKey::Color | AttributeKey::Background => {},
|
|
||||||
|
|
||||||
AttributeKey::Header
|
|
||||||
| AttributeKey::Width
|
|
||||||
| AttributeKey::Height
|
|
||||||
| AttributeKey::Font
|
|
||||||
| AttributeKey::Size
|
|
||||||
| AttributeKey::LeftAlignment
|
|
||||||
| AttributeKey::CenterAlignment
|
|
||||||
| AttributeKey::RightAlignment => {
|
|
||||||
if let Err(e) = value.0.parse::<usize>() {
|
|
||||||
log::error!(
|
|
||||||
"Parser failed: {:?}. expected usize, but receive {}",
|
|
||||||
e,
|
|
||||||
value.0
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct AttributeValue(pub(crate) String);
|
pub struct AttributeValue(pub(crate) String);
|
||||||
|
|
||||||
|
@ -213,13 +203,33 @@ impl AsRef<str> for AttributeValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<&usize> for AttributeValue {
|
impl std::convert::From<&usize> for AttributeValue {
|
||||||
fn from(val: &usize) -> Self { AttributeValue(format!("{}", val)) }
|
fn from(val: &usize) -> Self {
|
||||||
|
if *val > (0 as usize) {
|
||||||
|
AttributeValue(format!("{}", val))
|
||||||
|
} else {
|
||||||
|
AttributeValue(format!(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<usize> for AttributeValue {
|
||||||
|
fn from(val: usize) -> Self {
|
||||||
|
if val > (0 as usize) {
|
||||||
|
AttributeValue(format!("{}", val))
|
||||||
|
} else {
|
||||||
|
AttributeValue(format!(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<&str> for AttributeValue {
|
impl std::convert::From<&str> for AttributeValue {
|
||||||
fn from(val: &str) -> Self { AttributeValue(val.to_owned()) }
|
fn from(val: &str) -> Self { AttributeValue(val.to_owned()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<String> for AttributeValue {
|
||||||
|
fn from(val: String) -> Self { AttributeValue(val) }
|
||||||
|
}
|
||||||
|
|
||||||
impl std::convert::From<bool> for AttributeValue {
|
impl std::convert::From<bool> for AttributeValue {
|
||||||
fn from(val: bool) -> Self {
|
fn from(val: bool) -> Self {
|
||||||
let val = match val {
|
let val = match val {
|
||||||
|
|
|
@ -4,36 +4,34 @@ use std::{collections::HashMap, fmt};
|
||||||
pub const REMOVE_FLAG: &'static str = "";
|
pub const REMOVE_FLAG: &'static str = "";
|
||||||
pub(crate) fn should_remove(val: &AttributeValue) -> bool { val.0 == REMOVE_FLAG }
|
pub(crate) fn should_remove(val: &AttributeValue) -> bool { val.0 == REMOVE_FLAG }
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Attributes {
|
pub struct Attributes {
|
||||||
#[serde(skip_serializing_if = "HashMap::is_empty")]
|
#[serde(skip_serializing_if = "HashMap::is_empty")]
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub(crate) inner: HashMap<AttributeKey, AttributeValue>,
|
pub(crate) inner: HashMap<AttributeKey, AttributeValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Attributes {
|
impl std::default::Default for Attributes {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn default() -> Self {
|
||||||
f.write_fmt(format_args!("{:?}", self.inner))
|
Self {
|
||||||
|
inner: HashMap::with_capacity(0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attributes {
|
impl fmt::Display for Attributes {
|
||||||
pub fn new() -> Self {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{:?}", self.inner)) }
|
||||||
Attributes {
|
}
|
||||||
inner: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn empty() -> Self { Self::default() }
|
pub fn plain_attributes() -> Attributes { Attributes::default() }
|
||||||
|
|
||||||
|
impl Attributes {
|
||||||
|
pub fn new() -> Self { Attributes { inner: HashMap::new() } }
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool { self.inner.is_empty() }
|
pub fn is_empty(&self) -> bool { self.inner.is_empty() }
|
||||||
|
|
||||||
pub fn add(&mut self, attribute: Attribute) {
|
pub fn add(&mut self, attribute: Attribute) {
|
||||||
let Attribute {
|
let Attribute { key, value, scope: _ } = attribute;
|
||||||
key,
|
|
||||||
value,
|
|
||||||
scope: _,
|
|
||||||
} = attribute;
|
|
||||||
self.inner.insert(key, value);
|
self.inner.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,9 +43,7 @@ impl Attributes {
|
||||||
pub fn mark_all_as_removed_except(&mut self, attribute: Option<AttributeKey>) {
|
pub fn mark_all_as_removed_except(&mut self, attribute: Option<AttributeKey>) {
|
||||||
match attribute {
|
match attribute {
|
||||||
None => {
|
None => {
|
||||||
self.inner
|
self.inner.iter_mut().for_each(|(_k, v)| v.0 = REMOVE_FLAG.into());
|
||||||
.iter_mut()
|
|
||||||
.for_each(|(_k, v)| v.0 = REMOVE_FLAG.into());
|
|
||||||
},
|
},
|
||||||
Some(attribute) => {
|
Some(attribute) => {
|
||||||
self.inner.iter_mut().for_each(|(k, v)| {
|
self.inner.iter_mut().for_each(|(k, v)| {
|
||||||
|
@ -153,24 +149,21 @@ pub fn transform_operation(left: &Option<Operation>, right: &Option<Operation>)
|
||||||
|
|
||||||
let left = attr_l.unwrap();
|
let left = attr_l.unwrap();
|
||||||
let right = attr_r.unwrap();
|
let right = attr_r.unwrap();
|
||||||
left.iter()
|
left.iter().fold(Attributes::new(), |mut new_attributes, (k, v)| {
|
||||||
.fold(Attributes::new(), |mut new_attributes, (k, v)| {
|
if !right.contains_key(k) {
|
||||||
if !right.contains_key(k) {
|
new_attributes.insert(k.clone(), v.clone());
|
||||||
new_attributes.insert(k.clone(), v.clone());
|
}
|
||||||
}
|
new_attributes
|
||||||
new_attributes
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invert_attributes(attr: Attributes, base: Attributes) -> Attributes {
|
pub fn invert_attributes(attr: Attributes, base: Attributes) -> Attributes {
|
||||||
let base_inverted = base
|
let base_inverted = base.iter().fold(Attributes::new(), |mut attributes, (k, v)| {
|
||||||
.iter()
|
if base.get(k) != attr.get(k) && attr.contains_key(k) {
|
||||||
.fold(Attributes::new(), |mut attributes, (k, v)| {
|
attributes.insert(k.clone(), v.clone());
|
||||||
if base.get(k) != attr.get(k) && attr.contains_key(k) {
|
}
|
||||||
attributes.insert(k.clone(), v.clone());
|
attributes
|
||||||
}
|
});
|
||||||
attributes
|
|
||||||
});
|
|
||||||
|
|
||||||
let inverted = attr.iter().fold(base_inverted, |mut attributes, (k, _)| {
|
let inverted = attr.iter().fold(base_inverted, |mut attributes, (k, _)| {
|
||||||
if base.get(k) != attr.get(k) && !base.contains_key(k) {
|
if base.get(k) != attr.get(k) && !base.contains_key(k) {
|
||||||
|
|
|
@ -21,9 +21,7 @@ impl<'de> Deserialize<'de> for AttributeValue {
|
||||||
impl<'de> Visitor<'de> for OperationSeqVisitor {
|
impl<'de> Visitor<'de> for OperationSeqVisitor {
|
||||||
type Value = AttributeValue;
|
type Value = AttributeValue;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a string") }
|
||||||
formatter.write_str("a string")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,33 +1,9 @@
|
||||||
use crate::core::{Attribute, AttributeKey, AttributeValue, Attributes, REMOVE_FLAG};
|
#![allow(non_snake_case)]
|
||||||
|
use crate::core::{Attribute, Attributes};
|
||||||
pub struct AttributeBuilder {
|
pub struct AttributeBuilder {
|
||||||
inner: Attributes,
|
inner: Attributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_bool_attribute {
|
|
||||||
($name: ident,$key: expr) => {
|
|
||||||
pub fn $name(self, value: bool) -> Self {
|
|
||||||
let value = match value {
|
|
||||||
true => "true",
|
|
||||||
false => REMOVE_FLAG,
|
|
||||||
};
|
|
||||||
self.insert($key, value)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_str_attribute {
|
|
||||||
($name: ident,$key: expr) => {
|
|
||||||
pub fn $name(self, s: &str, value: bool) -> Self {
|
|
||||||
let value = match value {
|
|
||||||
true => s,
|
|
||||||
false => REMOVE_FLAG,
|
|
||||||
};
|
|
||||||
self.insert($key, value)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AttributeBuilder {
|
impl AttributeBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -40,23 +16,5 @@ impl AttributeBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert<T: Into<AttributeValue>>(mut self, key: AttributeKey, value: T) -> Self {
|
|
||||||
self.inner.add(key.value(value));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove<T: Into<String>>(mut self, key: AttributeKey) -> Self {
|
|
||||||
self.inner.add(key.value(REMOVE_FLAG));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// AttributeBuilder::new().bold(true).build()
|
|
||||||
impl_bool_attribute!(bold, AttributeKey::Bold);
|
|
||||||
impl_bool_attribute!(italic, AttributeKey::Italic);
|
|
||||||
impl_bool_attribute!(underline, AttributeKey::Underline);
|
|
||||||
impl_bool_attribute!(strike_through, AttributeKey::StrikeThrough);
|
|
||||||
impl_str_attribute!(link, AttributeKey::Link);
|
|
||||||
// impl_str_attribute!(header, AttributeKey::Header);
|
|
||||||
|
|
||||||
pub fn build(self) -> Attributes { self.inner }
|
pub fn build(self) -> Attributes { self.inner }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
use crate::core::{Attributes, Delta, Operation};
|
use crate::core::{plain_attributes, Attributes, Delta, Operation};
|
||||||
|
|
||||||
pub struct DeltaBuilder {
|
pub struct DeltaBuilder {
|
||||||
delta: Delta,
|
delta: Delta,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeltaBuilder {
|
impl DeltaBuilder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Self { delta: Delta::new() } }
|
||||||
Self {
|
|
||||||
delta: Delta::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retain_with_attributes(mut self, n: usize, attrs: Attributes) -> Self {
|
pub fn retain_with_attributes(mut self, n: usize, attrs: Attributes) -> Self {
|
||||||
self.delta.retain(n, attrs);
|
self.delta.retain(n, attrs);
|
||||||
|
@ -17,7 +13,7 @@ impl DeltaBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retain(mut self, n: usize) -> Self {
|
pub fn retain(mut self, n: usize) -> Self {
|
||||||
self.delta.retain(n, Attributes::empty());
|
self.delta.retain(n, plain_attributes());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +28,7 @@ impl DeltaBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(mut self, s: &str) -> Self {
|
pub fn insert(mut self, s: &str) -> Self {
|
||||||
self.delta.insert(s, Attributes::empty());
|
self.delta.insert(s, plain_attributes());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,7 @@ impl<'a> OpCursor<'a> {
|
||||||
let mut consume_len = 0;
|
let mut consume_len = 0;
|
||||||
while find_op.is_none() && next_op.is_some() {
|
while find_op.is_none() && next_op.is_some() {
|
||||||
let op = next_op.take().unwrap();
|
let op = next_op.take().unwrap();
|
||||||
let interval = self
|
let interval = self.next_iv_before(force_end).unwrap_or(Interval::new(0, 0));
|
||||||
.next_iv_before(force_end)
|
|
||||||
.unwrap_or(Interval::new(0, 0));
|
|
||||||
|
|
||||||
// cache the op if the interval is empty. e.g. last_op_before(Some(0))
|
// cache the op if the interval is empty. e.g. last_op_before(Some(0))
|
||||||
if interval.is_empty() {
|
if interval.is_empty() {
|
||||||
|
@ -188,9 +186,7 @@ fn check_bound(current: usize, target: usize) -> Result<(), OTError> {
|
||||||
debug_assert!(current <= target);
|
debug_assert!(current <= target);
|
||||||
if current > target {
|
if current > target {
|
||||||
let msg = format!("{} should be greater than current: {}", target, current);
|
let msg = format!("{} should be greater than current: {}", target, current);
|
||||||
return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength)
|
return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength).msg(&msg).build());
|
||||||
.msg(&msg)
|
|
||||||
.build());
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl Delta {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, s: &str, attrs: Attributes) {
|
pub fn insert(&mut self, s: &str, attributes: Attributes) {
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -111,18 +111,18 @@ impl Delta {
|
||||||
let new_last = match self.ops.as_mut_slice() {
|
let new_last = match self.ops.as_mut_slice() {
|
||||||
[.., Operation::Insert(insert)] => {
|
[.., Operation::Insert(insert)] => {
|
||||||
//
|
//
|
||||||
insert.merge_or_new_op(s, attrs)
|
insert.merge_or_new_op(s, attributes)
|
||||||
},
|
},
|
||||||
[.., Operation::Insert(pre_insert), Operation::Delete(_)] => {
|
[.., Operation::Insert(pre_insert), Operation::Delete(_)] => {
|
||||||
//
|
//
|
||||||
pre_insert.merge_or_new_op(s, attrs)
|
pre_insert.merge_or_new_op(s, attributes)
|
||||||
},
|
},
|
||||||
[.., op_last @ Operation::Delete(_)] => {
|
[.., op_last @ Operation::Delete(_)] => {
|
||||||
let new_last = op_last.clone();
|
let new_last = op_last.clone();
|
||||||
*op_last = OpBuilder::insert(s).attributes(attrs).build();
|
*op_last = OpBuilder::insert(s).attributes(attributes).build();
|
||||||
Some(new_last)
|
Some(new_last)
|
||||||
},
|
},
|
||||||
_ => Some(OpBuilder::insert(s).attributes(attrs).build()),
|
_ => Some(OpBuilder::insert(s).attributes(attributes).build()),
|
||||||
};
|
};
|
||||||
|
|
||||||
match new_last {
|
match new_last {
|
||||||
|
@ -131,7 +131,7 @@ impl Delta {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retain(&mut self, n: usize, attrs: Attributes) {
|
pub fn retain(&mut self, n: usize, attributes: Attributes) {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -139,11 +139,11 @@ impl Delta {
|
||||||
self.target_len += n as usize;
|
self.target_len += n as usize;
|
||||||
|
|
||||||
if let Some(Operation::Retain(retain)) = self.ops.last_mut() {
|
if let Some(Operation::Retain(retain)) = self.ops.last_mut() {
|
||||||
if let Some(new_op) = retain.merge_or_new_op(n, attrs) {
|
if let Some(new_op) = retain.merge_or_new(n, attributes) {
|
||||||
self.ops.push(new_op);
|
self.ops.push(new_op);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.ops.push(OpBuilder::retain(n).attributes(attrs).build());
|
self.ops.push(OpBuilder::retain(n).attributes(attributes).build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,7 @@ impl<'de> Deserialize<'de> for Delta {
|
||||||
impl<'de> Visitor<'de> for OperationSeqVisitor {
|
impl<'de> Visitor<'de> for OperationSeqVisitor {
|
||||||
type Value = Delta;
|
type Value = Delta;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence") }
|
||||||
formatter.write_str("a sequence")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
where
|
where
|
||||||
|
|
|
@ -39,9 +39,7 @@ impl<'a> DeltaIter<'a> {
|
||||||
|
|
||||||
pub fn next_op(&mut self) -> Option<Operation> { self.cursor.next() }
|
pub fn next_op(&mut self) -> Option<Operation> { self.cursor.next() }
|
||||||
|
|
||||||
pub fn next_op_with_len(&mut self, len: usize) -> Option<Operation> {
|
pub fn next_op_with_len(&mut self, len: usize) -> Option<Operation> { self.cursor.next_with_len(Some(len)) }
|
||||||
self.cursor.next_with_len(Some(len))
|
|
||||||
}
|
|
||||||
|
|
||||||
// find next op contains NEW_LINE
|
// find next op contains NEW_LINE
|
||||||
pub fn next_op_with_newline(&mut self) -> Option<(Operation, usize)> {
|
pub fn next_op_with_newline(&mut self) -> Option<(Operation, usize)> {
|
||||||
|
@ -210,9 +208,7 @@ impl OpNewline {
|
||||||
|
|
||||||
pub fn is_not_found(&self) -> bool { self == &OpNewline::NotFound }
|
pub fn is_not_found(&self) -> bool { self == &OpNewline::NotFound }
|
||||||
|
|
||||||
pub fn is_contain(&self) -> bool {
|
pub fn is_contain(&self) -> bool { self.is_start() || self.is_end() || self.is_equal() || self == &OpNewline::Contain }
|
||||||
self.is_start() || self.is_end() || self.is_equal() || self == &OpNewline::Contain
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_equal(&self) -> bool { self == &OpNewline::Equal }
|
pub fn is_equal(&self) -> bool { self == &OpNewline::Equal }
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,7 @@ impl Interval {
|
||||||
|
|
||||||
pub fn contains(&self, val: usize) -> bool { self.start <= val && val < self.end }
|
pub fn contains(&self, val: usize) -> bool { self.start <= val && val < self.end }
|
||||||
|
|
||||||
pub fn contains_range(&self, start: usize, end: usize) -> bool {
|
pub fn contains_range(&self, start: usize, end: usize) -> bool { !self.intersect(Interval::new(start, end)).is_empty() }
|
||||||
!self.intersect(Interval::new(start, end)).is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_after(&self, val: usize) -> bool { self.start > val }
|
pub fn is_after(&self, val: usize) -> bool { self.start > val }
|
||||||
|
|
||||||
|
@ -101,9 +99,7 @@ impl std::default::Default for Interval {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Interval {
|
impl fmt::Display for Interval {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{}, {})", self.start(), self.end()) }
|
||||||
write!(f, "[{}, {})", self.start(), self.end())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Interval {
|
impl fmt::Debug for Interval {
|
||||||
|
@ -122,15 +118,11 @@ impl From<RangeTo<usize>> for Interval {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RangeInclusive<usize>> for Interval {
|
impl From<RangeInclusive<usize>> for Interval {
|
||||||
fn from(src: RangeInclusive<usize>) -> Interval {
|
fn from(src: RangeInclusive<usize>) -> Interval { Interval::new(*src.start(), src.end().saturating_add(1)) }
|
||||||
Interval::new(*src.start(), src.end().saturating_add(1))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RangeToInclusive<usize>> for Interval {
|
impl From<RangeToInclusive<usize>> for Interval {
|
||||||
fn from(src: RangeToInclusive<usize>) -> Interval {
|
fn from(src: RangeToInclusive<usize>) -> Interval { Interval::new(0, src.end.saturating_add(1)) }
|
||||||
Interval::new(0, src.end.saturating_add(1))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -186,29 +178,18 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn intersect() {
|
fn intersect() {
|
||||||
assert_eq!(
|
assert_eq!(Interval::new(2, 3), Interval::new(1, 3).intersect(Interval::new(2, 4)));
|
||||||
Interval::new(2, 3),
|
assert!(Interval::new(1, 2).intersect(Interval::new(2, 43)).is_empty());
|
||||||
Interval::new(1, 3).intersect(Interval::new(2, 4))
|
|
||||||
);
|
|
||||||
assert!(Interval::new(1, 2)
|
|
||||||
.intersect(Interval::new(2, 43))
|
|
||||||
.is_empty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prefix() {
|
fn prefix() {
|
||||||
assert_eq!(
|
assert_eq!(Interval::new(1, 2), Interval::new(1, 4).prefix(Interval::new(2, 3)));
|
||||||
Interval::new(1, 2),
|
|
||||||
Interval::new(1, 4).prefix(Interval::new(2, 3))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn suffix() {
|
fn suffix() {
|
||||||
assert_eq!(
|
assert_eq!(Interval::new(3, 4), Interval::new(1, 4).suffix(Interval::new(2, 3)));
|
||||||
Interval::new(3, 4),
|
|
||||||
Interval::new(1, 4).suffix(Interval::new(2, 3))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -42,9 +42,7 @@ impl Operation {
|
||||||
|
|
||||||
pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() }
|
pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() }
|
||||||
|
|
||||||
pub fn contain_attribute(&self, attribute: &Attribute) -> bool {
|
pub fn contain_attribute(&self, attribute: &Attribute) -> bool { self.get_attributes().contains_key(&attribute.key) }
|
||||||
self.get_attributes().contains_key(&attribute.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
|
@ -72,11 +70,7 @@ impl Operation {
|
||||||
},
|
},
|
||||||
Operation::Insert(insert) => {
|
Operation::Insert(insert) => {
|
||||||
let attributes = self.get_attributes();
|
let attributes = self.get_attributes();
|
||||||
left = Some(
|
left = Some(OpBuilder::insert(&insert.s[0..index]).attributes(attributes.clone()).build());
|
||||||
OpBuilder::insert(&insert.s[0..index])
|
|
||||||
.attributes(attributes.clone())
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
right = Some(
|
right = Some(
|
||||||
OpBuilder::insert(&insert.s[index..insert.num_chars()])
|
OpBuilder::insert(&insert.s[index..insert.num_chars()])
|
||||||
.attributes(attributes)
|
.attributes(attributes)
|
||||||
|
@ -99,13 +93,9 @@ impl Operation {
|
||||||
OpBuilder::insert("").build()
|
OpBuilder::insert("").build()
|
||||||
} else {
|
} else {
|
||||||
let chars = insert.chars().skip(interval.start);
|
let chars = insert.chars().skip(interval.start);
|
||||||
let s = &chars
|
let s = &chars.take(min(interval.size(), insert.num_chars())).collect::<String>();
|
||||||
.take(min(interval.size(), insert.num_chars()))
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
OpBuilder::insert(s)
|
OpBuilder::insert(s).attributes(insert.attributes.clone()).build()
|
||||||
.attributes(insert.attributes.clone())
|
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -166,22 +156,12 @@ pub struct Retain {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Retain {
|
impl fmt::Display for Retain {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("retain: {}, attributes: {}", self.n, self.attributes)) }
|
||||||
f.write_fmt(format_args!(
|
|
||||||
"retain: {}, attributes: {}",
|
|
||||||
self.n, self.attributes
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Retain {
|
impl Retain {
|
||||||
pub fn merge_or_new_op(&mut self, n: usize, attributes: Attributes) -> Option<Operation> {
|
pub fn merge_or_new(&mut self, n: usize, attributes: Attributes) -> Option<Operation> {
|
||||||
log::debug!(
|
log::debug!("merge_retain_or_new_op: len: {:?}, l: {} - r: {}", n, self.attributes, attributes);
|
||||||
"merge_retain_or_new_op: len: {:?}, l: {} - r: {}",
|
|
||||||
n,
|
|
||||||
self.attributes,
|
|
||||||
attributes
|
|
||||||
);
|
|
||||||
|
|
||||||
if self.attributes == attributes {
|
if self.attributes == attributes {
|
||||||
self.n += n;
|
self.n += n;
|
||||||
|
@ -232,10 +212,7 @@ impl fmt::Display for Insert {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write_fmt(format_args!(
|
f.write_fmt(format_args!("insert: {}, attributes: {}", s, self.attributes))
|
||||||
"insert: {}, attributes: {}",
|
|
||||||
s, self.attributes
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,7 @@ pub struct OTError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OTError {
|
impl OTError {
|
||||||
pub fn new(code: OTErrorCode, msg: &str) -> OTError {
|
pub fn new(code: OTErrorCode, msg: &str) -> OTError { Self { code, msg: msg.to_owned() } }
|
||||||
Self {
|
|
||||||
code,
|
|
||||||
msg: msg.to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for OTError {
|
impl fmt::Display for OTError {
|
||||||
|
@ -24,11 +19,7 @@ impl Error for OTError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<serde_json::Error> for OTError {
|
impl std::convert::From<serde_json::Error> for OTError {
|
||||||
fn from(error: serde_json::Error) -> Self {
|
fn from(error: serde_json::Error) -> Self { ErrorBuilder::new(OTErrorCode::SerdeError).error(error).build() }
|
||||||
ErrorBuilder::new(OTErrorCode::SerdeError)
|
|
||||||
.error(error)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -68,7 +59,5 @@ impl ErrorBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(mut self) -> OTError {
|
pub fn build(mut self) -> OTError { OTError::new(self.code, &self.msg.take().unwrap_or("".to_owned())) }
|
||||||
OTError::new(self.code, &self.msg.take().unwrap_or("".to_owned()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,7 @@ fn attributes_bold_added_and_invert_partial_suffix() {
|
||||||
Bold(0, Interval::new(0, 4), true),
|
Bold(0, Interval::new(0, 4), true),
|
||||||
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
||||||
Bold(0, Interval::new(2, 4), false),
|
Bold(0, Interval::new(2, 4), false),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
OpTester::new().run_script(ops);
|
OpTester::new().run_script(ops);
|
||||||
}
|
}
|
||||||
|
@ -54,10 +51,7 @@ fn attributes_bold_added_and_invert_partial_suffix2() {
|
||||||
Bold(0, Interval::new(0, 4), true),
|
Bold(0, Interval::new(0, 4), true),
|
||||||
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
||||||
Bold(0, Interval::new(2, 4), false),
|
Bold(0, Interval::new(2, 4), false),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#,
|
|
||||||
),
|
|
||||||
Bold(0, Interval::new(2, 4), true),
|
Bold(0, Interval::new(2, 4), true),
|
||||||
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
||||||
];
|
];
|
||||||
|
@ -69,10 +63,7 @@ fn attributes_bold_added_with_new_line() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Bold(0, Interval::new(0, 6), true),
|
Bold(0, Interval::new(0, 6), true),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}},{"insert":"\n"}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"123456","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
|
|
||||||
),
|
|
||||||
Insert(0, "\n", 3),
|
Insert(0, "\n", 3),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -99,10 +90,7 @@ fn attributes_bold_added_and_invert_partial_prefix() {
|
||||||
Bold(0, Interval::new(0, 4), true),
|
Bold(0, Interval::new(0, 4), true),
|
||||||
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
|
||||||
Bold(0, Interval::new(0, 2), false),
|
Bold(0, Interval::new(0, 2), false),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"12"},{"insert":"34","attributes":{"bold":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"12"},{"insert":"34","attributes":{"bold":"true"}}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
OpTester::new().run_script(ops);
|
OpTester::new().run_script(ops);
|
||||||
}
|
}
|
||||||
|
@ -112,15 +100,9 @@ fn attributes_bold_added_consecutive() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "1234", 0),
|
Insert(0, "1234", 0),
|
||||||
Bold(0, Interval::new(0, 1), true),
|
Bold(0, Interval::new(0, 1), true),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"1","attributes":{"bold":"true"}},{"insert":"234"}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"1","attributes":{"bold":"true"}},{"insert":"234"}]"#,
|
|
||||||
),
|
|
||||||
Bold(0, Interval::new(1, 2), true),
|
Bold(0, Interval::new(1, 2), true),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
OpTester::new().run_script(ops);
|
OpTester::new().run_script(ops);
|
||||||
}
|
}
|
||||||
|
@ -239,10 +221,7 @@ fn attributes_bold_added_italic_delete() {
|
||||||
"#,
|
"#,
|
||||||
),
|
),
|
||||||
Delete(0, Interval::new(0, 5)),
|
Delete(0, Interval::new(0, 5)),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"67"},{"insert":"89","attributes":{"bold":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"67"},{"insert":"89","attributes":{"bold":"true"}}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
OpTester::new().run_script(ops);
|
OpTester::new().run_script(ops);
|
||||||
|
@ -387,10 +366,7 @@ fn attributes_replace_with_text() {
|
||||||
InsertBold(0, "123456", Interval::new(0, 6)),
|
InsertBold(0, "123456", Interval::new(0, 6)),
|
||||||
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
|
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
|
||||||
Replace(0, Interval::new(0, 3), "ab"),
|
Replace(0, Interval::new(0, 3), "ab"),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"ab"},{"insert":"456","attributes":{"bold":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"ab"},{"insert":"456","attributes":{"bold":"true"}}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
OpTester::new().run_script(ops);
|
OpTester::new().run_script(ops);
|
||||||
|
@ -400,11 +376,8 @@ fn attributes_replace_with_text() {
|
||||||
fn attributes_header_insert_newline_at_middle() {
|
fn attributes_header_insert_newline_at_middle() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Header(0, Interval::new(0, 6), 1, true),
|
Header(0, Interval::new(0, 6), 1),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":"1"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":"1"}}]"#,
|
|
||||||
),
|
|
||||||
Insert(0, "\n", 3),
|
Insert(0, "\n", 3),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -419,7 +392,7 @@ fn attributes_header_insert_newline_at_middle() {
|
||||||
fn attributes_header_insert_double_newline_at_middle() {
|
fn attributes_header_insert_double_newline_at_middle() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Header(0, Interval::new(0, 6), 1, true),
|
Header(0, Interval::new(0, 6), 1),
|
||||||
Insert(0, "\n", 3),
|
Insert(0, "\n", 3),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -444,7 +417,7 @@ fn attributes_header_insert_double_newline_at_middle() {
|
||||||
fn attributes_header_insert_newline_at_trailing() {
|
fn attributes_header_insert_newline_at_trailing() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Header(0, Interval::new(0, 6), 1, true),
|
Header(0, Interval::new(0, 6), 1),
|
||||||
Insert(0, "\n", 6),
|
Insert(0, "\n", 6),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -459,7 +432,7 @@ fn attributes_header_insert_newline_at_trailing() {
|
||||||
fn attributes_header_insert_double_newline_at_trailing() {
|
fn attributes_header_insert_double_newline_at_trailing() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Header(0, Interval::new(0, 6), 1, true),
|
Header(0, Interval::new(0, 6), 1),
|
||||||
Insert(0, "\n", 6),
|
Insert(0, "\n", 6),
|
||||||
Insert(0, "\n", 7),
|
Insert(0, "\n", 7),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
|
@ -475,7 +448,7 @@ fn attributes_header_insert_double_newline_at_trailing() {
|
||||||
fn attributes_link_added() {
|
fn attributes_link_added() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Link(0, Interval::new(0, 6), "https://appflowy.io", true),
|
Link(0, Interval::new(0, 6), "https://appflowy.io"),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
|
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
|
||||||
|
@ -489,7 +462,7 @@ fn attributes_link_added() {
|
||||||
fn attributes_link_format_with_bold() {
|
fn attributes_link_format_with_bold() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Link(0, Interval::new(0, 6), "https://appflowy.io", true),
|
Link(0, Interval::new(0, 6), "https://appflowy.io"),
|
||||||
Bold(0, Interval::new(0, 3), true),
|
Bold(0, Interval::new(0, 3), true),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -508,7 +481,7 @@ fn attributes_link_format_with_bold() {
|
||||||
fn attributes_link_insert_char_at_head() {
|
fn attributes_link_insert_char_at_head() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Link(0, Interval::new(0, 6), "https://appflowy.io", true),
|
Link(0, Interval::new(0, 6), "https://appflowy.io"),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
|
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
|
||||||
|
@ -527,7 +500,7 @@ fn attributes_link_insert_char_at_head() {
|
||||||
fn attributes_link_insert_char_at_middle() {
|
fn attributes_link_insert_char_at_middle() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "1256", 0),
|
Insert(0, "1256", 0),
|
||||||
Link(0, Interval::new(0, 4), "https://appflowy.io", true),
|
Link(0, Interval::new(0, 4), "https://appflowy.io"),
|
||||||
Insert(0, "34", 2),
|
Insert(0, "34", 2),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -542,7 +515,7 @@ fn attributes_link_insert_char_at_middle() {
|
||||||
fn attributes_link_insert_char_at_trailing() {
|
fn attributes_link_insert_char_at_trailing() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Link(0, Interval::new(0, 6), "https://appflowy.io", true),
|
Link(0, Interval::new(0, 6), "https://appflowy.io"),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
|
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
|
||||||
|
@ -561,7 +534,7 @@ fn attributes_link_insert_char_at_trailing() {
|
||||||
fn attributes_link_insert_newline_at_middle() {
|
fn attributes_link_insert_newline_at_middle() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Link(0, Interval::new(0, 6), "https://appflowy.io", true),
|
Link(0, Interval::new(0, 6), "https://appflowy.io"),
|
||||||
Insert(0, NEW_LINE, 3),
|
Insert(0, NEW_LINE, 3),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -593,7 +566,7 @@ fn attributes_link_auto_format_exist() {
|
||||||
let site = "https://appflowy.io";
|
let site = "https://appflowy.io";
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, site, 0),
|
Insert(0, site, 0),
|
||||||
Link(0, Interval::new(0, site.len()), site, true),
|
Link(0, Interval::new(0, site.len()), site),
|
||||||
Insert(0, WHITESPACE, site.len()),
|
Insert(0, WHITESPACE, site.len()),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -609,7 +582,7 @@ fn attributes_link_auto_format_exist2() {
|
||||||
let site = "https://appflowy.io";
|
let site = "https://appflowy.io";
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, site, 0),
|
Insert(0, site, 0),
|
||||||
Link(0, Interval::new(0, site.len() / 2), site, true),
|
Link(0, Interval::new(0, site.len() / 2), site),
|
||||||
Insert(0, WHITESPACE, site.len()),
|
Insert(0, WHITESPACE, site.len()),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -625,10 +598,7 @@ fn attributes_bullet_added() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "12", 0),
|
Insert(0, "12", 0),
|
||||||
Bullet(0, Interval::new(0, 1), true),
|
Bullet(0, Interval::new(0, 1), true),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"12"},{"insert":"\n","attributes":{"bullet":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"12"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
OpTester::new().run_script_with_newline(ops);
|
OpTester::new().run_script_with_newline(ops);
|
||||||
|
@ -639,15 +609,9 @@ fn attributes_bullet_added_2() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "1", 0),
|
Insert(0, "1", 0),
|
||||||
Bullet(0, Interval::new(0, 1), true),
|
Bullet(0, Interval::new(0, 1), true),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
|
||||||
),
|
|
||||||
Insert(0, NEW_LINE, 1),
|
Insert(0, NEW_LINE, 1),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"1"},{"insert":"\n\n","attributes":{"bullet":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"1"},{"insert":"\n\n","attributes":{"bullet":"true"}}]"#,
|
|
||||||
),
|
|
||||||
Insert(0, "2", 2),
|
Insert(0, "2", 2),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -697,10 +661,7 @@ fn attributes_preserve_block_when_insert_newline_inside() {
|
||||||
Insert(0, "12", 0),
|
Insert(0, "12", 0),
|
||||||
Bullet(0, Interval::new(0, 2), true),
|
Bullet(0, Interval::new(0, 2), true),
|
||||||
Insert(0, NEW_LINE, 2),
|
Insert(0, NEW_LINE, 2),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"12"},{"insert":"\n\n","attributes":{"bullet":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"12"},{"insert":"\n\n","attributes":{"bullet":"true"}}]"#,
|
|
||||||
),
|
|
||||||
Insert(0, "34", 3),
|
Insert(0, "34", 3),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
@ -735,17 +696,14 @@ fn attributes_preserve_block_when_insert_newline_inside() {
|
||||||
fn attributes_preserve_header_format_on_merge() {
|
fn attributes_preserve_header_format_on_merge() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Header(0, Interval::new(0, 6), 1, true),
|
Header(0, Interval::new(0, 6), 1),
|
||||||
Insert(0, NEW_LINE, 3),
|
Insert(0, NEW_LINE, 3),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":"1"}},{"insert":"456"},{"insert":"\n","attributes":{"header":"1"}}]"#,
|
r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":"1"}},{"insert":"456"},{"insert":"\n","attributes":{"header":"1"}}]"#,
|
||||||
),
|
),
|
||||||
Delete(0, Interval::new(3, 4)),
|
Delete(0, Interval::new(3, 4)),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":"1"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":"1"}}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
OpTester::new().run_script_with_newline(ops);
|
OpTester::new().run_script_with_newline(ops);
|
||||||
|
@ -762,10 +720,7 @@ fn attributes_preserve_list_format_on_merge() {
|
||||||
r#"[{"insert":"123"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
r#"[{"insert":"123"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
||||||
),
|
),
|
||||||
Delete(0, Interval::new(3, 4)),
|
Delete(0, Interval::new(3, 4)),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
OpTester::new().run_script_with_newline(ops);
|
OpTester::new().run_script_with_newline(ops);
|
||||||
|
|
|
@ -28,10 +28,10 @@ pub enum TestOp {
|
||||||
Italic(usize, Interval, bool),
|
Italic(usize, Interval, bool),
|
||||||
|
|
||||||
#[display(fmt = "Header")]
|
#[display(fmt = "Header")]
|
||||||
Header(usize, Interval, usize, bool),
|
Header(usize, Interval, usize),
|
||||||
|
|
||||||
#[display(fmt = "Link")]
|
#[display(fmt = "Link")]
|
||||||
Link(usize, Interval, &'static str, bool),
|
Link(usize, Interval, &'static str),
|
||||||
|
|
||||||
#[display(fmt = "Bullet")]
|
#[display(fmt = "Bullet")]
|
||||||
Bullet(usize, Interval, bool),
|
Bullet(usize, Interval, bool),
|
||||||
|
@ -93,48 +93,34 @@ impl OpTester {
|
||||||
TestOp::InsertBold(delta_i, s, iv) => {
|
TestOp::InsertBold(delta_i, s, iv) => {
|
||||||
let document = &mut self.documents[*delta_i];
|
let document = &mut self.documents[*delta_i];
|
||||||
document.insert(iv.start, s).unwrap();
|
document.insert(iv.start, s).unwrap();
|
||||||
document
|
document.format(*iv, Attribute::Bold(true)).unwrap();
|
||||||
.format(*iv, AttributeKey::Bold.value(true))
|
|
||||||
.unwrap();
|
|
||||||
},
|
},
|
||||||
TestOp::Bold(delta_i, iv, enable) => {
|
TestOp::Bold(delta_i, iv, enable) => {
|
||||||
let document = &mut self.documents[*delta_i];
|
let document = &mut self.documents[*delta_i];
|
||||||
let attribute = match *enable {
|
let attribute = Attribute::Bold(*enable);
|
||||||
true => AttributeKey::Bold.value(true),
|
|
||||||
false => AttributeKey::Bold.remove(),
|
|
||||||
};
|
|
||||||
document.format(*iv, attribute).unwrap();
|
document.format(*iv, attribute).unwrap();
|
||||||
},
|
},
|
||||||
TestOp::Italic(delta_i, iv, enable) => {
|
TestOp::Italic(delta_i, iv, enable) => {
|
||||||
let document = &mut self.documents[*delta_i];
|
let document = &mut self.documents[*delta_i];
|
||||||
let attribute = match *enable {
|
let attribute = match *enable {
|
||||||
true => AttributeKey::Italic.value("true"),
|
true => Attribute::Italic(true),
|
||||||
false => AttributeKey::Italic.remove(),
|
false => Attribute::Italic(false),
|
||||||
};
|
};
|
||||||
document.format(*iv, attribute).unwrap();
|
document.format(*iv, attribute).unwrap();
|
||||||
},
|
},
|
||||||
TestOp::Header(delta_i, iv, level, enable) => {
|
TestOp::Header(delta_i, iv, level) => {
|
||||||
let document = &mut self.documents[*delta_i];
|
let document = &mut self.documents[*delta_i];
|
||||||
let attribute = match *enable {
|
let attribute = Attribute::Header(*level);
|
||||||
true => AttributeKey::Header.value(level),
|
|
||||||
false => AttributeKey::Header.remove(),
|
|
||||||
};
|
|
||||||
document.format(*iv, attribute).unwrap();
|
document.format(*iv, attribute).unwrap();
|
||||||
},
|
},
|
||||||
TestOp::Link(delta_i, iv, link, enable) => {
|
TestOp::Link(delta_i, iv, link) => {
|
||||||
let document = &mut self.documents[*delta_i];
|
let document = &mut self.documents[*delta_i];
|
||||||
let attribute = match *enable {
|
let attribute = Attribute::Link(link.to_owned());
|
||||||
true => AttributeKey::Link.value(link.to_owned()),
|
|
||||||
false => AttributeKey::Link.remove(),
|
|
||||||
};
|
|
||||||
document.format(*iv, attribute).unwrap();
|
document.format(*iv, attribute).unwrap();
|
||||||
},
|
},
|
||||||
TestOp::Bullet(delta_i, iv, enable) => {
|
TestOp::Bullet(delta_i, iv, enable) => {
|
||||||
let document = &mut self.documents[*delta_i];
|
let document = &mut self.documents[*delta_i];
|
||||||
let attribute = match *enable {
|
let attribute = Attribute::Bullet(*enable);
|
||||||
true => AttributeKey::Bullet.value("true"),
|
|
||||||
false => AttributeKey::Bullet.remove(),
|
|
||||||
};
|
|
||||||
document.format(*iv, attribute).unwrap();
|
document.format(*iv, attribute).unwrap();
|
||||||
},
|
},
|
||||||
TestOp::Transform(delta_a_i, delta_b_i) => {
|
TestOp::Transform(delta_a_i, delta_b_i) => {
|
||||||
|
@ -236,9 +222,7 @@ impl Default for Rng {
|
||||||
impl Rng {
|
impl Rng {
|
||||||
pub fn from_seed(seed: [u8; 32]) -> Self { Rng(StdRng::from_seed(seed)) }
|
pub fn from_seed(seed: [u8; 32]) -> Self { Rng(StdRng::from_seed(seed)) }
|
||||||
|
|
||||||
pub fn gen_string(&mut self, len: usize) -> String {
|
pub fn gen_string(&mut self, len: usize) -> String { (0..len).map(|_| self.0.gen::<char>()).collect() }
|
||||||
(0..len).map(|_| self.0.gen::<char>()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gen_delta(&mut self, s: &str) -> Delta {
|
pub fn gen_delta(&mut self, s: &str) -> Delta {
|
||||||
let mut delta = Delta::default();
|
let mut delta = Delta::default();
|
||||||
|
@ -265,10 +249,7 @@ impl Rng {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.0.gen_range(0.0, 1.0) < 0.3 {
|
if self.0.gen_range(0.0, 1.0) < 0.3 {
|
||||||
delta.insert(
|
delta.insert(&("1".to_owned() + &self.gen_string(10)), Attributes::default());
|
||||||
&("1".to_owned() + &self.gen_string(10)),
|
|
||||||
Attributes::default(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
delta
|
delta
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,10 +71,7 @@ fn delta_get_ops_in_interval_2() {
|
||||||
vec![OpBuilder::insert("23").build()]
|
vec![OpBuilder::insert("23").build()]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(), vec![insert_a.clone()]);
|
||||||
DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(),
|
|
||||||
vec![insert_a.clone()]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIter::from_interval(&delta, Interval::new(0, 4)).ops(),
|
DeltaIter::from_interval(&delta, Interval::new(0, 4)).ops(),
|
||||||
|
@ -114,25 +111,13 @@ fn delta_get_ops_in_interval_4() {
|
||||||
delta.ops.push(insert_b.clone());
|
delta.ops.push(insert_b.clone());
|
||||||
delta.ops.push(insert_c.clone());
|
delta.ops.push(insert_c.clone());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(), vec![insert_a]);
|
||||||
DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(),
|
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(2, 4)).ops(), vec![insert_b]);
|
||||||
vec![insert_a]
|
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(), vec![insert_c]);
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
DeltaIter::from_interval(&delta, Interval::new(2, 4)).ops(),
|
|
||||||
vec![insert_b]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(),
|
|
||||||
vec![insert_c]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIter::from_interval(&delta, Interval::new(2, 5)).ops(),
|
DeltaIter::from_interval(&delta, Interval::new(2, 5)).ops(),
|
||||||
vec![
|
vec![OpBuilder::insert("34").build(), OpBuilder::insert("5").build()]
|
||||||
OpBuilder::insert("34").build(),
|
|
||||||
OpBuilder::insert("5").build()
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,10 +130,7 @@ fn delta_get_ops_in_interval_5() {
|
||||||
delta.ops.push(insert_b.clone());
|
delta.ops.push(insert_b.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIter::from_interval(&delta, Interval::new(4, 8)).ops(),
|
DeltaIter::from_interval(&delta, Interval::new(4, 8)).ops(),
|
||||||
vec![
|
vec![OpBuilder::insert("56").build(), OpBuilder::insert("78").build()]
|
||||||
OpBuilder::insert("56").build(),
|
|
||||||
OpBuilder::insert("78").build()
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert_eq!(
|
// assert_eq!(
|
||||||
|
@ -182,10 +164,7 @@ fn delta_get_ops_in_interval_7() {
|
||||||
assert_eq!(iter_1.next_op().unwrap(), OpBuilder::retain(3).build());
|
assert_eq!(iter_1.next_op().unwrap(), OpBuilder::retain(3).build());
|
||||||
|
|
||||||
let mut iter_2 = DeltaIter::new(&delta);
|
let mut iter_2 = DeltaIter::new(&delta);
|
||||||
assert_eq!(
|
assert_eq!(iter_2.next_op_with_len(2).unwrap(), OpBuilder::insert("12").build());
|
||||||
iter_2.next_op_with_len(2).unwrap(),
|
|
||||||
OpBuilder::insert("12").build()
|
|
||||||
);
|
|
||||||
assert_eq!(iter_2.next_op().unwrap(), OpBuilder::insert("345").build());
|
assert_eq!(iter_2.next_op().unwrap(), OpBuilder::insert("345").build());
|
||||||
|
|
||||||
assert_eq!(iter_2.next_op().unwrap(), OpBuilder::retain(3).build());
|
assert_eq!(iter_2.next_op().unwrap(), OpBuilder::retain(3).build());
|
||||||
|
@ -209,10 +188,7 @@ fn delta_seek_2() {
|
||||||
delta.add(OpBuilder::insert("12345").build());
|
delta.add(OpBuilder::insert("12345").build());
|
||||||
|
|
||||||
let mut iter = DeltaIter::new(&delta);
|
let mut iter = DeltaIter::new(&delta);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(1).unwrap(), OpBuilder::insert("1").build());
|
||||||
iter.next_op_with_len(1).unwrap(),
|
|
||||||
OpBuilder::insert("1").build()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -221,20 +197,11 @@ fn delta_seek_3() {
|
||||||
delta.add(OpBuilder::insert("12345").build());
|
delta.add(OpBuilder::insert("12345").build());
|
||||||
|
|
||||||
let mut iter = DeltaIter::new(&delta);
|
let mut iter = DeltaIter::new(&delta);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("12").build());
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OpBuilder::insert("12").build()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("34").build());
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OpBuilder::insert("34").build()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("5").build());
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OpBuilder::insert("5").build()
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(iter.next_op_with_len(1), None);
|
assert_eq!(iter.next_op_with_len(1), None);
|
||||||
}
|
}
|
||||||
|
@ -246,21 +213,18 @@ fn delta_seek_4() {
|
||||||
|
|
||||||
let mut iter = DeltaIter::new(&delta);
|
let mut iter = DeltaIter::new(&delta);
|
||||||
iter.seek::<CharMetric>(3);
|
iter.seek::<CharMetric>(3);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("45").build());
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OpBuilder::insert("45").build()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_seek_5() {
|
fn delta_seek_5() {
|
||||||
let mut delta = Delta::default();
|
let mut delta = Delta::default();
|
||||||
let attributes = AttributeBuilder::new().bold(true).italic(true).build();
|
let attributes = AttributeBuilder::new()
|
||||||
delta.add(
|
.add(Attribute::Bold(true))
|
||||||
OpBuilder::insert("1234")
|
.add(Attribute::Italic(true))
|
||||||
.attributes(attributes.clone())
|
.build();
|
||||||
.build(),
|
|
||||||
);
|
delta.add(OpBuilder::insert("1234").attributes(attributes.clone()).build());
|
||||||
delta.add(OpBuilder::insert("\n").build());
|
delta.add(OpBuilder::insert("\n").build());
|
||||||
|
|
||||||
let mut iter = DeltaIter::new(&delta);
|
let mut iter = DeltaIter::new(&delta);
|
||||||
|
@ -280,10 +244,7 @@ fn delta_next_op_len_test() {
|
||||||
let mut iter = DeltaIter::new(&delta);
|
let mut iter = DeltaIter::new(&delta);
|
||||||
iter.seek::<CharMetric>(3);
|
iter.seek::<CharMetric>(3);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 2);
|
assert_eq!(iter.next_op_len().unwrap(), 2);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(1).unwrap(), OpBuilder::insert("4").build());
|
||||||
iter.next_op_with_len(1).unwrap(),
|
|
||||||
OpBuilder::insert("4").build()
|
|
||||||
);
|
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 1);
|
assert_eq!(iter.next_op_len().unwrap(), 1);
|
||||||
assert_eq!(iter.next_op().unwrap(), OpBuilder::insert("5").build());
|
assert_eq!(iter.next_op().unwrap(), OpBuilder::insert("5").build());
|
||||||
}
|
}
|
||||||
|
@ -295,10 +256,7 @@ fn delta_next_op_len_test2() {
|
||||||
let mut iter = DeltaIter::new(&delta);
|
let mut iter = DeltaIter::new(&delta);
|
||||||
|
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 5);
|
assert_eq!(iter.next_op_len().unwrap(), 5);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(5).unwrap(), OpBuilder::insert("12345").build());
|
||||||
iter.next_op_with_len(5).unwrap(),
|
|
||||||
OpBuilder::insert("12345").build()
|
|
||||||
);
|
|
||||||
assert_eq!(iter.next_op_len(), None);
|
assert_eq!(iter.next_op_len(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,10 +279,7 @@ fn delta_next_op_with_len_cross_op_return_last() {
|
||||||
let mut iter = DeltaIter::new(&delta);
|
let mut iter = DeltaIter::new(&delta);
|
||||||
iter.seek::<CharMetric>(4);
|
iter.seek::<CharMetric>(4);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 1);
|
assert_eq!(iter.next_op_len().unwrap(), 1);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::retain(1).build());
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OpBuilder::retain(1).build()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -523,7 +478,7 @@ fn transform2() {
|
||||||
fn delta_transform_test() {
|
fn delta_transform_test() {
|
||||||
let mut a = Delta::default();
|
let mut a = Delta::default();
|
||||||
let mut a_s = String::new();
|
let mut a_s = String::new();
|
||||||
a.insert("123", AttributeBuilder::new().bold(true).build());
|
a.insert("123", AttributeBuilder::new().add(Attribute::Bold(true)).build());
|
||||||
a_s = a.apply(&a_s).unwrap();
|
a_s = a.apply(&a_s).unwrap();
|
||||||
assert_eq!(&a_s, "123");
|
assert_eq!(&a_s, "123");
|
||||||
|
|
||||||
|
@ -625,10 +580,7 @@ fn delta_invert_no_attribute_delta_with_attribute_delta() {
|
||||||
Insert(0, "123", 0),
|
Insert(0, "123", 0),
|
||||||
Insert(1, "4567", 0),
|
Insert(1, "4567", 0),
|
||||||
Bold(1, Interval::new(0, 3), true),
|
Bold(1, Interval::new(0, 3), true),
|
||||||
AssertOpsJson(
|
AssertOpsJson(1, r#"[{"insert":"456","attributes":{"bold":"true"}},{"insert":"7"}]"#),
|
||||||
1,
|
|
||||||
r#"[{"insert":"456","attributes":{"bold":"true"}},{"insert":"7"}]"#,
|
|
||||||
),
|
|
||||||
Invert(0, 1),
|
Invert(0, 1),
|
||||||
AssertOpsJson(0, r#"[{"insert":"123"}]"#),
|
AssertOpsJson(0, r#"[{"insert":"123"}]"#),
|
||||||
];
|
];
|
||||||
|
|
|
@ -2,7 +2,10 @@ use flowy_ot::{client::Document, core::*};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn operation_insert_serialize_test() {
|
fn operation_insert_serialize_test() {
|
||||||
let attributes = AttributeBuilder::new().bold(true).italic(true).build();
|
let attributes = AttributeBuilder::new()
|
||||||
|
.add(Attribute::Bold(true))
|
||||||
|
.add(Attribute::Italic(true))
|
||||||
|
.build();
|
||||||
let operation = OpBuilder::insert("123").attributes(attributes).build();
|
let operation = OpBuilder::insert("123").attributes(attributes).build();
|
||||||
let json = serde_json::to_string(&operation).unwrap();
|
let json = serde_json::to_string(&operation).unwrap();
|
||||||
eprintln!("{}", json);
|
eprintln!("{}", json);
|
||||||
|
@ -32,7 +35,10 @@ fn operation_delete_serialize_test() {
|
||||||
fn delta_serialize_test() {
|
fn delta_serialize_test() {
|
||||||
let mut delta = Delta::default();
|
let mut delta = Delta::default();
|
||||||
|
|
||||||
let attributes = AttributeBuilder::new().bold(true).italic(true).build();
|
let attributes = AttributeBuilder::new()
|
||||||
|
.add(Attribute::Bold(true))
|
||||||
|
.add(Attribute::Italic(true))
|
||||||
|
.build();
|
||||||
let retain = OpBuilder::insert("123").attributes(attributes).build();
|
let retain = OpBuilder::insert("123").attributes(attributes).build();
|
||||||
|
|
||||||
delta.add(retain);
|
delta.add(retain);
|
||||||
|
|
|
@ -8,11 +8,7 @@ use flowy_ot::{
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn history_insert_undo() {
|
fn history_insert_undo() {
|
||||||
let ops = vec![
|
let ops = vec![Insert(0, "123", 0), Undo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#)];
|
||||||
Insert(0, "123", 0),
|
|
||||||
Undo(0),
|
|
||||||
AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
|
|
||||||
];
|
|
||||||
OpTester::new().run_script_with_newline(ops);
|
OpTester::new().run_script_with_newline(ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,10 +89,7 @@ fn history_bold_redo() {
|
||||||
Undo(0),
|
Undo(0),
|
||||||
AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
|
AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
|
||||||
Redo(0),
|
Redo(0),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#" [{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#),
|
||||||
0,
|
|
||||||
r#" [{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
OpTester::new().run_script_with_newline(ops);
|
OpTester::new().run_script_with_newline(ops);
|
||||||
}
|
}
|
||||||
|
@ -110,10 +103,7 @@ fn history_bold_redo_with_lagging() {
|
||||||
Undo(0),
|
Undo(0),
|
||||||
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#),
|
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#),
|
||||||
Redo(0),
|
Redo(0),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
OpTester::new().run_script_with_newline(ops);
|
OpTester::new().run_script_with_newline(ops);
|
||||||
}
|
}
|
||||||
|
@ -226,10 +216,7 @@ fn history_replace_undo_with_lagging() {
|
||||||
"#,
|
"#,
|
||||||
),
|
),
|
||||||
Undo(0),
|
Undo(0),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
OpTester::new().run_script_with_newline(ops);
|
OpTester::new().run_script_with_newline(ops);
|
||||||
}
|
}
|
||||||
|
@ -257,7 +244,7 @@ fn history_replace_redo() {
|
||||||
fn history_header_added_undo() {
|
fn history_header_added_undo() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, "123456", 0),
|
Insert(0, "123456", 0),
|
||||||
Header(0, Interval::new(0, 6), 1, true),
|
Header(0, Interval::new(0, 6), 1),
|
||||||
Insert(0, "\n", 3),
|
Insert(0, "\n", 3),
|
||||||
Insert(0, "\n", 4),
|
Insert(0, "\n", 4),
|
||||||
Undo(0),
|
Undo(0),
|
||||||
|
@ -278,7 +265,7 @@ fn history_link_added_undo() {
|
||||||
let ops = vec![
|
let ops = vec![
|
||||||
Insert(0, site, 0),
|
Insert(0, site, 0),
|
||||||
Wait(RECORD_THRESHOLD),
|
Wait(RECORD_THRESHOLD),
|
||||||
Link(0, Interval::new(0, site.len()), site, true),
|
Link(0, Interval::new(0, site.len()), site),
|
||||||
Undo(0),
|
Undo(0),
|
||||||
AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#),
|
AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#),
|
||||||
Redo(0),
|
Redo(0),
|
||||||
|
@ -347,10 +334,7 @@ fn history_bullet_undo_with_lagging() {
|
||||||
r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"2"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"2"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
||||||
),
|
),
|
||||||
Undo(0),
|
Undo(0),
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
|
||||||
),
|
|
||||||
Undo(0),
|
Undo(0),
|
||||||
AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
|
AssertOpsJson(0, r#"[{"insert":"\n"}]"#),
|
||||||
Redo(0),
|
Redo(0),
|
||||||
|
@ -377,10 +361,7 @@ fn history_undo_attribute_on_merge_between_line() {
|
||||||
r#"[{"insert":"123"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
r#"[{"insert":"123"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
||||||
),
|
),
|
||||||
Delete(0, Interval::new(3, 4)), // delete the newline
|
Delete(0, Interval::new(3, 4)), // delete the newline
|
||||||
AssertOpsJson(
|
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#),
|
||||||
0,
|
|
||||||
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#,
|
|
||||||
),
|
|
||||||
Undo(0),
|
Undo(0),
|
||||||
AssertOpsJson(
|
AssertOpsJson(
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use diesel::{
|
use diesel::{dsl::sql, expression::SqlLiteral, query_dsl::LoadQuery, Connection, RunQueryDsl, SqliteConnection};
|
||||||
dsl::sql,
|
|
||||||
expression::SqlLiteral,
|
|
||||||
query_dsl::LoadQuery,
|
|
||||||
Connection,
|
|
||||||
RunQueryDsl,
|
|
||||||
SqliteConnection,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait ConnectionExtension: Connection {
|
pub trait ConnectionExtension: Connection {
|
||||||
fn query<ST, T>(&self, query: &str) -> Result<T>
|
fn query<ST, T>(&self, query: &str) -> Result<T>
|
||||||
|
@ -24,7 +17,5 @@ impl ConnectionExtension for SqliteConnection {
|
||||||
Ok(sql::<ST>(query).get_result(self)?)
|
Ok(sql::<ST>(query).get_result(self)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(&self, query: impl AsRef<str>) -> Result<usize> {
|
fn exec(&self, query: impl AsRef<str>) -> Result<usize> { Ok(SqliteConnection::execute(self, query.as_ref())?) }
|
||||||
Ok(SqliteConnection::execute(self, query.as_ref())?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,7 @@ impl Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
let pool = ConnectionPool::new(pool_config, &uri)?;
|
let pool = ConnectionPool::new(pool_config, &uri)?;
|
||||||
Ok(Self {
|
Ok(Self { uri, pool: Arc::new(pool) })
|
||||||
uri,
|
|
||||||
pool: Arc::new(pool),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_uri(&self) -> &str { &self.uri }
|
pub fn get_uri(&self) -> &str { &self.uri }
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
use error_chain::{
|
use error_chain::{error_chain, error_chain_processing, impl_error_chain_kind, impl_error_chain_processed, impl_extract_backtrace};
|
||||||
error_chain,
|
|
||||||
error_chain_processing,
|
|
||||||
impl_error_chain_kind,
|
|
||||||
impl_error_chain_processed,
|
|
||||||
impl_extract_backtrace,
|
|
||||||
};
|
|
||||||
|
|
||||||
error_chain! {
|
error_chain! {
|
||||||
errors {
|
errors {
|
||||||
|
|
|
@ -119,9 +119,7 @@ impl ManageConnection for ConnectionManager {
|
||||||
|
|
||||||
fn connect(&self) -> Result<Self::Connection> { Ok(SqliteConnection::establish(&self.db_uri)?) }
|
fn connect(&self) -> Result<Self::Connection> { Ok(SqliteConnection::establish(&self.db_uri)?) }
|
||||||
|
|
||||||
fn is_valid(&self, conn: &mut Self::Connection) -> Result<()> {
|
fn is_valid(&self, conn: &mut Self::Connection) -> Result<()> { Ok(conn.execute("SELECT 1").map(|_| ())?) }
|
||||||
Ok(conn.execute("SELECT 1").map(|_| ())?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_broken(&self, _conn: &mut Self::Connection) -> bool { false }
|
fn has_broken(&self, _conn: &mut Self::Connection) -> bool { false }
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,7 @@ pub trait PragmaExtension: ConnectionExtension {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pragma_ret<ST, T, D: std::fmt::Display>(
|
fn pragma_ret<ST, T, D: std::fmt::Display>(&self, key: &str, val: D, schema: Option<&str>) -> Result<T>
|
||||||
&self,
|
|
||||||
key: &str,
|
|
||||||
val: D,
|
|
||||||
schema: Option<&str>,
|
|
||||||
) -> Result<T>
|
|
||||||
where
|
where
|
||||||
SqlLiteral<ST>: LoadQuery<SqliteConnection, T>,
|
SqlLiteral<ST>: LoadQuery<SqliteConnection, T>,
|
||||||
{
|
{
|
||||||
|
@ -57,36 +52,22 @@ pub trait PragmaExtension: ConnectionExtension {
|
||||||
self.pragma_ret::<Integer, i32, i32>("busy_timeout", timeout_ms, None)
|
self.pragma_ret::<Integer, i32, i32>("busy_timeout", timeout_ms, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pragma_get_busy_timeout(&self) -> Result<i32> {
|
fn pragma_get_busy_timeout(&self) -> Result<i32> { self.pragma_get::<Integer, i32>("busy_timeout", None) }
|
||||||
self.pragma_get::<Integer, i32>("busy_timeout", None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pragma_set_journal_mode(
|
fn pragma_set_journal_mode(&self, mode: SQLiteJournalMode, schema: Option<&str>) -> Result<i32> {
|
||||||
&self,
|
|
||||||
mode: SQLiteJournalMode,
|
|
||||||
schema: Option<&str>,
|
|
||||||
) -> Result<i32> {
|
|
||||||
self.pragma_ret::<Integer, i32, SQLiteJournalMode>("journal_mode", mode, schema)
|
self.pragma_ret::<Integer, i32, SQLiteJournalMode>("journal_mode", mode, schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pragma_get_journal_mode(&self, schema: Option<&str>) -> Result<SQLiteJournalMode> {
|
fn pragma_get_journal_mode(&self, schema: Option<&str>) -> Result<SQLiteJournalMode> {
|
||||||
Ok(self
|
Ok(self.pragma_get::<Text, String>("journal_mode", schema)?.parse()?)
|
||||||
.pragma_get::<Text, String>("journal_mode", schema)?
|
|
||||||
.parse()?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pragma_set_synchronous(
|
fn pragma_set_synchronous(&self, synchronous: SQLiteSynchronous, schema: Option<&str>) -> Result<()> {
|
||||||
&self,
|
|
||||||
synchronous: SQLiteSynchronous,
|
|
||||||
schema: Option<&str>,
|
|
||||||
) -> Result<()> {
|
|
||||||
self.pragma("synchronous", synchronous as u8, schema)
|
self.pragma("synchronous", synchronous as u8, schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pragma_get_synchronous(&self, schema: Option<&str>) -> Result<SQLiteSynchronous> {
|
fn pragma_get_synchronous(&self, schema: Option<&str>) -> Result<SQLiteSynchronous> {
|
||||||
Ok(self
|
Ok(self.pragma_get::<Integer, i32>("synchronous", schema)?.try_into()?)
|
||||||
.pragma_get::<Integer, i32>("synchronous", schema)?
|
|
||||||
.try_into()?)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PragmaExtension for SqliteConnection {}
|
impl PragmaExtension for SqliteConnection {}
|
||||||
|
|
|
@ -57,7 +57,5 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[quickcheck_macros::quickcheck]
|
#[quickcheck_macros::quickcheck]
|
||||||
fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool {
|
fn valid_emails_are_parsed_successfully(valid_email: ValidEmailFixture) -> bool { UserEmail::parse(valid_email.0).is_ok() }
|
||||||
UserEmail::parse(valid_email.0).is_ok()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,7 @@ use derive_more::Display;
|
||||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||||
use flowy_dispatch::prelude::{EventResponse, ResponseBuilder};
|
use flowy_dispatch::prelude::{EventResponse, ResponseBuilder};
|
||||||
|
|
||||||
use std::{
|
use std::{convert::TryInto, fmt::Debug};
|
||||||
convert::TryInto,
|
|
||||||
fmt::{Debug, Formatter},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||||
pub struct UserError {
|
pub struct UserError {
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
// Auto-generated, do not edit
|
// Auto-generated, do not edit
|
||||||
|
|
||||||
mod observable;
|
mod observable;
|
||||||
pub use observable::*;
|
pub use observable::*;
|
||||||
|
|
||||||
mod user_table;
|
mod user_table;
|
||||||
pub use user_table::*;
|
pub use user_table::*;
|
||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
pub use errors::*;
|
pub use errors::*;
|
||||||
|
|
||||||
mod user_profile;
|
mod user_profile;
|
||||||
pub use user_profile::*;
|
pub use user_profile::*;
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
pub use auth::*;
|
pub use auth::*;
|
||||||
|
|
|
@ -22,11 +22,7 @@ impl TryInto<DeleteWorkspaceParams> for DeleteWorkspaceRequest {
|
||||||
|
|
||||||
fn try_into(self) -> Result<DeleteWorkspaceParams, Self::Error> {
|
fn try_into(self) -> Result<DeleteWorkspaceParams, Self::Error> {
|
||||||
let workspace_id = WorkspaceId::parse(self.workspace_id)
|
let workspace_id = WorkspaceId::parse(self.workspace_id)
|
||||||
.map_err(|e| {
|
.map_err(|e| ErrorBuilder::new(ErrorCode::WorkspaceIdInvalid).msg(e).build())?
|
||||||
ErrorBuilder::new(ErrorCode::WorkspaceIdInvalid)
|
|
||||||
.msg(e)
|
|
||||||
.build()
|
|
||||||
})?
|
|
||||||
.0;
|
.0;
|
||||||
|
|
||||||
Ok(DeleteWorkspaceParams { workspace_id })
|
Ok(DeleteWorkspaceParams { workspace_id })
|
||||||
|
|
|
@ -54,6 +54,15 @@ pub(crate) async fn update_view_handler(
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
#[tracing::instrument(skip(data, controller), err)]
|
||||||
|
pub(crate) async fn update_view_data_handler(
|
||||||
|
data: Data<UpdateViewDataRequest>,
|
||||||
|
controller: Unit<Arc<ViewController>>,
|
||||||
|
) -> Result<(), WorkspaceError> {
|
||||||
|
let params: UpdateDocParams = data.into_inner().try_into()?;
|
||||||
|
let _ = controller.update_view_data(params).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(data, controller), err)]
|
#[tracing::instrument(skip(data, controller), err)]
|
||||||
pub(crate) async fn delete_view_handler(
|
pub(crate) async fn delete_view_handler(
|
||||||
|
@ -74,13 +83,3 @@ pub(crate) async fn open_view_handler(
|
||||||
let doc = controller.open_view(params).await?;
|
let doc = controller.open_view(params).await?;
|
||||||
data_result(doc)
|
data_result(doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(data, controller), err)]
|
|
||||||
pub(crate) async fn update_view_data_handler(
|
|
||||||
data: Data<UpdateViewDataRequest>,
|
|
||||||
controller: Unit<Arc<ViewController>>,
|
|
||||||
) -> Result<(), WorkspaceError> {
|
|
||||||
let params: UpdateDocParams = data.into_inner().try_into()?;
|
|
||||||
let _ = controller.update_view_data(params).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_sql_binary_expression {
|
macro_rules! impl_sql_binary_expression {
|
||||||
($target:ident) => {
|
($target:ident) => {
|
||||||
impl diesel::serialize::ToSql<diesel::sql_types::Binary, diesel::sqlite::Sqlite>
|
impl diesel::serialize::ToSql<diesel::sql_types::Binary, diesel::sqlite::Sqlite> for $target {
|
||||||
for $target
|
|
||||||
{
|
|
||||||
fn to_sql<W: std::io::Write>(
|
fn to_sql<W: std::io::Write>(
|
||||||
&self,
|
&self,
|
||||||
out: &mut diesel::serialize::Output<W, diesel::sqlite::Sqlite>,
|
out: &mut diesel::serialize::Output<W, diesel::sqlite::Sqlite>,
|
||||||
) -> diesel::serialize::Result {
|
) -> diesel::serialize::Result {
|
||||||
let bytes: Vec<u8> = self.try_into().map_err(|e| format!("{:?}", e))?;
|
let bytes: Vec<u8> = self.try_into().map_err(|e| format!("{:?}", e))?;
|
||||||
diesel::serialize::ToSql::<diesel::sql_types::Binary,diesel::sqlite::Sqlite,>::to_sql(&bytes, out)
|
diesel::serialize::ToSql::<diesel::sql_types::Binary, diesel::sqlite::Sqlite>::to_sql(&bytes, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// https://docs.diesel.rs/src/diesel/sqlite/types/mod.rs.html#30-33
|
// https://docs.diesel.rs/src/diesel/sqlite/types/mod.rs.html#30-33
|
||||||
|
@ -25,20 +23,13 @@ macro_rules! impl_sql_binary_expression {
|
||||||
*const [u8]: diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>,
|
*const [u8]: diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>,
|
||||||
{
|
{
|
||||||
fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
|
fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
|
||||||
let slice_ptr = <*const [u8] as diesel::deserialize::FromSql<
|
let slice_ptr = <*const [u8] as diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>>::from_sql(bytes)?;
|
||||||
diesel::sql_types::Binary,
|
|
||||||
DB,
|
|
||||||
>>::from_sql(bytes)?;
|
|
||||||
let bytes = unsafe { &*slice_ptr };
|
let bytes = unsafe { &*slice_ptr };
|
||||||
|
|
||||||
match $target::try_from(bytes) {
|
match $target::try_from(bytes) {
|
||||||
Ok(object) => Ok(object),
|
Ok(object) => Ok(object),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(
|
log::error!("{:?} deserialize from bytes fail. {:?}", std::any::type_name::<$target>(), e);
|
||||||
"{:?} deserialize from bytes fail. {:?}",
|
|
||||||
std::any::type_name::<$target>(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
panic!();
|
panic!();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -63,9 +54,7 @@ macro_rules! impl_sql_integer_expression {
|
||||||
DB: diesel::backend::Backend,
|
DB: diesel::backend::Backend,
|
||||||
i32: ToSql<Integer, DB>,
|
i32: ToSql<Integer, DB>,
|
||||||
{
|
{
|
||||||
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
|
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result { (*self as i32).to_sql(out) }
|
||||||
(*self as i32).to_sql(out)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DB> FromSql<Integer, DB> for $target
|
impl<DB> FromSql<Integer, DB> for $target
|
||||||
|
@ -105,9 +94,7 @@ macro_rules! impl_def_and_def_mut {
|
||||||
|
|
||||||
impl $target {
|
impl $target {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn take_items(&mut self) -> Vec<$item> {
|
pub fn take_items(&mut self) -> Vec<$item> { ::std::mem::replace(&mut self.items, vec![]) }
|
||||||
::std::mem::replace(&mut self.items, vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn push(&mut self, item: $item) {
|
pub fn push(&mut self, item: $item) {
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
|
|
||||||
mod model;
|
mod model;
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
|
|
|
@ -1,49 +1,49 @@
|
||||||
// Auto-generated, do not edit
|
// Auto-generated, do not edit
|
||||||
|
|
||||||
mod view_update;
|
mod view_update;
|
||||||
pub use view_update::*;
|
pub use view_update::*;
|
||||||
|
|
||||||
mod view_delete;
|
mod view_delete;
|
||||||
pub use view_delete::*;
|
pub use view_delete::*;
|
||||||
|
|
||||||
mod app_query;
|
mod app_query;
|
||||||
pub use app_query::*;
|
pub use app_query::*;
|
||||||
|
|
||||||
mod workspace_delete;
|
mod workspace_delete;
|
||||||
pub use workspace_delete::*;
|
pub use workspace_delete::*;
|
||||||
|
|
||||||
mod observable;
|
mod observable;
|
||||||
pub use observable::*;
|
pub use observable::*;
|
||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
pub use errors::*;
|
pub use errors::*;
|
||||||
|
|
||||||
mod workspace_update;
|
mod workspace_update;
|
||||||
pub use workspace_update::*;
|
pub use workspace_update::*;
|
||||||
|
|
||||||
mod app_create;
|
mod app_create;
|
||||||
pub use app_create::*;
|
pub use app_create::*;
|
||||||
|
|
||||||
mod workspace_query;
|
mod workspace_query;
|
||||||
pub use workspace_query::*;
|
pub use workspace_query::*;
|
||||||
|
|
||||||
mod event;
|
mod event;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
|
|
||||||
mod view_create;
|
mod view_create;
|
||||||
pub use view_create::*;
|
pub use view_create::*;
|
||||||
|
|
||||||
mod workspace_user_detail;
|
mod workspace_user_detail;
|
||||||
pub use workspace_user_detail::*;
|
pub use workspace_user_detail::*;
|
||||||
|
|
||||||
mod workspace_create;
|
mod workspace_create;
|
||||||
pub use workspace_create::*;
|
pub use workspace_create::*;
|
||||||
|
|
||||||
mod app_update;
|
mod app_update;
|
||||||
pub use app_update::*;
|
pub use app_update::*;
|
||||||
|
|
||||||
mod view_query;
|
mod view_query;
|
||||||
pub use view_query::*;
|
pub use view_query::*;
|
||||||
|
|
||||||
mod app_delete;
|
mod app_delete;
|
||||||
pub use app_delete::*;
|
pub use app_delete::*;
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl AppController {
|
||||||
match server.read_app(&token, params).await {
|
match server.read_app(&token, params).await {
|
||||||
Ok(option) => match option {
|
Ok(option) => match option {
|
||||||
None => {},
|
None => {},
|
||||||
Some(app) => {},
|
Some(_app) => {},
|
||||||
},
|
},
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ pub fn read_workspace(sdk: &FlowyTestSDK, request: QueryWorkspaceRequest) -> Opt
|
||||||
.sync_send()
|
.sync_send()
|
||||||
.parse::<RepeatedWorkspace>();
|
.parse::<RepeatedWorkspace>();
|
||||||
|
|
||||||
let mut workspaces = vec![];
|
let mut workspaces;
|
||||||
if let Some(workspace_id) = &request.workspace_id {
|
if let Some(workspace_id) = &request.workspace_id {
|
||||||
workspaces = repeated_workspace
|
workspaces = repeated_workspace
|
||||||
.take_items()
|
.take_items()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue