Markdown renderer for docs

This commit is contained in:
Connor Slade
2025-02-15 13:49:25 -05:00
parent 284f156e51
commit dbd87b6829
8 changed files with 196 additions and 16 deletions

19
Cargo.lock generated
View File

@@ -2799,6 +2799,17 @@ dependencies = [
"libc",
]
[[package]]
name = "markdown"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef3aab6a1d529b112695f72beec5ee80e729cb45af58663ec902c8fac764ecdd"
dependencies = [
"lazy_static",
"pipeline",
"regex",
]
[[package]]
name = "matrixmultiply"
version = "0.2.4"
@@ -2910,6 +2921,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"bincode",
"bitflags 2.5.0",
"bytemuck",
"chrono",
"clone-macro",
@@ -2928,6 +2940,7 @@ dependencies = [
"imageproc",
"itertools 0.13.0",
"libblur",
"markdown",
"nalgebra 0.32.6",
"notify-rust",
"open",
@@ -3613,6 +3626,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pipeline"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d15b6607fa632996eb8a17c9041cb6071cb75ac057abd45dece578723ea8c7c0"
[[package]]
name = "piper"
version = "0.2.3"

View File

@@ -25,6 +25,7 @@ image = "0.25.1"
imageproc = "0.25.0"
itertools = "0.13.0"
libblur = "0.15.1"
markdown = "0.3.0"
md5 = "0.7.0"
nalgebra = { version = "0.32.6", features = ["serde-serialize"] }
notify-rust = "4.11.0"

11
docs/getting_started.md Normal file
View File

@@ -0,0 +1,11 @@
# Getting Started
Welcome to mslicer!
Currently, mslicer can only output `.goo` files, which is a format spsific to [ELEGOO](https://www.elegoo.com) resin printers. In the future I plan to add support for other formats, but in the meantime you can use [UVTools](https://github.com/sn4k3/UVtools) to convert between formats.
If you are using mslicer for the first time, in order for the sliced results to be loadable by your printer, you will first need to configure the platform resolution and build volume in the `Slice Config` panel on the left. The defaults are for the ElEGOO [Saturn 3 Ultra](https://us.elegoo.com/products/elegoo-saturn-3-ultra-resin-3d-printer-12k). If these values are wrong, your printer may fail to load the sliced .goo file without even showing an error message.
mslicer can load `.stl` and `.obj` models, either by finding the `Import Model` button under the File menu, or by dragging the files onto the window. For now you can load the built in test model (it's the [Utah Teapot](https://en.wikipedia.org/wiki/Utah_teapot)) by pressing `Ctrl+T`.
To be continued

View File

@@ -1,9 +0,0 @@
Welcome to mslicer!
Currently, mslicer can only output .goo files, which is a format spsific to ELEGOO resin printers. In the future I plan to add support for other formats, but in the meantime you can use UVTools to convert between formats.
If you are using mslicer for the first time, in order for the sliced results to be loadable by your printer, you will first need to configure the platform resolution and build volume in the `Slice Config` panel on the left. The defaults are for the ElEGOO Saturn 3 Ultra. If these values are wrong, your printer may fail to load the sliced .goo file without even showing an error message.
mslicer can load .stl and .obj models, either by finding the `Import Model` button under the File menu, or by dragging the files onto the window. For now you can load the built in test model (it's the Utah Teapot) by pressing `Ctrl+T`.
To be continued

View File

@@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
anyhow.workspace = true
bincode.workspace = true
bitflags.workspace = true
bytemuck.workspace = true
chrono.workspace = true
clone-macro.workspace = true
@@ -22,6 +23,7 @@ image.workspace = true
imageproc.workspace = true
itertools.workspace = true
libblur.workspace = true
markdown.workspace = true
nalgebra.workspace = true
notify-rust.workspace = true
open.workspace = true

157
mslicer/src/ui/markdown.rs Normal file
View File

@@ -0,0 +1,157 @@
use bitflags::bitflags;
use egui::{Align, Layout, RichText, Sense, TextStyle, Ui, Vec2};
use markdown::{Block, Span};
const BODY_SIZE: f32 = 12.5;
const HEADING_SIZES: [f32; 6] = [18.0, 16.0, 14.0, 12.0, 10.0, 8.0];
pub struct CompiledMarkdown {
nodes: Vec<Node>,
}
enum Node {
Body(Vec<BodyNode>),
Break,
}
enum BodyNode {
Text {
text: String,
size: f32,
flags: TextFlags,
},
Link {
text: String,
url: String,
},
}
bitflags! {
#[derive(Clone, Copy)]
struct TextFlags: u8 {
const HEADER = 1 << 0;
const WEAK = 1 << 1;
const BOLD = 1 << 2;
const ITALIC = 1 << 3;
const MONOSPACE = 1 << 4;
}
}
impl TextFlags {
pub fn apply(&self, mut text: RichText) -> RichText {
if self.contains(TextFlags::HEADER) {
text = text.heading();
}
if self.contains(TextFlags::WEAK) {
text = text.weak();
}
if self.contains(TextFlags::BOLD) {
text = text.strong();
}
if self.contains(TextFlags::ITALIC) {
text = text.italics();
}
if self.contains(TextFlags::MONOSPACE) {
text = text.monospace();
}
text
}
}
impl CompiledMarkdown {
pub fn compile(source: &str) -> Self {
let mut nodes = Vec::new();
for token in markdown::tokenize(source) {
match token {
Block::Header(span, level) => {
let mut flags = TextFlags::HEADER;
if level > 1 {
flags |= TextFlags::WEAK;
}
nodes.push(Node::Body(span_text(span, HEADING_SIZES[level - 1], flags)));
nodes.push(Node::Break);
}
Block::Paragraph(span) => {
nodes.push(Node::Body(span_text(span, BODY_SIZE, TextFlags::empty())));
nodes.push(Node::Break);
}
_ => {}
}
}
Self { nodes }
}
pub fn render(&self, ui: &mut Ui) {
ui.allocate_ui_with_layout(
Vec2::new(ui.available_width(), ui.spacing().interact_size.y),
Layout::left_to_right(Align::Max).with_main_wrap(true),
|ui| {
let row_height = ui.text_style_height(&TextStyle::Heading);
ui.set_row_height(row_height);
ui.spacing_mut().item_spacing.x = 0.0;
for node in self.nodes.iter() {
match node {
Node::Body(body_nodes) => {
for node in body_nodes {
match node {
BodyNode::Text { text, size, flags } => {
ui.label(flags.apply(RichText::new(text).size(*size)));
}
BodyNode::Link { text, url } => {
ui.hyperlink_to(text, url).on_hover_text(url);
}
}
}
}
Node::Break => {
ui.allocate_exact_size(Vec2::new(0.0, row_height), Sense::hover());
ui.end_row();
ui.set_row_height(row_height);
}
}
}
},
);
}
}
fn span_text(span: Vec<Span>, size: f32, flags: TextFlags) -> Vec<BodyNode> {
fn span_text_inner(out: &mut Vec<BodyNode>, span: &[Span], size: f32, flags: TextFlags) {
for node in span {
match node {
Span::Text(text) => out.push(BodyNode::Text {
text: text.to_owned(),
flags,
size,
}),
Span::Code(text) => out.push(BodyNode::Text {
text: text.to_owned(),
flags: flags | TextFlags::MONOSPACE,
size,
}),
Span::Link(text, url, _) => out.push(BodyNode::Link {
text: text.to_owned(),
url: url.to_owned(),
}),
Span::Emphasis(vec) => span_text_inner(out, vec, size, flags | TextFlags::ITALIC),
Span::Strong(vec) => span_text_inner(out, vec, size, flags | TextFlags::BOLD),
_ => {}
}
}
}
let mut out = Vec::new();
span_text_inner(&mut out, &span, size, flags);
out
}

View File

@@ -1,4 +1,5 @@
pub mod components;
pub mod drag_and_drop;
pub mod markdown;
pub mod popup;
pub mod state;

View File

@@ -1,25 +1,23 @@
use egui::{Context, Ui};
use crate::app::App;
use crate::{app::App, ui::markdown::CompiledMarkdown};
const DESCRIPTION: &str = "A work in progress FOSS slicer for resin printers, created by Connor Slade. Source code is available on Github at ";
const GITHUB_LINK: &str = "https://github.com/connorslade/mslicer";
pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
ui.monospace(concat!("mslicer v", env!("CARGO_PKG_VERSION")));
ui.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.label(DESCRIPTION);
ui.hyperlink_to(
"@connorslade/mslicer",
"https://github.com/connorslade/mslicer",
);
ui.hyperlink_to("@connorslade/mslicer", GITHUB_LINK)
.on_hover_text(GITHUB_LINK);
ui.label(".");
});
ui.add_space(16.0);
ui.heading("Getting Started");
ui.label(include_str!("../../../docs/getting_started.txt"));
CompiledMarkdown::compile(include_str!("../../../docs/getting_started.md")).render(ui);
ui.add_space(16.0);
ui.heading("Stats");