refactor attribute key

This commit is contained in:
appflowy 2021-09-13 15:51:13 +08:00
parent 26aa4e951e
commit 4d139b3f56
83 changed files with 480 additions and 1044 deletions

View file

@ -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::*;

View file

@ -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},

View file

@ -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)

View file

@ -7,7 +7,6 @@ use flowy_workspace::entities::{
DeleteWorkspaceParams, DeleteWorkspaceParams,
QueryWorkspaceParams, QueryWorkspaceParams,
UpdateWorkspaceParams, UpdateWorkspaceParams,
Workspace,
}, },
}; };

View file

@ -1,4 +1,2 @@
mod model; mod model;
pub use model::*; pub use model::*;

View file

@ -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::*;

View file

@ -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()

View file

@ -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!()
} }

View file

@ -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();

View file

@ -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,
);

View file

@ -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;

View file

@ -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,

View file

@ -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 {

View file

@ -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());

View file

@ -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;

View file

@ -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! {

View file

@ -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"),
);
} }
} }

View file

@ -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))

View file

@ -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::*,
};
} }

View file

@ -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)
}

View file

@ -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()))
} }

View file

@ -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()
}
} }
}; };
} }

View file

@ -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)
})
} }
} }

View file

@ -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) }
} }

View file

@ -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(())
} }

View file

@ -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()
} }

View file

@ -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());
} }

View file

@ -1,4 +1,2 @@
mod model; mod model;
pub use model::*; pub use model::*;

View file

@ -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::*;

View file

@ -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();

View file

@ -1,4 +1,2 @@
mod model; mod model;
pub use model::*; pub use model::*;

View file

@ -1,4 +1,4 @@
// Auto-generated, do not edit // Auto-generated, do not edit
mod kv; mod kv;
pub use kv::*; pub use kv::*;

View file

@ -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";

View file

@ -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,

View file

@ -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)

View file

@ -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"];

View file

@ -1,4 +1,2 @@
mod model; mod model;
pub use model::*; pub use model::*;

View file

@ -1,4 +1,4 @@
// Auto-generated, do not edit // Auto-generated, do not edit
mod subject; mod subject;
pub use subject::*; pub use subject::*;

View file

@ -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(),
)
} }
} }

View file

@ -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;
}, },

View file

@ -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),
} }
} }

View file

@ -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;
}, },

View file

@ -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(),
} }
} }

View file

@ -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
}
} }

View file

@ -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());
} }

View file

@ -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);
} }

View file

@ -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;

View file

@ -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 } }
} }

View file

@ -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 {}),
]
}

View file

@ -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 {

View file

@ -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) {

View file

@ -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

View file

@ -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 }
} }

View file

@ -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
} }

View file

@ -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(())
} }

View file

@ -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());
} }
} }

View file

@ -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

View file

@ -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 }
} }

View file

@ -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]

View file

@ -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
))
} }
} }

View file

@ -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()))
}
} }

View file

@ -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);

View file

@ -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
} }

View file

@ -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"}]"#),
]; ];

View file

@ -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);

View file

@ -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,

View file

@ -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())?)
}
} }

View file

@ -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 }

View file

@ -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 {

View file

@ -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 }
} }

View file

@ -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 {}

View file

@ -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()
}
} }

View file

@ -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 {

View file

@ -1,4 +1,2 @@
mod model; mod model;
pub use model::*; pub use model::*;

View file

@ -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::*;

View file

@ -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 })

View file

@ -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(())
}

View file

@ -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) {

View file

@ -1,4 +1,2 @@
mod model; mod model;
pub use model::*; pub use model::*;

View file

@ -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::*;

View file

@ -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(_) => {},
} }

View file

@ -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()