diff --git a/src/interpreter/html.rs b/src/interpreter/html.rs
index 8861527f..b64e080b 100644
--- a/src/interpreter/html.rs
+++ b/src/interpreter/html.rs
@@ -53,7 +53,6 @@ pub struct TextOptions {
pub enum Element {
List(List),
- ListItem,
Input,
Table(Table),
TableRow(Vec),
diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs
index 477f96f3..83a74f19 100644
--- a/src/interpreter/mod.rs
+++ b/src/interpreter/mod.rs
@@ -49,6 +49,7 @@ struct State {
span_color: [f32; 4],
// Stores the row and a counter of newlines after each image
inline_images: Option<(Row, usize)>,
+ pending_list_prefix: Option,
}
// Images are loaded in a separate thread and use a callback to indicate when they're finished
@@ -415,7 +416,31 @@ impl TokenSink for HtmlInterpreter {
"bold" | "strong" => self.state.text_options.bold += 1,
"code" => self.state.text_options.code += 1,
"li" => {
- self.state.element_stack.push(html::Element::ListItem);
+ // Push a pending list prefix based on the list type
+ let mut list = None;
+ for element in self.state.element_stack.iter_mut().rev() {
+ if let html::Element::List(html_list) = element {
+ list = Some(html_list);
+ break;
+ }
+ }
+ let list = list.expect("List ended unexpectedly");
+ if self.current_textbox.texts.is_empty() {
+ if let html::List {
+ list_type: html::ListType::Ordered(index),
+ ..
+ } = list
+ {
+ self.state.pending_list_prefix = Some(format!("{}. ", index));
+ *index += 1;
+ } else if let html::List {
+ list_type: html::ListType::Unordered,
+ ..
+ } = list
+ {
+ self.state.pending_list_prefix = Some("· ".to_owned());
+ }
+ }
}
"ul" => {
self.push_current_textbox();
@@ -523,6 +548,9 @@ impl TokenSink for HtmlInterpreter {
if &name.local == "type" {
let value = value.to_string();
if value == "checkbox" {
+ // Checkbox uses a custom prefix, so remove pending text
+ // prefix
+ let _ = self.state.pending_list_prefix.take();
self.push_current_textbox();
self.current_textbox.set_checkbox(Some(
tag.attrs
@@ -631,7 +659,6 @@ impl TokenSink for HtmlInterpreter {
}
"li" => {
self.push_current_textbox();
- self.state.element_stack.pop();
}
"input" => {
self.push_current_textbox();
@@ -742,45 +769,16 @@ impl TokenSink for HtmlInterpreter {
self.hidpi_scale,
native_color(self.theme.text_color, &self.surface_format),
);
- if let Some(html::Element::ListItem) = self.state.element_stack.last() {
- let mut list = None;
- for element in self.state.element_stack.iter_mut().rev() {
- if let html::Element::List(html_list) = element {
- list = Some(html_list);
- break;
- }
- }
- let list = list.expect("List ended unexpectedly");
-
+ if let Some(prefix) = self.state.pending_list_prefix.take() {
if self.current_textbox.texts.is_empty() {
- if let html::List {
- list_type: html::ListType::Ordered(index),
- ..
- } = list
- {
- self.current_textbox.texts.push(
- Text::new(
- format!("{}. ", index),
- self.hidpi_scale,
- native_color(self.theme.text_color, &self.surface_format),
- )
- .make_bold(true),
- );
- *index += 1;
- } else if let html::List {
- list_type: html::ListType::Unordered,
- ..
- } = list
- {
- self.current_textbox.texts.push(
- Text::new(
- "· ".to_string(),
- self.hidpi_scale,
- native_color(self.theme.text_color, &self.surface_format),
- )
- .make_bold(true),
+ self.current_textbox.texts.push(
+ Text::new(
+ prefix,
+ self.hidpi_scale,
+ native_color(self.theme.text_color, &self.surface_format),
)
- }
+ .make_bold(true),
+ );
}
}
if self.state.text_options.block_quote >= 1 {
diff --git a/src/interpreter/snapshots/inlyne__interpreter__tests__code_in_ordered_list.snap b/src/interpreter/snapshots/inlyne__interpreter__tests__code_in_ordered_list.snap
new file mode 100644
index 00000000..2c881922
--- /dev/null
+++ b/src/interpreter/snapshots/inlyne__interpreter__tests__code_in_ordered_list.snap
@@ -0,0 +1,84 @@
+---
+source: src/interpreter/tests.rs
+expression: interpret_md(text)
+---
+[
+ TextBox(
+ TextBox {
+ indent: 50.0,
+ texts: [
+ Text {
+ text: "1. ",
+ default_color: Color(BLACK),
+ style: BOLD ,
+ ..
+ },
+ Text {
+ text: "1st item",
+ default_color: Color(BLACK),
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+ TextBox(
+ TextBox {
+ indent: 50.0,
+ background_color: Some(Color { r: 0.86, g: 0.88, b: 0.91 }),
+ is_code_block: true,
+ texts: [
+ Text {
+ text: "fn ",
+ size: 18.0,
+ color: Some(Color { r: 0.46, g: 0.27, b: 0.42 }),
+ ..
+ },
+ Text {
+ text: "main",
+ size: 18.0,
+ color: Some(Color { r: 0.27, g: 0.36, b: 0.45 }),
+ ..
+ },
+ Text {
+ text: "() {}",
+ size: 18.0,
+ color: Some(Color { r: 0.08, g: 0.10, b: 0.13 }),
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+ TextBox(
+ TextBox {
+ indent: 50.0,
+ texts: [
+ Text {
+ text: "2. ",
+ default_color: Color(BLACK),
+ style: BOLD ,
+ ..
+ },
+ Text {
+ text: "2nd item",
+ default_color: Color(BLACK),
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+]
diff --git a/src/interpreter/snapshots/inlyne__interpreter__tests__para_in_ordered_list.snap b/src/interpreter/snapshots/inlyne__interpreter__tests__para_in_ordered_list.snap
new file mode 100644
index 00000000..b00f8e2a
--- /dev/null
+++ b/src/interpreter/snapshots/inlyne__interpreter__tests__para_in_ordered_list.snap
@@ -0,0 +1,70 @@
+---
+source: src/interpreter/tests.rs
+description: " --- md\n\n1. 1st item\n\n Nested paragraph\n\n2. 2nd item\n\n\n --- html\n\n\n- \n
1st item
\nNested paragraph
\n \n- \n
2nd item
\n \n
\n"
+expression: interpret_md(text)
+---
+[
+ TextBox(
+ TextBox {
+ indent: 50.0,
+ texts: [
+ Text {
+ text: "1. ",
+ default_color: Color(BLACK),
+ style: BOLD ,
+ ..
+ },
+ Text {
+ text: "1st item",
+ default_color: Color(BLACK),
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+ TextBox(
+ TextBox {
+ indent: 50.0,
+ texts: [
+ Text {
+ text: "Nested paragraph",
+ default_color: Color(BLACK),
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+ TextBox(
+ TextBox {
+ indent: 50.0,
+ texts: [
+ Text {
+ text: "2. ",
+ default_color: Color(BLACK),
+ style: BOLD ,
+ ..
+ },
+ Text {
+ text: "2nd item",
+ default_color: Color(BLACK),
+ ..
+ },
+ ],
+ ..
+ },
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+ Spacer(
+ InvisibleSpacer(5),
+ ),
+]
diff --git a/src/interpreter/tests.rs b/src/interpreter/tests.rs
index 012641cd..a1f9e1cf 100644
--- a/src/interpreter/tests.rs
+++ b/src/interpreter/tests.rs
@@ -159,6 +159,24 @@ const ORDERED_LIST_IN_UNORDERED: &str = "\
- bullet
";
+const PARA_IN_ORDERED_LIST: &str = "\
+1. 1st item
+
+ Nested paragraph
+
+2. 2nd item
+";
+
+const CODE_IN_ORDERED_LIST: &str = "\
+1. 1st item
+
+ ```rust
+ fn main() {}
+ ```
+
+2. 2nd item
+";
+
snapshot_interpreted_elements!(
(sanity, SANITY),
(checklist_has_no_text_prefix, CHECKLIST_HAS_NO_TEXT_PREFIX),
@@ -167,6 +185,8 @@ snapshot_interpreted_elements!(
(unordered_list_in_ordered, UNORDERED_LIST_IN_ORDERED),
(nested_ordered_list, NESTED_ORDERED_LIST),
(ordered_list_in_unordered, ORDERED_LIST_IN_UNORDERED),
+ (para_in_ordered_list, PARA_IN_ORDERED_LIST),
+ (code_in_ordered_list, CODE_IN_ORDERED_LIST),
);
/// Spin up a server, so we can test network requests without external services
diff --git a/src/main.rs b/src/main.rs
index e17570dd..047d5eec 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -536,14 +536,14 @@ impl Inlyne {
}
}
}
- } else if open::that(link).is_err() {
- if let Some(anchor_pos) =
- self.renderer.positioner.anchors.get(link)
- {
- self.renderer.set_scroll_y(*anchor_pos);
- self.window.request_redraw();
- self.window.set_cursor_icon(CursorIcon::Default);
- }
+ } else if let Some(anchor_pos) =
+ self.renderer.positioner.anchors.get(link)
+ {
+ self.renderer.set_scroll_y(*anchor_pos);
+ self.window.request_redraw();
+ self.window.set_cursor_icon(CursorIcon::Default);
+ } else {
+ open::that(link).unwrap();
}
} else if self.renderer.selection.is_none() {
// Only set selection when not over link