Skip to content
This repository was archived by the owner on Sep 27, 2024. It is now read-only.

Integrate mention parsing #719

Merged
merged 56 commits into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
df6b832
add new mention node types
Jun 13, 2023
93c97c8
add TODOs to clear match errors
Jun 13, 2023
1e2b95f
bit more type manipulation
Jun 13, 2023
437feee
handle invalid URIs early in `insert*` methods
Jun 14, 2023
5fb76eb
move at-room logic check to dom node layer
Jun 14, 2023
64de4f6
export MentionKind
Jun 14, 2023
d60112f
move to `Room` and `User` mention types
Jun 14, 2023
2d2cdad
fix most tests
Jun 14, 2023
6e16114
get all tests passing
Jun 14, 2023
4a56495
make `new` Mention return a `Result`, fix all tests/uses
Jun 14, 2023
3a82ef8
tidy up the logic
Jun 14, 2023
65bfbaf
rename function
Jun 14, 2023
8712fc1
update comment
Jun 14, 2023
8e159f8
update comments, strip out unused code
Jun 14, 2023
8e7c42d
make the message output use mx_id for room mentions
Jun 14, 2023
e0d2f1c
tidy up parsing
Jun 14, 2023
834e5cc
tidy up match branches and functions
Jun 14, 2023
1b0568b
tidy
Jun 14, 2023
1cd484a
fix clippy errors
Jun 14, 2023
d011a5b
fix typo
Jun 14, 2023
d3a0b74
extract `@room` checking/setting
Jun 14, 2023
d2f0edf
add import
Jun 14, 2023
1108eca
add test
Jun 14, 2023
e018d42
try to fix wasm error
Jun 14, 2023
b6d86e6
put import in correct place
Jun 14, 2023
7a6bf6f
get solution for custom links working
Jun 15, 2023
09e6c5d
add test and get it passing
Jun 15, 2023
e28717c
tidy up code
Jun 15, 2023
dde0295
add more tests
Jun 15, 2023
e383123
fix clippy error
Jun 15, 2023
4c08a5f
reinstate removed comment
Jun 15, 2023
a2e3361
separate out user and room in markdown
Jun 15, 2023
cacc965
extract AT_ROOM to constant in other crate
Jun 15, 2023
66ede7e
extract at room utils to matrix mention crate
Jun 15, 2023
6e90343
first hack at splitting at-room behaviour
Jun 15, 2023
38dc7cc
split dom node methods apart
Jun 15, 2023
e46895e
fix broken tests
Jun 15, 2023
554c049
remove unused import
Jun 15, 2023
3720b6c
add special case for example app
Jun 15, 2023
c5802f4
change function call
Jun 15, 2023
c946c94
change function name
Jun 15, 2023
b6b07bd
read new functions across to mobile
Jun 15, 2023
ca571d7
add test
Jun 15, 2023
a1aaf8b
remove unused code
Jun 15, 2023
393d0d9
reduce repeated code
Jun 15, 2023
afd8efb
refactor
Jun 15, 2023
a5f4fd5
redo comments
Jun 15, 2023
4d55895
get all tests passing
Jun 15, 2023
24e03cb
move AT_ROOM back where it belongs
Jun 15, 2023
2b81075
reinstate whitespace
Jun 15, 2023
98bb0f3
correct bindings error, update udl
Jun 15, 2023
c7fc5ec
update comment
Jun 15, 2023
18910a0
add TODOs, fix issues from call
Jun 16, 2023
8417740
add the configuration for the matrix_mentions crate
Jun 16, 2023
4028efc
fix TODO
Jun 16, 2023
46f48cb
address comments
Jun 16, 2023
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
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;
pub use crate::mention::{Mention, MentionKind};
5 changes: 5 additions & 0 deletions crates/matrix_mentions/src/mention.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ impl Mention {
&self.kind
}

/// Determine if a uri is a valid matrix uri
pub fn is_valid_uri(uri: &str) -> bool {
parse_matrix_id(uri).is_some()
}

/// Create a mention from a URI
///
/// If the URI is a valid room or user, it creates a mention using the
Expand Down
73 changes: 42 additions & 31 deletions crates/wysiwyg/src/composer_model/mentions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@
// 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 matrix_mentions::Mention;

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

