///|
fn markdown_editor_active_heading(
blocks : Array[MarkdownEditorBlock],
) -> String {
for block in blocks {
match block.block.kind {
Heading(_) => return block.block.text
_ => ()
}
}
"Untitled"
}
///|
pub(all) struct MarkdownEditorFrontMatterMetadata {
title : String
tags : Array[String]
}
///|
fn markdown_editor_front_matter_metadata(
blocks : Array[MarkdownEditorBlock],
) -> MarkdownEditorFrontMatterMetadata {
if blocks.length() == 0 {
return { title: "", tags: [] }
}
match blocks[0].block.kind {
FrontMatter =>
markdown_editor_parse_front_matter_metadata(blocks[0].block.text)
_ => { title: "", tags: [] }
}
}
///|
fn markdown_editor_parse_front_matter_metadata(
source : String,
) -> MarkdownEditorFrontMatterMetadata {
let tags : Array[String] = []
let mut title = ""
let mut collecting_tags = false
for line in markdown_editor_lines(source) {
let text = line.text.trim().to_owned()
if text.has_prefix("title:") {
let value = markdown_editor_substring(
text,
6,
markdown_editor_text_length(text),
)
.trim()
.to_owned()
title = markdown_editor_front_matter_scalar(value)
collecting_tags = false
} else if text.has_prefix("tags:") {
tags.clear()
let value = markdown_editor_substring(
text,
5,
markdown_editor_text_length(text),
)
.trim()
.to_owned()
if value == "" {
collecting_tags = true
} else {
tags.append(markdown_editor_front_matter_tags(value))
collecting_tags = false
}
} else if collecting_tags && text.has_prefix("- ") {
let value = markdown_editor_substring(
text,
2,
markdown_editor_text_length(text),
)
.trim()
.to_owned()
let tag = markdown_editor_front_matter_scalar(value)
if tag != "" {
tags.push(tag)
}
} else if text != "" {
collecting_tags = false
}
}
{ title, tags }
}
///|
fn markdown_editor_front_matter_tags(source : String) -> Array[String] {
let text = source.trim().to_owned()
if text == "" {
[]
} else if text.has_prefix("[") && text.has_suffix("]") {
let length = markdown_editor_text_length(text)
markdown_editor_split_front_matter_tag_list(
markdown_editor_substring(text, 1, length - 1),
)
} else {
let tag = markdown_editor_front_matter_scalar(text)
if tag == "" {
[]
} else {
[tag]
}
}
}
///|
fn markdown_editor_split_front_matter_tag_list(
source : String,
) -> Array[String] {
let tags : Array[String] = []
let current : Array[Char] = []
let mut quoted = false
let mut quote = '"'
for ch in source {
if quoted {
current.push(ch)
if ch == quote {
quoted = false
}
} else if ch == '"' || ch == '\'' {
quoted = true
quote = ch
current.push(ch)
} else if ch == ',' {
markdown_editor_push_front_matter_tag(tags, String::from_array(current))
current.clear()
} else {
current.push(ch)
}
}
markdown_editor_push_front_matter_tag(tags, String::from_array(current))
tags
}
///|
fn markdown_editor_push_front_matter_tag(
tags : Array[String],
source : String,
) -> Unit {
let tag = markdown_editor_front_matter_scalar(source.trim().to_owned())
if tag != "" {
tags.push(tag)
}
}
///|
fn markdown_editor_front_matter_scalar(source : String) -> String {
let text = source.trim().to_owned()
let chars = text.to_array()
if chars.length() >= 2 &&
(
(chars[0] == '"' && chars[chars.length() - 1] == '"') ||
(chars[0] == '\'' && chars[chars.length() - 1] == '\'')
) {
String::from_array(chars[1:chars.length() - 1]).trim().to_owned()
} else {
text
}
}
///|
fn markdown_editor_reading_minutes(word_count : Int) -> Int {
if word_count <= 0 {
0
} else {
(word_count + 219) / 220
}
}
///|
fn markdown_editor_outline(
blocks : Array[MarkdownEditorBlock],
) -> Array[MarkdownEditorOutlineItem] {
let items : Array[MarkdownEditorOutlineItem] = []
for block in blocks {
match block.block.kind {
Heading(level) =>
items.push({
level,
title: block.block.text,
source_start: block.content_range.start,
})
_ => ()
}
}
items
}