///|
pub(all) struct Statistics {
input_bytes : Int
paragraphs : Int
runs : Int
characters : Int
hidden_characters : Int
words : Int
tables : Int
rows : Int
cells : Int
links : Int
fonts : Int
colors : Int
attachments : Int
body_paragraphs : Int
header_paragraphs : Int
footer_paragraphs : Int
note_paragraphs : Int
} derive(Eq, Debug, ToJson)
///|
fn word_space(c : Char) -> Bool {
match c.to_int() {
9
| 10
| 11
| 12
| 13
| 32
| 0x85
| 0xA0
| 0x1680
| 0x2000
| 0x2001
| 0x2002
| 0x2003
| 0x2004
| 0x2005
| 0x2006
| 0x2007
| 0x2008
| 0x2009
| 0x200A
| 0x2028
| 0x2029
| 0x202F
| 0x205F
| 0x3000 => true
_ => false
}
}
///|
/// Words are whitespace-delimited segments, not language-specific segmentation.
pub fn Document::statistics(self : Document) -> Statistics {
let mut runs = 0
let mut characters = 0
let mut hidden_characters = 0
let mut words = 0
let mut body = 0
let mut headers = 0
let mut footers = 0
let mut notes = 0
for paragraph in self.paragraphs {
match paragraph.region {
Body => body += 1
Header => headers += 1
Footer => footers += 1
Footnote | Annotation => notes += 1
}
let mut in_word = false
runs += paragraph.runs.length()
for run in paragraph.runs {
for c in run.text.iter() {
characters += 1
if run.style.hidden {
hidden_characters += 1
} else if word_space(c) {
in_word = false
} else if !in_word {
words += 1
in_word = true
}
}
}
}
let tables = self.tables()
let mut rows = 0
let mut cells = 0
for table in tables {
rows += table.rows.length()
for row in table.rows {
cells += row.cells.length()
}
}
{
input_bytes: self.input_bytes,
paragraphs: self.paragraphs.length(),
runs,
characters,
hidden_characters,
words,
tables: tables.length(),
rows,
cells,
links: self.links().length(),
fonts: self.fonts.length(),
colors: self.colors.length(),
attachments: self.attachments.length(),
body_paragraphs: body,
header_paragraphs: headers,
footer_paragraphs: footers,
note_paragraphs: notes,
}
}
///|
pub fn Statistics::to_text(self : Statistics) -> String {
let out = StringBuilder()
out.write_string("Input bytes: \{self.input_bytes}\n")
out.write_string("Paragraphs: \{self.paragraphs}\n")
out.write_string("Runs: \{self.runs}\n")
out.write_string("Unicode scalars: \{self.characters}\n")
out.write_string("Hidden scalars: \{self.hidden_characters}\n")
out.write_string("Whitespace-delimited words: \{self.words}\n")
out.write_string("Tables: \{self.tables}\n")
out.write_string("Rows: \{self.rows}\n")
out.write_string("Cells: \{self.cells}\n")
out.write_string("Unique links: \{self.links}\n")
out.write_string("Fonts: \{self.fonts}\n")
out.write_string("Colors: \{self.colors}\n")
out.write_string("Attachments: \{self.attachments}\n")
out.write_string(
"Regions: body=\{self.body_paragraphs}, headers=\{self.header_paragraphs}, footers=\{self.footer_paragraphs}, notes=\{self.note_paragraphs}\n",
)
out.to_string()
}
///|
pub fn ParseResult::inspect(self : ParseResult) -> String {
let out = StringBuilder()
out.write_string("MoonRTF document inspection\n")
out.write_string("Complete: \{self.complete}\n")
out.write_string(self.document.statistics().to_text())
for item in self.document.metadata {
out.write_string("Metadata \{item.key}: \{item.value}\n")
}
for font in self.document.fonts {
out.write_string(
"Font \{font.id}: \{font.name} (charset \{font.charset})\n",
)
}
for attachment in self.document.attachments {
out.write_string(
"Embedded \{attachment.kind}: bytes \{attachment.span.start}..\{attachment.span.end}\n",
)
}
for d in self.diagnostics {
out.write_string("\{d.code} at byte \{d.span.start}: \{d.message}\n")
}
out.to_string()
}