Skip to main content

max / makenotwork

3.6 KB · 97 lines History Blame Raw
1 //! Machine text in a line of reading, described.
2 //!
3 //! The Askama entry point for an inline [`quasi_router::Node::Code`]: a clone
4 //! URL, a DNS record, a backup code, a license key, a file path. Not a widget
5 //! (`super::widgets`) but a primitive with an entry point, which is why it sits
6 //! here beside `rich_field.rs` and `export_act.rs` rather than in that
7 //! directory. `super::widgets`'s header states the rule.
8 //!
9 //! # Why 26 templates go through one function
10 //!
11 //! `19d7602d` ruled that a description carries code as pre-classified runs.
12 //! Most of the tree's `<code>` is not source and has no lexer behind it: it is
13 //! one plain run, said once here rather than as a hand-written element in every
14 //! template that has a value a reader is meant to copy.
15 //!
16 //! What that buys beyond tidiness is the escaping. Each of these sites wrote
17 //! `<code>{{ value }}</code>`, so the element was the template's and the
18 //! escaping was Askama's; through here both are the renderer's, which is the
19 //! same seam the file view and the diff now use.
20 //!
21 //! A template that keeps its own `<code>` is a template whose content is not a
22 //! value: a `<pre>` holding a worked example belongs to the prose around it.
23
24 use quasi_router::Node;
25 use quasi_router::screen::Lexeme;
26
27 /// One run of machine text, as markup for a template to drop in.
28 ///
29 /// Inline, because these all sit in a line of reading. A block of source is
30 /// `crate::quasi::git_browse`, which has a lexer behind it and line numbers
31 /// beside it.
32 #[must_use]
33 pub fn html(text: &str) -> String {
34 use quasi_axum::Serves as _;
35
36 // No shell: this lands inside a document Askama already built, which is
37 // what `fragment` is for.
38 quasi_webview::Webview::new().fragment(&Node::Code {
39 runs: vec![Lexeme::plain(text)],
40 language: None,
41 inline: true,
42 })
43 }
44
45 /// The same, from parts a template has in hand.
46 ///
47 /// Askama rewrites the identifiers in an expression it parses and cannot reach
48 /// inside a `format!` it does not, so a template building a clone URL out of
49 /// three of its own fields writes them as a list rather than as a format
50 /// string. That is the whole of why this exists beside [`html`].
51 ///
52 /// The array is taken by reference and the call site writes it without one:
53 /// Askama adds the `&` itself when it passes an argument.
54 #[must_use]
55 pub fn of<const N: usize>(parts: &[&str; N]) -> String {
56 html(&parts.concat())
57 }
58
59 #[cfg(test)]
60 mod tests {
61 use super::*;
62
63 /// The value arrives as the value, in the element the renderer picks.
64 #[test]
65 fn a_literal_is_the_text_it_carries() {
66 let html = html("git clone https://makenot.work/git/ada/engine.git");
67
68 assert!(html.contains("<code"), "{html}");
69 assert!(
70 html.contains("git clone https://makenot.work/git/ada/engine.git"),
71 "{html}"
72 );
73 }
74
75 /// A literal built out of a template's own fields is the same literal.
76 #[test]
77 fn parts_make_one_literal() {
78 let html = of(&["git clone ", "https://makenot.work", "/git/ada/engine.git"]);
79
80 assert!(
81 html.contains("git clone https://makenot.work/git/ada/engine.git"),
82 "{html}"
83 );
84 assert_eq!(html.matches("<code").count(), 1, "{html}");
85 }
86
87 /// These carry values a reader typed or a server generated, and they go
88 /// into a document. The renderer escapes them.
89 #[test]
90 fn a_literal_cannot_smuggle_markup() {
91 let html = html("<script>alert(1)</script>");
92
93 assert!(!html.contains("<script>"), "{html}");
94 assert!(html.contains("&lt;script&gt;"), "{html}");
95 }
96 }
97