impl<S> ComposerModel<S>
where
S: UnicodeString,
{
/// Remove the suggestion text and then insert a mention into the composer, using the following rules
/// - Do not insert a mention if the uri is invalid
/// - Do not insert a mention if the range includes link or code leaves
/// - If the composer contains a selection, remove the contents of the selection
/// prior to inserting a mention at the cursor.
Expand All @@ -33,7 +36,7 @@ where
suggestion: SuggestionPattern,
attributes: Vec<(S, S)>,
) -> ComposerUpdate<S> {
if self.should_not_insert_mention() {
if self.should_not_insert_mention(&url, &text) {
return ComposerUpdate::keep();
}

Expand All @@ -45,6 +48,7 @@ where
}

/// Inserts a mention into the composer. It uses the following rules:
/// - Do not insert a mention if the uri is invalid
/// - Do not insert a mention if the range includes link or code leaves
/// - If the composer contains a selection, remove the contents of the selection
/// prior to inserting a mention at the cursor.
Expand All @@ -55,7 +59,7 @@ where
text: S,
attributes: Vec<(S, S)>,
) -> ComposerUpdate<S> {
if self.should_not_insert_mention() {
if self.should_not_insert_mention(&url, &text) {
return ComposerUpdate::keep();
}

Expand All @@ -66,8 +70,9 @@ where
self.do_insert_mention(url, text, attributes)
}

/// Creates a new mention node then inserts the node at the cursor position. It adds a trailing space when the inserted
/// mention is the last node in it's parent.
/// Creates a new mention node then inserts the node at the cursor position. If creation fails due to
/// an invalid uri, it will return `ComposerUpdate::keep()`.
/// It adds a trailing space when the inserted mention is the last node in it's parent.
fn do_insert_mention(
&mut self,
url: S,
Expand All @@ -77,45 +82,51 @@ where
let (start, end) = self.safe_selection();
let range = self.state.dom.find_range(start, end);

// use the display text decide the mention type
// TODO extract this into a util function if it is reused when parsing the html prior to editing a message
// TODO decide if this do* function should be separated to handle mention vs at-room mention
// TODO handle invalid mention urls after permalink parsing methods have been created
let new_node = if text == "@room".into() {
DomNode::new_at_room_mention(attributes)
} else {
DomNode::new_mention(url, text, attributes)
};

let new_cursor_index = start + new_node.text_len();
if let Ok(new_node) = DomNode::new_mention(url, text, attributes) {
let new_cursor_index = start + new_node.text_len();

let handle = self.state.dom.insert_node_at_cursor(&range, new_node);
let handle = self.state.dom.insert_node_at_cursor(&range, new_node);

// manually move the cursor to the end of the mention
self.state.start = Location::from(new_cursor_index);
self.state.end = self.state.start;
// manually move the cursor to the end of the mention
self.state.start = Location::from(new_cursor_index);
self.state.end = self.state.start;

// add a trailing space in cases when we do not have a next sibling
if self.state.dom.is_last_in_parent(&handle) {
self.do_replace_text(" ".into())
// add a trailing space in cases when we do not have a next sibling
if self.state.dom.is_last_in_parent(&handle) {
self.do_replace_text(" ".into())
} else {
self.create_update_replace_all()
}
} else {
self.create_update_replace_all()
ComposerUpdate::keep()
}
}

/// Utility function for the insert_mention* methods. It returns false if the range
/// includes any link or code type leaves.
/// Utility function for the insert_mention* methods. It returns false if:
/// - the range includes any link or code type leaves
/// - the url is not a valid matrix uri (with special case for at-room)
///
/// Related issue is here:
/// https://github.com/matrix-org/matrix-rich-text-editor/issues/702
/// We do not allow mentions to be inserted into links, the planned behaviour is
/// detailed in the above issue.
fn should_not_insert_mention(&self) -> bool {
fn should_not_insert_mention(&self, url: &S, text: &S) -> bool {
let (start, end) = self.safe_selection();
let range = self.state.dom.find_range(start, end);

range.locations.iter().any(|l: &DomLocation| {
l.kind.is_link_kind() || l.kind.is_code_kind()
})
let invalid_uri = !Mention::is_valid_uri(url.to_string().as_str());

let range_contains_link_or_code_leaves =
range.locations.iter().any(|l: &DomLocation| {
l.kind.is_link_kind() || l.kind.is_code_kind()
});

// when we have an at-room mention, it doesn't matter about the url as we do not use
// it, rendering the mention as raw text in the html output
if MentionNode::is_at_room_display_text(text) {
range_contains_link_or_code_leaves
} else {
invalid_uri || range_contains_link_or_code_leaves
}
}
}
19 changes: 16 additions & 3 deletions crates/wysiwyg/src/dom/nodes/dom_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// 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 crate::composer_model::example_format::SelectionWriter;
use crate::dom::dom_handle::DomHandle;
use crate::dom::nodes::{
Expand All @@ -26,6 +25,7 @@ use crate::dom::unicode_string::UnicodeStrExt;
use crate::dom::{self, UnicodeString};
use crate::{InlineFormatType, ListType};

use super::mention_node::UriParseError;
use super::MentionNode;

#[derive(Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -138,12 +138,25 @@ where
DomNode::Container(ContainerNode::new_link(url, children, attributes))
}

/// Create a new mention node. This function will perform a single check of the display
/// text and return an at-room mention if that text exactly matches `@room`
///
/// Returns a result as creating a mention node can fail with an invalid uri
pub fn new_mention(
url: S,
display_text: S,
attributes: Vec<(S, S)>,
) -> DomNode<S> {
DomNode::Mention(MentionNode::new(url, display_text, attributes))
) -> Result<DomNode<S>, UriParseError> {
// special case for at-room
if MentionNode::is_at_room_display_text(&display_text) {
Ok(DomNode::Mention(MentionNode::new_at_room(attributes)))
} else if let Ok(mention_node) =
MentionNode::new(url, display_text, attributes)
{
Ok(DomNode::Mention(mention_node))
} else {
Err(UriParseError)
}
}

pub fn new_at_room_mention(attributes: Vec<(S, S)>) -> DomNode<S> {
Expand Down
Loading