Initial commit

This commit is contained in:
Isaac Mills 2024-03-18 18:33:03 -04:00
commit f7b7310259
Signed by: fnmain
GPG key ID: B67D7410F33A0F61
4 changed files with 620 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

370
Cargo.lock generated Normal file
View file

@ -0,0 +1,370 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "bytemuck"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
[[package]]
name = "cosmic-jotdown"
version = "0.1.0"
dependencies = [
"cosmic-text",
"jotdown",
"log",
"range-map",
]
[[package]]
name = "cosmic-text"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c578f2b9abb4d5f3fbb12aba4008084d435dc6a8425c195cfe0b3594bfea0c25"
dependencies = [
"bitflags",
"fontdb",
"libm",
"log",
"rangemap",
"rustc-hash",
"rustybuzz",
"self_cell",
"swash",
"sys-locale",
"ttf-parser",
"unicode-bidi",
"unicode-linebreak",
"unicode-script",
"unicode-segmentation",
]
[[package]]
name = "databake"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82175d72e69414ceafbe2b49686794d3a8bed846e0d50267355f83ea8fdd953a"
dependencies = [
"databake-derive",
"proc-macro2",
"quote",
]
[[package]]
name = "databake-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]]
name = "font-types"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b7f6040d337bd44434ab21fc6509154edf2cece88b23758d9d64654c4e7730b"
[[package]]
name = "fontconfig-parser"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a595cb550439a117696039dfc69830492058211b771a2a165379f2a1a53d84d"
dependencies = [
"roxmltree",
]
[[package]]
name = "fontdb"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3"
dependencies = [
"fontconfig-parser",
"log",
"memmap2",
"slotmap",
"tinyvec",
"ttf-parser",
]
[[package]]
name = "jotdown"
version = "0.3.2"
dependencies = [
"databake",
]
[[package]]
name = "libc"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libm"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "memmap2"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
dependencies = [
"libc",
]
[[package]]
name = "num-traits"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]]
name = "proc-macro2"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "range-map"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12a5a2d6c7039059af621472a4389be1215a816df61aa4d531cfe85264aee95f"
dependencies = [
"num-traits",
]
[[package]]
name = "rangemap"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684"
[[package]]
name = "read-fonts"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81c524658d3b77930a391f559756d91dbe829ab6cf4687083f615d395df99722"
dependencies = [
"font-types",
]
[[package]]
name = "roxmltree"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustybuzz"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0ae5692c5beaad6a9e22830deeed7874eae8a4e3ba4076fb48e12c56856222c"
dependencies = [
"bitflags",
"bytemuck",
"libm",
"smallvec",
"ttf-parser",
"unicode-bidi-mirroring",
"unicode-ccc",
"unicode-properties",
"unicode-script",
]
[[package]]
name = "self_cell"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba"
[[package]]
name = "slotmap"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
dependencies = [
"version_check",
]
[[package]]
name = "smallvec"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
[[package]]
name = "swash"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9af636fb90d39858650cae1088a37e2862dab4e874a0bb49d6dfb5b2dacf0e24"
dependencies = [
"read-fonts",
"yazi",
"zeno",
]
[[package]]
name = "syn"
version = "2.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sys-locale"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0"
dependencies = [
"libc",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "ttf-parser"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
[[package]]
name = "unicode-bidi"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-bidi-mirroring"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694"
[[package]]
name = "unicode-ccc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-linebreak"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
[[package]]
name = "unicode-properties"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
[[package]]
name = "unicode-script"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd"
[[package]]
name = "unicode-segmentation"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "yazi"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
[[package]]
name = "zeno"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"

12
Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "cosmic-jotdown"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cosmic-text = "0.11.2"
jotdown = { version = "0.3.2", path = "../jotdown" }
log = "0.4.21"
range-map = "0.2.0"

237
src/lib.rs Normal file
View file

@ -0,0 +1,237 @@
use std::borrow::Cow;
use cosmic_text::{Attrs, Buffer, Color, Family, FontSystem, Metrics, Shaping, Style, Weight};
use jotdown::{Container, Event, ListKind};
pub use jotdown;
use range_map::RangeMap;
pub struct JotdownBufferIter<'a, 'b, T: Iterator<Item = Event<'a>>> {
djot: T,
font_system: &'b mut FontSystem,
width: f32,
metrics: Metrics,
indent: Vec<Indent>,
}
struct JotdownIntoBuffer<'a, 'b, T: Iterator<Item = Event<'a>>> {
djot: &'b mut T,
attrs: Attrs<'a>,
metrics: Metrics,
indent: &'b mut Vec<Indent>,
image_url: Option<Cow<'a, str>>,
link_start: usize,
urls: Vec<(range_map::Range<usize>, &'a str)>,
location: usize,
added: bool,
}
#[derive(Default, Clone, Copy)]
pub struct Indent {
pub modifier: Option<ListKind>,
pub indent: f32,
}
pub const INDENT_AMOUNT: f32 = 18.0;
impl<'a, 'b, T: Iterator<Item = Event<'a>>> Iterator for JotdownIntoBuffer<'a, 'b, T> {
type Item = (&'a str, Attrs<'a>);
fn next(&mut self) -> Option<Self::Item> {
while let Some(event) = self.djot.next() {
match event {
Event::LeftSingleQuote => {
self.added = true;
self.location += "".len();
return Some(("", self.attrs.clone()));
}
Event::LeftDoubleQuote => {
self.added = true;
self.location += "".len();
return Some(("", self.attrs.clone()));
}
Event::RightSingleQuote => {
self.added = true;
self.location += "".len();
return Some(("", self.attrs.clone()));
}
Event::RightDoubleQuote => {
self.added = true;
self.location += "".len();
return Some(("", self.attrs.clone()));
}
Event::Ellipsis => {
self.added = true;
self.location += "".len();
return Some(("", self.attrs.clone()));
}
Event::EmDash => {
self.added = true;
self.location += "".len();
return Some(("", self.attrs.clone()));
}
Event::EnDash => {
self.added = true;
self.location += "".len();
return Some(("", self.attrs.clone()));
}
Event::Softbreak | Event::NonBreakingSpace => {
self.added = true;
self.location += " ".len();
return Some((" ", self.attrs.clone()));
}
Event::Str(Cow::Borrowed(s)) | Event::Symbol(Cow::Borrowed(s)) => {
self.added = true;
self.location += s.len();
return Some((s, self.attrs.clone()));
}
Event::Start(container, _) => match container {
Container::Heading { level, .. } => {
self.metrics = Metrics::new(
self.metrics.font_size * (4.0 - level as f32),
self.metrics.line_height * (4.0 - level as f32),
);
}
Container::Emphasis => self.attrs = self.attrs.style(Style::Italic),
Container::Strong => self.attrs = self.attrs.weight(Weight::BOLD),
Container::Verbatim => self.attrs = self.attrs.family(Family::Monospace),
Container::List { kind, .. } => self.indent.push(Indent {
indent: self.indent.last().copied().unwrap_or_default().indent
+ INDENT_AMOUNT,
modifier: Some(kind),
}),
Container::Image(url, _) => self.image_url = Some(url),
Container::Link(_, _) => {
self.link_start = self.location + 1;
self.attrs = self.attrs.color(Color::rgb(96, 198, 233));
}
_ => {}
},
Event::End(container) => match container {
Container::Emphasis => self.attrs = self.attrs.style(Style::Normal),
Container::Strong => self.attrs = self.attrs.weight(Weight::NORMAL),
Container::Verbatim => self.attrs = self.attrs.family(Family::SansSerif),
Container::List { .. } => {
self.indent.pop();
}
Container::Heading { .. } | Container::Paragraph | Container::Image(_, _) => {
if self.added {
return None;
}
}
Container::Link(Cow::Borrowed(url), _) => {
self.urls
.push((range_map::Range::new(self.link_start, self.location), url));
self.attrs = self.attrs.color(Color::rgb(255, 255, 255));
}
_ => {}
},
Event::Hardbreak | Event::ThematicBreak(_) => {}
Event::Blankline | Event::Escape | Event::FootnoteReference(_) => {}
Event::Str(Cow::Owned(_)) | Event::Symbol(Cow::Owned(_)) => panic!(),
}
}
return None;
}
}
pub struct JotdownItem<'a> {
pub indent: Indent,
pub buffer: Buffer,
pub image_url: Option<Cow<'a, str>>,
pub url_map: Option<RangeMap<usize, &'a str>>,
}
impl<'a, 'b, T: Iterator<Item = Event<'a>>> Iterator for JotdownBufferIter<'a, 'b, T> {
type Item = JotdownItem<'a>;
fn next(&mut self) -> Option<Self::Item> {
let mut buffer = Buffer::new(&mut self.font_system, self.metrics);
let mut jot = JotdownIntoBuffer {
djot: &mut self.djot,
attrs: Attrs::new().family(Family::SansSerif),
metrics: self.metrics,
indent: &mut self.indent,
image_url: None,
added: false,
link_start: 0,
location: 0,
urls: Vec::new(),
};
buffer.set_rich_text(
&mut self.font_system,
&mut jot,
Attrs::new().family(Family::SansSerif),
Shaping::Advanced,
);
buffer.set_wrap(&mut self.font_system, cosmic_text::Wrap::WordOrGlyph);
buffer.set_metrics(&mut self.font_system, jot.metrics);
let image_url = jot.image_url;
let urls = jot.urls;
let added = jot.added;
let indent = self.indent.last().copied().unwrap_or_default();
buffer.set_size(&mut self.font_system, self.width - indent.indent, f32::MAX);
if !added {
return None;
} else {
buffer.shape_until_scroll(&mut self.font_system, true);
return Some(JotdownItem {
indent,
url_map: if urls.is_empty() {
None
} else {
RangeMap::try_from_iter(
urls.into_iter(), // .scan(
// (
// 0,
// buffer
// .layout_runs()
// .flat_map(|run| run.glyphs.into_iter())
// .enumerate(),
// ),
// |(len, glyphs), range| {
// let mut start = None;
// while let Some(glyph) = glyphs.next() {
// *len += glyph.1.end - glyph.1.start;
// if start.is_none() && *len >= range.0.start {
// start = Some(glyph.0);
// } else if *len >= range.0.end {
// return Some((
// range_map::Range::new(start.unwrap(), glyph.0),
// range.1,
// ));
// }
// }
// log::info!("{:?}", start);
// return None;
// },
// ),
)
.ok()
},
buffer,
image_url,
});
}
}
}
pub fn jotdown_into_buffers<'a, 'b, T: Iterator<Item = Event<'a>>>(
djot: T,
font_system: &'b mut FontSystem,
metrics: Metrics,
width: f32,
) -> JotdownBufferIter<'a, 'b, T> {
JotdownBufferIter {
djot,
font_system,
width,
metrics,
indent: Vec::new(),
}
}