diff --git a/Makefile b/Makefile index 74f10190..24e38b7c 100644 --- a/Makefile +++ b/Makefile @@ -3,26 +3,26 @@ all: android ios web android: android-aarch64 android-x86_64 android-aarch64: - cd bindings/wysiwyg-ffi && cargo build --target aarch64-linux-android + cd bindings/wysiwyg-ffi && cargo build --release --target aarch64-linux-android echo Outputs for android-aarch64: - echo - target/aarch64-linux-android/debug/libwysiwyg_ffi.so + echo - target/aarch64-linux-android/release/libwysiwyg_ffi.so echo - bindings/wysiwyg-ffi/src/wysiwyg_composer.udl android-x86_64: - cd bindings/wysiwyg-ffi && cargo build --target x86_64-linux-android + cd bindings/wysiwyg-ffi && cargo build --release --target x86_64-linux-android echo Outputs for android-x86_64: - echo - target/x86_64-linux-android/debug/libwysiwyg_ffi.so + echo - target/x86_64-linux-android/release/libwysiwyg_ffi.so echo - bindings/wysiwyg-ffi/src/wysiwyg_composer.udl ios: cd bindings/ffi && \ - cargo build --target aarch64-apple-ios && \ - cargo build --target aarch64-apple-ios-sim && \ - cargo build --target x86_64-apple-ios && \ + cargo build -release --target aarch64-apple-ios && \ + cargo build -release --target aarch64-apple-ios-sim && \ + cargo build -release --target x86_64-apple-ios && \ mkdir -p ../../target/ios-combined && \ lipo -create \ - ../../target/x86_64-apple-ios/debug/libwysiwyg_composer.a \ - ../../target/aarch64-apple-ios-sim/debug/libwysiwyg_composer.a \ + ../../target/x86_64-apple-ios/release/libwysiwyg_composer.a \ + ../../target/aarch64-apple-ios-sim/release/libwysiwyg_composer.a \ -output ../../target/ios-combined/libwysiwyg_composer.a echo Outputs for iOS: echo - target/ios-combined/libwysiwyg_composer.a diff --git a/bindings/wysiwyg-ffi/src/ffi_action_request.rs b/bindings/wysiwyg-ffi/src/ffi_action_request.rs new file mode 100644 index 00000000..95fa8f2e --- /dev/null +++ b/bindings/wysiwyg-ffi/src/ffi_action_request.rs @@ -0,0 +1,11 @@ +pub enum ActionRequest { + Dummy, +} + +impl ActionRequest { + pub fn from(inner: wysiwyg::ActionRequest) -> Self { + match inner { + wysiwyg::ActionRequest::Dummy => Self::Dummy, + } + } +} diff --git a/bindings/wysiwyg-ffi/src/ffi_action_response.rs b/bindings/wysiwyg-ffi/src/ffi_action_response.rs new file mode 100644 index 00000000..beb070ff --- /dev/null +++ b/bindings/wysiwyg-ffi/src/ffi_action_response.rs @@ -0,0 +1,11 @@ +pub enum ActionResponse { + Dummy, +} + +impl From for wysiwyg::ActionResponse { + fn from(inner: ActionResponse) -> Self { + match inner { + ActionResponse::Dummy => wysiwyg::ActionResponse::Dummy, + } + } +} diff --git a/bindings/wysiwyg-ffi/src/ffi_composer_action.rs b/bindings/wysiwyg-ffi/src/ffi_composer_action.rs new file mode 100644 index 00000000..75210628 --- /dev/null +++ b/bindings/wysiwyg-ffi/src/ffi_composer_action.rs @@ -0,0 +1,19 @@ +use crate::ActionRequest; + +pub struct ComposerAction { + inner: wysiwyg::ComposerAction, +} + +impl ComposerAction { + pub fn from(inner: wysiwyg::ComposerAction) -> Self { + Self { inner } + } + + pub fn action_id(&self) -> String { + self.inner.action_id.clone() + } + + pub fn action(&self) -> ActionRequest { + ActionRequest::from(self.inner.action.clone()) + } +} diff --git a/bindings/wysiwyg-ffi/src/ffi_composer_model.rs b/bindings/wysiwyg-ffi/src/ffi_composer_model.rs new file mode 100644 index 00000000..5bd80243 --- /dev/null +++ b/bindings/wysiwyg-ffi/src/ffi_composer_model.rs @@ -0,0 +1,53 @@ +use std::sync::{Arc, Mutex}; + +use crate::ffi_action_response::ActionResponse; +use crate::ffi_composer_update::ComposerUpdate; + +pub struct ComposerModel { + inner: Mutex, +} + +impl ComposerModel { + pub fn new() -> Self { + Self { + inner: Mutex::new(wysiwyg::ComposerModel::new()), + } + } + + pub fn select(self: &Arc, start_codepoint: u32, end_codepoint: u32) { + self.inner.lock().unwrap().select( + usize::try_from(start_codepoint).unwrap(), + usize::try_from(end_codepoint).unwrap(), + ) + } + + pub fn replace_text( + self: &Arc, + new_text: String, + ) -> Arc { + Arc::new(ComposerUpdate::from( + self.inner.lock().unwrap().replace_text(new_text), + )) + } + + pub fn backspace(self: &Arc) -> Arc { + Arc::new(ComposerUpdate::from(self.inner.lock().unwrap().backspace())) + } + + pub fn delete(self: &Arc) -> Arc { + Arc::new(ComposerUpdate::from(self.inner.lock().unwrap().delete())) + } + + pub fn action_response( + self: &Arc, + action_id: String, + response: ActionResponse, + ) -> Arc { + Arc::new(ComposerUpdate::from( + self.inner + .lock() + .unwrap() + .action_response(action_id, response.into()), + )) + } +} diff --git a/bindings/wysiwyg-ffi/src/ffi_composer_update.rs b/bindings/wysiwyg-ffi/src/ffi_composer_update.rs new file mode 100644 index 00000000..29c37fc5 --- /dev/null +++ b/bindings/wysiwyg-ffi/src/ffi_composer_update.rs @@ -0,0 +1,31 @@ +use std::sync::Arc; + +use crate::ffi_composer_action::ComposerAction; +use crate::ffi_menu_state::MenuState; +use crate::ffi_text_update::TextUpdate; + +pub struct ComposerUpdate { + inner: wysiwyg::ComposerUpdate, +} + +impl ComposerUpdate { + pub fn from(inner: wysiwyg::ComposerUpdate) -> Self { + Self { inner } + } + + pub fn text_update(&self) -> TextUpdate { + TextUpdate::from(self.inner.text_update.clone()) + } + + pub fn menu_state(&self) -> MenuState { + MenuState::from(self.inner.menu_state.clone()) + } + + pub fn actions(&self) -> Vec> { + self.inner + .actions + .iter() + .map(|action| Arc::new(ComposerAction::from(action.clone()))) + .collect() + } +} diff --git a/bindings/wysiwyg-ffi/src/ffi_menu_state.rs b/bindings/wysiwyg-ffi/src/ffi_menu_state.rs new file mode 100644 index 00000000..c98ba5c5 --- /dev/null +++ b/bindings/wysiwyg-ffi/src/ffi_menu_state.rs @@ -0,0 +1,11 @@ +pub enum MenuState { + None, +} + +impl MenuState { + pub fn from(inner: wysiwyg::MenuState) -> Self { + match inner { + wysiwyg::MenuState::None => Self::None, + } + } +} diff --git a/bindings/wysiwyg-ffi/src/ffi_text_update.rs b/bindings/wysiwyg-ffi/src/ffi_text_update.rs new file mode 100644 index 00000000..40a8ae5c --- /dev/null +++ b/bindings/wysiwyg-ffi/src/ffi_text_update.rs @@ -0,0 +1,15 @@ +pub enum TextUpdate { + Keep, + ReplaceAll { replacement_text: String }, +} + +impl TextUpdate { + pub fn from(inner: wysiwyg::TextUpdate) -> Self { + match inner { + wysiwyg::TextUpdate::Keep => Self::Keep, + wysiwyg::TextUpdate::ReplaceAll(replacement_text) => { + Self::ReplaceAll { replacement_text } + } + } + } +} diff --git a/bindings/wysiwyg-ffi/src/lib.rs b/bindings/wysiwyg-ffi/src/lib.rs index ff3b42bc..bd8f1da7 100644 --- a/bindings/wysiwyg-ffi/src/lib.rs +++ b/bindings/wysiwyg-ffi/src/lib.rs @@ -14,10 +14,24 @@ uniffi_macros::include_scaffolding!("wysiwyg_composer"); +mod ffi_action_request; +mod ffi_action_response; +mod ffi_composer_action; +mod ffi_composer_model; +mod ffi_composer_update; +mod ffi_menu_state; +mod ffi_text_update; + use std::sync::Arc; -pub use wysiwyg::ComposerModel; +pub use crate::ffi_action_request::ActionRequest; +pub use crate::ffi_action_response::ActionResponse; +pub use crate::ffi_composer_action::ComposerAction; +pub use crate::ffi_composer_model::ComposerModel; +pub use crate::ffi_composer_update::ComposerUpdate; +pub use crate::ffi_menu_state::MenuState; +pub use crate::ffi_text_update::TextUpdate; pub fn new_composer_model() -> Arc { - Arc::new(ComposerModel {}) + Arc::new(ComposerModel::new()) } diff --git a/bindings/wysiwyg-ffi/src/wysiwyg_composer.udl b/bindings/wysiwyg-ffi/src/wysiwyg_composer.udl index e1d30a17..a9e46d68 100644 --- a/bindings/wysiwyg-ffi/src/wysiwyg_composer.udl +++ b/bindings/wysiwyg-ffi/src/wysiwyg_composer.udl @@ -1,7 +1,57 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + namespace wysiwyg_composer { ComposerModel new_composer_model(); }; interface ComposerModel { - string identify_thyself(); + void select(u32 start_codepoint, u32 end_codepoint); + ComposerUpdate replace_text(string new_text); + ComposerUpdate backspace(); + ComposerUpdate delete(); + ComposerUpdate action_response(string action_id, ActionResponse response); +}; + +interface ComposerUpdate { + TextUpdate text_update(); + MenuState menu_state(); + sequence actions(); +}; + +[Enum] +interface TextUpdate { + Keep(); + ReplaceAll(string replacement_text); +}; + +[Enum] +interface MenuState { + None(); +}; + +interface ComposerAction { + string action_id(); + ActionRequest action(); +}; + +[Enum] +interface ActionRequest { + Dummy(); +}; + +[Enum] +interface ActionResponse { + Dummy(); }; diff --git a/crates/wysiwyg/src/lib.rs b/crates/wysiwyg/src/lib.rs index f286d1b5..df62823b 100644 --- a/crates/wysiwyg/src/lib.rs +++ b/crates/wysiwyg/src/lib.rs @@ -12,12 +12,85 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! WYSIWYG composer library - pub struct ComposerModel {} impl ComposerModel { - pub fn identify_thyself(&self) -> String { - String::from("I am a ComposerModel") + pub fn new() -> Self { + Self {} + } + + /** + * Cursor is at end_codepoint. + */ + pub fn select(&mut self, start_codepoint: usize, end_codepoint: usize) { + drop(start_codepoint); + drop(end_codepoint); + } + + pub fn replace_text(&mut self, new_text: String) -> ComposerUpdate { + drop(new_text); + ComposerUpdate::keep(MenuState::None) + } + + pub fn backspace(&mut self) -> ComposerUpdate { + ComposerUpdate::keep(MenuState::None) + } + + pub fn delete(&mut self) -> ComposerUpdate { + ComposerUpdate::keep(MenuState::None) + } + + pub fn action_response( + &mut self, + action_id: String, + response: ActionResponse, + ) -> ComposerUpdate { + drop(action_id); + drop(response); + ComposerUpdate::keep(MenuState::None) } } + +#[derive(Debug, Clone)] +pub struct ComposerUpdate { + pub text_update: TextUpdate, + pub menu_state: MenuState, + pub actions: Vec, +} + +impl ComposerUpdate { + pub fn keep(menu_state: MenuState) -> Self { + Self { + text_update: TextUpdate::Keep, + menu_state, + actions: Vec::new(), + } + } +} + +#[derive(Debug, Clone)] +pub enum TextUpdate { + Keep, + ReplaceAll(String), +} + +#[derive(Debug, Clone)] +pub enum MenuState { + None, +} + +#[derive(Debug, Clone)] +pub struct ComposerAction { + pub action_id: String, + pub action: ActionRequest, +} + +#[derive(Debug, Clone)] +pub enum ActionRequest { + Dummy, +} + +#[derive(Debug, Clone)] +pub enum ActionResponse { + Dummy, +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..df99c691 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +max_width = 80