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
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?
275 276 277 278 279 280 281 282 283 284 285 286 287 288
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?
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 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
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?
520 521 522 523 524 525 526 527 528 529 530 531 532 533
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!