Allow linebreaks after mentions

This commit is contained in:
silverpill 2021-12-21 22:25:35 +00:00
parent 07b711fd61
commit c13b110ca2
2 changed files with 46 additions and 34 deletions

View file

@ -9,15 +9,8 @@ use crate::models::profiles::queries::get_profiles_by_accts;
use crate::models::profiles::types::DbActorProfile;
const MENTION_RE: &str = r"@?(?P<user>\w+)@(?P<instance>.+)";
const MENTION_SEARCH_RE: &str = r"(?m)(?P<space>^|\s)@(?P<user>\w+)@(?P<instance>\S+)";
fn pattern_to_address(caps: &Captures, instance_host: &str) -> ActorAddress {
ActorAddress {
username: caps["user"].to_string(),
instance: caps["instance"].to_string(),
is_local: &caps["instance"] == instance_host,
}
}
const MENTION_SEARCH_RE: &str = r"(?m)(?P<before>^|\s)@(?P<user>\w+)@(?P<instance>\S+)";
const MENTION_SEARCH_SECONDARY_RE: &str = r"^(?P<instance>[\w\.-]+\w)(?P<after>(\.|<br>|\.<br>)?)$";
/// Finds everything that looks like a mention
fn find_mentions(
@ -25,11 +18,19 @@ fn find_mentions(
text: &str,
) -> Vec<String> {
let mention_re = Regex::new(MENTION_SEARCH_RE).unwrap();
let mention_secondary_re = Regex::new(MENTION_SEARCH_SECONDARY_RE).unwrap();
let mut mentions = vec![];
for caps in mention_re.captures_iter(text) {
let acct = pattern_to_address(&caps, instance_host).acct();
if !mentions.contains(&acct) {
mentions.push(acct);
if let Some(secondary_caps) = mention_secondary_re.captures(&caps["instance"]) {
let actor_address = ActorAddress {
username: caps["user"].to_string(),
instance: secondary_caps["instance"].to_string(),
is_local: &secondary_caps["instance"] == instance_host,
};
let acct = actor_address.acct();
if !mentions.contains(&acct) {
mentions.push(acct);
};
};
};
mentions
@ -56,23 +57,31 @@ pub fn replace_mentions(
text: &str,
) -> String {
let mention_re = Regex::new(MENTION_SEARCH_RE).unwrap();
let mention_secondary_re = Regex::new(MENTION_SEARCH_SECONDARY_RE).unwrap();
let result = mention_re.replace_all(text, |caps: &Captures| {
let acct = pattern_to_address(caps, instance_host).acct();
match mention_map.get(&acct) {
Some(profile) => {
if let Some(secondary_caps) = mention_secondary_re.captures(&caps["instance"]) {
let actor_address = ActorAddress {
username: caps["user"].to_string(),
instance: secondary_caps["instance"].to_string(),
is_local: &secondary_caps["instance"] == instance_host,
};
let acct = actor_address.acct();
if let Some(profile) = mention_map.get(&acct) {
// Replace with a link to profile.
// Actor URL may differ from actor ID.
let url = profile.actor_url(instance_url).unwrap();
format!(
return format!(
// https://microformats.org/wiki/h-card
r#"{}<span class="h-card"><a class="u-url mention" href="{}">@{}</a></span>"#,
caps["space"].to_string(),
r#"{}<span class="h-card"><a class="u-url mention" href="{}">@{}</a></span>{}"#,
caps["before"].to_string(),
url,
profile.username,
)
},
None => caps[0].to_string(), // leave unchanged if actor is not known
}
secondary_caps["after"].to_string(),
);
};
};
// Leave unchanged if actor is not known
caps[0].to_string()
});
result.to_string()
}
@ -84,7 +93,11 @@ pub fn mention_to_address(
let mention_re = Regex::new(MENTION_RE).unwrap();
let mention_caps = mention_re.captures(mention)
.ok_or(ValidationError("invalid mention tag"))?;
let actor_address = pattern_to_address(&mention_caps, instance_host);
let actor_address = ActorAddress {
username: mention_caps["user"].to_string(),
instance: mention_caps["instance"].to_string(),
is_local: &mention_caps["instance"] == instance_host,
};
Ok(actor_address)
}
@ -111,7 +124,6 @@ mod tests {
assert_eq!(results, vec![
"user1",
"user2@server2.com",
"test@server3.com@nospace@server4.com",
]);
}
@ -131,7 +143,10 @@ mod tests {
})),
..Default::default()
};
let text = "@user1@server1.com @user2@server2.com sometext @notmention @test@unknown.org";
let text = concat!(
"@user1@server1.com @user2@server2.com.\n",
"sometext @notmention @test@unknown.org"
);
let mention_map = HashMap::from([
("user1".to_string(), profile_1),
("user2@server2.com".to_string(), profile_2),
@ -140,7 +155,7 @@ mod tests {
let expected_result = concat!(
r#"<span class="h-card"><a class="u-url mention" href="https://server1.com/users/user1">@user1</a></span> "#,
r#"<span class="h-card"><a class="u-url mention" href="https://server2.com/@user2">@user2</a></span> "#,
r#"<span class="h-card"><a class="u-url mention" href="https://server2.com/@user2">@user2</a></span>."#, "\n",
r#"sometext @notmention @test@unknown.org"#,
);
assert_eq!(result, expected_result);

View file

@ -35,19 +35,16 @@ pub fn replace_tags(instance_url: &str, text: &str, tags: &[String]) -> String {
let after = secondary_caps["after"].to_string();
if tags.contains(&tag_name) {
let tag_page_url = get_tag_page_url(instance_url, &tag_name);
format!(
return format!(
r#"{}<a class="hashtag" href="{}">#{}</a>{}"#,
before,
tag_page_url,
tag,
after,
)
} else {
caps[0].to_string()
}
} else {
caps[0].to_string()
}
);
};
};
caps[0].to_string()
});
result.to_string()
}