Skip to content
This repository was archived by the owner on Sep 27, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bindings/wysiwyg-ffi/src/ffi_composer_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::ffi_composer_state::ComposerState;
use crate::ffi_composer_update::ComposerUpdate;
use crate::ffi_dom_creation_error::DomCreationError;
use crate::ffi_link_actions::LinkAction;
use crate::ffi_mentions_state::MentionsState;
use crate::into_ffi::IntoFfi;
use crate::{ActionState, ComposerAction, SuggestionPattern};

Expand Down Expand Up @@ -370,6 +371,10 @@ impl ComposerModel {
self.inner.lock().unwrap().get_link_action().into()
}

pub fn get_mentions_state(self: &Arc<Self>) -> MentionsState {
self.inner.lock().unwrap().get_mentions_state().into()
}

/// Force a panic for test purposes
pub fn debug_panic(self: &Arc<Self>) {
#[cfg(debug_assertions)]
Expand Down
18 changes: 18 additions & 0 deletions bindings/wysiwyg-ffi/src/ffi_mentions_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#[derive(uniffi::Record)]
pub struct MentionsState {
pub user_ids: Vec<String>,
pub room_ids: Vec<String>,
pub room_aliases: Vec<String>,
pub has_at_room_mention: bool,
}

impl From<wysiwyg::MentionsState> for MentionsState {
fn from(value: wysiwyg::MentionsState) -> Self {
Self {
user_ids: value.user_ids.into_iter().collect(),
room_ids: value.room_ids.into_iter().collect(),
room_aliases: value.room_aliases.into_iter().collect(),
has_at_room_mention: value.has_at_room_mention,
}
}
}
2 changes: 2 additions & 0 deletions bindings/wysiwyg-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod ffi_composer_state;
mod ffi_composer_update;
mod ffi_dom_creation_error;
mod ffi_link_actions;
mod ffi_mentions_state;
mod ffi_menu_action;
mod ffi_menu_state;
mod ffi_pattern_key;
Expand All @@ -38,6 +39,7 @@ pub use crate::ffi_composer_state::ComposerState;
pub use crate::ffi_composer_update::ComposerUpdate;
pub use crate::ffi_dom_creation_error::DomCreationError;
pub use crate::ffi_link_actions::LinkAction;
pub use crate::ffi_mentions_state::MentionsState;
pub use crate::ffi_menu_action::MenuAction;
pub use crate::ffi_menu_state::MenuState;
pub use crate::ffi_pattern_key::PatternKey;
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix_mentions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@

mod mention;

pub use crate::mention::{Mention, MentionKind};
pub use crate::mention::{Mention, MentionKind, RoomIdentificationType};
64 changes: 52 additions & 12 deletions crates/matrix_mentions/src/mention.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,22 @@ pub struct Mention {

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MentionKind {
Room,
Room(RoomIdentificationType),
User,
}

impl MentionKind {
pub fn is_room(&self) -> bool {
matches!(self, MentionKind::Room(_))
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RoomIdentificationType {
Id,
Alias,
}

impl Mention {
fn new(
uri: String,
Expand Down Expand Up @@ -134,17 +146,24 @@ impl Mention {
fn from_room(room_uri: &str) -> Option<Mention> {
// In all cases, use the alias/room ID being linked to as the
// anchor’s text.
let room_id_type: RoomIdentificationType;
let text = match parse_matrix_id(room_uri)? {
MatrixId::Room(room_id) => room_id.to_string(),
MatrixId::RoomAlias(room_alias) => room_alias.to_string(),
MatrixId::Room(room_id) => {
room_id_type = RoomIdentificationType::Id;
room_id.to_string()
}
MatrixId::RoomAlias(room_alias) => {
room_id_type = RoomIdentificationType::Alias;
room_alias.to_string()
}
_ => return None,
};

Some(Mention::new(
room_uri.to_string(),
text.clone(),
text,
MentionKind::Room,
MentionKind::Room(room_id_type),
))
}
}
Expand Down Expand Up @@ -200,7 +219,7 @@ fn parse_external_id(uri: &str) -> Result<MatrixToUri, IdParseError> {
mod test {
use ruma_common::{MatrixToUri, MatrixUri};

use crate::mention::{Mention, MentionKind};
use crate::mention::{Mention, MentionKind, RoomIdentificationType};

#[test]
fn parse_uri_matrix_to_valid_user() {
Expand Down Expand Up @@ -232,7 +251,10 @@ mod test {
assert_eq!(parsed.uri(), uri);
assert_eq!(parsed.mx_id(), "!roomid:example.org");
assert_eq!(parsed.display_text(), "!roomid:example.org");
assert_eq!(parsed.kind(), &MentionKind::Room);
assert_eq!(
parsed.kind(),
&MentionKind::Room(RoomIdentificationType::Id)
);
}

#[test]
Expand All @@ -243,7 +265,10 @@ mod test {
assert_eq!(parsed.uri(), uri);
assert_eq!(parsed.mx_id(), "!roomid:example.org");
assert_eq!(parsed.display_text(), "!roomid:example.org");
assert_eq!(parsed.kind(), &MentionKind::Room);
assert_eq!(
parsed.kind(),
&MentionKind::Room(RoomIdentificationType::Id)
);
}

#[test]
Expand All @@ -254,7 +279,10 @@ mod test {
assert_eq!(parsed.uri(), uri);
assert_eq!(parsed.mx_id(), "#room:example.org");
assert_eq!(parsed.display_text(), "#room:example.org");
assert_eq!(parsed.kind(), &MentionKind::Room);
assert_eq!(
parsed.kind(),
&MentionKind::Room(RoomIdentificationType::Alias)
);
}

#[test]
Expand All @@ -265,7 +293,10 @@ mod test {
assert_eq!(parsed.uri(), uri);
assert_eq!(parsed.mx_id(), "#room:example.org");
assert_eq!(parsed.display_text(), "#room:example.org");
assert_eq!(parsed.kind(), &MentionKind::Room);
assert_eq!(
parsed.kind(),
&MentionKind::Room(RoomIdentificationType::Alias)
);
}

#[test]
Expand Down Expand Up @@ -319,7 +350,10 @@ mod test {
assert_eq!(parsed.uri(), uri);
assert_eq!(parsed.mx_id(), "!roomid:example.org");
assert_eq!(parsed.display_text(), "!roomid:example.org");
assert_eq!(parsed.kind(), &MentionKind::Room);
assert_eq!(
parsed.kind(),
&MentionKind::Room(RoomIdentificationType::Id)
);
}

#[test]
Expand Down Expand Up @@ -347,7 +381,10 @@ mod test {
assert_eq!(parsed.uri(), uri);
assert_eq!(parsed.mx_id(), "!room:example.org");
assert_eq!(parsed.display_text(), "!room:example.org"); // note the display_text is overridden
assert_eq!(parsed.kind(), &MentionKind::Room);
assert_eq!(
parsed.kind(),
&MentionKind::Room(RoomIdentificationType::Id)
);
}

#[test]
Expand All @@ -361,7 +398,10 @@ mod test {
assert_eq!(parsed.uri(), uri);
assert_eq!(parsed.mx_id(), "#room:example.org");
assert_eq!(parsed.display_text(), "#room:example.org"); // note the display_text is overridden
assert_eq!(parsed.kind(), &MentionKind::Room);
assert_eq!(
parsed.kind(),
&MentionKind::Room(RoomIdentificationType::Alias)
);
}

#[test]
Expand Down
43 changes: 40 additions & 3 deletions crates/wysiwyg/src/composer_model/mentions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,52 @@
// limitations under the License.

use crate::{
dom::{nodes::MentionNode, DomLocation},
ComposerModel, ComposerUpdate, DomNode, Location, SuggestionPattern,
UnicodeString,
dom::{
nodes::{MentionNode, MentionNodeKind},
DomLocation,
},
ComposerModel, ComposerUpdate, DomNode, Location, MentionsState,
SuggestionPattern, UnicodeString,
};

impl<S> ComposerModel<S>
where
S: UnicodeString,
{
/// Returns the current mentions state of the content of the RTE editor.
pub fn get_mentions_state(&self) -> MentionsState {
let mut mentions_state = MentionsState::default();
for node in self.state.dom.iter_mentions() {
match node.kind() {
MentionNodeKind::AtRoom => {
mentions_state.has_at_room_mention = true
}
MentionNodeKind::MatrixUri { mention } => match mention.kind() {
matrix_mentions::MentionKind::Room(id_type) => {
match id_type {
matrix_mentions::RoomIdentificationType::Id => {
mentions_state
.room_ids
.insert(mention.mx_id().to_string());
}
matrix_mentions::RoomIdentificationType::Alias => {
mentions_state
.room_aliases
.insert(mention.mx_id().to_string());
}
}
}
matrix_mentions::MentionKind::User => {
mentions_state
.user_ids
.insert(mention.mx_id().to_string());
}
},
}
}
mentions_state
}

/// Checks to see if the mention should be inserted and also if the mention can be created.
/// If both of these checks are passed it will remove the suggestion and then insert a mention.
pub fn insert_mention_at_suggestion(
Expand Down
8 changes: 7 additions & 1 deletion crates/wysiwyg/src/dom/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{DomHandle, DomNode, UnicodeString};
use std::collections::HashSet;

use super::{
nodes::{ContainerNode, TextNode},
nodes::{ContainerNode, MentionNode, TextNode},
Dom,
};

Expand All @@ -48,6 +48,12 @@ where
self.iter().filter_map(DomNode::as_container)
}

/// Returns an iterator over all the mention nodes of this DOM, in depth-first
/// order
pub fn iter_mentions(&self) -> impl Iterator<Item = &MentionNode<S>> {
self.iter().filter_map(DomNode::as_mention)
}

/// Return an iterator over all nodes of the DOM from the passed node,
/// depth-first order (including self).
pub fn iter_from<'a>(&'a self, node: &'a DomNode<S>) -> DomNodeIterator<S> {
Expand Down
8 changes: 8 additions & 0 deletions crates/wysiwyg/src/dom/nodes/dom_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,14 @@ where
}
}

pub(crate) fn as_mention(&self) -> Option<&MentionNode<S>> {
if let Self::Mention(v) = self {
Some(v)
} else {
None
}
}

pub fn kind(&self) -> DomNodeKind {
match self {
DomNode::Text(_) => DomNodeKind::Text,
Expand Down
17 changes: 8 additions & 9 deletions crates/wysiwyg/src/dom/nodes/mention_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl<S: UnicodeString> MentionNode<S> {
// this is now only required for us to attach a custom style attribute for web
let mut attrs = self.attributes.clone();
let data_mention_type = match mention.kind() {
MentionKind::Room => "room",
MentionKind::Room(_) => "room",
MentionKind::User => "user",
};
attrs.push((
Expand All @@ -177,12 +177,11 @@ impl<S: UnicodeString> MentionNode<S> {
attrs
};

let display_text =
if as_message && mention.kind() == &MentionKind::Room {
S::from(mention.mx_id())
} else {
self.display_text()
};
let display_text = if as_message && mention.kind().is_room() {
S::from(mention.mx_id())
} else {
self.display_text()
};

self.fmt_tag_open(tag, formatter, &Some(attributes));
formatter.push(display_text);
Expand Down Expand Up @@ -286,7 +285,7 @@ where
// For a mention in a message, display the `mx_id` for a room mention, `display_text` otherwise
let text = match this.kind() {
MentionNodeKind::MatrixUri { mention }
if mention.kind() == &MentionKind::Room =>
if mention.kind().is_room() =>
{
S::from(mention.mx_id())
}
Expand All @@ -305,7 +304,7 @@ where
match this.kind() {
MentionNodeKind::MatrixUri { mention } => {
data_mention_type = match mention.kind() {
MentionKind::Room => "room",
MentionKind::Room(_) => "room",
MentionKind::User => "user",
};
href = mention.uri();
Expand Down
2 changes: 2 additions & 0 deletions crates/wysiwyg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod format_type;
mod link_action;
mod list_type;
mod location;
mod mentions_state;
mod menu_action;
mod menu_state;
mod pattern_key;
Expand Down Expand Up @@ -51,6 +52,7 @@ pub use crate::link_action::LinkAction;
pub use crate::link_action::LinkActionUpdate;
pub use crate::list_type::ListType;
pub use crate::location::Location;
pub use crate::mentions_state::MentionsState;
pub use crate::menu_action::MenuAction;
pub use crate::menu_action::MenuActionSuggestion;
pub use crate::menu_state::MenuState;
Expand Down
23 changes: 23 additions & 0 deletions crates/wysiwyg/src/mentions_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2023 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.

use std::collections::HashSet;

#[derive(Default, Debug, PartialEq, Eq)]
pub struct MentionsState {
pub user_ids: HashSet<String>,
pub room_ids: HashSet<String>,
pub room_aliases: HashSet<String>,
pub has_at_room_mention: bool,
}
Loading