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