use std::path::PathBuf;
use crate::pcontent::{
pabstractcontent::{PAbstractContent, PAbstractLectureBackend},
pcontent::PContent,
pcontentdetail::PContentDetail,
pcontentenvironment::PContentEnvironment,
pcontentfootnote::PContentFootnote,
pcontentformula::PContentFormula,
pcontentitem::{PContentItem, PItemType, list_item_from_item},
pcontentmedia::{PContentMedia, PMediaType},
pcontentparagraph::PContentParagraph,
pcontentparser::PContentParser,
pcontentreference::PContentReference,
pcontentstyle::PContentStyle,
pcontenttable::PContentTable,
pcontenttext::PContentText,
pcontenttitle::PContentTitle,
pcontenturl::PContentUrl,
pcontentenvlist::PContentEnvList,
pcontenttimetable::PContentTimeTable,
pcontentspeaker::PContentSpeaker,
pcontentclipboardtext::PContentClipboardText,
pidcounter::PIdCounter,
plabeler::{PLabelId, PLabeler},
preferenceurl::PReferenceUrl
};
#[derive(Debug, Clone, PartialEq)]
pub enum PContentType{
Url(PLabeler<PContentUrl>),
Media(PLabeler<PContentMedia>),
Title(PLabeler<PContentTitle>),
FootNote(PLabeler<PContentFootnote>),
Content(PLabeler<PContent>),
TextBf(PLabeler<PVecContent>),
TextIt(PLabeler<PVecContent>),
TextCode(PLabeler<PVecContent>),
TextStyle(PLabeler<PContentStyle>),
Text(PLabeler<PContentText>),
Paragraph(PLabeler<PContentParagraph>),
Formula(PLabeler<PContentFormula>),
Parser(PLabeler<PContentParser>),
Environment(PLabeler<PContentEnvironment>),
Reference(PLabeler<PContentReference>),
ListItem(PLabeler<PContentItem>),
Table(PLabeler<PContentTable>),
Detail(PLabeler<PContentDetail>),
EnvList(PLabeler<PContentEnvList>),
TimeTable(PLabeler<PContentTimeTable>),
Speaker(PLabeler<PContentSpeaker>),
ClipboardText(PLabeler<PContentClipboardText>),
NewLine,
}
impl PContentType{
pub fn from_text(id: usize, text: &String) -> Self{
PContentType::Text(PLabeler::new(id, &PContentText::new(text)))
}
pub fn from_textbf(id_counter: &mut PIdCounter, text: &String) -> Self{
let text_content = PContentType::from_text(id_counter.get_id(), text);
let mut vec_content = PVecContent::new();
vec_content.add_child(&text_content);
return PContentType::TextBf(PLabeler::new(id_counter.get_id(), &vec_content));
}
pub fn from_text_style(id_counter: &mut PIdCounter, style: &String, text: &String) -> Self{
let text_content = PContentType::from_text(id_counter.get_id(), text);
let mut content_style = PContentStyle::new(style);
content_style.get_content_mut().add_child(&text_content);
return PContentType::TextStyle(PLabeler::new(id_counter.get_id(), &content_style));
}
pub fn from_media(id: usize, filename: &PathBuf, width: usize, media_type: &PMediaType, is_figure: bool) -> Self{
let content = PContentMedia::new(filename, width, media_type, is_figure);
PContentType::Media(PLabeler::new(id, &content))
}
pub fn from_url(id: usize, text: &String, url: &String) -> Self{
let mut content = PContentUrl::new();
content.set_url(url);
content.get_text_mut().add_child(&PContentType::from_text(id + 4000000000, text));
PContentType::Url(PLabeler::new(id, &content))
}
pub fn set_label(&mut self, label: &String){
match self {
PContentType::Url(url) => url.set_label(label),
PContentType::Media(media) => media.set_label(label),
PContentType::Title(title) => title.set_label(label),
PContentType::FootNote(footnote) => footnote.set_label(label),
PContentType::Content(content) => content.set_label(label),
PContentType::TextBf(textbf) => textbf.set_label(label),
PContentType::TextIt(textit) => textit.set_label(label),
PContentType::TextCode(code) => code.set_label(label),
PContentType::TextStyle(textstyle) => textstyle.set_label(label),
PContentType::Text(text) => text.set_label(label),
PContentType::Paragraph(paragraph) => paragraph.set_label(label),
PContentType::Parser(parser) => parser.set_label(label),
PContentType::Environment(env) => env.set_label(label),
PContentType::Formula(formula) => formula.set_label(label),
PContentType::Reference(reference) => reference.set_label(label),
PContentType::ListItem(listitem) => listitem.set_label(label),
PContentType::Table(table) => table.set_label(label),
PContentType::Detail(detail) => detail.set_label(label),
PContentType::EnvList(envlist) => envlist.set_label(label),
PContentType::TimeTable(timetable) => timetable.set_label(label),
PContentType::Speaker(speaker) => speaker.set_label(label),
PContentType::ClipboardText(clipboardtext) => clipboardtext.set_label(label),
PContentType::NewLine => {},
};
}
pub fn get_label(&self) -> Option<&String>{
match self {
PContentType::Url(url) => Some(url.get_label()),
PContentType::Media(media) => Some(media.get_label()),
PContentType::Title(title) => Some(title.get_label()),
PContentType::FootNote(footnote) => Some(footnote.get_label()),
PContentType::Content(content) => Some(content.get_label()),
PContentType::TextBf(textbf) => Some(textbf.get_label()),
PContentType::TextIt(textit) => Some(textit.get_label()),
PContentType::TextCode(code) => Some(code.get_label()),
PContentType::TextStyle(textstyle) => Some(textstyle.get_label()),
PContentType::Text(text) => Some(text.get_label()),
PContentType::Paragraph(paragraph) => Some(paragraph.get_label()),
PContentType::Parser(parser) => Some(parser.get_label()),
PContentType::Environment(env) => Some(env.get_label()),
PContentType::Formula(formula) => Some(formula.get_label()),
PContentType::Reference(reference) => Some(reference.get_label()),
PContentType::ListItem(listitem) => Some(listitem.get_label()),
PContentType::Table(table) => Some(table.get_label()),
PContentType::Detail(detail) => Some(detail.get_label()),
PContentType::EnvList(envlist) => Some(envlist.get_label()),
PContentType::TimeTable(timetable) => Some(timetable.get_label()),
PContentType::Speaker(speaker) => Some(speaker.get_label()),
PContentType::ClipboardText(clipboardtext) => Some(clipboardtext.get_label()),
PContentType::NewLine => None,
}
}
pub fn get_id(&self) -> usize {
match &self {
PContentType::Url(url) => url.get_id(),
PContentType::Media(media) => media.get_id(),
PContentType::Title(title) => title.get_id(),
PContentType::FootNote(footnote) => footnote.get_id(),
PContentType::Content(content) => content.get_id(),
PContentType::TextBf(textbf) => textbf.get_id(),
PContentType::TextIt(textit) => textit.get_id(),
PContentType::TextCode(code) => code.get_id(),
PContentType::TextStyle(textstyle) => textstyle.get_id(),
PContentType::Text(text) => text.get_id(),
PContentType::Paragraph(paragraph) => paragraph.get_id(),
PContentType::Parser(parser) => parser.get_id(),
PContentType::Environment(env) => env.get_id(),
PContentType::Formula(formula) => formula.get_id(),
PContentType::Reference(reference) => reference.get_id(),
PContentType::ListItem(listitem) => listitem.get_id(),
PContentType::Table(table) => table.get_id(),
PContentType::Detail(detail) => detail.get_id(),
PContentType::EnvList(envlist) => envlist.get_id(),
PContentType::TimeTable(timetable) => timetable.get_id(),
PContentType::Speaker(speaker) => speaker.get_id(),
PContentType::ClipboardText(clipboardtext) => clipboardtext.get_id(),
PContentType::NewLine => 0,
}
}
pub fn get_reference_url(&self, current_file: &String) -> PReferenceUrl{
match &self {
PContentType::Url(url) => url.get_reference_url(current_file),
PContentType::Media(media) => media.get_reference_url(current_file),
PContentType::Title(title) => title.get_reference_url(current_file),
PContentType::FootNote(footnote) => footnote.get_reference_url(current_file),
PContentType::Content(content) => content.get_reference_url(current_file),
PContentType::TextBf(textbf) => textbf.get_reference_url(current_file),
PContentType::TextIt(textit) => textit.get_reference_url(current_file),
PContentType::TextCode(code) => code.get_reference_url(current_file),
PContentType::TextStyle(textstyle) => textstyle.get_reference_url(current_file),
PContentType::Text(text) => text.get_reference_url(current_file),
PContentType::Paragraph(paragraph) => paragraph.get_reference_url(current_file),
PContentType::Parser(parser) => parser.get_reference_url(current_file),
PContentType::Environment(env) => env.get_reference_url(current_file),
PContentType::Formula(formula) => formula.get_reference_url(current_file),
PContentType::Reference(reference) => reference.get_reference_url(current_file),
PContentType::ListItem(listitem) => listitem.get_reference_url(current_file),
PContentType::Table(table) => table.get_reference_url(current_file),
PContentType::Detail(detail) => detail.get_reference_url(current_file),
PContentType::EnvList(envlist) => envlist.get_reference_url(current_file),
PContentType::TimeTable(timetable) => timetable.get_reference_url(current_file),
PContentType::Speaker(speaker) => speaker.get_reference_url(current_file),
PContentType::ClipboardText(clipboardtext) => clipboardtext.get_reference_url(current_file),
PContentType::NewLine => PReferenceUrl::from_text(current_file, 0, &String::from("PContentType::NewLine")),
}
}
pub fn is_in_paragraph(&self) -> bool {
match &self {
PContentType::Url(_) => true,
PContentType::Media(media) => !media.get_data().is_figure(),
PContentType::Title(_) => false,
PContentType::FootNote(_) => true,
PContentType::Content(_) => false,
PContentType::TextBf(_) => true,
PContentType::TextIt(_) => true,
PContentType::TextCode(_) => true,
PContentType::TextStyle(_) => true,
PContentType::Text(_) => true,
PContentType::Paragraph(_) => false,
PContentType::Formula(formula) => formula.get_data().is_inlined(),
PContentType::Parser(parser) => parser.get_data().is_inlined(),
PContentType::Environment(_) => false,
PContentType::Reference(_) => true,
PContentType::ListItem(_) => false,
PContentType::Table(_) => false,
PContentType::Detail(_) => false,
PContentType::EnvList(_) => false,
PContentType::TimeTable(_) => false,
PContentType::Speaker(_) => false,
PContentType::ClipboardText(_) => true,
PContentType::NewLine => true,
}
}
}
#[derive(Debug, Default, Clone, PartialEq)]
pub struct PVecContent{
p_vec_child: Vec<PContentType>,
}
impl PVecContent {
pub fn new() -> Self{
PVecContent {
p_vec_child: vec![]
}
}
pub fn len(&self) -> usize{
self.p_vec_child.len()
}
pub fn add_child(&mut self, content_type: &PContentType){
self.p_vec_child.push(content_type.clone());
}
pub fn append_content(&mut self, content: &PVecContent){
for child in content.p_vec_child.iter(){
self.p_vec_child.push(child.clone());
}
}
pub fn get_vec_child(&self) -> &Vec<PContentType> {
&self.p_vec_child
}
pub fn get_vec_child_mut(&mut self) -> &mut Vec<PContentType> {
&mut self.p_vec_child
}
pub fn update_title_number(&mut self, vec_title_number: &mut Vec<usize>){
for content in self.p_vec_child.iter_mut() {
match content {
PContentType::Title(section) => {
let section_level: usize = section.get_data().get_level();
let section_data = section.get_data_mut();
if section_data.is_enumerated() {
if vec_title_number.len() > section_level {
vec_title_number.truncate(section_level);
}
match vec_title_number.get_mut(section_level - 1) {
Some(section_number) => {
*section_number += 1;
section_data.set_title_number(&vec_title_number);
},
None => {
vec_title_number.push(1);
section_data.set_title_number(&vec_title_number);
}
};
section_data.make_filename();
}
},
&mut _ => {}
};
}
}
pub fn add_content(&mut self, id: &mut PIdCounter, content_type: &PContentType, is_paragraph_enabled: bool){
if !is_paragraph_enabled { self.add_child(content_type);
return;
}
if content_type.is_in_paragraph() { self.add_content_in_paragraph(id, content_type, is_paragraph_enabled);
}else{
match content_type {
PContentType::ListItem(content_list_item) => {
self.add_content_item(id, content_list_item);
},
_ => self.add_child(content_type),
}
}
}
fn add_content_item(&mut self, id: &mut PIdCounter, content_list_item: &PLabeler<PContentItem>){
match self.p_vec_child.last_mut() {
Some(last_content) => {
match last_content {
PContentType::ListItem(last_list_item) => {
match last_list_item.get_data().get_type() {
PItemType::Item => {
if last_list_item.get_data().get_indentation_level() >= content_list_item.get_data().get_indentation_level() {
self.add_child(&PContentType::ListItem(content_list_item.clone()));
}else{
let list_from_item: PContentItem = list_item_from_item(&content_list_item);
self.add_child(&PContentType::ListItem(PLabeler::new(content_list_item.get_id(), &list_from_item)));
}
},
PItemType::List => {
if last_list_item.get_data().get_indentation_level() >= content_list_item.get_data().get_indentation_level() {
last_list_item.get_data_mut().get_content_mut().add_child(&PContentType::ListItem(content_list_item.clone()));
}else{
last_list_item.get_data_mut().get_content_mut().add_content_item(id, content_list_item);
}
}
}
},
_ => self.add_list_item_in_content(id, content_list_item),
}
},
None => self.add_list_item_in_content(id, content_list_item)
}
}
fn add_list_item_in_content(&mut self, id: &mut PIdCounter, list_item: &PLabeler<PContentItem>){
match list_item.get_data().get_type() {
PItemType::List => self.add_child(&PContentType::ListItem(list_item.clone())),
PItemType::Item => {
let mut tmp_list = PContentItem::new(list_item.get_data().get_indentation_level(), &PItemType::List);
tmp_list.get_content_mut().add_child(&PContentType::ListItem(list_item.clone()));
self.add_child(&PContentType::ListItem(PLabeler::new(id.get_id(), &tmp_list)));
}
}
}
fn add_content_in_paragraph(&mut self, id: &mut PIdCounter, content_type: &PContentType, is_paragraph_enabled: bool){
match self.p_vec_child.last_mut() {
Some(last_child) => {
match last_child {
PContentType::ListItem(last_list_item) => {
match last_list_item.get_data().get_type() {
PItemType::List => last_list_item.get_data_mut().get_content_mut().add_content(id, content_type, is_paragraph_enabled),
PItemType::Item => last_list_item.get_data_mut().get_content_mut().add_content(id, content_type, is_paragraph_enabled),
}
},
PContentType::Paragraph(last_paragraph) => last_paragraph.get_data_mut().get_content_mut().add_child(content_type),
_ => self.add_content_create_paragraph(id, content_type)
}
},
None => self.add_content_create_paragraph(id, content_type)
}
}
fn add_content_create_paragraph(&mut self, id: &mut PIdCounter, content_type: &PContentType){
let mut paragraph: PContentParagraph = PContentParagraph::new();
paragraph.get_content_mut().add_child(content_type);
self.add_child(&PContentType::Paragraph(PLabeler::new(id.get_id(), ¶graph)));
}
pub fn add_text(&mut self, id: &mut PIdCounter, text: &String) -> bool{
let mut trim_text = String::from(text.trim_matches('\n'));
if trim_text.is_empty() { return false;
}
if text.starts_with("\n"){
trim_text = String::from(&format!(" {}", trim_text));
}
match self.get_vec_child_mut().last_mut() {
Some(last_content) => { match last_content {
PContentType::ListItem(last_item) => last_item.get_data_mut().add_text(id, &trim_text),
PContentType::Paragraph(last_paragraph) => last_paragraph.get_data_mut().add_text(id, &trim_text),
_ => self.create_paragraph_with_text(id, &trim_text)
}
},
None => self.create_paragraph_with_text(id, &trim_text)
}
return true;
}
pub fn create_paragraph_with_text(&mut self, id: &mut PIdCounter, trim_text: &String){
let text_content = PContentType::Text(PLabeler::new(id.get_id(), &PContentText::new(&trim_text)));
let mut paragraph = PContentParagraph::new();
paragraph.get_content_mut().add_child(&text_content);
self.add_child(&PContentType::Paragraph(PLabeler::new(id.get_id(), ¶graph)));
}
}
impl PAbstractContent for PVecContent{
fn has_embeded_label(&self) -> bool{
false
}
fn get_reference_url(&self, current_file: &String, id: usize) -> PReferenceUrl{
PReferenceUrl::from_text(current_file, id, &String::from("PVecContent"))
}
fn to_html<TLectureBackend>(&self, backend: &mut TLectureBackend, _id: &PLabelId)
where TLectureBackend: PAbstractLectureBackend
{
for content in self.p_vec_child.iter() {
match content {
PContentType::Url(url) => url.to_html(backend),
PContentType::Media(media) => media.to_html(backend),
PContentType::Title(title) => title.to_html(backend),
PContentType::FootNote(footnote) => footnote.to_html(backend),
PContentType::Content(content) => content.to_html(backend),
PContentType::TextBf(textbf) => {
backend.write(&String::from("<b>"));
textbf.to_html(backend);
backend.write(&String::from("</b>"));
},
PContentType::TextIt(textit) => {
backend.write(&String::from("<em>"));
textit.to_html(backend);
backend.write(&String::from("</em>"));
},
PContentType::TextCode(code) => {
backend.write(&String::from("<span class=\"code_inline\">"));
code.to_html(backend);
backend.write(&String::from("</span>"));
},
PContentType::TextStyle(textstyle) => textstyle.to_html(backend),
PContentType::Text(text) => text.to_html(backend),
PContentType::Paragraph(paragraph) => paragraph.to_html(backend),
PContentType::Parser(parser) => parser.to_html(backend),
PContentType::Environment(env) => env.to_html(backend),
PContentType::Formula(formula) => formula.to_html(backend),
PContentType::Reference(reference) => reference.to_html(backend),
PContentType::ListItem(listitem) => listitem.to_html(backend),
PContentType::Table(table) => table.to_html(backend),
PContentType::Detail(detail) => detail.to_html(backend),
PContentType::EnvList(envlist) => envlist.to_html(backend),
PContentType::TimeTable(timetable) => timetable.to_html(backend),
PContentType::Speaker(speaker) => speaker.to_html(backend),
PContentType::ClipboardText(clipboardtext) => clipboardtext.to_html(backend),
PContentType::NewLine => backend.write(&String::from("<br />")),
};
}
}
}
#[cfg(test)]
mod tests{
use super::*;
use crate::phighlighter::PLocation;
use std::path::PathBuf;
#[test]
fn test_pveccontent_add_content_title(){
let id = &mut PIdCounter::new(0); let mut vec_content: PVecContent = Default::default();
let title = PContentTitle::new(1, true, &PLocation::new(&PathBuf::from("index.md"), 1, 1));
let title_id = id.get_id();
vec_content.add_content(id, &PContentType::Title(PLabeler::new(title_id, &title.clone())), true);
assert_eq!(vec_content.get_vec_child().len(), 1);
assert_eq!(vec_content.get_vec_child().last().unwrap(), &PContentType::Title(PLabeler::new(title_id, &title)));
}
#[test]
fn test_pveccontent_add_content_text(){
let id = &mut PIdCounter::new(0); let mut vec_content: PVecContent = Default::default();
let text = PContentText::new(&String::from("Hello world"));
let text_id = id.get_id();
vec_content.add_content(id, &PContentType::Text(PLabeler::new(text_id, &text)), true);
assert_eq!(vec_content.get_vec_child().len(), 1);
let mut expected_paragraph = PContentParagraph::new();
expected_paragraph.get_content_mut().add_child(&PContentType::Text(PLabeler::new(text_id, &text)));
let expected_paragraph_type = PContentType::Paragraph(PLabeler::new(1, &expected_paragraph));
assert_eq!(vec_content.get_vec_child().last().unwrap(), &expected_paragraph_type);
}
#[test]
fn test_pveccontent_add_content_item(){
let id = &mut PIdCounter::new(0); let mut vec_content: PVecContent = Default::default();
let item = PContentItem::new(1, &PItemType::Item);
let item_id = id.get_id();
vec_content.add_content(id, &PContentType::ListItem(PLabeler::new(item_id, &item)), true);
assert_eq!(vec_content.get_vec_child().len(), 1);
let text = PContentText::new(&String::from("Hello world"));
let text_id = id.get_id();
vec_content.add_content(id, &PContentType::Text(PLabeler::new(text_id, &text)), true);
assert_eq!(vec_content.get_vec_child().len(), 1);
let item1 = PContentItem::new(1, &PItemType::Item);
let item1_id = id.get_id();
vec_content.add_content(id, &PContentType::ListItem(PLabeler::new(item1_id, &item1)), true);
let text1 = PContentText::new(&String::from("Hello world 1"));
let text1_id = id.get_id();
vec_content.add_content(id, &PContentType::Text(PLabeler::new(text1_id, &text1)), true);
let item2 = PContentItem::new(2, &PItemType::Item);
let item2_id = id.get_id();
vec_content.add_content(id, &PContentType::ListItem(PLabeler::new(item2_id, &item2)), true);
let text2 = PContentText::new( &String::from("Hello world 2"));
let text2_id = id.get_id();
vec_content.add_content(id, &PContentType::Text(PLabeler::new(text2_id, &text2)), true);
let item12 = PContentItem::new(1, &PItemType::Item);
let item12_id = id.get_id();
vec_content.add_content(id, &PContentType::ListItem(PLabeler::new(item12_id, &item12)), true);
let text12 = PContentText::new(&String::from("Hello world 1 2"));
let text12_id = id.get_id();
vec_content.add_content(id, &PContentType::Text(PLabeler::new(text12_id, &text12)), true);
assert_eq!(vec_content.get_vec_child().len(), 1); }
#[test]
fn test_veccontent_append_content(){
let mut content_base = PVecContent::new();
content_base.add_child(&PContentType::NewLine);
let mut content_dest = PVecContent::new();
content_dest.add_child(&PContentType::NewLine);
content_dest.append_content(&content_base);
assert_eq!(content_dest.len(), 2);
}
}