mirror of
https://github.com/ankitects/anki.git
synced 2025-09-23 16:26:40 -04:00
render deck description with markdown; strip images
To support images on that screen, we'll first need to adjust the base url for each platform, or rewrite the local image URLs, as otherwise they are resolved to _anki/pages/...
This commit is contained in:
parent
6ba321f818
commit
ded626f0b9
15 changed files with 391 additions and 8 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
@ -77,6 +77,7 @@ dependencies = [
|
|||
"proc-macro-nested",
|
||||
"prost",
|
||||
"prost-build",
|
||||
"pulldown-cmark",
|
||||
"rand 0.7.3",
|
||||
"regex",
|
||||
"reqwest",
|
||||
|
@ -780,6 +781,15 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
@ -1717,6 +1727,18 @@ dependencies = [
|
|||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"getopts",
|
||||
"memchr",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyo3"
|
||||
version = "0.13.1"
|
||||
|
@ -2704,6 +2726,12 @@ version = "1.7.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
|
|
|
@ -801,6 +801,16 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.generic-array-0.14.4.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__getopts__0_2_21",
|
||||
url = "https://crates.io/api/v1/crates/getopts/0.2.21/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5",
|
||||
strip_prefix = "getopts-0.2.21",
|
||||
build_file = Label("//cargo/remote:BUILD.getopts-0.2.21.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__getrandom__0_1_16",
|
||||
|
@ -1781,6 +1791,16 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.prost-types-0.7.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__pulldown_cmark__0_8_0",
|
||||
url = "https://crates.io/api/v1/crates/pulldown-cmark/0.8.0/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8",
|
||||
strip_prefix = "pulldown-cmark-0.8.0",
|
||||
build_file = Label("//cargo/remote:BUILD.pulldown-cmark-0.8.0.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__pyo3__0_13_1",
|
||||
|
@ -2751,6 +2771,16 @@ def raze_fetch_remote_crates():
|
|||
build_file = Label("//cargo/remote:BUILD.unicode-segmentation-1.7.1.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__unicode_width__0_1_8",
|
||||
url = "https://crates.io/api/v1/crates/unicode-width/0.1.8/download",
|
||||
type = "tar.gz",
|
||||
sha256 = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3",
|
||||
strip_prefix = "unicode-width-0.1.8",
|
||||
build_file = Label("//cargo/remote:BUILD.unicode-width-0.1.8.bazel"),
|
||||
)
|
||||
|
||||
maybe(
|
||||
http_archive,
|
||||
name = "raze__unicode_xid__0_2_1",
|
||||
|
|
|
@ -728,6 +728,15 @@
|
|||
"license_file": null,
|
||||
"description": "Generic types implementing functionality of arrays"
|
||||
},
|
||||
{
|
||||
"name": "getopts",
|
||||
"version": "0.2.21",
|
||||
"authors": "The Rust Project Developers",
|
||||
"repository": "https://github.com/rust-lang/getopts",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "getopts-like option parsing."
|
||||
},
|
||||
{
|
||||
"name": "getrandom",
|
||||
"version": "0.1.16",
|
||||
|
@ -1610,6 +1619,15 @@
|
|||
"license_file": null,
|
||||
"description": "A Protocol Buffers implementation for the Rust Language."
|
||||
},
|
||||
{
|
||||
"name": "pulldown-cmark",
|
||||
"version": "0.8.0",
|
||||
"authors": "Raph Levien <raph.levien@gmail.com>|Marcus Klaas de Vries <mail@marcusklaas.nl>",
|
||||
"repository": "https://github.com/raphlinus/pulldown-cmark",
|
||||
"license": "MIT",
|
||||
"license_file": null,
|
||||
"description": "A pull parser for CommonMark"
|
||||
},
|
||||
{
|
||||
"name": "pyo3",
|
||||
"version": "0.13.1",
|
||||
|
@ -2492,6 +2510,15 @@
|
|||
"license_file": null,
|
||||
"description": "This crate provides Grapheme Cluster, Word and Sentence boundaries according to Unicode Standard Annex #29 rules."
|
||||
},
|
||||
{
|
||||
"name": "unicode-width",
|
||||
"version": "0.1.8",
|
||||
"authors": "kwantam <kwantam@gmail.com>|Manish Goregaokar <manishsmail@gmail.com>",
|
||||
"repository": "https://github.com/unicode-rs/unicode-width",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"license_file": null,
|
||||
"description": "Determine displayed width of `char` and `str` types according to Unicode Standard Annex #11 rules."
|
||||
},
|
||||
{
|
||||
"name": "unicode-xid",
|
||||
"version": "0.2.1",
|
||||
|
|
56
cargo/remote/BUILD.getopts-0.2.21.bazel
vendored
Normal file
56
cargo/remote/BUILD.getopts-0.2.21.bazel
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@io_bazel_rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "getopts",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2015",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.2.21",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
"@raze__unicode_width__0_1_8//:unicode_width",
|
||||
],
|
||||
)
|
||||
|
||||
# Unsupported target "smoke" with type "test" omitted
|
138
cargo/remote/BUILD.pulldown-cmark-0.8.0.bazel
vendored
Normal file
138
cargo/remote/BUILD.pulldown-cmark-0.8.0.bazel
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@io_bazel_rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
# buildifier: disable=load-on-top
|
||||
load(
|
||||
"@io_bazel_rules_rust//cargo:cargo_build_script.bzl",
|
||||
"cargo_build_script",
|
||||
)
|
||||
|
||||
cargo_build_script(
|
||||
name = "pulldown_cmark_build_script",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
build_script_env = {
|
||||
},
|
||||
crate_features = [
|
||||
"default",
|
||||
"getopts",
|
||||
],
|
||||
crate_root = "build.rs",
|
||||
data = glob(["**"]),
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.8.0",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
],
|
||||
)
|
||||
|
||||
# Unsupported target "html_rendering" with type "bench" omitted
|
||||
|
||||
# Unsupported target "lib" with type "bench" omitted
|
||||
|
||||
rust_binary(
|
||||
# Prefix bin name to disambiguate from (probable) collision with lib name
|
||||
# N.B.: The exact form of this is subject to change.
|
||||
name = "cargo_bin_pulldown_cmark",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"default",
|
||||
"getopts",
|
||||
],
|
||||
crate_root = "src/main.rs",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.8.0",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
# Binaries get an implicit dependency on their crate's lib
|
||||
":pulldown_cmark",
|
||||
":pulldown_cmark_build_script",
|
||||
"@raze__bitflags__1_2_1//:bitflags",
|
||||
"@raze__getopts__0_2_21//:getopts",
|
||||
"@raze__memchr__2_3_4//:memchr",
|
||||
"@raze__unicase__2_6_0//:unicase",
|
||||
],
|
||||
)
|
||||
|
||||
# Unsupported target "broken-link-callbacks" with type "example" omitted
|
||||
|
||||
# Unsupported target "event-filter" with type "example" omitted
|
||||
|
||||
# Unsupported target "string-to-string" with type "example" omitted
|
||||
|
||||
rust_library(
|
||||
name = "pulldown_cmark",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"default",
|
||||
"getopts",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2018",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.8.0",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
":pulldown_cmark_build_script",
|
||||
"@raze__bitflags__1_2_1//:bitflags",
|
||||
"@raze__getopts__0_2_21//:getopts",
|
||||
"@raze__memchr__2_3_4//:memchr",
|
||||
"@raze__unicase__2_6_0//:unicase",
|
||||
],
|
||||
)
|
||||
|
||||
# Unsupported target "errors" with type "test" omitted
|
||||
|
||||
# Unsupported target "html" with type "test" omitted
|
||||
|
||||
# Unsupported target "lib" with type "test" omitted
|
54
cargo/remote/BUILD.unicode-width-0.1.8.bazel
vendored
Normal file
54
cargo/remote/BUILD.unicode-width-0.1.8.bazel
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
"""
|
||||
@generated
|
||||
cargo-raze crate build file.
|
||||
|
||||
DO NOT EDIT! Replaced on runs of cargo-raze
|
||||
"""
|
||||
|
||||
# buildifier: disable=load
|
||||
load(
|
||||
"@io_bazel_rules_rust//rust:rust.bzl",
|
||||
"rust_binary",
|
||||
"rust_library",
|
||||
"rust_test",
|
||||
)
|
||||
|
||||
# buildifier: disable=load
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
package(default_visibility = [
|
||||
# Public for visibility by "@raze__crate__version//" targets.
|
||||
#
|
||||
# Prefer access through "//cargo", which limits external
|
||||
# visibility to explicit Cargo.toml dependencies.
|
||||
"//visibility:public",
|
||||
])
|
||||
|
||||
licenses([
|
||||
"notice", # MIT from expression "MIT OR Apache-2.0"
|
||||
])
|
||||
|
||||
# Generated Targets
|
||||
|
||||
rust_library(
|
||||
name = "unicode_width",
|
||||
srcs = glob(["**/*.rs"]),
|
||||
crate_features = [
|
||||
"default",
|
||||
],
|
||||
crate_root = "src/lib.rs",
|
||||
crate_type = "lib",
|
||||
data = [],
|
||||
edition = "2015",
|
||||
rustc_flags = [
|
||||
"--cap-lints=allow",
|
||||
],
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
version = "0.1.8",
|
||||
# buildifier: leave-alone
|
||||
deps = [
|
||||
],
|
||||
)
|
|
@ -97,6 +97,7 @@ rust_library(
|
|||
"//rslib/cargo:once_cell",
|
||||
"//rslib/cargo:pin_project",
|
||||
"//rslib/cargo:prost",
|
||||
"//rslib/cargo:pulldown_cmark",
|
||||
"//rslib/cargo:rand",
|
||||
"//rslib/cargo:regex",
|
||||
"//rslib/cargo:reqwest",
|
||||
|
|
|
@ -80,3 +80,4 @@ async-trait = "0.1.42"
|
|||
# only in Bazel)
|
||||
proc-macro-nested = "=0.1.6"
|
||||
ammonia = "3.1.0"
|
||||
pulldown-cmark = "0.8.0"
|
||||
|
|
|
@ -264,6 +264,15 @@ alias(
|
|||
],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "pulldown_cmark",
|
||||
actual = "@raze__pulldown_cmark__0_8_0//:pulldown_cmark",
|
||||
tags = [
|
||||
"cargo-raze",
|
||||
"manual",
|
||||
],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "rand",
|
||||
actual = "@raze__rand__0_7_3//:rand",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::backend_proto as pb;
|
||||
pub use crate::backend_proto::{
|
||||
deck_kind::Kind as DeckKind, filtered_search_term::FilteredSearchOrder, Deck as DeckProto,
|
||||
DeckCommon, DeckKind as DeckKindProto, FilteredDeck, FilteredSearchTerm, NormalDeck,
|
||||
};
|
||||
use crate::{backend_proto as pb, markdown::render_markdown, text::sanitize_html_no_images};
|
||||
use crate::{
|
||||
collection::Collection,
|
||||
deckconf::DeckConfID,
|
||||
|
@ -92,6 +92,17 @@ impl Deck {
|
|||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rendered_description(&self) -> String {
|
||||
if let DeckKind::Normal(normal) = &self.kind {
|
||||
let description = render_markdown(&normal.description);
|
||||
// before allowing images, we'll need to handle relative image
|
||||
// links on the various platforms
|
||||
sanitize_html_no_images(&description)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_char_for_deck_component(c: char) -> bool {
|
||||
|
|
|
@ -19,6 +19,7 @@ mod fluent_proto;
|
|||
pub mod i18n;
|
||||
pub mod latex;
|
||||
pub mod log;
|
||||
mod markdown;
|
||||
pub mod media;
|
||||
pub mod notes;
|
||||
pub mod notetype;
|
||||
|
|
11
rslib/src/markdown.rs
Normal file
11
rslib/src/markdown.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use pulldown_cmark::{html, Parser};
|
||||
|
||||
pub(crate) fn render_markdown(markdown: &str) -> String {
|
||||
let mut buf = String::with_capacity(markdown.len());
|
||||
let parser = Parser::new(markdown);
|
||||
html::push_html(&mut buf, parser);
|
||||
buf
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
use crate::backend_proto as pb;
|
||||
use crate::decks::DeckKind;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -22,11 +21,7 @@ impl Collection {
|
|||
let today = self.timing_today()?.days_elapsed;
|
||||
let info = self.storage.congrats_info(&deck, today)?;
|
||||
let is_filtered_deck = deck.is_filtered();
|
||||
let deck_description = if let DeckKind::Normal(normal) = &deck.kind {
|
||||
ammonia::clean(&normal.description)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let deck_description = deck.rendered_description();
|
||||
let secs_until_next_learn = ((info.next_learn_due as i64)
|
||||
- self.learn_ahead_secs() as i64
|
||||
- TimestampSecs::now().0)
|
||||
|
|
|
@ -226,6 +226,18 @@ pub fn strip_html_preserving_media_filenames(html: &str) -> Cow<str> {
|
|||
without_html.into_owned().into()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn sanitize_html(html: &str) -> String {
|
||||
ammonia::clean(html)
|
||||
}
|
||||
|
||||
pub(crate) fn sanitize_html_no_images(html: &str) -> String {
|
||||
ammonia::Builder::default()
|
||||
.rm_tags(&["img"])
|
||||
.clean(html)
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub(crate) fn normalize_to_nfc(s: &str) -> Cow<str> {
|
||||
if !is_nfc(s) {
|
||||
s.chars().nfc().collect::<String>().into()
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
.congrats-inner {
|
||||
max-width: 30em;
|
||||
}
|
||||
|
||||
.description {
|
||||
border: 1px solid var(--border);
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="congrats-outer">
|
||||
|
@ -62,6 +67,10 @@
|
|||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if info.deckDescription}
|
||||
<div class="description">
|
||||
{@html info.deckDescription}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue