Fix markdown monospace in headings

This commit is contained in:
2025-08-03 10:08:03 +02:00
parent 0acab0413c
commit 2fb9908329
6 changed files with 65 additions and 42 deletions

View File

@ -11,10 +11,11 @@ use crate::{
file_editor::{FileEditor, SaveStatus}, file_editor::{FileEditor, SaveStatus},
folder::Folder, folder::Folder,
preferences::Preferences, preferences::Preferences,
text_styles::{H1, H1_MONO, H2, H2_MONO, H3, H3_MONO, H4, H4_MONO, H5, H5_MONO, H6, H6_MONO},
util::{GuiSender, file_mtime, log_error}, util::{GuiSender, file_mtime, log_error},
}; };
use egui::{ use egui::{
Align, Button, Context, FontData, FontDefinitions, FontId, Image, Key, Modifiers, Align, Button, Context, FontData, FontDefinitions, FontFamily, FontId, Image, Key, Modifiers,
PointerButton, RichText, ScrollArea, Theme, Widget, include_image, PointerButton, RichText, ScrollArea, Theme, Widget, include_image,
}; };
use eyre::eyre; use eyre::eyre;
@ -190,35 +191,35 @@ impl App {
.map(|(name, data)| (name.to_string(), Arc::new(FontData::from_static(data)))) .map(|(name, data)| (name.to_string(), Arc::new(FontData::from_static(data))))
.collect(); .collect();
fonts.families.insert( fonts
egui::FontFamily::Proportional, .families
vec!["IosevkaAile-Regular".into()], .insert(FontFamily::Proportional, vec!["IosevkaAile-Regular".into()]);
);
fonts fonts
.families .families
.insert(egui::FontFamily::Monospace, vec!["Iosevka-Thin".into()]); .insert(FontFamily::Monospace, vec!["Iosevka-Thin".into()]);
cc.egui_ctx.set_fonts(fonts); cc.egui_ctx.set_fonts(fonts);
// markdown font styles // markdown font styles
for theme in [Theme::Dark, Theme::Light] { for theme in [Theme::Dark, Theme::Light] {
cc.egui_ctx.style_mut_of(theme, |style| { cc.egui_ctx.style_mut_of(theme, |style| {
for (name, size) in [ for (name, size, family) in [
("H1", 28.0), (H1, 28.0, FontFamily::Proportional),
("H2", 26.0), (H2, 26.0, FontFamily::Proportional),
("H3", 24.0), (H3, 24.0, FontFamily::Proportional),
("H4", 22.0), (H4, 22.0, FontFamily::Proportional),
("H5", 20.0), (H5, 20.0, FontFamily::Proportional),
("H6", 18.0), (H6, 18.0, FontFamily::Proportional),
(H1_MONO, 28.0, FontFamily::Monospace),
(H2_MONO, 26.0, FontFamily::Monospace),
(H3_MONO, 24.0, FontFamily::Monospace),
(H4_MONO, 22.0, FontFamily::Monospace),
(H5_MONO, 20.0, FontFamily::Monospace),
(H6_MONO, 18.0, FontFamily::Monospace),
] { ] {
style.text_styles.insert( let name = egui::TextStyle::Name(name.into());
egui::TextStyle::Name(name.into()), style.text_styles.insert(name, FontId { size, family });
FontId {
size,
family: egui::FontFamily::Proportional,
},
);
} }
}); });
} }

View File

@ -82,6 +82,8 @@ struct Ephemeral {
current_stroke: Vec<Pos2>, current_stroke: Vec<Pos2>,
/// The lines that have not been blitted to `texture` yet. /// The lines that have not been blitted to `texture` yet.
///
/// Each pair of [Pos2]s is the start and end of one line.
unblitted_lines: Vec<[Pos2; 2]>, unblitted_lines: Vec<[Pos2; 2]>,
tessellator: Option<Tessellator>, tessellator: Option<Tessellator>,
@ -425,7 +427,7 @@ impl Handwriting {
last_mesh_ctx, last_mesh_ctx,
.. ..
} = &mut self.e; } = &mut self.e;
// TODO: don't tessellate and rasterize on the GUI thread // TODO: avoid tessellating and rasterizing on the GUI thread
*last_mesh_ctx = Some(mesh_context); *last_mesh_ctx = Some(mesh_context);
@ -444,10 +446,7 @@ impl Handwriting {
.iter() .iter()
.chain([&*current_stroke]) .chain([&*current_stroke])
.filter(|stroke| stroke.len() >= 2) .filter(|stroke| stroke.len() >= 2)
.map(|stroke| { .map(|stroke| egui::Shape::line(stroke.clone(), style.stroke))
//let points: Vec<Pos2> = stroke.iter().map(|&p| to_screen * p).collect();
egui::Shape::line(stroke.clone(), style.stroke)
})
.for_each(|shape| { .for_each(|shape| {
tessellator.tessellate_shape(shape, mesh); tessellator.tessellate_shape(shape, mesh);
}); });
@ -480,7 +479,6 @@ impl Handwriting {
ui.vertical_centered_justified(|ui| { ui.vertical_centered_justified(|ui| {
self.ui_control(None, ui, &mut response); self.ui_control(None, ui, &mut response);
//ui.label("Paint with your mouse/touch!");
Frame::canvas(ui.style()) Frame::canvas(ui.style())
.corner_radius(20.0) .corner_radius(20.0)
.stroke(Stroke::new(5.0, Color32::from_black_alpha(40))) .stroke(Stroke::new(5.0, Color32::from_black_alpha(40)))

View File

@ -8,6 +8,7 @@ pub mod markdown;
pub mod preferences; pub mod preferences;
pub mod rasterizer; pub mod rasterizer;
pub mod text_editor; pub mod text_editor;
pub mod text_styles;
pub mod util; pub mod util;
pub use app::App; pub use app::App;

View File

@ -1,6 +1,9 @@
use egui::text::{CCursorRange, LayoutJob}; use egui::text::{CCursorRange, LayoutJob};
use crate::markdown::Heading; use crate::{
markdown::Heading,
text_styles::{H1, H1_MONO, H2, H2_MONO, H3, H3_MONO, H4, H4_MONO, H5, H5_MONO, H6, H6_MONO},
};
use super::{Item, Style, parse}; use super::{Item, Style, parse};
@ -36,7 +39,6 @@ pub fn highlight_markdown(
_cursor: Option<CCursorRange>, _cursor: Option<CCursorRange>,
) -> LayoutJob { ) -> LayoutJob {
let mut job = LayoutJob::default(); let mut job = LayoutJob::default();
let code_style = Style { let code_style = Style {
code: true, code: true,
..Default::default() ..Default::default()
@ -74,14 +76,23 @@ fn format_from_style(egui_style: &egui::Style, style: &Style) -> egui::text::Tex
}; };
let text_style = if let Some(heading) = style.heading { let text_style = if let Some(heading) = style.heading {
match heading { let text_style = match (heading, style.code) {
Heading::H1 => TextStyle::Name("H1".into()), (Heading::H1, false) => H1,
Heading::H2 => TextStyle::Name("H2".into()), (Heading::H2, false) => H2,
Heading::H3 => TextStyle::Name("H3".into()), (Heading::H3, false) => H3,
Heading::H4 => TextStyle::Name("H4".into()), (Heading::H4, false) => H4,
Heading::H5 => TextStyle::Name("H5".into()), (Heading::H5, false) => H5,
Heading::H6 => TextStyle::Name("H6".into()), (Heading::H6, false) => H6,
}
(Heading::H1, true) => H1_MONO,
(Heading::H2, true) => H2_MONO,
(Heading::H3, true) => H3_MONO,
(Heading::H4, true) => H4_MONO,
(Heading::H5, true) => H5_MONO,
(Heading::H6, true) => H6_MONO,
};
TextStyle::Name(text_style.into())
} else if style.code { } else if style.code {
TextStyle::Monospace TextStyle::Monospace
} else if style.small | style.raised { } else if style.small | style.raised {

View File

@ -16,11 +16,6 @@ pub fn parse_tokens<'a>(mut tokens: &[Token<'a>]) -> Vec<Item<'a>> {
let mut style = Style::default(); let mut style = Style::default();
let mono_style = Style {
code: true,
..Default::default()
};
iter::from_fn(move || { iter::from_fn(move || {
if tokens.is_empty() { if tokens.is_empty() {
return None; return None;
@ -73,7 +68,10 @@ pub fn parse_tokens<'a>(mut tokens: &[Token<'a>]) -> Vec<Item<'a>> {
any_of([TokenKind::Mono, TokenKind::CodeBlock, TokenKind::Newline]), any_of([TokenKind::Mono, TokenKind::CodeBlock, TokenKind::Newline]),
); );
return Some(Item::Text { span, style: mono_style}); let mut style = style;
style.code = true;
return Some(Item::Text { span, style });
} }
// TODO: different heading strengths // TODO: different heading strengths

14
src/text_styles.rs Normal file
View File

@ -0,0 +1,14 @@
//! Name of custom [egui::TextStyle]s
pub const H1: &str = "H1";
pub const H2: &str = "H2";
pub const H3: &str = "H3";
pub const H4: &str = "H4";
pub const H5: &str = "H5";
pub const H6: &str = "H6";
pub const H1_MONO: &str = "H1-mono";
pub const H2_MONO: &str = "H2-mono";
pub const H3_MONO: &str = "H3-mono";
pub const H4_MONO: &str = "H4-mono";
pub const H5_MONO: &str = "H5-mono";
pub const H6_MONO: &str = "H6-mono";