Expand description
The main bbcode system. You create this to parse bbcode! Inexpensive clones, since fields are all reference counted.
Fields§
§matchers: Arc<Vec<MatchInfo>>Supply this!
Implementations§
source§impl BBCode
impl BBCode
sourcepub fn default() -> Result<Self, Error>
pub fn default() -> Result<Self, Error>
Get a default bbcode parser. Should hopefully have reasonable defaults!
sourcepub fn from_matchers(matchers: Vec<MatchInfo>) -> Self
pub fn from_matchers(matchers: Vec<MatchInfo>) -> Self
Create a BBCode parser from the given list of matchers. If you’re building a custom set of tags,
or merging [BBCode::basic()] with BBCode::extras() (and maybe more), use this endpoint
sourcepub fn get_tagregex(
tag: &'static str,
open_consume: Option<(i32, i32)>,
close_consume: Option<(i32, i32)>
) -> (String, String)
pub fn get_tagregex(
tag: &'static str,
open_consume: Option<(i32, i32)>,
close_consume: Option<(i32, i32)>
) -> (String, String)
Produce the two basic regexes (open and close) for bbcode tags
Examples found in repository?
298 299 300 301 302 303 304 305 306 307 308 309 310 311
pub fn add_tagmatcher(matchers: &mut Vec<MatchInfo>, tag: &'static str, info: ScopeInfo, open_consume: Option<(i32,i32)>, close_consume: Option<(i32,i32)>) -> Result<(), Error> { //open_regex: String, close_regex: String) -> Result<(), Error> {
let (open_tag, close_tag) = Self::get_tagregex(tag, open_consume, close_consume);
matchers.push(MatchInfo {
id: tag,
regex: Regex::new(&open_tag)?,
match_type: MatchType::Open(Arc::new(info))
});
matchers.push(MatchInfo {
id: tag,
regex: Regex::new(&close_tag)?,
match_type: MatchType::Close,
});
Ok(())
}sourcepub fn add_tagmatcher(
matchers: &mut Vec<MatchInfo>,
tag: &'static str,
info: ScopeInfo,
open_consume: Option<(i32, i32)>,
close_consume: Option<(i32, i32)>
) -> Result<(), Error>
pub fn add_tagmatcher(
matchers: &mut Vec<MatchInfo>,
tag: &'static str,
info: ScopeInfo,
open_consume: Option<(i32, i32)>,
close_consume: Option<(i32, i32)>
) -> Result<(), Error>
Add the open and close matches to the given vector for the given tag (you must construct ScopeInfo yourself). open_consume and close_consume are the amount of newlines to take before and after the open and close tag
Examples found in repository?
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
pub fn basics() -> Result<Vec<MatchInfo>, regex::Error>
{
//First, get the default direct replacements
let mut matches : Vec<MatchInfo> = Vec::new();
//This is an optimization: any large block of characters that has no meaning in bbcode can go straight through.
matches.push(MatchInfo {
id: NORMALTEXTID,
//We use h to catch ourselves on https. this unfortunately breaks up large sections of text into much
//smaller ones, but it should be ok... I don't know. My parser is stupid lol
regex: Regex::new(r#"^[^\[\n\rh]+"#)?,
match_type : MatchType::Simple(Box::new(|c| String::from(html_escape::encode_quoted_attribute(&c[0]))))
});
matches.push(MatchInfo {
id: CONSUMETEXTID,
regex: Regex::new(r#"^[\r]+"#)?,
match_type: MatchType::Simple(Box::new(|_c| String::new()))
});
#[allow(unused_variables)]
{
Self::add_tagmatcher(&mut matches, "b", ScopeInfo::basic(Box::new(|o,b,c| format!("<b>{b}</b>"))), None, None)?;
Self::add_tagmatcher(&mut matches, "i", ScopeInfo::basic(Box::new(|o,b,c| format!("<i>{b}</i>"))), None, None)?;
Self::add_tagmatcher(&mut matches, "sup", ScopeInfo::basic(Box::new(|o,b,c| format!("<sup>{b}</sup>"))), None, None)?;
Self::add_tagmatcher(&mut matches, "sub", ScopeInfo::basic(Box::new(|o,b,c| format!("<sub>{b}</sub>"))), None, None)?;
Self::add_tagmatcher(&mut matches, "u", ScopeInfo::basic(Box::new(|o,b,c| format!("<u>{b}</u>"))), None, None)?;
Self::add_tagmatcher(&mut matches, "s", ScopeInfo::basic(Box::new(|o,b,c| format!("<s>{b}</s>"))), None, None)?;
Self::add_tagmatcher(&mut matches, "list", ScopeInfo::basic(Box::new(|o,b,c| format!("<ul>{b}</ul>"))), Some((0,1)), Some((0,1)))?;
Self::add_tagmatcher(&mut matches, r"\*", ScopeInfo {
only: None, double_closes: true, emit: Box::new(|o,b,c| format!("<li>{b}</li>"))
}, Some((1,0)), Some((1,0)))?;
Self::add_tagmatcher(&mut matches, r"url", ScopeInfo {
only: Some(vec![NORMALTEXTID, CONSUMETEXTID]),
double_closes: false,
emit: Box::new(|o,b,c| format!(r#"<a href="{}" target="_blank">{}</a>"#, Self::attr_or_body(o,b), b) )
}, None, None)?;
Self::add_tagmatcher(&mut matches, r"img", ScopeInfo {
only: Some(vec![NORMALTEXTID, CONSUMETEXTID]),
double_closes: false,
emit: Box::new(|o,b,c| format!(r#"<img src="{}">"#, Self::attr_or_body(o,b)) )
}, None, None)?;
}
//This new autolinker is taken from 12 since it works better
let url_chars = r#"[-a-zA-Z0-9_/%&=#+~@$*'!?,.;:]*"#;
let end_chars = r#"[-a-zA-Z0-9_/%&=#+~@$*']"#;
let autolink_regex = format!("^https?://{0}{1}([(]{0}[)]({0}{1})?)?", url_chars, end_chars);
//Don't forget about autolinking! This is a crappy autolinker and it doesn't matter too much!
matches.push(MatchInfo {
id: AUTOLINKID,
//characters taken from google's page https://developers.google.com/maps/url-encoding
//NOTE: removed certain characters from autolinking because they SUCK
regex: Regex::new(&autolink_regex)?,
match_type: MatchType::Simple(Box::new(|c| format!(r#"<a href="{0}" target="_blank">{0}</a>"#, &c[0])))
});
//There's a [list=1] thing, wonder how to do that. It's nonstandard, our list format is entirely nonstandard
Ok(matches)
}
/// Some fancy extra bbcode. Does not include basics! These are nonstandard, you don't have to use them!
pub fn extras() -> Result<Vec<MatchInfo>, Error>
{
let mut matches : Vec<MatchInfo> = Vec::new();
Self::add_tagmatcher(&mut matches, "h1", ScopeInfo::basic(Box::new(|_o,b,_c| format!("<h1>{}</h1>",b))), None, None)?;
Self::add_tagmatcher(&mut matches, "h2", ScopeInfo::basic(Box::new(|_o,b,_c| format!("<h2>{}</h2>",b))), None, None)?;
Self::add_tagmatcher(&mut matches, "h3", ScopeInfo::basic(Box::new(|_o,b,_c| format!("<h3>{}</h3>",b))), None, None)?;
Self::add_tagmatcher(&mut matches, r"quote", ScopeInfo::basic(
Box::new(|o,b,_c| format!(r#"<blockquote{}>{}</blockquote>"#, Self::attr_or_nothing(o,"cite"), b) )
), Some((0,1)), Some((0,1)))?;
Self::add_tagmatcher(&mut matches, r"spoiler", ScopeInfo::basic(
Box::new(|o,b,_c| format!(r#"<details class="spoiler">{}{}</details>"#, Self::tag_or_something(o,"summary", Some("Spoiler")), b) )
), None, None)?;
Self::add_tagmatcher(&mut matches, r"anchor", ScopeInfo {
only: Some(vec![NORMALTEXTID,CONSUMETEXTID]),
double_closes: false,
emit: Box::new(|o,b,_c| format!(r#"<a{}>{}</a>"#, Self::attr_or_nothing(o,"name"), b) )
}, None, None)?;
Self::add_tagmatcher(&mut matches, r"icode", ScopeInfo {
only: Some(vec![NORMALTEXTID,CONSUMETEXTID]),
double_closes: false,
emit: Box::new(|_o,b,_c| format!(r#"<span class="icode">{b}</span>"#) )
}, None, None)?;
Self::add_tagmatcher(&mut matches, r"code", ScopeInfo {
only: Some(vec![NORMALTEXTID,CONSUMETEXTID]),
double_closes: false,
emit: Box::new(|o,b,_c| format!(r#"<pre{}>{}</pre>"#, Self::attr_or_nothing(o, "data-code"), b) )
}, Some((0,1)), Some((0,1)))?;
Self::add_tagmatcher(&mut matches, r"youtube", ScopeInfo {
only: Some(vec![NORMALTEXTID,CONSUMETEXTID]),
double_closes: false,
emit: Box::new(|o,b,_c| format!(r#"<a href={} target="_blank" data-youtube>{}</a>"#, Self::attr_or_body(o, b), b) )
}, None, None)?;
Ok(matches)
}sourcepub fn basics() -> Result<Vec<MatchInfo>, Error>
pub fn basics() -> Result<Vec<MatchInfo>, Error>
Get a vector of ALL basic matchers! This is the function you want to call to get a vector for the bbcode generator!
sourcepub fn extras() -> Result<Vec<MatchInfo>, Error>
pub fn extras() -> Result<Vec<MatchInfo>, Error>
Some fancy extra bbcode. Does not include basics! These are nonstandard, you don’t have to use them!
sourcepub fn parse(&self, input: &str) -> String
pub fn parse(&self, input: &str) -> String
Main function! You call this to parse your raw bbcode! It also escapes html stuff so it can be used raw! Current version keeps newlines as-is and it’s expected you use pre-wrap, later there may be modes for more standard implementations
Examples found in repository?
544 545 546 547 548 549 550 551 552 553 554 555 556 557
pub fn parse_profiled_opt(&mut self, input: &str, _name: String) -> String
{
#[cfg(feature = "profiling")]
{
let mut profile = onestop::OneDuration::new(_name);
let result = self.parse(input);
profile.finish();
self.profiler.add(profile);
result
}
#[cfg(not(feature = "profiling"))]
return self.parse(input);
}sourcepub fn parse_profiled_opt(&mut self, input: &str, _name: String) -> String
pub fn parse_profiled_opt(&mut self, input: &str, _name: String) -> String
This MAY OR MAY NOT profile, depending on your featureset!