From 71e71fffe857e79037e8e0517db06b6a7c2e6efd Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 15:33:27 +0100 Subject: [PATCH 01/18] Define 'is_library' for 'CheckedModule' So that we can separate libraries from executable modules if necessary. --- crates/project/src/lib.rs | 9 ++------- crates/project/src/module.rs | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index eb45600d..cd5e5077 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -7,6 +7,7 @@ pub mod pretty; pub mod script; pub mod telemetry; +use crate::module::{CERT, MINT, SPEND, VALIDATOR_NAMES, WITHDRAW}; use aiken_lang::{ ast::{Definition, Function, ModuleKind, TypedDataType, TypedDefinition, TypedFunction}, builder::{DataTypeKey, FunctionAccessKey}, @@ -50,12 +51,6 @@ pub struct Source { pub kind: ModuleKind, } -pub const SPEND: &str = "spend"; -pub const CERT: &str = "cert"; -pub const MINT: &str = "mint"; -pub const WITHDRAWL: &str = "withdrawl"; -pub const VALIDATOR_NAMES: [&str; 4] = [SPEND, CERT, MINT, WITHDRAWL]; - pub struct Project where T: EventListener, @@ -351,7 +346,7 @@ where // depending on name, validate the minimum number of arguments // if too low, push a new error on to errors - if [MINT, CERT, WITHDRAWL].contains(&func_def.name.as_str()) + if [MINT, CERT, WITHDRAW].contains(&func_def.name.as_str()) && func_def.arguments.len() < 2 { errors.push(Error::WrongValidatorArity { diff --git a/crates/project/src/module.rs b/crates/project/src/module.rs index 022d369b..4a50ddf1 100644 --- a/crates/project/src/module.rs +++ b/crates/project/src/module.rs @@ -4,7 +4,7 @@ use std::{ path::PathBuf, }; -use aiken_lang::ast::{ModuleKind, TypedModule, UntypedModule}; +use aiken_lang::ast::{Definition, ModuleKind, TypedModule, UntypedModule}; use petgraph::{algo, graph::NodeIndex, Direction, Graph}; use crate::error::Error; @@ -155,6 +155,12 @@ fn find_cycle( false } +pub const SPEND: &str = "spend"; +pub const CERT: &str = "cert"; +pub const MINT: &str = "mint"; +pub const WITHDRAW: &str = "withdraw"; +pub const VALIDATOR_NAMES: [&str; 4] = [SPEND, CERT, MINT, WITHDRAW]; + #[derive(Debug, Clone)] pub struct CheckedModule { pub name: String, @@ -165,6 +171,15 @@ pub struct CheckedModule { // pub extra: ModuleExtra, } +impl CheckedModule { + pub fn is_library(&self) -> bool { + self.ast.definitions().any(|def| match def { + Definition::Fn(func_def) => VALIDATOR_NAMES.contains(&func_def.name.as_str()), + _ => false, + }) + } +} + #[derive(Debug, Clone)] pub struct CheckedModules(HashMap); From 16b0a9fbe4216c43353787b42e6689eb1bb405b1 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 18:33:04 +0100 Subject: [PATCH 02/18] Introduce 'docs' for generating documentation for aiken libraries. --- Cargo.lock | 143 ++ crates/project/Cargo.toml | 11 +- crates/project/src/docs.rs | 374 +++++ crates/project/templates/_layout.html | 269 ++++ .../templates/css/atom-one-dark.min.css | 1 + .../templates/css/atom-one-light.min.css | 1 + crates/project/templates/css/index.css | 1105 +++++++++++++++ crates/project/templates/js/highlight.min.js | 1198 +++++++++++++++++ .../project/templates/js/highlightjs-gleam.js | 103 ++ crates/project/templates/js/index.js | 609 +++++++++ crates/project/templates/js/lunr.min.js | 6 + crates/project/templates/module.html | 159 +++ crates/project/templates/page.html | 9 + 13 files changed, 3984 insertions(+), 4 deletions(-) create mode 100644 crates/project/src/docs.rs create mode 100644 crates/project/templates/_layout.html create mode 100644 crates/project/templates/css/atom-one-dark.min.css create mode 100644 crates/project/templates/css/atom-one-light.min.css create mode 100644 crates/project/templates/css/index.css create mode 100644 crates/project/templates/js/highlight.min.js create mode 100644 crates/project/templates/js/highlightjs-gleam.js create mode 100644 crates/project/templates/js/index.js create mode 100644 crates/project/templates/js/lunr.min.js create mode 100644 crates/project/templates/module.html create mode 100644 crates/project/templates/page.html diff --git a/Cargo.lock b/Cargo.lock index 07455dc5..fe179d14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,12 +108,15 @@ name = "aiken-project" version = "0.0.26" dependencies = [ "aiken-lang", + "askama", "hex", "ignore", + "itertools", "miette", "pallas", "pallas-traverse", "petgraph", + "pulldown-cmark", "regex", "serde", "serde_json", @@ -135,6 +138,52 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "askama" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134" +dependencies = [ + "askama_derive", + "askama_escape", + "askama_shared", +] + +[[package]] +name = "askama_derive" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" +dependencies = [ + "askama_shared", + "proc-macro2", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d6083ccb191711e9c2b80b22ee24a8381a18524444914c746d4239e21d1afaf" +dependencies = [ + "askama_escape", + "humansize", + "nom", + "num-traits", + "percent-encoding", + "proc-macro2", + "quote", + "serde", + "syn", + "toml", +] + [[package]] name = "atty" version = "0.2.14" @@ -200,6 +249,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "0.19.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "bstr" version = "0.2.17" @@ -389,6 +450,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "getrandom" version = "0.2.7" @@ -455,6 +522,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "humansize" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" + [[package]] name = "idna" version = "0.3.0" @@ -535,6 +608,19 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.133" @@ -642,6 +728,19 @@ dependencies = [ "adler", ] +[[package]] +name = "nom" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +dependencies = [ + "bitvec", + "funty", + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -937,6 +1036,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -958,6 +1068,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + [[package]] name = "rand" version = "0.8.5" @@ -1120,6 +1236,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -1184,6 +1306,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.3.0" @@ -1334,6 +1462,15 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.8" @@ -1482,6 +1619,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "yansi" version = "0.5.1" diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 2f2188f5..5e61d066 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -10,16 +10,19 @@ authors = ["Lucas Rosa ", "Kasey White "] [dependencies] aiken-lang = { path = "../lang", version = "0.0.26" } +askama = "0.10.5" +hex = "0.4.3" ignore = "0.4.18" -uplc = { path = '../uplc', version = "0.0.25" } +itertools = "0.10.1" miette = { version = "5.3.0", features = ["fancy"] } +pallas = "0.14.0" +pallas-traverse = "0.14.0" petgraph = "0.6.2" +pulldown-cmark = { version = "0.8.0", default-features = false } regex = "1.6.0" serde = { version = "1.0.144", features = ["derive"] } serde_json = { version = "1.0.85", features = ["preserve_order"] } thiserror = "1.0.37" toml = "0.5.9" +uplc = { path = '../uplc', version = "0.0.25" } walkdir = "2.3.2" -hex = "0.4.3" -pallas = "0.14.0" -pallas-traverse = "0.14.0" diff --git a/crates/project/src/docs.rs b/crates/project/src/docs.rs new file mode 100644 index 00000000..33a03a23 --- /dev/null +++ b/crates/project/src/docs.rs @@ -0,0 +1,374 @@ +use crate::{config::Config, module::CheckedModule}; +use aiken_lang::{ + ast::{Definition, TypedDefinition}, + format, +}; +use askama::Template; +use itertools::Itertools; +use pulldown_cmark as markdown; +use serde::Serialize; +use serde_json as json; +use std::{ + path::PathBuf, + time::{Duration, SystemTime}, +}; + +const MAX_COLUMNS: isize = 80; +const VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct DocFile { + pub path: PathBuf, + pub content: String, +} + +#[derive(Template)] +#[template(path = "module.html")] +struct ModuleTemplate<'a> { + aiken_version: &'a str, + breadcrumbs: String, + page_title: &'a str, + module_name: String, + project_name: &'a str, + project_version: &'a str, + links: &'a Vec, + modules: &'a Vec, + functions: Vec, + types: Vec, + constants: Vec, + documentation: String, + timestamp: String, +} + +#[derive(Template)] +#[template(path = "page.html")] +struct PageTemplate<'a> { + aiken_version: &'a str, + breadcrumbs: &'a str, + page_title: &'a str, + project_name: &'a str, + project_version: &'a str, + links: &'a Vec, + modules: &'a Vec, + content: String, + timestamp: &'a str, +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)] +struct DocLink { + name: String, + path: String, +} + +#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)] +struct SearchIndex { + doc: String, + title: String, + content: String, + url: String, +} + +/// Generate documentation files for a given project. +/// +/// The documentation is built using template files located at the root of this crate. +/// With the documentation, we also build a client-side search index to ease navigation +/// across multiple modules. +pub fn generate_all(root: &PathBuf, config: &Config, modules: Vec<&CheckedModule>) -> Vec { + let timestamp = new_timestamp(); + + let mut output_files: Vec = vec![]; + let mut search_indexes: Vec = vec![]; + + for module in &modules { + let (indexes, file) = generate_module(config, module, ×tamp); + search_indexes.extend(indexes); + output_files.push(file); + } + + output_files.extend(generate_static_assets(search_indexes)); + output_files.push(generate_readme(root, config, modules, ×tamp)); + output_files +} + +fn generate_module( + config: &Config, + module: &CheckedModule, + timestamp: &Duration, +) -> (Vec, DocFile) { + let mut search_indexes = vec![]; + + // Functions + let functions: Vec = module + .ast + .definitions + .iter() + .flat_map(DocFunction::from_definition) + .sorted() + .collect(); + + functions.iter().for_each(|function| { + search_indexes.push(SearchIndex { + doc: module.name.to_string(), + title: function.name.to_string(), + content: format!("{}\n{}", function.signature, function.documentation), + url: format!("{}.html#{}", module.name, function.name), + }) + }); + + // Types + + // Constants + + // Template + + search_indexes.push(SearchIndex { + doc: module.name.to_string(), + title: module.name.to_string(), + content: String::new(), + url: format!("{}.html", module.name), + }); + + let template = ModuleTemplate { + aiken_version: VERSION, + breadcrumbs: to_breadcrumbs(&module.name), + links: &vec![], + documentation: render_markdown(&module.ast.docs.iter().join("\n")), + modules: &vec![], + project_name: &config.name, + page_title: &format!("{} - {}", module.name, config.name), + module_name: module.name.clone(), + project_version: &config.version.to_string(), + functions, + types: vec![], + constants: vec![], + timestamp: timestamp.as_secs().to_string(), + }; + + ( + search_indexes, + DocFile { + path: PathBuf::from(format!("{}.html", module.name)), + content: template + .render() + .expect("Module documentation template rendering"), + }, + ) +} + +fn generate_static_assets(search_indexes: Vec) -> Vec { + let mut assets: Vec = vec![]; + + assets.push(DocFile { + path: PathBuf::from("css/atom-one-light.min.css"), + content: std::include_str!("../templates/css/atom-one-light.min.css").to_string(), + }); + + assets.push(DocFile { + path: PathBuf::from("css/atom-one-dark.min.css"), + content: std::include_str!("../templates/css/atom-one-dark.min.css").to_string(), + }); + + assets.push(DocFile { + path: PathBuf::from("css/index.css"), + content: std::include_str!("../templates/css/index.css").to_string(), + }); + + assets.push(DocFile { + path: PathBuf::from("js/highlight.min.js"), + content: std::include_str!("../templates/js/highlight.min.js").to_string(), + }); + + assets.push(DocFile { + path: PathBuf::from("js/highlightjs-gleam.js"), + content: std::include_str!("../templates/js/highlightjs-gleam.js").to_string(), + }); + + assets.push(DocFile { + path: PathBuf::from("js/lunr.min.js"), + content: std::include_str!("../templates/js/lunr.min.js").to_string(), + }); + + assets.push(DocFile { + path: PathBuf::from("js/index.js"), + content: std::include_str!("../templates/js/index.js").to_string(), + }); + + assets.push(DocFile { + path: PathBuf::from("search-data.js"), + content: format!( + "window.Aiken.initSearch({});", + json::to_string(&escape_html_contents(search_indexes)) + .expect("search index serialization") + ), + }); + + assets +} + +fn generate_readme( + root: &PathBuf, + config: &Config, + modules: Vec<&CheckedModule>, + timestamp: &Duration, +) -> DocFile { + let path = PathBuf::from("index.html"); + + let content = std::fs::read_to_string(root.join("README.md")).unwrap_or_default(); + + let mut modules_links = vec![]; + for module in modules { + let module_path = [&module.name.clone(), ".html"].concat(); + modules_links.push(DocLink { + path: module_path, + name: module.name.to_string().clone(), + }); + } + modules_links.sort(); + + let template = PageTemplate { + aiken_version: VERSION, + breadcrumbs: ".", + links: &vec![], + modules: &modules_links, + project_name: &config.name, + page_title: &config.name, + project_version: &config.version.to_string(), + content: render_markdown(&content), + timestamp: ×tamp.as_secs().to_string(), + }; + + DocFile { + path, + content: template.render().expect("Page template rendering"), + } +} + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +struct DocFunction { + name: String, + signature: String, + documentation: String, + source_url: String, +} + +impl DocFunction { + fn from_definition(def: &TypedDefinition) -> Option { + match def { + Definition::Fn(func_def) if func_def.public => Some(DocFunction { + name: func_def.name.clone(), + documentation: func_def + .doc + .as_deref() + .map(render_markdown) + .unwrap_or_default(), + signature: format::Formatter::new() + .docs_fn_signature( + true, + &func_def.name, + &func_def.arguments, + func_def.return_type.clone(), + ) + .to_pretty_string(MAX_COLUMNS), + source_url: "TODO: source_url".to_string(), + }), + _ => None, + } + } +} + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +struct DocConstant { + name: String, + definition: String, + documentation: String, + text_documentation: String, + source_url: String, +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +struct DocType { + name: String, + definition: String, + documentation: String, + constructors: Vec, + text_documentation: String, + source_url: String, +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +struct DocTypeConstructor { + definition: String, + documentation: String, + text_documentation: String, + arguments: Vec, +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] +struct DocTypeConstructorArg { + name: String, + doc: String, +} + +// ------ Extra Helpers + +fn render_markdown(text: &str) -> String { + let mut s = String::with_capacity(text.len() * 3 / 2); + let p = markdown::Parser::new_ext(text, markdown::Options::all()); + markdown::html::push_html(&mut s, p); + s +} + +fn escape_html_contents(indexes: Vec) -> Vec { + fn escape_html_content(it: String) -> String { + it.replace('&', "&") + .replace('<', "<") + .replace('>', ">") + .replace('\"', """) + .replace('\'', "'") + } + + indexes + .into_iter() + .map(|idx| SearchIndex { + doc: idx.doc, + title: idx.title, + content: escape_html_content(idx.content), + url: idx.url, + }) + .collect::>() +} + +fn new_timestamp() -> Duration { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("get current timestamp") +} + +fn to_breadcrumbs(path: &str) -> String { + let unnest = path + .strip_prefix('/') + .unwrap_or(path) + .split('/') + .skip(1) + .map(|_| "..") + .join("/"); + if unnest.is_empty() { + ".".to_string() + } else { + unnest + } +} + +#[test] +fn to_breadcrumbs_test() { + // Pages + assert_eq!(to_breadcrumbs("a.html"), "."); + assert_eq!(to_breadcrumbs("/a.html"), "."); + assert_eq!(to_breadcrumbs("/a/b.html"), ".."); + assert_eq!(to_breadcrumbs("/a/b/c.html"), "../.."); + + // Modules + assert_eq!(to_breadcrumbs("a"), "."); + assert_eq!(to_breadcrumbs("a/b"), ".."); + assert_eq!(to_breadcrumbs("a/b/c"), "../.."); +} diff --git a/crates/project/templates/_layout.html b/crates/project/templates/_layout.html new file mode 100644 index 00000000..fd23a59a --- /dev/null +++ b/crates/project/templates/_layout.html @@ -0,0 +1,269 @@ + + + + + + {{ page_title }} + + + + + + + + + + + + + + +
+ + +
+ {% block content %}{% endblock %} +
+
+
+ + + +
+
Lucy
+
says
+
trans
+
rights
+
now
+
+ + + + + + + + + + + + + + + + + + + + + + + + + Search + + + + + + + Document + + + + + + + + + + + + + + + + diff --git a/crates/project/templates/css/atom-one-dark.min.css b/crates/project/templates/css/atom-one-dark.min.css new file mode 100644 index 00000000..5344ee38 --- /dev/null +++ b/crates/project/templates/css/atom-one-dark.min.css @@ -0,0 +1 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline} \ No newline at end of file diff --git a/crates/project/templates/css/atom-one-light.min.css b/crates/project/templates/css/atom-one-light.min.css new file mode 100644 index 00000000..2e58473d --- /dev/null +++ b/crates/project/templates/css/atom-one-light.min.css @@ -0,0 +1 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#383a42;background:#fafafa}.hljs-comment,.hljs-quote{color:#a0a1a7;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#a626a4}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e45649}.hljs-literal{color:#0184bb}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#50a14f}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#986801}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#4078f2}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#c18401}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline} diff --git a/crates/project/templates/css/index.css b/crates/project/templates/css/index.css new file mode 100644 index 00000000..af10c40b --- /dev/null +++ b/crates/project/templates/css/index.css @@ -0,0 +1,1105 @@ +@import url("https://fonts.googleapis.com/css2?family=Karla:wght@400;700&family=Ubuntu+Mono&display=swap"); + +:root { + /* Colours */ + --black: #2a2020; + --hard-black: #000; + --pink: #ffaff3; + --hot-pink: #d900b8; + --white: #fff; + --pink-white: #fff8fe; + --mid-grey: #dfe2e5; + --light-grey: #f5f5f5; + --boi-blue: #a6f0fc; + + /* Derived colours */ + --text: var(--black); + --background: var(--white); + --accented-background: var(--pink-white); + --code-border: var(--pink); + --code-background: var(--light-grey); + --table-border: var(--mid-grey); + --table-background: var(--pink-white); + --links: var(--hot-pink); + --accent: var(--pink); + + /* Sizes */ + --content-width: 680px; + --header-height: 60px; + --hash-offset: calc(var(--header-height) * 1.67); + --sidebar-width: 240px; + --gap: 24px; + --small-gap: calc(var(--gap) / 2); + --tiny-gap: calc(var(--small-gap) / 2); + --large-gap: calc(var(--gap) * 2); + --sidebar-toggle-size: 33px; + --search-height: 4rem; + + /* etc */ + --shadow: 0 0 0 1px rgba(50, 50, 93, 0.075), 0 0 1px #e9ecef, + 0 2px 4px -2px rgba(138, 141, 151, 0.6); + --nav-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.1); +} + +* { + box-sizing: border-box; +} + +body, +html { + padding: 0; + margin: 0; + font-family: "Karla", sans-serif; + font-size: 17px; + line-height: 1.4; + position: relative; + min-height: 100vh; + word-break: break-word; +} + +html { + /* This is necessary so hash targets appear below the fixed header */ + scroll-padding-top: var(--hash-offset); +} + +a, +a:visited { + color: var(--links); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +button, +select { + background: transparent; + border: 0 none; + cursor: pointer; + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0; + text-transform: none; +} + +button::-moz-focus-inner { + border-style: none; + padding: 0; +} + +button:-moz-focusring { + outline: 1px dotted ButtonText; +} + +button { + -webkit-appearance: button; + line-height: 1; + margin: 0; + overflow: visible; + padding: 0; +} + +button:active, +select:active { + outline: 0 none; +} + +li { + margin-bottom: 4px; +} + +p { + margin: var(--small-gap) 0; +} + +.rendered-markdown h1, +.rendered-markdown h2, +.rendered-markdown h3, +.rendered-markdown h4, +.rendered-markdown h5 { + font-size: 1.3rem; +} + +/* Code */ + +pre, +code { + font-family: "Ubuntu Mono", monospace; + line-height: 1.2; + background-color: var(--code-background); +} + +pre { + margin: var(--gap) 0; + border-radius: 1px; + overflow: auto; + box-shadow: var(--shadow); +} + +pre > code, +code.hljs { + padding: var(--small-gap) var(--gap); + background: transparent; +} + +p code { + margin: 0 2px; + border-radius: 3px; + padding: 0 0.2em; + color: var(--inline-code); +} + +/* Page layout */ + +.page { + display: flex; +} + +.content { + margin-left: var(--sidebar-width); + padding: calc(var(--header-height) + var(--gap)) var(--gap) 0 var(--gap); + width: calc(100% - var(--sidebar-width)); + max-width: var(--content-width); +} + +.content img { + max-width: 100%; +} + +/* Page header */ + +.page-header { + box-shadow: var(--nav-shadow); + height: var(--header-height); + color: black; + color: var(--hard-black); + background-color: var(--pink); + display: flex; + padding: var(--small-gap) var(--gap); + position: fixed; + left: 0; + right: 0; + top: 0; + z-index: 300; +} + +.page-header h2 { + align-items: baseline; + display: flex; + margin: 0; + width: var(--sidebar-width); +} + +.page-header a, +.page-header a:visited { + color: black; + color: var(--hard-black); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.sidebar-toggle { + display: none; + font-size: var(--sidebar-toggle-size); + opacity: 0; + transition: opacity 1s ease; +} + +.search-nav-button { + display: none; + font-size: var(--sidebar-toggle-size); + opacity: 0; + transition: opacity 1s ease; +} + +.page-header .sidebar-toggle { + color: white; + color: var(--white); + margin: 0 var(--small-gap) 0 0; +} + +.page-header .search-nav-button { + color: white; + color: var(--white); + margin: 0 var(--small-gap) 0 0; +} + +/* Version selector */ + +#project-version { + --half-small-gap: calc(var(--small-gap) / 2); + --icon-size: 0.75em; + flex-shrink: 0; + font-size: 0.9rem; + font-weight: normal; + margin-left: var(--half-small-gap); +} + +#project-version > span { + padding-left: var(--half-small-gap); +} + +#project-version form { + align-items: center; + display: inline-flex; + justify-content: flex-end; +} + +#project-version select { + appearance: none; + -webkit-appearance: none; + padding: 0.6rem calc(1.3 * var(--icon-size)) 0.6rem var(--half-small-gap); + position: relative; + z-index: 1; +} + +#project-version option { + background-color: var(--code-background); +} + +#project-version .icon { + font-size: var(--icon-size); + margin-left: calc(-1.65 * var(--icon-size)); +} + +/* Module doc */ + +.module-name > a, +.module-member-kind > a { + color: inherit; +} + +.module-name > a:hover, +.module-member-kind > a:hover { + text-decoration: none; +} + +.module-name { + color: var(--hard-black); + margin: 0 0 var(--gap); + font-weight: 700; +} + +/* Sidebar */ + +.sidebar { + background-color: var(--background); + font-size: 0.95rem; + max-height: calc(100vh - var(--header-height)); + overflow-y: auto; + overscroll-behavior: contain; + padding-top: var(--gap); + padding-bottom: calc(3 * var(--gap)); + padding-left: var(--gap); + position: fixed; + top: var(--header-height); + transition: transform 0.5s ease; + width: var(--sidebar-width); + z-index: 100; +} + +.sidebar h2 { + margin: 0; +} + +.sidebar ul { + list-style: none; + margin: var(--small-gap) 0; + padding: 0; +} + +.sidebar li { + line-height: 1.2; + margin-bottom: 4px; +} + +.sidebar .sidebar-toggle { + color: var(--pink); + font-size: calc(0.8 * var(--sidebar-toggle-size)); +} + +body.drawer-closed .label-open, +body.drawer-open .label-closed { + display: none; +} + +.display-controls { + display: flex; + flex-wrap: wrap; + margin-top: var(--small-gap); + padding-right: var(--gap); +} + +.display-controls .control { + margin: 0.5rem 0; +} + +.display-controls .control:not(:first-child) { + margin-left: 1rem; +} + +.toggle { + align-items: center; + display: flex; + font-size: 0.96rem; +} + +.toggle-0 .label:not(.label-0), +.toggle-1 .label:not(.label-1) { + display: none; +} + +.label { + display: flex; +} + +.label .icon { + margin: 0 0.28rem; +} + +/* Module members (types, functions) */ + +.module-members { + margin-top: var(--large-gap); +} + +.module-member-kind { + font-size: 2rem; + color: var(--text); +} + +.member { + margin: var(--large-gap) 0; + padding-bottom: var(--gap); +} + +.member-name { + display: flex; + align-items: center; + justify-content: space-between; + border-left: 4px solid var(--accent); + padding: var(--small-gap) var(--gap); + background-color: var(--accented-background); +} + +.member-name h2 { + display: flex; + font-size: 1.5rem; + margin: 0; +} + +.member-name h2 a { + color: var(--text); +} + +.member-source { + align-self: baseline; + flex-shrink: 0; + line-height: calc(1.4 * 1.5rem); + margin: 0 0 0 var(--small-gap); +} + +/* Custom type constructors */ + +.constructor-list { + list-style: none; + padding: 0; +} + +.constructor-row { + align-items: center; + display: flex; +} + +.constructor-item { + margin-bottom: var(--small-gap); +} + +.constructor-argument-item { + display: flex; +} + +.constructor-argument-label { + flex-shrink: 0; +} + +.constructor-argument-doc { + margin-left: var(--gap); +} + +.constructor-argument-list { + margin-bottom: var(--small-gap); +} + +.constructor-item-docs { + margin-left: var(--large-gap); + margin-bottom: var(--gap); +} + +.constructor-item .icon { + flex-shrink: 0; + font-size: 0.7rem; + margin: 0 0.88rem; +} + +.constructor-name { + box-shadow: unset; + margin: 0; +} + +.constructor-name > code { + padding: var(--small-gap); +} + +/* Tables */ + +table { + border-spacing: 0; + border-collapse: collapse; +} + +table td, +table th { + padding: 6px 13px; + border: 1px solid var(--table-border); +} + +table tr:nth-child(2n) { + background-color: var(--table-background); +} + +/* Footer */ + +.pride { + width: 100%; + display: none; + flex-direction: row; + position: absolute; + bottom: 0; + z-index: 100; +} + +.show-pride .pride { + display: flex; +} + +.show-pride .sidebar { + margin-bottom: var(--gap); +} + +.pride div { + flex: 1; + text-align: center; + padding: var(--tiny-gap); +} + +.pride .white { + background-color: var(--white); +} +.pride .pink { + background-color: var(--pink); +} +.pride .blue { + background-color: var(--boi-blue); +} + +.pride-button { + position: absolute; + right: 2px; + bottom: 2px; + opacity: 0.2; + font-size: 0.9rem; +} + +.pride-button { + text-decoration: none; + cursor: default; +} + +/* Icons */ + +.svg-lib { + height: 0; + overflow: hidden; + position: absolute; + width: 0; +} + +.icon { + display: inline-block; + fill: currentColor; + height: 1em; + stroke: currentColor; + stroke-width: 0; + width: 1em; +} + +/* Pre-Wrap Option */ + +body.prewrap-on code, +body.prewrap-on pre { + white-space: pre-wrap; +} + +/* Dark Theme Option */ + +body.theme-dark { + /* Colour palette adapted from: + * https://github.com/dustypomerleau/yarra-valley + */ + + --argument-atom: #c651e5; + --class-module: #ff89b5; + --comment: #7e818b; + --escape: #7cdf89; + --function-call: #abb8c0; + --function-definition: #8af899; + --interpolation-regex: #ee37aa; + --keyword-operator: #ff9d35; + --number-boolean: #f14360; + --object: #99c2eb; + --punctuation: #4ce7ff; + --string: #aecc00; + + --inline-code: #ff9d35; + + --bg: #292d3e; + --bg-tint-1: #3e4251; + --bg-tint-2: #535664; + --bg-tint-3: #696c77; + --bg-tint-4: #7e818b; + --bg-shade-1: #242837; + --bg-shade-2: #202431; + --bg-shade-3: #1c1f2b; + --bg-mono-1: #33384d; + --bg-mono-2: #3d435d; + --bg-mono-3: #474e6c; + --bg-mono-4: #51597b; + + --fg: #cac0a9; + --fg-tint-1: #fdf2d8; + --fg-tint-2: #fdf3dc; + --fg-tint-3: #fdf5e0; + --fg-shade-1: #e3d8be; + --fg-shade-2: #cac0a9; + --fg-shade-3: #b1a894; + --fg-shade-4: #97907f; + + --orange-shade-1: #e58d2f; + --orange-shade-2: #cc7d2a; + --orange-shade-3: #b26d25; + + --taupe-mono-1: #fdf1d4; + --taupe-mono-2: #fce9bc; + --taupe-mono-3: #fbe1a3; + + /* Theme Overrides */ + + --accent: var(--pink); + --accented-background: var(--bg-shade-1); + --background: var(--bg); + --code-background: var(--bg-shade-2); + --table-background: var(--bg-mono-1); + --hard-black: var(--taupe-mono-1); + --links: var(--pink); + --text: var(--taupe-mono-1); + + --shadow: 0 0 0 1px rgba(50, 50, 93, 0.075), 0 0 1px var(--fg-shade-3), + 0 2px 4px -2px rgba(138, 141, 151, 0.2); + --nav-shadow: 0 0 5px 5px rgba(0, 0, 0, 0.1); +} + +body.theme-dark { + background-color: var(--bg); + color: var(--fg-shade-1); +} + +body.theme-dark .page-header { + background-color: var(--bg-mono-1); +} + +body.theme-dark .page-header h2 { + color: var(--fg-shade-1); +} + +body.theme-dark .page-header a, +body.theme-dark .page-header a:visited { + color: var(--pink); +} + +body.theme-dark .page-header .sidebar-toggle { + color: var(--fg-shade-1); +} +body.theme-dark .page-header .search-nav-button { + color: var(--fg-shade-1); +} + +body.theme-dark #project-version select, +body.theme-dark .control { + color: var(--fg-shade-1); +} + +body.theme-dark .module-name { + color: var(--taupe-mono-1); +} + +body.theme-dark .pride { + color: var(--bg-shade-3); +} + +body.theme-dark .pride .white { + background-color: var(--fg-shade-1); +} + +body.theme-dark .pride .pink { + background-color: var(--argument-atom); +} + +body.theme-dark .pride .blue { + background-color: var(--punctuation); +} + +/* Medium and larger displays */ +@media (min-width: 680px) { + #prewrap-toggle { + display: none; + } +} + +/* Small displays */ +@media (max-width: 920px) { + .page-header { + padding-left: var(--small-gap); + padding-right: var(--small-gap); + } + + .page-header h2 { + width: calc( + 100% - var(--sidebar-toggle-size) - var(--small-gap) - + var(--sidebar-toggle-size) - var(--small-gap) + ); + } + + .content { + width: 100%; + max-width: unset; + margin-left: unset; + } + + .sidebar { + box-shadow: var(--nav-shadow); + height: 100vh; + max-height: unset; + top: 0; + transform: translate(calc(-10px - var(--sidebar-width))); + z-index: 500; + } + + body.drawer-open .sidebar { + transform: translate(0); + } + + .sidebar-toggle { + display: block; + opacity: 1; + } + + .search-nav-button { + display: block; + opacity: 1; + } + + .sidebar .sidebar-toggle { + height: var(--sidebar-toggle-size); + position: absolute; + right: var(--small-gap); + top: var(--small-gap); + width: var(--sidebar-toggle-size); + } +} + +/* Search */ + +.search { + display: none; + position: relative; + z-index: 2; + flex-grow: 1; + height: var(--search-height); + padding: 0.5rem; + transition: padding linear 200ms; +} + +@media (min-width: 919px) { + .search { + margin-left: var(--small-gap); + display: block; + position: relative !important; + width: auto !important; + height: 100% !important; + padding: 0; + transition: none; + } +} + +.search-input-wrap { + position: relative; + z-index: 1; + height: 3rem; + overflow: hidden; + border-radius: 4px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + transition: height linear 200ms; +} + +@media (min-width: 919px) { + .search-input-wrap { + position: absolute; + width: 100%; + max-width: calc(var(--content-width) - var(--gap) - var(--gap)); + height: 100% !important; + border-radius: 0; + box-shadow: none; + transition: width ease 400ms; + } +} + +.search-input { + position: absolute; + width: 100%; + height: 100%; + padding: 0.5rem 1rem; + font-size: 16px; + background-color: transparent; + color: var(--text); + border-top: 0; + border-right: 0; + border-bottom: 0; + border-left: 0; + border-radius: 0; +} + +@media (min-width: 919px) { + .search-input { + padding: 1rem; + font-size: 14px; + background-color: transparent; + transition: padding-left linear 200ms; + } +} + +.search-input:focus { + outline: 0; +} + +.search-input:focus + .search-label .search-icon { + color: var(--pink); +} + +.search-label { + position: absolute; + right: 0; + display: flex; + height: 100%; + padding-right: 1rem; + cursor: pointer; +} + +@media (min-width: 919px) { + .search-label { + padding-right: 0.6rem; + transition: padding-left linear 200ms; + } +} + +.search-label .search-icon { + width: 1.2rem; + height: 1.2rem; + align-self: center; + color: var(--text); +} + +.search-results { + position: absolute; + left: 0; + display: none; + width: 100%; + max-height: calc(100% - var(--search-height)); + overflow-y: auto; + background-color: var(--background); + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); +} + +@media (min-width: 919px) { + .search-results { + top: 100%; + width: calc(var(--content-width) - var(--gap) - var(--gap)); + max-height: calc(100vh - 200%) !important; + } +} + +.search-results-list { + padding-left: 0; + margin-bottom: 0.25rem; + list-style: none; + font-size: 14px !important; +} + +@media (min-width: 31.25rem) { + .search-results-list { + font-size: 16px !important; + } +} + +@media (min-width: 919px) { + .search-results-list { + font-size: 12px !important; + } +} + +@media (min-width: 919px) and (min-width: 31.25rem) { + .search-results-list { + font-size: 14px !important; + } +} + +.search-results-list-item { + padding: 0; + margin: 0; +} + +.search-result { + display: block; + padding-top: 0.25rem; + padding-right: 0.75rem; + padding-bottom: 0.25rem; + padding-left: 0.75rem; +} + +.search-result:hover, +.search-result.active { + background-color: var(--code-background); +} + +.search-result-title { + display: block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +@media (min-width: 31.25rem) { + .search-result-title { + display: inline-block; + width: 40%; + padding-right: 0.5rem; + vertical-align: top; + } +} + +.search-result-doc { + display: flex; + align-items: center; + word-wrap: break-word; +} + +.search-result-doc.search-result-doc-parent { + opacity: 0.5; + font-size: 12px !important; +} + +@media (min-width: 31.25rem) { + .search-result-doc.search-result-doc-parent { + font-size: 14px !important; + } +} + +@media (min-width: 919px) { + .search-result-doc.search-result-doc-parent { + font-size: 11px !important; + } +} + +@media (min-width: 919px) and (min-width: 31.25rem) { + .search-result-doc.search-result-doc-parent { + font-size: 12px !important; + } +} + +.search-result-doc .search-result-icon { + width: 1rem; + height: 1rem; + margin-right: 0.5rem; + color: var(--pink); + flex-shrink: 0; +} + +.search-result-doc .search-result-doc-title { + overflow: auto; +} + +.search-result-section { + margin-left: 1.5rem; + word-wrap: break-word; +} + +.search-result-rel-url { + display: block; + margin-left: 1.5rem; + overflow: hidden; + color: var(--text); + text-overflow: ellipsis; + white-space: nowrap; + font-size: 9px !important; +} + +@media (min-width: 31.25rem) { + .search-result-rel-url { + font-size: 10px !important; + } +} + +.search-result-previews { + display: block; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 1rem; + margin-left: 0.5rem; + color: var(--text); + word-wrap: break-word; + border-left: 1px solid; + border-left-color: #eeebee; + font-size: 11px !important; + /* TODO: fix it by not adding at the parent? */ + white-space: initial !important; +} + +@media (min-width: 31.25rem) { + .search-result-previews { + font-size: 12px !important; + } +} + +@media (min-width: 31.25rem) { + .search-result-previews { + display: inline-block; + width: 60%; + padding-left: 0.5rem; + margin-left: 0; + vertical-align: top; + } +} + +.search-result-preview + .search-result-preview { + margin-top: 0.25rem; +} + +.search-result-highlight { + font-weight: bold; +} + +.search-no-result { + padding-top: 0.5rem; + padding-right: 0.75rem; + padding-bottom: 0.5rem; + padding-left: 0.75rem; + font-size: 12px !important; +} + +@media (min-width: 31.25rem) { + .search-no-result { + font-size: 14px !important; + } +} + +.search-button { + position: fixed; + right: 1rem; + bottom: 1rem; + display: flex; + width: 3.5rem; + height: 3.5rem; + background-color: var(--background); + border: 1px solid rgba(114, 83, 237, 0.3); + border-radius: 1.75rem; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + align-items: center; + justify-content: center; +} + +.search-overlay { + position: fixed; + top: 0; + left: 0; + z-index: 101; + width: 0; + height: 0; + background-color: rgba(0, 0, 0, 0.3); + opacity: 0; + transition: opacity ease 400ms, width 0s 400ms, height 0s 400ms; +} + +.search-active .search { + display: block; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 0; +} + +.search-active .search-input-wrap { + height: var(--search-height); + border-radius: 0; +} + +@media (min-width: 919px) { + .search-active .search-input-wrap { + width: calc(var(--content-width) - var(--gap) - var(--gap)); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); + } +} + +.search-active .search-input { + background-color: var(--background); +} + +@media (min-width: 919px) { + .search-active .search-label { + padding-left: 0.6rem; + } +} + +.search-active .search-results { + display: block; +} + +.search-active .search-overlay { + width: 100%; + height: 100%; + opacity: 1; + transition: opacity ease 400ms, width 0s, height 0s; +} + +@media (min-width: 919px) { + .search-active .main { + position: fixed; + right: 0; + left: 0; + } +} + +.search-active .main-header { + padding-top: var(--search-height); +} + +@media (min-width: 919px) { + .search-active .main-header { + padding-top: 0; + } +} diff --git a/crates/project/templates/js/highlight.min.js b/crates/project/templates/js/highlight.min.js new file mode 100644 index 00000000..43482e35 --- /dev/null +++ b/crates/project/templates/js/highlight.min.js @@ -0,0 +1,1198 @@ +/*! + Highlight.js v11.6.0 (git: bed790f3f3) + (c) 2006-2022 undefined and other contributors + License: BSD-3-Clause + */ +var hljs=function(){"use strict";var e={exports:{}};function n(e){ +return e instanceof Map?e.clear=e.delete=e.set=()=>{ +throw Error("map is read-only")}:e instanceof Set&&(e.add=e.clear=e.delete=()=>{ +throw Error("set is read-only") +}),Object.freeze(e),Object.getOwnPropertyNames(e).forEach((t=>{var a=e[t] +;"object"!=typeof a||Object.isFrozen(a)||n(a)})),e} +e.exports=n,e.exports.default=n;class t{constructor(e){ +void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} +ignoreMatch(){this.isMatchIgnored=!0}}function a(e){ +return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") +}function i(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n] +;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t} +const r=e=>!!e.scope||e.sublanguage&&e.language;class s{constructor(e,n){ +this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ +this.buffer+=a(e)}openNode(e){if(!r(e))return;let n="" +;n=e.sublanguage?"language-"+e.language:((e,{prefix:n})=>{if(e.includes(".")){ +const t=e.split(".") +;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ") +}return`${n}${e}`})(e.scope,{prefix:this.classPrefix}),this.span(n)} +closeNode(e){r(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ +this.buffer+=``}}const o=(e={})=>{const n={children:[]} +;return Object.assign(n,e),n};class l{constructor(){ +this.rootNode=o(),this.stack=[this.rootNode]}get top(){ +return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ +this.top.children.push(e)}openNode(e){const n=o({scope:e}) +;this.add(n),this.stack.push(n)}closeNode(){ +if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ +for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} +walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ +return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), +n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ +"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ +l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e} +addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())} +addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root +;t.sublanguage=!0,t.language=n,this.add(t)}toHTML(){ +return new s(this,this.options).value()}finalize(){return!0}}function d(e){ +return e?"string"==typeof e?e:e.source:null}function g(e){return m("(?=",e,")")} +function u(e){return m("(?:",e,")*")}function b(e){return m("(?:",e,")?")} +function m(...e){return e.map((e=>d(e))).join("")}function p(...e){const n=(e=>{ +const n=e[e.length-1] +;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} +})(e);return"("+(n.capture?"":"?:")+e.map((e=>d(e))).join("|")+")"} +function _(e){return RegExp(e.toString()+"|").exec("").length-1} +const h=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ +;function f(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t +;let a=d(e),i="";for(;a.length>0;){const e=h.exec(a);if(!e){i+=a;break} +i+=a.substring(0,e.index), +a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0], +"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)} +const E="[a-zA-Z]\\w*",y="[a-zA-Z_]\\w*",w="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",v="\\b(0b[01]+)",O={ +begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'", +illegal:"\\n",contains:[O]},x={scope:"string",begin:'"',end:'"',illegal:"\\n", +contains:[O]},M=(e,n,t={})=>{const a=i({scope:"comment",begin:e,end:n, +contains:[]},t);a.contains.push({scope:"doctag", +begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", +end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) +;const r=p("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) +;return a.contains.push({begin:m(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),a +},S=M("//","$"),A=M("/\\*","\\*/"),C=M("#","$");var T=Object.freeze({ +__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:E,UNDERSCORE_IDENT_RE:y, +NUMBER_RE:w,C_NUMBER_RE:N,BINARY_NUMBER_RE:v, +RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", +SHEBANG:(e={})=>{const n=/^#![ ]*\// +;return e.binary&&(e.begin=m(n,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:n, +end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)}, +BACKSLASH_ESCAPE:O,APOS_STRING_MODE:k,QUOTE_STRING_MODE:x,PHRASAL_WORDS_MODE:{ +begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ +},COMMENT:M,C_LINE_COMMENT_MODE:S,C_BLOCK_COMMENT_MODE:A,HASH_COMMENT_MODE:C, +NUMBER_MODE:{scope:"number",begin:w,relevance:0},C_NUMBER_MODE:{scope:"number", +begin:N,relevance:0},BINARY_NUMBER_MODE:{scope:"number",begin:v,relevance:0}, +REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{scope:"regexp",begin:/\//, +end:/\/[gimuy]*/,illegal:/\n/,contains:[O,{begin:/\[/,end:/\]/,relevance:0, +contains:[O]}]}]},TITLE_MODE:{scope:"title",begin:E,relevance:0}, +UNDERSCORE_TITLE_MODE:{scope:"title",begin:y,relevance:0},METHOD_GUARD:{ +begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:e=>Object.assign(e,{ +"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{ +n.data._beginMatch!==e[1]&&n.ignoreMatch()}})});function R(e,n){ +"."===e.input[e.index-1]&&n.ignoreMatch()}function D(e,n){ +void 0!==e.className&&(e.scope=e.className,delete e.className)}function I(e,n){ +n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", +e.__beforeBegin=R,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, +void 0===e.relevance&&(e.relevance=0))}function L(e,n){ +Array.isArray(e.illegal)&&(e.illegal=p(...e.illegal))}function B(e,n){ +if(e.match){ +if(e.begin||e.end)throw Error("begin & end are not supported with match") +;e.begin=e.match,delete e.match}}function $(e,n){ +void 0===e.relevance&&(e.relevance=1)}const z=(e,n)=>{if(!e.beforeMatch)return +;if(e.starts)throw Error("beforeMatch cannot be used with starts") +;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n] +})),e.keywords=t.keywords,e.begin=m(t.beforeMatch,g(t.begin)),e.starts={ +relevance:0,contains:[Object.assign(t,{endsParent:!0})] +},e.relevance=0,delete t.beforeMatch +},F=["of","and","for","in","not","or","if","then","parent","list","value"] +;function U(e,n,t="keyword"){const a=Object.create(null) +;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{ +Object.assign(a,U(e[t],n,t))})),a;function i(e,t){ +n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|") +;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){ +return n?Number(n):(e=>F.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{ +console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{ +P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0) +},Z=Error();function G(e,n,{key:t}){let a=0;const i=e[t],r={},s={} +;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=_(n[e-1]) +;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{ +e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, +delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ +_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope +}),(e=>{if(Array.isArray(e.begin)){ +if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), +Z +;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"), +Z;G(e,e.begin,{key:"beginScope"}),e.begin=f(e.begin,{joinWith:""})}})(e),(e=>{ +if(Array.isArray(e.end)){ +if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"), +Z +;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"), +Z;G(e,e.end,{key:"endScope"}),e.end=f(e.end,{joinWith:""})}})(e)}function Q(e){ +function n(n,t){ +return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":"")) +}class t{constructor(){ +this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} +addRule(e,n){ +n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), +this.matchAt+=_(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) +;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(f(e,{joinWith:"|" +}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex +;const n=this.matcherRe.exec(e);if(!n)return null +;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t] +;return n.splice(0,t),Object.assign(n,a)}}class a{constructor(){ +this.rules=[],this.multiRegexes=[], +this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ +if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t +;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), +n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ +return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ +this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ +const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex +;let t=n.exec(e) +;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ +const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} +return t&&(this.regexIndex+=t.position+1, +this.regexIndex===this.count&&this.considerAll()),t}} +if(e.compilerExtensions||(e.compilerExtensions=[]), +e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") +;return e.classNameAliases=i(e.classNameAliases||{}),function t(r,s){const o=r +;if(r.isCompiled)return o +;[D,B,W,z].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))), +r.__beforeBegin=null,[I,L,$].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null +;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), +l=r.keywords.$pattern, +delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=U(r.keywords,e.case_insensitive)), +o.keywordPatternRe=n(l,!0), +s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), +r.end&&(o.endRe=n(o.end)), +o.terminatorEnd=d(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)), +r.illegal&&(o.illegalRe=n(r.illegal)), +r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>i(e,{ +variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?i(e,{ +starts:e.starts?i(e.starts):null +}):Object.isFrozen(e)?i(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o) +})),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new a +;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" +}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end" +}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){ +return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{ +constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}} +const J=a,Y=i,ee=Symbol("nomatch");var ne=(n=>{ +const a=Object.create(null),i=Object.create(null),r=[];let s=!0 +;const o="Could not find the language '{}', did you forget to load/include a language module?",l={ +disableAutodetect:!0,name:"Plain text",contains:[]};let d={ +ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, +languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", +cssSelector:"pre code",languages:null,__emitter:c};function _(e){ +return d.noHighlightRe.test(e)}function h(e,n,t){let a="",i="" +;"object"==typeof n?(a=e, +t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."), +q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), +i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r) +;const s=r.result?r.result:f(r.language,r.code,t) +;return s.code=r.code,x("after:highlight",s),s}function f(e,n,i,r){ +const l=Object.create(null);function c(){if(!k.keywords)return void M.addText(S) +;let e=0;k.keywordPatternRe.lastIndex=0;let n=k.keywordPatternRe.exec(S),t="" +;for(;n;){t+=S.substring(e,n.index) +;const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,k.keywords[a]);if(r){ +const[e,a]=r +;if(M.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(A+=a),e.startsWith("_"))t+=n[0];else{ +const t=w.classNameAliases[e]||e;M.addKeyword(n[0],t)}}else t+=n[0] +;e=k.keywordPatternRe.lastIndex,n=k.keywordPatternRe.exec(S)}var a +;t+=S.substring(e),M.addText(t)}function g(){null!=k.subLanguage?(()=>{ +if(""===S)return;let e=null;if("string"==typeof k.subLanguage){ +if(!a[k.subLanguage])return void M.addText(S) +;e=f(k.subLanguage,S,!0,x[k.subLanguage]),x[k.subLanguage]=e._top +}else e=E(S,k.subLanguage.length?k.subLanguage:null) +;k.relevance>0&&(A+=e.relevance),M.addSublanguage(e._emitter,e.language) +})():c(),S=""}function u(e,n){let t=1;const a=n.length-1;for(;t<=a;){ +if(!e._emit[t]){t++;continue}const a=w.classNameAliases[e[t]]||e[t],i=n[t] +;a?M.addKeyword(i,a):(S=i,c(),S=""),t++}}function b(e,n){ +return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope), +e.beginScope&&(e.beginScope._wrap?(M.addKeyword(S,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), +S=""):e.beginScope._multi&&(u(e.beginScope,n),S="")),k=Object.create(e,{parent:{ +value:k}}),k}function m(e,n,a){let i=((e,n)=>{const t=e&&e.exec(n) +;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new t(e) +;e["on:end"](n,a),a.isMatchIgnored&&(i=!1)}if(i){ +for(;e.endsParent&&e.parent;)e=e.parent;return e}} +if(e.endsWithParent)return m(e.parent,n,a)}function p(e){ +return 0===k.matcher.regexIndex?(S+=e[0],1):(R=!0,0)}function _(e){ +const t=e[0],a=n.substring(e.index),i=m(k,e,a);if(!i)return ee;const r=k +;k.endScope&&k.endScope._wrap?(g(), +M.addKeyword(t,k.endScope._wrap)):k.endScope&&k.endScope._multi?(g(), +u(k.endScope,e)):r.skip?S+=t:(r.returnEnd||r.excludeEnd||(S+=t), +g(),r.excludeEnd&&(S=t));do{ +k.scope&&M.closeNode(),k.skip||k.subLanguage||(A+=k.relevance),k=k.parent +}while(k!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:t.length} +let h={};function y(a,r){const o=r&&r[0];if(S+=a,null==o)return g(),0 +;if("begin"===h.type&&"end"===r.type&&h.index===r.index&&""===o){ +if(S+=n.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`) +;throw n.languageName=e,n.badRule=h.rule,n}return 1} +if(h=r,"begin"===r.type)return(e=>{ +const n=e[0],a=e.rule,i=new t(a),r=[a.__beforeBegin,a["on:begin"]] +;for(const t of r)if(t&&(t(e,i),i.isMatchIgnored))return p(n) +;return a.skip?S+=n:(a.excludeBegin&&(S+=n), +g(),a.returnBegin||a.excludeBegin||(S=n)),b(a,e),a.returnBegin?0:n.length})(r) +;if("illegal"===r.type&&!i){ +const e=Error('Illegal lexeme "'+o+'" for mode "'+(k.scope||"")+'"') +;throw e.mode=k,e}if("end"===r.type){const e=_(r);if(e!==ee)return e} +if("illegal"===r.type&&""===o)return 1 +;if(T>1e5&&T>3*r.index)throw Error("potential infinite loop, way more iterations than matches") +;return S+=o,o.length}const w=v(e) +;if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"') +;const N=Q(w);let O="",k=r||N;const x={},M=new d.__emitter(d);(()=>{const e=[] +;for(let n=k;n!==w;n=n.parent)n.scope&&e.unshift(n.scope) +;e.forEach((e=>M.openNode(e)))})();let S="",A=0,C=0,T=0,R=!1;try{ +for(k.matcher.considerAll();;){ +T++,R?R=!1:k.matcher.considerAll(),k.matcher.lastIndex=C +;const e=k.matcher.exec(n);if(!e)break;const t=y(n.substring(C,e.index),e) +;C=e.index+t} +return y(n.substring(C)),M.closeAllNodes(),M.finalize(),O=M.toHTML(),{ +language:e,value:O,relevance:A,illegal:!1,_emitter:M,_top:k}}catch(t){ +if(t.message&&t.message.includes("Illegal"))return{language:e,value:J(n), +illegal:!0,relevance:0,_illegalBy:{message:t.message,index:C, +context:n.slice(C-100,C+100),mode:t.mode,resultSoFar:O},_emitter:M};if(s)return{ +language:e,value:J(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:k} +;throw t}}function E(e,n){n=n||d.languages||Object.keys(a);const t=(e=>{ +const n={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new d.__emitter(d)} +;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(k).map((n=>f(n,e,!1))) +;i.unshift(t);const r=i.sort(((e,n)=>{ +if(e.relevance!==n.relevance)return n.relevance-e.relevance +;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1 +;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,c=s +;return c.secondBest=o,c}function y(e){let n=null;const t=(e=>{ +let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"" +;const t=d.languageDetectRe.exec(n);if(t){const n=v(t[1]) +;return n||(H(o.replace("{}",t[1])), +H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"} +return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return +;if(x("before:highlightElement",{el:e,language:t +}),e.children.length>0&&(d.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), +console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), +console.warn("The element with unescaped HTML:"), +console.warn(e)),d.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML) +;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a) +;e.innerHTML=r.value,((e,n,t)=>{const a=n&&i[n]||t +;e.classList.add("hljs"),e.classList.add("language-"+a) +})(e,t,r.language),e.result={language:r.language,re:r.relevance, +relevance:r.relevance},r.secondBest&&(e.secondBest={ +language:r.secondBest.language,relevance:r.secondBest.relevance +}),x("after:highlightElement",{el:e,result:r,text:a})}let w=!1;function N(){ +"loading"!==document.readyState?document.querySelectorAll(d.cssSelector).forEach(y):w=!0 +}function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} +function O(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ +i[e.toLowerCase()]=n}))}function k(e){const n=v(e) +;return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach((e=>{ +e[t]&&e[t](n)}))} +"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ +w&&N()}),!1),Object.assign(n,{highlight:h,highlightAuto:E,highlightAll:N, +highlightElement:y, +highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"), +q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{d=Y(d,e)}, +initHighlighting:()=>{ +N(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, +initHighlightingOnLoad:()=>{ +N(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") +},registerLanguage:(e,t)=>{let i=null;try{i=t(n)}catch(n){ +if(K("Language definition for '{}' could not be registered.".replace("{}",e)), +!s)throw n;K(n),i=l} +i.name||(i.name=e),a[e]=i,i.rawDefinition=t.bind(null,n),i.aliases&&O(i.aliases,{ +languageName:e})},unregisterLanguage:e=>{delete a[e] +;for(const n of Object.keys(i))i[n]===e&&delete i[n]}, +listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:O, +autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{ +e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{ +e["before:highlightBlock"](Object.assign({block:n.el},n)) +}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{ +e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)} +}),n.debugMode=()=>{s=!1},n.safeMode=()=>{s=!0 +},n.versionString="11.6.0",n.regex={concat:m,lookahead:g,either:p,optional:b, +anyNumberOfTimes:u};for(const n in T)"object"==typeof T[n]&&e.exports(T[n]) +;return Object.assign(n,T),n})({});const te=e=>({IMPORTANT:{scope:"meta", +begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{ +scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/}, +FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/}, +ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", +contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ +scope:"number", +begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", +relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z][A-Za-z0-9_-]*/} +}),ae=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],ie=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],re=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],se=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],oe=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),le=re.concat(se) +;var ce="\\.([0-9](_*[0-9])*)",de="[0-9a-fA-F](_*[0-9a-fA-F])*",ge={ +className:"number",variants:[{ +begin:`(\\b([0-9](_*[0-9])*)((${ce})|\\.)?|(${ce}))[eE][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` +},{begin:`\\b([0-9](_*[0-9])*)((${ce})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ +begin:`(${ce})[fFdD]?\\b`},{begin:"\\b([0-9](_*[0-9])*)[fFdD]\\b"},{ +begin:`\\b0[xX]((${de})\\.?|(${de})?\\.(${de}))[pP][+-]?([0-9](_*[0-9])*)[fFdD]?\\b` +},{begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${de})[lL]?\\b`},{ +begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], +relevance:0};function ue(e,n,t){return-1===t?"":e.replace(n,(a=>ue(e,n,t-1)))} +const be="[A-Za-z$_][0-9A-Za-z$_]*",me=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],pe=["true","false","null","undefined","NaN","Infinity"],_e=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],he=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],fe=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],Ee=["arguments","this","super","console","window","document","localStorage","module","global"],ye=[].concat(fe,_e,he) +;function we(e){const n=e.regex,t=be,a={begin:/<[A-Za-z0-9\\._:-]+/, +end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ +const t=e[0].length+e.index,a=e.input[t] +;if("<"===a||","===a)return void n.ignoreMatch();let i +;">"===a&&(((e,{after:n})=>{const t="",k={ +match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(O)], +keywords:"async",className:{1:"keyword",3:"title.function"},contains:[_]} +;return{name:"Javascript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{ +PARAMS_CONTAINS:p,CLASS_REFERENCE:f},illegal:/#(?![$_A-z])/, +contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ +label:"use_strict",className:"meta",relevance:10, +begin:/^\s*['"]use (strict|asm)['"]/ +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,c,d,g,u,o,f,{className:"attr", +begin:t+n.lookahead(":"),relevance:0},k,{ +begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", +keywords:"return throw case",relevance:0,contains:[u,e.REGEXP_MODE,{ +className:"function",begin:O,returnBegin:!0,end:"\\s*=>",contains:[{ +className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{ +className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, +excludeEnd:!0,keywords:i,contains:p}]}]},{begin:/,/,relevance:0},{match:/\s+/, +relevance:0},{variants:[{begin:"<>",end:""},{ +match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin, +"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{ +begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},E,{ +beginKeywords:"while if switch catch for"},{ +begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", +returnBegin:!0,label:"func.def",contains:[_,e.inherit(e.TITLE_MODE,{begin:t, +className:"title.function"})]},{match:/\.\.\./,relevance:0},N,{match:"\\$"+t, +relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, +contains:[_]},y,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, +className:"variable.constant"},h,v,{match:/\$[(.]/}]}} +const Ne=e=>m(/\b/,e,/\w$/.test(e)?/\b/:/\B/),ve=["Protocol","Type"].map(Ne),Oe=["init","self"].map(Ne),ke=["Any","Self"],xe=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","break","case","catch","class","continue","convenience","default","defer","deinit","didSet","distributed","do","dynamic","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Me=["false","nil","true"],Se=["assignment","associativity","higherThan","left","lowerThan","none","right"],Ae=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warn_unqualified_access","#warning"],Ce=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Te=p(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Re=p(Te,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),De=m(Te,Re,"*"),Ie=p(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),Le=p(Ie,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Be=m(Ie,Le,"*"),$e=m(/[A-Z]/,Le,"*"),ze=["autoclosure",m(/convention\(/,p("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",m(/objc\(/,Be,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","testable","UIApplicationMain","unknown","usableFromInline"],Fe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] +;var Ue=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={ +begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} +;Object.assign(t,{className:"variable",variants:[{ +begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ +className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={ +begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, +end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$\(\(/, +end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] +},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 +}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, +contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ +name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, +keyword:["if","then","else","elif","fi","for","while","in","do","done","case","esac","function"], +literal:["true","false"], +built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] +},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{ +className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},t]}}, +grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] +}),a="[a-zA-Z_]\\w*::",i="(decltype\\(auto\\)|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",r={ +className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ +match:/\batomic_[a-z]{3,6}\b/}]},s={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},c={ +className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0 +},d=n.optional(a)+e.IDENT_RE+"\\s*\\(",g={ +keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], +type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"], +literal:"true false NULL", +built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" +},u=[l,r,t,e.C_BLOCK_COMMENT_MODE,o,s],b={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:g,contains:u.concat([{begin:/\(/,end:/\)/,keywords:g, +contains:u.concat(["self"]),relevance:0}]),relevance:0},m={ +begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:g,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)", +keywords:g,relevance:0},{begin:d,returnBegin:!0,contains:[e.inherit(c,{ +className:"title.function"})],relevance:0},{relevance:0,match:/,/},{ +className:"params",begin:/\(/,end:/\)/,keywords:g,relevance:0, +contains:[t,e.C_BLOCK_COMMENT_MODE,s,o,r,{begin:/\(/,end:/\)/,keywords:g, +relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,s,o,r]}] +},r,t,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C",aliases:["h"],keywords:g, +disableAutodetect:!0,illegal:"=]/,contains:[{ +beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:l, +strings:s,keywords:g}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ +contains:[{begin:/\\\n/}] +}),a="[a-zA-Z_]\\w*::",i="(?!struct)(decltype\\(auto\\)|"+n.optional(a)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",r={ +className:"type",begin:"\\b[a-z\\d_]*_t\\b"},s={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},c={ +className:"title",begin:n.optional(a)+e.IDENT_RE,relevance:0 +},d=n.optional(a)+e.IDENT_RE+"\\s*\\(",g={ +type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], +keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], +literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], +_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] +},u={className:"function.dispatch",relevance:0,keywords:{ +_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] +}, +begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) +},b=[u,l,r,t,e.C_BLOCK_COMMENT_MODE,o,s],m={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:g,contains:b.concat([{begin:/\(/,end:/\)/,keywords:g, +contains:b.concat(["self"]),relevance:0}]),relevance:0},p={className:"function", +begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:g,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:"decltype\\(auto\\)", +keywords:g,relevance:0},{begin:d,returnBegin:!0,contains:[c],relevance:0},{ +begin:/::/,relevance:0},{begin:/:/,endsWithParent:!0,contains:[s,o]},{ +relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,keywords:g, +relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,s,o,r,{begin:/\(/,end:/\)/, +keywords:g,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,s,o,r]}] +},r,t,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C++", +aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:g,illegal:"",keywords:g,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:g},{ +match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], +className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ +keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), +built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], +literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ +begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ +begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] +},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, +keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, +end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ +},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ +begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, +contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) +;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], +o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ +illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] +},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t] +},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ +begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], +keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, +contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ +begin:"\x3c!--|--\x3e"},{begin:""}]}] +}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", +end:"$",keywords:{ +keyword:"if else elif endif define undef warning error line region endregion pragma checksum" +}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, +illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" +},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", +relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", +begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ +className:"string",begin:/"/,end:/"/}]},{ +beginKeywords:"new return throw await else",relevance:0},{className:"function", +begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ +beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", +relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", +begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, +contains:[g,a,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ +const n=e.regex,t=te(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ +name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ +keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, +contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ +},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 +},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 +},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ +begin:":("+re.join("|")+")"},{begin:":(:)?("+se.join("|")+")"}] +},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b"},{ +begin:/:/,end:/[;}{]/, +contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ +begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" +},contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, +excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", +relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ +},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ +$pattern:/[a-z-]+/,keyword:"and or not only",attribute:ie.join(" ")},contains:[{ +begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ +className:"selector-tag",begin:"\\b("+ae.join("|")+")\\b"}]}},grmr_diff:e=>{ +const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ +className:"meta",relevance:10, +match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) +},{className:"comment",variants:[{ +begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), +end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ +className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, +end:/$/}]}},grmr_go:e=>{const n={ +keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], +type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], +literal:["true","false","iota","nil"], +built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] +};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex;return{name:"GraphQL",aliases:["gql"], +case_insensitive:!0,disableAutodetect:!1,keywords:{ +keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], +literal:["true","false","null"]}, +contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ +scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", +begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, +end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ +scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), +relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ +className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ +begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, +end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ +begin:/\$\{(.*?)\}/}]},r={className:"literal", +begin:/\bon|off|true|false|yes|no\b/},s={className:"string", +contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ +begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] +},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 +},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ +name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, +contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ +begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), +className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ +const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+ue("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ +keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed"], +literal:["false","true","null"], +type:["char","boolean","long","float","int","byte","short","double"], +built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ +begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} +;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, +relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ +begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, +className:"string",contains:[e.BACKSLASH_ESCAPE] +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ +match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ +1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ +begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", +3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", +3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"new throw return else",relevance:0},{ +begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ +2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0, +contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,ge,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},ge,r]}},grmr_javascript:we, +grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", +beginKeywords:n.join(" ")};return{name:"JSON",keywords:{literal:n},contains:[{ +className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{ +match:/[{}[\],:]/,className:"punctuation",relevance:0 +},e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], +illegal:"\\S"}},grmr_kotlin:e=>{const n={ +keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", +built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", +literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" +},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ +className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", +variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", +illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, +contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ +className:"meta", +begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" +},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, +end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] +},l=ge,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ +variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, +contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], +{name:"Kotlin",aliases:["kt","kts"],keywords:n, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", +begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", +begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", +begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", +returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ +begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, +contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, +keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, +endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, +endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 +},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ +begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ +3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, +illegal:"extends implements",contains:[{ +beginKeywords:"public protected internal private constructor" +},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, +excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, +excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", +end:"$",illegal:"\n"},l]}},grmr_less:e=>{ +const n=te(e),t=le,a="([\\w-]+|@\\{[\\w-]+\\})",i=[],r=[],s=e=>({ +className:"string",begin:"~?"+e+".*?"+e}),o=(e,n,t)=>({className:e,begin:n, +relevance:t}),l={$pattern:/[a-z-]+/,keyword:"and or not only", +attribute:ie.join(" ")},c={begin:"\\(",end:"\\)",contains:r,keywords:l, +relevance:0} +;r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s("'"),s('"'),n.CSS_NUMBER_MODE,{ +begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", +excludeEnd:!0} +},n.HEXCOLOR,c,o("variable","@@?[\\w-]+",10),o("variable","@\\{[\\w-]+\\}"),o("built_in","~?`[^`]*?`"),{ +className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0 +},n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const d=r.concat({ +begin:/\{/,end:/\}/,contains:i}),g={beginKeywords:"when",endsWithParent:!0, +contains:[{beginKeywords:"and not"}].concat(r)},u={begin:a+"\\s*:", +returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ +},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+oe.join("|")+")\\b", +end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:r}}] +},b={className:"keyword", +begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", +starts:{end:"[;{}]",keywords:l,returnEnd:!0,contains:r,relevance:0}},m={ +className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{ +begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:d}},p={variants:[{ +begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:a,end:/\{/}],returnBegin:!0, +returnEnd:!0,illegal:"[<='$\"]",relevance:0, +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,o("keyword","all\\b"),o("variable","@\\{[\\w-]+\\}"),{ +begin:"\\b("+ae.join("|")+")\\b",className:"selector-tag" +},n.CSS_NUMBER_MODE,o("selector-tag",a,0),o("selector-id","#"+a),o("selector-class","\\."+a,0),o("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ +className:"selector-pseudo",begin:":("+re.join("|")+")"},{ +className:"selector-pseudo",begin:":(:)?("+se.join("|")+")"},{begin:/\(/, +end:/\)/,relevance:0,contains:d},{begin:"!important"},n.FUNCTION_DISPATCH]},_={ +begin:`[\\w-]+:(:)?(${t.join("|")})`,returnBegin:!0,contains:[p]} +;return i.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,b,m,_,u,p,g,n.FUNCTION_DISPATCH), +{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:i}}, +grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] +},i=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[",t,{contains:[a], +relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, +literal:"true false nil", +keyword:"and break do else elseif end for goto if in local not or repeat return then until while", +built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" +},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", +contains:[e.inherit(e.TITLE_MODE,{ +begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", +begin:"\\(",endsWithParent:!0,contains:i}].concat(i) +},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", +begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ +className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ +const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ +className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, +contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] +},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ +className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ +endsWithParent:!0,illegal:/`]+/}]}]}]};return{ +name:"HTML, XML", +aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], +case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ +className:"meta",begin://,contains:[i,r,o,s]}]}] +},e.COMMENT(//,{relevance:10}),{begin://, +relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, +relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ +end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ +end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ +className:"tag",begin:/<>|<\/>/},{className:"tag", +begin:n.concat(//,/>/,/\s/)))), +end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ +className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ +className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} +},grmr_markdown:e=>{const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml", +relevance:0},t={variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ +begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, +relevance:2},{ +begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), +relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ +begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ +},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, +returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", +excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", +end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[], +variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},i={ +className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{ +begin:/_(?!_)/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] +}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) +;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) +})),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ +className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ +begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", +contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", +end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, +end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ +begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ +begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", +contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ +begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ +className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ +className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{ +const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, +keyword:["@interface","@class","@protocol","@implementation"]};return{ +name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], +keywords:{"variable.language":["this","super"],$pattern:n, +keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], +literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], +built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], +type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] +},illegal:"/,end:/$/,illegal:"\\n" +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", +begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, +contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, +relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ +$pattern:/[\w.]+/, +keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" +},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, +end:/\}/},s={variants:[{begin:/\$\d/},{ +begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") +},{begin:/[$%@][^\s\w{]/,relevance:0}] +},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{ +const r="\\1"===i?i:n.concat(i,a) +;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) +},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ +endsWithParent:!0}),r,{className:"string",contains:o,variants:[{ +begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", +end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ +begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", +relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", +contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ +begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number", +begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", +relevance:0},{ +begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", +keywords:"split return print reverse grep",relevance:0, +contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ +begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{ +begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{ +className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ +begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0 +}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{ +begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub", +end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ +begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", +subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] +}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a, +contains:g}},grmr_php:e=>{ +const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ +scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ +begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null +}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ +illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s) +}),o,e.END_SAME_AS_BEGIN({begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/, +contains:e.QUOTE_STRING_MODE.contains.concat(s)})]},d={scope:"number", +variants:[{begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{ +begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ +begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ +begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" +}],relevance:0 +},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ +keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ +n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) +})),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ +match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ +1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ +match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" +}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ +match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", +3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], +scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", +3:"variable.language"}}]},E={scope:"attr", +match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, +begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] +},w={relevance:0, +match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], +scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(w) +;const N=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, +keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, +endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ +begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, +contains:["self",...N]},...N,{scope:"meta",match:i}] +},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ +scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, +keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, +contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ +begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ +begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,w,f,{ +match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ +scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, +excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" +},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", +begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, +contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ +beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", +illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ +beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ +beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, +contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ +beginKeywords:"use",relevance:0,end:";",contains:[{ +match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} +},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ +begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", +end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 +},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, +skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, +contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", +aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ +const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ +$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, +built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], +literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], +type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] +},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, +end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ +className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, +end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, +relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ +begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, +end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, +contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] +},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ +className:"number",relevance:0,variants:[{ +begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ +begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ +begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` +},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` +}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, +contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ +className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, +end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, +contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ +name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, +illegal:/(<\/|->|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if", +relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{ +1:"keyword",3:"title.function"},contains:[m]},{variants:[{ +match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], +scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ +className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, +grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", +starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ +begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ +const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) +;return{name:"R",keywords:{$pattern:t, +keyword:"function if in break next repeat else for while", +literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", +built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" +},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, +starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), +endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ +scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 +}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] +}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], +variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', +relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ +1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, +match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ +2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, +match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ +match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", +contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ +const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ +"variable.constant":["__FILE__","__LINE__"], +"variable.language":["self","super"], +keyword:["alias","and","attr_accessor","attr_reader","attr_writer","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","include","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield"], +built_in:["proc","lambda"],literal:["true","false","nil"]},s={ +className:"doctag",begin:"@[A-Za-z]+"},o={begin:"#<",end:">" +},l=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^=begin","^=end",{ +contains:[s],relevance:10}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={ +className:"subst",begin:/#\{/,end:/\}/,keywords:r},d={className:"string", +contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ +},{begin:/`/,end:/`/},{begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/, +end:/\]/},{begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{ +begin:/%[qQwWx]?\//,end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/, +end:/-/},{begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ +begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ +begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ +begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ +begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), +contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, +contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", +relevance:0,variants:[{ +begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ +begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" +},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ +begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ +begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ +className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, +keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ +match:[/class\s+/,i]}],scope:{2:"title.class",4:"title.class.inherited"}, +keywords:r},{relevance:0,match:[i,/\.new[ (]/],scope:{1:"title.class"}},{ +relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/,className:"variable.constant"},{ +match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ +begin:e.IDENT_RE+"::"},{className:"symbol", +begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", +begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", +begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ +className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, +relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", +keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], +illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ +begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", +end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) +;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} +},{className:"meta.prompt", +begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", +starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", +aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, +contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, +grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0, +begin:n.concat(/\b/,/(?!let\b)/,e.IDENT_RE,n.lookahead(/\s*\(/)) +},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] +;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r, +keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"], +literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}}, +grmr_scss:e=>{const n=te(e),t=se,a=re,i="@[a-z-]+",r={className:"variable", +begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", +case_insensitive:!0,illegal:"[=/|']", +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ +className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ +className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 +},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", +begin:"\\b("+ae.join("|")+")\\b",relevance:0},{className:"selector-pseudo", +begin:":("+a.join("|")+")"},{className:"selector-pseudo", +begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, +contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", +begin:"\\b("+oe.join("|")+")\\b"},{ +begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" +},{begin:/:/,end:/[;}{]/,relevance:0, +contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] +},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ +begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, +keyword:"and or not only",attribute:ie.join(" ")},contains:[{begin:i, +className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" +},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] +},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", +aliases:["console","shellsession"],contains:[{className:"meta.prompt", +begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, +subLanguage:"bash"}}]}),grmr_sql:e=>{ +const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ +begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} +;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ +$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t +;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) +})(l,{when:e=>e.length<3}),literal:a,type:i, +built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] +},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, +keyword:l.concat(s),literal:a,type:i}},{className:"type", +begin:n.either("double precision","large object","with timezone","without timezone") +},c,{className:"variable",begin:/@[a-z0-9]+/},{className:"string",variants:[{ +begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/,contains:[{ +begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{className:"operator", +begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}}, +grmr_swift:e=>{const n={match:/\s+/,relevance:0},t=e.COMMENT("/\\*","\\*/",{ +contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={match:[/\./,p(...ve,...Oe)], +className:{2:"keyword"}},r={match:m(/\./,p(...xe)),relevance:0 +},s=xe.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ +className:"keyword", +match:p(...xe.filter((e=>"string"!=typeof e)).concat(ke).map(Ne),...Oe)}]},l={ +$pattern:p(/\b\w+/,/#\w+/),keyword:s.concat(Ae),literal:Me},c=[i,r,o],d=[{ +match:m(/\./,p(...Ce)),relevance:0},{className:"built_in", +match:m(/\b/,p(...Ce),/(?=\()/)}],u={match:/->/,relevance:0},b=[u,{ +className:"operator",relevance:0,variants:[{match:De},{match:`\\.(\\.|${Re})+`}] +}],_="([0-9a-fA-F]_*)+",h={className:"number",relevance:0,variants:[{ +match:"\\b(([0-9]_*)+)(\\.(([0-9]_*)+))?([eE][+-]?(([0-9]_*)+))?\\b"},{ +match:`\\b0x(${_})(\\.(${_}))?([pP][+-]?(([0-9]_*)+))?\\b`},{ +match:/\b0o([0-7]_*)+\b/},{match:/\b0b([01]_*)+\b/}]},f=(e="")=>({ +className:"subst",variants:[{match:m(/\\/,e,/[0\\tnr"']/)},{ +match:m(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}]}),E=(e="")=>({className:"subst", +match:m(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/)}),y=(e="")=>({className:"subst", +label:"interpol",begin:m(/\\/,e,/\(/),end:/\)/}),w=(e="")=>({begin:m(e,/"""/), +end:m(/"""/,e),contains:[f(e),E(e),y(e)]}),N=(e="")=>({begin:m(e,/"/), +end:m(/"/,e),contains:[f(e),y(e)]}),v={className:"string", +variants:[w(),w("#"),w("##"),w("###"),N(),N("#"),N("##"),N("###")]},O={ +match:m(/`/,Be,/`/)},k=[O,{className:"variable",match:/\$\d+/},{ +className:"variable",match:`\\$${Le}+`}],x=[{match:/(@|#(un)?)available/, +className:"keyword",starts:{contains:[{begin:/\(/,end:/\)/,keywords:Fe, +contains:[...b,h,v]}]}},{className:"keyword",match:m(/@/,p(...ze))},{ +className:"meta",match:m(/@/,Be)}],M={match:g(/\b[A-Z]/),relevance:0,contains:[{ +className:"type", +match:m(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,Le,"+") +},{className:"type",match:$e,relevance:0},{match:/[?!]+/,relevance:0},{ +match:/\.\.\./,relevance:0},{match:m(/\s+&\s+/,g($e)),relevance:0}]},S={ +begin://,keywords:l,contains:[...a,...c,...x,u,M]};M.contains.push(S) +;const A={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ +match:m(Be,/\s*:/),keywords:"_|0",relevance:0 +},...a,...c,...d,...b,h,v,...k,...x,M]},C={begin://,contains:[...a,M] +},T={begin:/\(/,end:/\)/,keywords:l,contains:[{ +begin:p(g(m(Be,/\s*:/)),g(m(Be,/\s+/,Be,/\s*:/))),end:/:/,relevance:0, +contains:[{className:"keyword",match:/\b_\b/},{className:"params",match:Be}] +},...a,...c,...b,h,v,...x,M,A],endsParent:!0,illegal:/["']/},R={ +match:[/func/,/\s+/,p(O.match,Be,De)],className:{1:"keyword",3:"title.function" +},contains:[C,T,n],illegal:[/\[/,/%/]},D={ +match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, +contains:[C,T,n],illegal:/\[|%/},I={match:[/operator/,/\s+/,De],className:{ +1:"keyword",3:"title"}},L={begin:[/precedencegroup/,/\s+/,$e],className:{ +1:"keyword",3:"title"},contains:[M],keywords:[...Se,...Me],end:/}/} +;for(const e of v.variants){const n=e.contains.find((e=>"interpol"===e.label)) +;n.keywords=l;const t=[...c,...d,...b,h,v,...k];n.contains=[...t,{begin:/\(/, +end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l, +contains:[...a,R,D,{beginKeywords:"struct protocol class extension enum actor", +end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{ +className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c] +},I,L,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0 +},...c,...d,...b,h,v,...k,...x,M,A]}},grmr_typescript:e=>{ +const n=we(e),t=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],a={ +beginKeywords:"namespace",end:/\{/,excludeEnd:!0, +contains:[n.exports.CLASS_REFERENCE]},i={beginKeywords:"interface",end:/\{/, +excludeEnd:!0,keywords:{keyword:"interface extends",built_in:t}, +contains:[n.exports.CLASS_REFERENCE]},r={$pattern:be, +keyword:me.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]), +literal:pe,built_in:ye.concat(t),"variable.language":Ee},s={className:"meta", +begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},o=(e,n,t)=>{ +const a=e.contains.findIndex((e=>e.label===n)) +;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} +;return Object.assign(n.keywords,r), +n.exports.PARAMS_CONTAINS.push(s),n.contains=n.contains.concat([s,a,i]), +o(n,"shebang",e.SHEBANG()),o(n,"use_strict",{className:"meta",relevance:10, +begin:/^\s*['"]use strict['"]/ +}),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ +name:"TypeScript",aliases:["ts","tsx"]}),n},grmr_vbnet:e=>{ +const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ +className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ +begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ +begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] +},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] +}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) +;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, +classNameAliases:{label:"symbol"},keywords:{ +keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", +built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", +type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", +literal:"true false nothing"}, +illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ +className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, +end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, +variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ +},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ +begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ +className:"label",begin:/^\w+:/},o,l,{className:"meta", +begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, +end:/$/,keywords:{ +keyword:"const disable else elseif enable end externalsource if region then"}, +contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) +;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, +keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] +},contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], +className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ +match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ +begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", +3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, +className:"type"},{className:"keyword", +match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ +},{className:"number",relevance:0, +match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ +}]}},grmr_yaml:e=>{ +const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ +className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ +},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", +variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ +end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, +end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", +contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ +begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ +begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", +relevance:10},{className:"string", +begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ +begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, +relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", +begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t +},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", +begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", +relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ +className:"number", +begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" +},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] +;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, +aliases:["yml"],contains:l}}});const je=ne;for(const e of Object.keys(Ue)){ +const n=e.replace("grmr_","").replace("_","-");je.registerLanguage(n,Ue[e])} +return je}() +;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file diff --git a/crates/project/templates/js/highlightjs-gleam.js b/crates/project/templates/js/highlightjs-gleam.js new file mode 100644 index 00000000..7d4423cf --- /dev/null +++ b/crates/project/templates/js/highlightjs-gleam.js @@ -0,0 +1,103 @@ +hljs.registerLanguage("gleam", function (hljs) { + const KEYWORDS = + "as assert case const external fn if import let " + + "use opaque pub todo try tuple type"; + const STRING = { + className: "string", + variants: [{ begin: /"/, end: /"/ }], + contains: [hljs.BACKSLASH_ESCAPE], + relevance: 0, + }; + const NAME = { + className: "variable", + begin: "\\b[a-z][a-z0-9_]*\\b", + relevance: 0, + }; + const DISCARD_NAME = { + className: "comment", + begin: "\\b_[a-z][a-z0-9_]*\\b", + relevance: 0, + }; + const NUMBER = { + className: "number", + variants: [ + { + // binary + begin: "\\b0[bB](?:_?[01]+)+", + }, + { + // octal + begin: "\\b0[oO](?:_?[0-7]+)+", + }, + { + // hex + begin: "\\b0[xX](?:_?[0-9a-fA-F]+)+", + }, + { + // dec, float + begin: "\\b\\d(?:_?\\d+)*(?:\\.(?:\\d(?:_?\\d+)*)*)?", + }, + ], + relevance: 0, + }; + + return { + name: "Gleam", + aliases: ["gleam"], + contains: [ + hljs.C_LINE_COMMENT_MODE, + STRING, + { + // bit string + begin: "<<", + end: ">>", + contains: [ + { + className: "keyword", + beginKeywords: + "binary bytes int float bit_string bits utf8 utf16 utf32 " + + "utf8_codepoint utf16_codepoint utf32_codepoint signed unsigned " + + "big little native unit size", + }, + KEYWORDS, + STRING, + NAME, + DISCARD_NAME, + NUMBER, + ], + relevance: 10, + }, + { + className: "function", + beginKeywords: "fn", + end: "\\(", + excludeEnd: true, + contains: [ + { + className: "title", + begin: "[a-z][a-z0-9_]*\\w*", + relevance: 0, + }, + ], + }, + { + className: "keyword", + beginKeywords: KEYWORDS, + }, + { + // Type names and constructors + className: "title", + begin: "\\b[A-Z][A-Za-z0-9]*\\b", + relevance: 0, + }, + { + className: "operator", + begin: "[+\\-*/%!=<>&|.]+", + relevance: 0, + }, + NAME, + DISCARD_NAME, + NUMBER, + ], + }; +}); diff --git a/crates/project/templates/js/index.js b/crates/project/templates/js/index.js new file mode 100644 index 00000000..2d614ce4 --- /dev/null +++ b/crates/project/templates/js/index.js @@ -0,0 +1,609 @@ +"use strict"; + +window.Aiken = (function () { + /* Global Object */ + const self = {}; + + /* Public Properties */ + + self.hashOffset = undefined; + + /* Public Methods */ + + self.getProperty = function (property) { + let value; + try { + value = localStorage.getItem(`Aiken.${property}`); + } catch (_error) {} + if (-1 < [null, undefined].indexOf(value)) { + return aikenConfig[property].values[0].value; + } + return value; + }; + + self.icons = function () { + return Array.from(arguments).reduce( + (acc, name) => + `${acc} + `, + "" + ); + }; + + self.scrollToHash = function () { + const locationHash = arguments[0] || window.location.hash; + const query = locationHash ? locationHash : "body"; + const hashTop = document.querySelector(query).offsetTop; + window.scrollTo(0, hashTop - self.hashOffset); + return locationHash; + }; + + self.toggleSidebar = function () { + const previousState = bodyClasses.contains("drawer-open") + ? "open" + : "closed"; + + let state; + if (0 < arguments.length) { + state = false === arguments[0] ? "closed" : "open"; + } else { + state = "open" === previousState ? "closed" : "open"; + } + + bodyClasses.remove(`drawer-${previousState}`); + bodyClasses.add(`drawer-${state}`); + + if ("open" === state) { + document.addEventListener("click", closeSidebar, false); + } + }; + + /* Private Properties */ + + const html = document.documentElement; + const body = document.body; + const bodyClasses = body.classList; + const sidebar = document.querySelector(".sidebar"); + const sidebarToggles = document.querySelectorAll(".sidebar-toggle"); + const displayControls = document.createElement("div"); + + displayControls.classList.add("display-controls"); + sidebar.appendChild(displayControls); + + /* Private Methods */ + + const initProperty = function (property) { + const config = aikenConfig[property]; + + displayControls.insertAdjacentHTML( + "beforeend", + config.values.reduce( + (acc, item, index) => { + const tooltip = item.label + ? `alt="${item.label}" title="${item.label}"` + : ""; + let inner; + if (item.icons) { + inner = self.icons(...item.icons); + } else if (item.label) { + inner = item.label; + } else { + inner = ""; + } + return ` + ${acc} + + ${inner} + + `; + }, + ` + ` + ); + + setProperty(null, property, function () { + return self.getProperty(property); + }); + }; + + const setProperty = function (_event, property) { + const previousValue = self.getProperty(property); + + const update = + 2 < arguments.length ? arguments[2] : aikenConfig[property].update; + const value = update(); + + try { + localStorage.setItem("Aiken." + property, value); + } catch (_error) {} + + bodyClasses.remove(`${property}-${previousValue}`); + bodyClasses.add(`${property}-${value}`); + + const isDefault = value === aikenConfig[property].values[0].value; + const toggleClasses = document.querySelector( + `#${property}-toggle` + ).classList; + toggleClasses.remove(`toggle-${isDefault ? 1 : 0}`); + toggleClasses.add(`toggle-${isDefault ? 0 : 1}`); + + try { + aikenConfig[property].callback(value); + } catch (_error) {} + + return value; + }; + + const setHashOffset = function () { + const el = document.createElement("div"); + el.style.cssText = ` + height: var(--hash-offset); + pointer-events: none; + position: absolute; + visibility: hidden; + width: 0; + `; + body.appendChild(el); + self.hashOffset = parseInt( + getComputedStyle(el).getPropertyValue("height") || "0" + ); + body.removeChild(el); + }; + + const closeSidebar = function (event) { + if (!event.target.closest(".sidebar-toggle")) { + document.removeEventListener("click", closeSidebar, false); + self.toggleSidebar(false); + } + }; + + const addEvent = function (el, type, handler) { + if (el.attachEvent) el.attachEvent("on" + type, handler); + else el.addEventListener(type, handler); + }; + + const searchLoaded = function (index, docs) { + const preview_words_after = 10; + const preview_words_before = 5; + const previews = 3; + + const searchInput = document.getElementById("search-input"); + const searchNavButton = document.getElementById("search-nav-button"); + const searchResults = document.getElementById("search-results"); + let currentInput; + let currentSearchIndex = 0; + + function showSearch() { + document.documentElement.classList.add("search-active"); + } + + searchNavButton.addEventListener("click", function (e) { + e.stopPropagation(); + showSearch(); + setTimeout(function () { + searchInput.focus(); + }, 0); + }); + + function hideSearch() { + document.documentElement.classList.remove("search-active"); + } + + function update() { + currentSearchIndex++; + + const input = searchInput.value; + showSearch(); + if (input === currentInput) { + return; + } + currentInput = input; + searchResults.innerHTML = ""; + if (input === "") { + return; + } + + let results = index.query(function (query) { + const tokens = lunr.tokenizer(input); + query.term(tokens, { + boost: 10, + }); + query.term(tokens, { + wildcard: lunr.Query.wildcard.TRAILING, + }); + }); + + if (results.length == 0 && input.length > 2) { + const tokens = lunr.tokenizer(input).filter(function (token, i) { + return token.str.length < 20; + }); + if (tokens.length > 0) { + results = index.query(function (query) { + query.term(tokens, { + editDistance: Math.round(Math.sqrt(input.length / 2 - 1)), + }); + }); + } + } + + if (results.length == 0) { + const noResultsDiv = document.createElement("div"); + noResultsDiv.classList.add("search-no-result"); + noResultsDiv.innerText = "No results found"; + searchResults.appendChild(noResultsDiv); + } else { + const resultsList = document.createElement("ul"); + resultsList.classList.add("search-results-list"); + searchResults.appendChild(resultsList); + + addResults(resultsList, results, 0, 10, 100, currentSearchIndex); + } + + function addResults( + resultsList, + results, + start, + batchSize, + batchMillis, + searchIndex + ) { + if (searchIndex != currentSearchIndex) { + return; + } + for (let i = start; i < start + batchSize; i++) { + if (i == results.length) { + return; + } + addResult(resultsList, results[i]); + } + setTimeout(function () { + addResults( + resultsList, + results, + start + batchSize, + batchSize, + batchMillis, + searchIndex + ); + }, batchMillis); + } + + function addResult(resultsList, result) { + const doc = docs[result.ref]; + const resultsListItem = document.createElement("li"); + resultsListItem.classList.add("search-results-list-item"); + resultsList.appendChild(resultsListItem); + const resultLink = document.createElement("a"); + resultLink.classList.add("search-result"); + resultLink.setAttribute("href", `${window.breadcrumbs}/${doc.url}`); + resultsListItem.appendChild(resultLink); + const resultTitle = document.createElement("div"); + resultTitle.classList.add("search-result-title"); + resultLink.appendChild(resultTitle); + const resultDoc = document.createElement("div"); + resultDoc.classList.add("search-result-doc"); + resultDoc.innerHTML = + ''; + resultTitle.appendChild(resultDoc); + const resultDocTitle = document.createElement("div"); + resultDocTitle.classList.add("search-result-doc-title"); + resultDocTitle.innerHTML = doc.doc; + resultDoc.appendChild(resultDocTitle); + let resultDocOrSection = resultDocTitle; + if (doc.doc != doc.title) { + resultDoc.classList.add("search-result-doc-parent"); + const resultSection = document.createElement("div"); + resultSection.classList.add("search-result-section"); + resultSection.innerHTML = doc.title; + resultTitle.appendChild(resultSection); + resultDocOrSection = resultSection; + } + const metadata = result.matchData.metadata; + const titlePositions = []; + const contentPositions = []; + for (let j in metadata) { + const meta = metadata[j]; + if (meta.title) { + const positions = meta.title.position; + for (let k in positions) { + titlePositions.push(positions[k]); + } + } + if (meta.content) { + const positions = meta.content.position; + for (let k in positions) { + const position = positions[k]; + let previewStart = position[0]; + let previewEnd = position[0] + position[1]; + let ellipsesBefore = true; + let ellipsesAfter = true; + for (let k = 0; k < preview_words_before; k++) { + const nextSpace = doc.content.lastIndexOf( + " ", + previewStart - 2 + ); + const nextDot = doc.content.lastIndexOf(". ", previewStart - 2); + if (nextDot >= 0 && nextDot > nextSpace) { + previewStart = nextDot + 1; + ellipsesBefore = false; + break; + } + if (nextSpace < 0) { + previewStart = 0; + ellipsesBefore = false; + break; + } + previewStart = nextSpace + 1; + } + for (let k = 0; k < preview_words_after; k++) { + const nextSpace = doc.content.indexOf(" ", previewEnd + 1); + const nextDot = doc.content.indexOf(". ", previewEnd + 1); + if (nextDot >= 0 && nextDot < nextSpace) { + previewEnd = nextDot; + ellipsesAfter = false; + break; + } + if (nextSpace < 0) { + previewEnd = doc.content.length; + ellipsesAfter = false; + break; + } + previewEnd = nextSpace; + } + contentPositions.push({ + highlight: position, + previewStart: previewStart, + previewEnd: previewEnd, + ellipsesBefore: ellipsesBefore, + ellipsesAfter: ellipsesAfter, + }); + } + } + } + if (titlePositions.length > 0) { + titlePositions.sort(function (p1, p2) { + return p1[0] - p2[0]; + }); + resultDocOrSection.innerHTML = ""; + addHighlightedText( + resultDocOrSection, + doc.title, + 0, + doc.title.length, + titlePositions + ); + } + if (contentPositions.length > 0) { + contentPositions.sort(function (p1, p2) { + return p1.highlight[0] - p2.highlight[0]; + }); + let contentPosition = contentPositions[0]; + let previewPosition = { + highlight: [contentPosition.highlight], + previewStart: contentPosition.previewStart, + previewEnd: contentPosition.previewEnd, + ellipsesBefore: contentPosition.ellipsesBefore, + ellipsesAfter: contentPosition.ellipsesAfter, + }; + const previewPositions = [previewPosition]; + for (let j = 1; j < contentPositions.length; j++) { + contentPosition = contentPositions[j]; + if (previewPosition.previewEnd < contentPosition.previewStart) { + previewPosition = { + highlight: [contentPosition.highlight], + previewStart: contentPosition.previewStart, + previewEnd: contentPosition.previewEnd, + ellipsesBefore: contentPosition.ellipsesBefore, + ellipsesAfter: contentPosition.ellipsesAfter, + }; + previewPositions.push(previewPosition); + } else { + previewPosition.highlight.push(contentPosition.highlight); + previewPosition.previewEnd = contentPosition.previewEnd; + previewPosition.ellipsesAfter = contentPosition.ellipsesAfter; + } + } + const resultPreviews = document.createElement("div"); + resultPreviews.classList.add("search-result-previews"); + resultLink.appendChild(resultPreviews); + const content = doc.content; + for ( + let j = 0; + j < Math.min(previewPositions.length, previews); + j++ + ) { + const position = previewPositions[j]; + const resultPreview = document.createElement("div"); + resultPreview.classList.add("search-result-preview"); + resultPreviews.appendChild(resultPreview); + if (position.ellipsesBefore) { + resultPreview.appendChild(document.createTextNode("... ")); + } + addHighlightedText( + resultPreview, + content, + position.previewStart, + position.previewEnd, + position.highlight + ); + if (position.ellipsesAfter) { + resultPreview.appendChild(document.createTextNode(" ...")); + } + } + } + const resultRelUrl = document.createElement("span"); + resultRelUrl.classList.add("search-result-rel-url"); + resultRelUrl.innerText = doc.url; + resultTitle.appendChild(resultRelUrl); + } + + function addHighlightedText(parent, text, start, end, positions) { + let index = start; + for (let i in positions) { + const position = positions[i]; + const span = document.createElement("span"); + span.innerHTML = text.substring(index, position[0]); + parent.appendChild(span); + index = position[0] + position[1]; + const highlight = document.createElement("span"); + highlight.classList.add("search-result-highlight"); + highlight.innerHTML = text.substring(position[0], index); + parent.appendChild(highlight); + } + const span = document.createElement("span"); + span.innerHTML = text.substring(index, end); + parent.appendChild(span); + } + } + + addEvent(searchInput, "focus", function () { + setTimeout(update, 0); + }); + + addEvent(searchInput, "keyup", function (e) { + switch (e.keyCode) { + case 27: // When esc key is pressed, hide the results and clear the field + searchInput.value = ""; + break; + case 38: // arrow up + case 40: // arrow down + case 13: // enter + e.preventDefault(); + return; + } + update(); + }); + + addEvent(searchInput, "keydown", function (e) { + let active; + switch (e.keyCode) { + case 38: // arrow up + e.preventDefault(); + active = document.querySelector(".search-result.active"); + if (active) { + active.classList.remove("active"); + if (active.parentElement.previousSibling) { + const previous = + active.parentElement.previousSibling.querySelector( + ".search-result" + ); + previous.classList.add("active"); + } + } + return; + case 40: // arrow down + e.preventDefault(); + active = document.querySelector(".search-result.active"); + if (active) { + if (active.parentElement.nextSibling) { + const next = + active.parentElement.nextSibling.querySelector( + ".search-result" + ); + active.classList.remove("active"); + next.classList.add("active"); + } + } else { + const next = document.querySelector(".search-result"); + if (next) { + next.classList.add("active"); + } + } + return; + case 13: // enter + e.preventDefault(); + active = document.querySelector(".search-result.active"); + if (active) { + active.click(); + } else { + const first = document.querySelector(".search-result"); + if (first) { + first.click(); + } + } + return; + } + }); + + addEvent(document, "click", function (e) { + if (e.target != searchInput) { + hideSearch(); + } + }); + }; + + self.initSearch = function initSeach(docs) { + // enable support for hyphenated search words + lunr.tokenizer.separator = /[\s/]+/; + + const index = lunr(function () { + this.ref("id"); + this.field("title", { boost: 200 }); + this.field("content", { boost: 2 }); + this.field("url"); + this.metadataWhitelist = ["position"]; + + for (let [i, entry] of docs.entries()) { + this.add({ + id: i, + title: entry.title, + content: entry.content, + url: `${window.breadcrumbs}/${entry.url}`, + }); + } + }); + + searchLoaded(index, docs); + }; + + const init = function () { + for (let property in aikenConfig) { + initProperty(property); + const toggle = document.querySelector(`#${property}-toggle`); + toggle.addEventListener("click", function (event) { + setProperty(event, property); + }); + } + + sidebarToggles.forEach(function (sidebarToggle) { + sidebarToggle.addEventListener("click", function (event) { + event.preventDefault(); + self.toggleSidebar(); + }); + }); + + setHashOffset(); + window.addEventListener("load", function (_event) { + self.scrollToHash(); + }); + window.addEventListener("hashchange", function (_event) { + self.scrollToHash(); + }); + + document + .querySelectorAll( + ` + .module-name > a, + .member-name a[href^='#'] + ` + ) + .forEach(function (title) { + title.innerHTML = title.innerHTML.replace( + /([A-Z])|([_/])/g, + "$2$1" + ); + }); + }; + + /* Initialise */ + + init(); + + return self; +})(); diff --git a/crates/project/templates/js/lunr.min.js b/crates/project/templates/js/lunr.min.js new file mode 100644 index 00000000..cdc94cd3 --- /dev/null +++ b/crates/project/templates/js/lunr.min.js @@ -0,0 +1,6 @@ +/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + */ +!function(){var e=function(t){var r=new e.Builder;return r.pipeline.add(e.trimmer,e.stopWordFilter,e.stemmer),r.searchPipeline.add(e.stemmer),t.call(r,r),r.build()};e.version="2.3.9",e.utils={},e.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),e.utils.asString=function(e){return void 0===e||null===e?"":e.toString()},e.utils.clone=function(e){if(null===e||void 0===e)return e;for(var t=Object.create(null),r=Object.keys(e),i=0;i0){var c=e.utils.clone(r)||{};c.position=[a,l],c.index=s.length,s.push(new e.Token(i.slice(a,o),c))}a=o+1}}return s},e.tokenizer.separator=/[\s\-]+/,e.Pipeline=function(){this._stack=[]},e.Pipeline.registeredFunctions=Object.create(null),e.Pipeline.registerFunction=function(t,r){r in this.registeredFunctions&&e.utils.warn("Overwriting existing registered function: "+r),t.label=r,e.Pipeline.registeredFunctions[t.label]=t},e.Pipeline.warnIfFunctionNotRegistered=function(t){var r=t.label&&t.label in this.registeredFunctions;r||e.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",t)},e.Pipeline.load=function(t){var r=new e.Pipeline;return t.forEach(function(t){var i=e.Pipeline.registeredFunctions[t];if(!i)throw new Error("Cannot load unregistered function: "+t);r.add(i)}),r},e.Pipeline.prototype.add=function(){var t=Array.prototype.slice.call(arguments);t.forEach(function(t){e.Pipeline.warnIfFunctionNotRegistered(t),this._stack.push(t)},this)},e.Pipeline.prototype.after=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,r)},e.Pipeline.prototype.before=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var i=this._stack.indexOf(t);if(i==-1)throw new Error("Cannot find existingFn");this._stack.splice(i,0,r)},e.Pipeline.prototype.remove=function(e){var t=this._stack.indexOf(e);t!=-1&&this._stack.splice(t,1)},e.Pipeline.prototype.run=function(e){for(var t=this._stack.length,r=0;r1&&(se&&(r=n),s!=e);)i=r-t,n=t+Math.floor(i/2),s=this.elements[2*n];return s==e?2*n:s>e?2*n:sa?l+=2:o==a&&(t+=r[u+1]*i[l+1],u+=2,l+=2);return t},e.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},e.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),t=1,r=0;t0){var o,a=s.str.charAt(0);a in s.node.edges?o=s.node.edges[a]:(o=new e.TokenSet,s.node.edges[a]=o),1==s.str.length&&(o["final"]=!0),n.push({node:o,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(0!=s.editsRemaining){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new e.TokenSet;s.node.edges["*"]=u}if(0==s.str.length&&(u["final"]=!0),n.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&n.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),1==s.str.length&&(s.node["final"]=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new e.TokenSet;s.node.edges["*"]=l}1==s.str.length&&(l["final"]=!0),n.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var c,h=s.str.charAt(0),d=s.str.charAt(1);d in s.node.edges?c=s.node.edges[d]:(c=new e.TokenSet,s.node.edges[d]=c),1==s.str.length&&(c["final"]=!0),n.push({node:c,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return i},e.TokenSet.fromString=function(t){for(var r=new e.TokenSet,i=r,n=0,s=t.length;n=e;t--){var r=this.uncheckedNodes[t],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r["char"]]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}},e.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},e.Index.prototype.search=function(t){return this.query(function(r){var i=new e.QueryParser(t,r);i.parse()})},e.Index.prototype.query=function(t){for(var r=new e.Query(this.fields),i=Object.create(null),n=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},e.Builder.prototype.k1=function(e){this._k1=e},e.Builder.prototype.add=function(t,r){var i=t[this._ref],n=Object.keys(this._fields);this._documents[i]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return e.QueryLexer.EOS;var t=this.str.charAt(this.pos);return this.pos+=1,t},e.QueryLexer.prototype.width=function(){return this.pos-this.start},e.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},e.QueryLexer.prototype.backup=function(){this.pos-=1},e.QueryLexer.prototype.acceptDigitRun=function(){var t,r;do t=this.next(),r=t.charCodeAt(0);while(r>47&&r<58);t!=e.QueryLexer.EOS&&this.backup()},e.QueryLexer.prototype.more=function(){return this.pos1&&(t.backup(),t.emit(e.QueryLexer.TERM)),t.ignore(),t.more())return e.QueryLexer.lexText},e.QueryLexer.lexEditDistance=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.EDIT_DISTANCE),e.QueryLexer.lexText},e.QueryLexer.lexBoost=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.BOOST),e.QueryLexer.lexText},e.QueryLexer.lexEOS=function(t){t.width()>0&&t.emit(e.QueryLexer.TERM)},e.QueryLexer.termSeparator=e.tokenizer.separator,e.QueryLexer.lexText=function(t){for(;;){var r=t.next();if(r==e.QueryLexer.EOS)return e.QueryLexer.lexEOS;if(92!=r.charCodeAt(0)){if(":"==r)return e.QueryLexer.lexField;if("~"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexEditDistance;if("^"==r)return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexBoost;if("+"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if("-"==r&&1===t.width())return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if(r.match(e.QueryLexer.termSeparator))return e.QueryLexer.lexTerm}else t.escapeCharacter()}},e.QueryParser=function(t,r){this.lexer=new e.QueryLexer(t),this.query=r,this.currentClause={},this.lexemeIdx=0},e.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var t=e.QueryParser.parseClause;t;)t=t(this);return this.query},e.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},e.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},e.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},e.QueryParser.parseClause=function(t){var r=t.peekLexeme();if(void 0!=r)switch(r.type){case e.QueryLexer.PRESENCE:return e.QueryParser.parsePresence;case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(i+=" with value '"+r.str+"'"),new e.QueryParseError(i,r.start,r.end)}},e.QueryParser.parsePresence=function(t){var r=t.consumeLexeme();if(void 0!=r){switch(r.str){case"-":t.currentClause.presence=e.Query.presence.PROHIBITED;break;case"+":t.currentClause.presence=e.Query.presence.REQUIRED;break;default:var i="unrecognised presence operator'"+r.str+"'";throw new e.QueryParseError(i,r.start,r.end)}var n=t.peekLexeme();if(void 0==n){var i="expecting term or field, found nothing";throw new e.QueryParseError(i,r.start,r.end)}switch(n.type){case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expecting term or field, found '"+n.type+"'";throw new e.QueryParseError(i,n.start,n.end)}}},e.QueryParser.parseField=function(t){var r=t.consumeLexeme();if(void 0!=r){if(t.query.allFields.indexOf(r.str)==-1){var i=t.query.allFields.map(function(e){return"'"+e+"'"}).join(", "),n="unrecognised field '"+r.str+"', possible fields: "+i;throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.fields=[r.str];var s=t.peekLexeme();if(void 0==s){var n="expecting term, found nothing";throw new e.QueryParseError(n,r.start,r.end)}switch(s.type){case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var n="expecting term, found '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseTerm=function(t){var r=t.consumeLexeme();if(void 0!=r){t.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(t.currentClause.usePipeline=!1);var i=t.peekLexeme();if(void 0==i)return void t.nextClause();switch(i.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+i.type+"'";throw new e.QueryParseError(n,i.start,i.end)}}},e.QueryParser.parseEditDistance=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="edit distance must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.editDistance=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},e.QueryParser.parseBoost=function(t){var r=t.consumeLexeme();if(void 0!=r){var i=parseInt(r.str,10);if(isNaN(i)){var n="boost must be numeric";throw new e.QueryParseError(n,r.start,r.end)}t.currentClause.boost=i;var s=t.peekLexeme();if(void 0==s)return void t.nextClause();switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var n="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(n,s.start,s.end)}}},function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.lunr=t()}(this,function(){return e})}(); diff --git a/crates/project/templates/module.html b/crates/project/templates/module.html new file mode 100644 index 00000000..7f127e79 --- /dev/null +++ b/crates/project/templates/module.html @@ -0,0 +1,159 @@ +{% extends "_layout.html" %} + +{% block sidebar_content %} +{% if !types.is_empty() %} +

Types

+ +{% endif %} + +{% if !constants.is_empty() %} +

Constants

+ +{% endif %} + +{% if !functions.is_empty() %} +

Functions

+ +{% endif %} +{% endblock %} + +{% block content %} +

+ {{ module_name }} +

+{{ documentation|safe }} + +{% if !types.is_empty() %} +
+

+ Types +

+ + {% for type_info in types %} +
+
+

+ + {{ type_info.name }} + +

+ {% if !type_info.source_url.is_empty() %} + + </> + + {% endif %} +
+
+
{{ type_info.documentation|safe }}
+
{{ type_info.definition }}
+ {% if !type_info.constructors.is_empty() %} +

+ Constructors +

+
    + {% for constructor in type_info.constructors %} +
  • +
    + +
    {{ constructor.definition }}
    +
    + +
    + {{ constructor.documentation|safe }} + + {% if !constructor.arguments.is_empty() %} +

    + Arguments +

    + +
      + {% for argument in constructor.arguments %} +
    • +
      +

      + {{ argument.name }} +

      +
      + {{ argument.doc|safe }} +
      +
      +
    • + {% endfor %} +
    + {% endif %} +
    +
  • + {% endfor %} +
+ {% endif %} +
+
+ {% endfor %} +
+{% endif %} + +{% if !constants.is_empty() %} +
+

+ Constants +

+ + {% for constant in constants %} +
+
+

+ + {{ constant.name }} + +

+ {% if !constant.source_url.is_empty() %} + + </> + + {% endif %} +
+
{{ constant.definition }}
+
{{ constant.documentation|safe }}
+
+ {% endfor %} +
+{% endif %} + +{% if !functions.is_empty() %} +
+

+ Functions +

+ {% for function in functions %} +
+
+

+ + {{ function.name }} + +

+ {% if !function.source_url.is_empty() %} + + </> + + {% endif %} +
+
{{ function.signature }}
+
{{ function.documentation|safe }}
+
+ {% endfor %} +
+{% endif %} +{% endblock %} diff --git a/crates/project/templates/page.html b/crates/project/templates/page.html new file mode 100644 index 00000000..fea54bd2 --- /dev/null +++ b/crates/project/templates/page.html @@ -0,0 +1,9 @@ +{% extends "_layout.html" %} + +{% block title %} +{{ title }} - {{ project_name }} +{% endblock %} + +{% block content %} +{{ content|safe }} +{% endblock %} From 6da53fd87526b1037a911a136d4da9ae8d2650b3 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 18:33:36 +0100 Subject: [PATCH 03/18] Add a 'docs' method to projects, using the newly introduced docs::generate_all --- crates/project/src/lib.rs | 43 ++++++++++++++++++++++++--------- crates/project/src/telemetry.rs | 5 ++++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index cd5e5077..09d3fe5e 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -1,4 +1,5 @@ pub mod config; +pub mod docs; pub mod error; pub mod format; pub mod module; @@ -97,6 +98,27 @@ where self.compile(options) } + pub fn docs(&mut self, destination: Option) -> Result<(), Error> { + self.event_listener + .handle_event(Event::GeneratingDocumentation { + root: self.root.clone(), + name: self.config.name.clone(), + version: self.config.version.clone(), + }); + + let destination = destination.unwrap_or(self.root.join("doc")); + let checked_modules = self.parse()?; + let doc_files = + docs::generate_all(&self.root, &self.config, checked_modules.values().collect()); + for file in doc_files { + let path = destination.join(file.path); + fs::create_dir_all(&path.parent().unwrap())?; + fs::write(&path, file.content)?; + } + + Ok(()) + } + pub fn check( &mut self, skip_tests: bool, @@ -117,6 +139,15 @@ where self.compile(options) } + pub fn parse(&mut self) -> Result { + self.event_listener.handle_event(Event::ParsingProjectFiles); + self.read_source_files()?; + let parsed_modules = self.parse_sources()?; + let processing_sequence = parsed_modules.sequence()?; + self.event_listener.handle_event(Event::TypeChecking); + self.type_check(parsed_modules, processing_sequence) + } + pub fn compile(&mut self, options: Options) -> Result<(), Error> { self.event_listener .handle_event(Event::StartingCompilation { @@ -125,17 +156,7 @@ where version: self.config.version.clone(), }); - self.event_listener.handle_event(Event::ParsingProjectFiles); - - self.read_source_files()?; - - let parsed_modules = self.parse_sources()?; - - let processing_sequence = parsed_modules.sequence()?; - - self.event_listener.handle_event(Event::TypeChecking); - - let mut checked_modules = self.type_check(parsed_modules, processing_sequence)?; + let mut checked_modules = self.parse()?; let validators = self.validate_validators(&mut checked_modules)?; diff --git a/crates/project/src/telemetry.rs b/crates/project/src/telemetry.rs index fd9fd41f..a4f7c65d 100644 --- a/crates/project/src/telemetry.rs +++ b/crates/project/src/telemetry.rs @@ -11,6 +11,11 @@ pub enum Event { version: String, root: PathBuf, }, + GeneratingDocumentation { + name: String, + version: String, + root: PathBuf, + }, ParsingProjectFiles, TypeChecking, GeneratingUPLC { From 1f3f769b53e0a5e273138dc3a47c61125b28fed6 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 18:34:05 +0100 Subject: [PATCH 04/18] Add command 'docs' for generating project documentation. --- crates/cli/src/cmd/docs.rs | 22 ++++++++++++++++++++++ crates/cli/src/cmd/mod.rs | 1 + crates/cli/src/lib.rs | 13 +++++++++++++ crates/cli/src/main.rs | 4 +++- 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 crates/cli/src/cmd/docs.rs diff --git a/crates/cli/src/cmd/docs.rs b/crates/cli/src/cmd/docs.rs new file mode 100644 index 00000000..da08c440 --- /dev/null +++ b/crates/cli/src/cmd/docs.rs @@ -0,0 +1,22 @@ +use std::path::PathBuf; + +#[derive(clap::Args)] +/// Build an Aiken project +pub struct Args { + /// Path to project + #[clap(short, long)] + directory: Option, + + /// Output directory for the documentation + #[clap(short = 'o', long)] + destination: Option, +} + +pub fn exec( + Args { + directory, + destination, + }: Args, +) -> miette::Result<()> { + crate::with_project(directory, |p| p.docs(destination.clone())) +} diff --git a/crates/cli/src/cmd/mod.rs b/crates/cli/src/cmd/mod.rs index 75b5fe74..b3b837cb 100644 --- a/crates/cli/src/cmd/mod.rs +++ b/crates/cli/src/cmd/mod.rs @@ -1,5 +1,6 @@ pub mod build; pub mod check; +pub mod docs; pub mod error; pub mod fmt; pub mod lsp; diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index dc195f14..20bf671c 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -68,6 +68,19 @@ impl telemetry::EventListener for Terminal { root.to_str().unwrap_or("").bright_blue() ); } + telemetry::Event::GeneratingDocumentation { + name, + version, + root, + } => { + println!( + "{} {} {} ({})", + "Generating documentation".bold().purple(), + name.bold(), + version, + root.to_str().unwrap_or("").bright_blue() + ); + } telemetry::Event::ParsingProjectFiles => { println!("{}", "...Parsing project files".bold().purple()); } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index d624ce6d..9413416f 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,4 +1,4 @@ -use aiken::cmd::{build, check, fmt, lsp, new, tx, uplc}; +use aiken::cmd::{build, check, docs, fmt, lsp, new, tx, uplc}; use clap::Parser; /// Aiken: a smart-contract language and toolchain for Cardano @@ -11,6 +11,7 @@ pub enum Cmd { Fmt(fmt::Args), Build(build::Args), Check(check::Args), + Docs(docs::Args), #[clap(hide = true)] Lsp(lsp::Args), @@ -34,6 +35,7 @@ fn main() -> miette::Result<()> { Cmd::New(args) => new::exec(args), Cmd::Fmt(args) => fmt::exec(args), Cmd::Build(args) => build::exec(args), + Cmd::Docs(args) => docs::exec(args), Cmd::Check(args) => check::exec(args), Cmd::Lsp(args) => lsp::exec(args), Cmd::Tx(sub_cmd) => tx::exec(sub_cmd), From d2c6d2754587f15129fdeef97cd627a7c0731a4c Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 19:37:15 +0100 Subject: [PATCH 05/18] Support data-types in documentation. --- crates/lang/src/ast.rs | 6 +- crates/lang/src/format.rs | 88 +++++++++++--- crates/lang/src/parser.rs | 4 +- crates/lang/src/tests/parser.rs | 12 +- crates/lang/src/tipo/infer.rs | 4 +- crates/project/src/docs.rs | 167 ++++++++++++++++++++++----- crates/project/templates/module.html | 4 +- 7 files changed, 228 insertions(+), 57 deletions(-) diff --git a/crates/lang/src/ast.rs b/crates/lang/src/ast.rs index ac9182ad..665e6588 100644 --- a/crates/lang/src/ast.rs +++ b/crates/lang/src/ast.rs @@ -130,14 +130,14 @@ impl TypedDataType { tipo: tipo.clone(), doc: None, }], - documentation: None, + doc: None, sugar: false, }, RecordConstructor { location: Span::empty(), name: "None".to_string(), arguments: vec![], - documentation: None, + doc: None, sugar: false, }, ], @@ -352,7 +352,7 @@ pub struct RecordConstructor { pub location: Span, pub name: String, pub arguments: Vec>, - pub documentation: Option, + pub doc: Option, pub sugar: bool, } diff --git a/crates/lang/src/format.rs b/crates/lang/src/format.rs index 5b6dfe72..aea70768 100644 --- a/crates/lang/src/format.rs +++ b/crates/lang/src/format.rs @@ -1172,37 +1172,93 @@ impl<'comments> Formatter<'comments> { .append("}") } - pub fn docs_opaque_custom_type<'a>( + pub fn docs_data_type<'a, A>( + &mut self, + name: &'a str, + args: &'a [String], + constructors: &'a [RecordConstructor], + location: &'a Span, + ) -> Document<'a> { + self.pop_empty_lines(location.start); + + let mut is_sugar = false; + + (if args.is_empty() { + name.to_doc() + } else { + name.to_doc() + .append(wrap_generics(args.iter().map(|e| e.to_doc()))) + .group() + }) + .append(" {") + .append(if constructors.len() == 1 && constructors[0].sugar { + is_sugar = true; + + self.record_constructor(&constructors[0]) + } else { + concat(constructors.iter().map(|c| { + if self.pop_empty_lines(c.location.start) { + lines(2) + } else { + line() + } + .append(self.record_constructor(c)) + .nest(INDENT) + .group() + })) + }) + .append(if is_sugar { nil() } else { line() }) + .append("}") + } + + pub fn docs_opaque_data_type<'a>( &mut self, - public: bool, name: &'a str, args: &'a [String], location: &'a Span, ) -> Document<'a> { self.pop_empty_lines(location.start); - pub_(public) - .to_doc() - .append("opaque type ") - .append(if args.is_empty() { - name.to_doc() - } else { - name.to_doc() - .append(wrap_args(args.iter().map(|e| (e.to_doc(), false)))) - }) + if args.is_empty() { + name.to_doc() + } else { + name.to_doc() + .append(wrap_args(args.iter().map(|e| (e.to_doc(), false)))) + } + } + + pub fn docs_type_alias<'a>( + &mut self, + name: &'a str, + args: &'a [String], + typ: &'a Annotation, + ) -> Document<'a> { + let head = name.to_doc(); + + let head = if args.is_empty() { + head + } else { + head.append(wrap_generics(args.iter().map(|e| e.to_doc())).group()) + }; + + head.append(" = ") + .append(self.annotation(typ).group().nest(INDENT)) + } + + pub fn docs_record_constructor<'a, A>( + &mut self, + constructor: &'a RecordConstructor, + ) -> Document<'a> { + constructor.name.to_doc() } pub fn docs_fn_signature<'a>( &mut self, - public: bool, name: &'a str, args: &'a [TypedArg], return_type: Arc, ) -> Document<'a> { let mut printer = tipo::pretty::Printer::new(); - - pub_(public) - .append("fn ") - .append(name) + name.to_doc() .append(self.docs_fn_args(args, &mut printer)) .append(" -> ".to_doc()) .append(printer.print(&return_type)) diff --git a/crates/lang/src/parser.rs b/crates/lang/src/parser.rs index 025e08ea..cc11d850 100644 --- a/crates/lang/src/parser.rs +++ b/crates/lang/src/parser.rs @@ -157,7 +157,7 @@ pub fn data_parser() -> impl Parser impl Parser) -> Vec { let timestamp = new_timestamp(); + let modules_links = generate_modules_links(&modules); let mut output_files: Vec = vec![]; let mut search_indexes: Vec = vec![]; for module in &modules { - let (indexes, file) = generate_module(config, module, ×tamp); + let (indexes, file) = generate_module(config, module, &modules_links, ×tamp); search_indexes.extend(indexes); output_files.push(file); } output_files.extend(generate_static_assets(search_indexes)); - output_files.push(generate_readme(root, config, modules, ×tamp)); + output_files.push(generate_readme(root, config, &modules_links, ×tamp)); output_files } fn generate_module( config: &Config, module: &CheckedModule, + modules: &Vec, timestamp: &Duration, ) -> (Vec, DocFile) { let mut search_indexes = vec![]; @@ -116,11 +120,44 @@ fn generate_module( }); // Types + let types: Vec = module + .ast + .definitions + .iter() + .flat_map(DocType::from_definition) + .sorted() + .collect(); + types.iter().for_each(|type_info| { + let constructors = type_info + .constructors + .iter() + .map(|constructor| { + let arguments = constructor + .arguments + .iter() + .map(|argument| format!("{}\n{}", argument.label, argument.documentation)) + .join("\n"); + format!( + "{}\n{}\n{}", + constructor.definition, constructor.documentation, arguments + ) + }) + .join("\n"); + search_indexes.push(SearchIndex { + doc: module.name.to_string(), + title: type_info.name.to_string(), + content: format!( + "{}\n{}\n{}", + type_info.definition, type_info.documentation, constructors, + ), + url: format!("{}.html#{}", module.name, type_info.name), + }) + }); // Constants + // TODO - // Template - + // Module search_indexes.push(SearchIndex { doc: module.name.to_string(), title: module.name.to_string(), @@ -133,13 +170,13 @@ fn generate_module( breadcrumbs: to_breadcrumbs(&module.name), links: &vec![], documentation: render_markdown(&module.ast.docs.iter().join("\n")), - modules: &vec![], + modules, project_name: &config.name, page_title: &format!("{} - {}", module.name, config.name), module_name: module.name.clone(), project_version: &config.version.to_string(), functions, - types: vec![], + types, constants: vec![], timestamp: timestamp.as_secs().to_string(), }; @@ -208,28 +245,18 @@ fn generate_static_assets(search_indexes: Vec) -> Vec { fn generate_readme( root: &PathBuf, config: &Config, - modules: Vec<&CheckedModule>, + modules: &Vec, timestamp: &Duration, ) -> DocFile { let path = PathBuf::from("index.html"); let content = std::fs::read_to_string(root.join("README.md")).unwrap_or_default(); - let mut modules_links = vec![]; - for module in modules { - let module_path = [&module.name.clone(), ".html"].concat(); - modules_links.push(DocLink { - path: module_path, - name: module.name.to_string().clone(), - }); - } - modules_links.sort(); - let template = PageTemplate { aiken_version: VERSION, breadcrumbs: ".", links: &vec![], - modules: &modules_links, + modules, project_name: &config.name, page_title: &config.name, project_version: &config.version.to_string(), @@ -243,6 +270,19 @@ fn generate_readme( } } +fn generate_modules_links(modules: &Vec<&CheckedModule>) -> Vec { + let mut modules_links = vec![]; + for module in modules { + let module_path = [&module.name.clone(), ".html"].concat(); + modules_links.push(DocLink { + path: module_path, + name: module.name.to_string().clone(), + }); + } + modules_links.sort(); + modules_links +} + #[derive(PartialEq, Eq, PartialOrd, Ord)] struct DocFunction { name: String, @@ -263,13 +303,12 @@ impl DocFunction { .unwrap_or_default(), signature: format::Formatter::new() .docs_fn_signature( - true, &func_def.name, &func_def.arguments, func_def.return_type.clone(), ) .to_pretty_string(MAX_COLUMNS), - source_url: "TODO: source_url".to_string(), + source_url: "#todo".to_string(), }), _ => None, } @@ -281,7 +320,6 @@ struct DocConstant { name: String, definition: String, documentation: String, - text_documentation: String, source_url: String, } @@ -291,22 +329,99 @@ struct DocType { definition: String, documentation: String, constructors: Vec, - text_documentation: String, source_url: String, } +impl DocType { + fn from_definition(def: &TypedDefinition) -> Option { + match def { + Definition::TypeAlias(info) if info.public => Some(DocType { + name: info.alias.clone(), + definition: format::Formatter::new() + .docs_type_alias(&info.alias, &info.parameters, &info.annotation) + .to_pretty_string(MAX_COLUMNS), + documentation: info.doc.as_deref().map(render_markdown).unwrap_or_default(), + constructors: vec![], + source_url: "#todo".to_string(), + }), + + Definition::DataType(info) if info.public && !info.opaque => Some(DocType { + name: info.name.clone(), + definition: format::Formatter::new() + .docs_data_type( + &info.name, + &info.parameters, + &info.constructors, + &info.location, + ) + .to_pretty_string(MAX_COLUMNS), + documentation: info.doc.as_deref().map(render_markdown).unwrap_or_default(), + constructors: info + .constructors + .iter() + .map(DocTypeConstructor::from_record_constructor) + .collect(), + source_url: "#todo".to_string(), + }), + + Definition::DataType(info) if info.public && info.opaque => Some(DocType { + name: info.name.clone(), + definition: format::Formatter::new() + .docs_opaque_data_type(&info.name, &info.parameters, &info.location) + .to_pretty_string(MAX_COLUMNS), + documentation: info.doc.as_deref().map(render_markdown).unwrap_or_default(), + constructors: vec![], + source_url: "#todo".to_string(), + }), + + _ => None, + } + } +} + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] struct DocTypeConstructor { definition: String, documentation: String, - text_documentation: String, arguments: Vec, } +impl DocTypeConstructor { + fn from_record_constructor(constructor: &RecordConstructor>) -> Self { + DocTypeConstructor { + definition: format::Formatter::new() + .docs_record_constructor(constructor) + .to_pretty_string(MAX_COLUMNS), + documentation: constructor + .doc + .as_deref() + .map(render_markdown) + .unwrap_or_default(), + arguments: constructor + .arguments + .iter() + .filter_map(DocTypeConstructorArg::from_record_constructor_arg) + .collect(), + } + } +} + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] struct DocTypeConstructorArg { - name: String, - doc: String, + label: String, + documentation: String, +} + +impl DocTypeConstructorArg { + fn from_record_constructor_arg(arg: &RecordConstructorArg>) -> Option { + match &arg.label { + None => None, + Some(label) => Some(DocTypeConstructorArg { + label: label.clone(), + documentation: arg.doc.as_deref().map(render_markdown).unwrap_or_default(), + }), + } + } } // ------ Extra Helpers diff --git a/crates/project/templates/module.html b/crates/project/templates/module.html index 7f127e79..ad5bf69f 100644 --- a/crates/project/templates/module.html +++ b/crates/project/templates/module.html @@ -83,10 +83,10 @@
  • - {{ argument.name }} + {{ argument.label }}

    - {{ argument.doc|safe }} + {{ argument.documentation|safe }}
  • From b323c95241f2b5acacef1b8adc5b8109b3e4e261 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 19:46:16 +0100 Subject: [PATCH 06/18] Fix type-parameter pretty printing (use chevrons) --- crates/lang/src/format.rs | 2 +- crates/lang/src/tipo/pretty.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/lang/src/format.rs b/crates/lang/src/format.rs index aea70768..7b7f6732 100644 --- a/crates/lang/src/format.rs +++ b/crates/lang/src/format.rs @@ -1222,7 +1222,7 @@ impl<'comments> Formatter<'comments> { name.to_doc() } else { name.to_doc() - .append(wrap_args(args.iter().map(|e| (e.to_doc(), false)))) + .append(wrap_generics(args.iter().map(|e| e.to_doc())).group()) } } diff --git a/crates/lang/src/tipo/pretty.rs b/crates/lang/src/tipo/pretty.rs index 586838b8..c5c692ad 100644 --- a/crates/lang/src/tipo/pretty.rs +++ b/crates/lang/src/tipo/pretty.rs @@ -61,9 +61,9 @@ impl Printer { if args.is_empty() { doc } else { - doc.append("(") + doc.append("<") .append(self.args_to_aiken_doc(args)) - .append(")") + .append(">") } } @@ -298,7 +298,7 @@ mod test { }), ], }, - "Pair(Int, Bool)", + "Pair", ); assert_string!( Type::Fn { From 536c9457b3d7ac83531837aa919dbb74022c2aff Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 22:33:26 +0100 Subject: [PATCH 07/18] Refactor project source parsing There was already a 'parse_sources' function, and 'parse' was actually more about typechecking than parsing. --- crates/cli/src/lib.rs | 9 ++++++++- crates/project/src/lib.rs | 33 +++++++++++++++------------------ crates/project/src/telemetry.rs | 5 ++++- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 20bf671c..28cb9f01 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -68,7 +68,7 @@ impl telemetry::EventListener for Terminal { root.to_str().unwrap_or("").bright_blue() ); } - telemetry::Event::GeneratingDocumentation { + telemetry::Event::BuildingDocumentation { name, version, root, @@ -94,6 +94,13 @@ impl telemetry::EventListener for Terminal { output_path.to_str().unwrap_or("").bright_blue() ); } + telemetry::Event::GeneratingDocFiles { output_path } => { + println!( + "{} in {}", + "...Generating documentation files".bold().purple(), + output_path.to_str().unwrap_or("").bright_blue() + ); + } telemetry::Event::EvaluatingFunction { results } => { println!("{}\n", "...Evaluating function".bold().purple()); diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 09d3fe5e..038191ce 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -100,14 +100,19 @@ where pub fn docs(&mut self, destination: Option) -> Result<(), Error> { self.event_listener - .handle_event(Event::GeneratingDocumentation { + .handle_event(Event::BuildingDocumentation { root: self.root.clone(), name: self.config.name.clone(), version: self.config.version.clone(), }); + self.read_source_files()?; let destination = destination.unwrap_or(self.root.join("doc")); - let checked_modules = self.parse()?; + let parsed_modules = self.parse_sources()?; + let checked_modules = self.type_check(parsed_modules)?; + self.event_listener.handle_event(Event::GeneratingDocFiles { + output_path: destination.clone(), + }); let doc_files = docs::generate_all(&self.root, &self.config, checked_modules.values().collect()); for file in doc_files { @@ -139,15 +144,6 @@ where self.compile(options) } - pub fn parse(&mut self) -> Result { - self.event_listener.handle_event(Event::ParsingProjectFiles); - self.read_source_files()?; - let parsed_modules = self.parse_sources()?; - let processing_sequence = parsed_modules.sequence()?; - self.event_listener.handle_event(Event::TypeChecking); - self.type_check(parsed_modules, processing_sequence) - } - pub fn compile(&mut self, options: Options) -> Result<(), Error> { self.event_listener .handle_event(Event::StartingCompilation { @@ -156,8 +152,9 @@ where version: self.config.version.clone(), }); - let mut checked_modules = self.parse()?; - + self.read_source_files()?; + let parsed_modules = self.parse_sources()?; + let mut checked_modules = self.type_check(parsed_modules)?; let validators = self.validate_validators(&mut checked_modules)?; match options.code_gen_mode { @@ -219,6 +216,8 @@ where } fn parse_sources(&mut self) -> Result { + self.event_listener.handle_event(Event::ParsingProjectFiles); + let mut errors = Vec::new(); let mut parsed_modules = HashMap::with_capacity(self.sources.len()); @@ -276,11 +275,9 @@ where } } - fn type_check( - &mut self, - mut parsed_modules: ParsedModules, - processing_sequence: Vec, - ) -> Result { + fn type_check(&mut self, mut parsed_modules: ParsedModules) -> Result { + self.event_listener.handle_event(Event::TypeChecking); + let processing_sequence = parsed_modules.sequence()?; let mut modules = HashMap::with_capacity(parsed_modules.len() + 1); for name in processing_sequence { diff --git a/crates/project/src/telemetry.rs b/crates/project/src/telemetry.rs index a4f7c65d..a09bbf63 100644 --- a/crates/project/src/telemetry.rs +++ b/crates/project/src/telemetry.rs @@ -11,13 +11,16 @@ pub enum Event { version: String, root: PathBuf, }, - GeneratingDocumentation { + BuildingDocumentation { name: String, version: String, root: PathBuf, }, ParsingProjectFiles, TypeChecking, + GeneratingDocFiles { + output_path: PathBuf, + }, GeneratingUPLC { output_path: PathBuf, }, From 873bd85d8ba2d27f6c3b7849d5032369e4a5b0c2 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 23:07:08 +0100 Subject: [PATCH 08/18] Implement modules' extra, to get function & module comments in docs. --- crates/lang/src/ast.rs | 12 +++++++ crates/lang/src/parser.rs | 4 --- crates/lang/src/parser/extra.rs | 20 ++++++++++++ crates/project/src/lib.rs | 11 +++++-- crates/project/src/module.rs | 58 +++++++++++++++++++++++++++++++-- 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/crates/lang/src/ast.rs b/crates/lang/src/ast.rs index 665e6588..880dde85 100644 --- a/crates/lang/src/ast.rs +++ b/crates/lang/src/ast.rs @@ -356,6 +356,12 @@ pub struct RecordConstructor { pub sugar: bool, } +impl
    RecordConstructor { + pub fn put_doc(&mut self, new_doc: String) { + self.doc = Some(new_doc); + } +} + #[derive(Debug, Clone, PartialEq)] pub struct RecordConstructorArg { pub label: Option, @@ -366,6 +372,12 @@ pub struct RecordConstructorArg { pub doc: Option, } +impl RecordConstructorArg { + pub fn put_doc(&mut self, new_doc: String) { + self.doc = Some(new_doc); + } +} + pub type TypedArg = Arg>; pub type UntypedArg = Arg<()>; diff --git a/crates/lang/src/parser.rs b/crates/lang/src/parser.rs index cc11d850..0a4253ba 100644 --- a/crates/lang/src/parser.rs +++ b/crates/lang/src/parser.rs @@ -33,22 +33,18 @@ pub fn module( let tokens = tokens.into_iter().filter(|(token, span)| match token { Token::ModuleComment => { extra.module_comments.push(*span); - false } Token::DocComment => { extra.doc_comments.push(*span); - false } Token::Comment => { extra.comments.push(*span); - false } Token::EmptyLine => { extra.empty_lines.push(span.start); - false } Token::NewLine => false, diff --git a/crates/lang/src/parser/extra.rs b/crates/lang/src/parser/extra.rs index 7f7c0b2d..fff7f63f 100644 --- a/crates/lang/src/parser/extra.rs +++ b/crates/lang/src/parser/extra.rs @@ -1,4 +1,5 @@ use crate::ast::Span; +use std::iter::Peekable; #[derive(Debug, PartialEq, Eq, Default, Clone)] pub struct ModuleExtra { @@ -33,3 +34,22 @@ impl<'a> From<(&Span, &'a str)> for Comment<'a> { } } } + +pub fn comments_before<'a>( + comment_spans: &mut Peekable>, + byte: usize, + src: &'a str, +) -> Vec<&'a str> { + let mut comments = vec![]; + while let Some(Span { start, .. }) = comment_spans.peek() { + if start <= &byte { + let comment = comment_spans + .next() + .expect("Comment before accessing next span"); + comments.push(Comment::from((comment, src)).content) + } else { + break; + } + } + comments +} diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 038191ce..159fe320 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -108,7 +108,10 @@ where self.read_source_files()?; let destination = destination.unwrap_or(self.root.join("doc")); - let parsed_modules = self.parse_sources()?; + let mut parsed_modules = self.parse_sources()?; + for (_, module) in parsed_modules.iter_mut() { + module.attach_doc_and_module_comments(); + } let checked_modules = self.type_check(parsed_modules)?; self.event_listener.handle_event(Event::GeneratingDocFiles { output_path: destination.clone(), @@ -229,7 +232,7 @@ where } in self.sources.drain(0..) { match aiken_lang::parser::module(&code, kind) { - Ok((mut ast, _)) => { + Ok((mut ast, extra)) => { // Store the name ast.name = name.clone(); @@ -239,6 +242,7 @@ where code, name, path, + extra, package: self.config.name.clone(), }; @@ -286,6 +290,7 @@ where path, code, kind, + extra, // TODO: come back and figure out where to use this package: _package, ast, @@ -324,7 +329,7 @@ where name.clone(), CheckedModule { kind, - // extra, + extra, name, code, ast, diff --git a/crates/project/src/module.rs b/crates/project/src/module.rs index 4a50ddf1..01bffdda 100644 --- a/crates/project/src/module.rs +++ b/crates/project/src/module.rs @@ -4,7 +4,10 @@ use std::{ path::PathBuf, }; -use aiken_lang::ast::{Definition, ModuleKind, TypedModule, UntypedModule}; +use aiken_lang::{ + ast::{DataType, Definition, ModuleKind, TypedModule, UntypedModule}, + parser::extra::{comments_before, Comment, ModuleExtra}, +}; use petgraph::{algo, graph::NodeIndex, Direction, Graph}; use crate::error::Error; @@ -17,7 +20,7 @@ pub struct ParsedModule { pub kind: ModuleKind, pub package: String, pub ast: UntypedModule, - // extra: ModuleExtra, + pub extra: ModuleExtra, } impl ParsedModule { @@ -33,6 +36,55 @@ impl ParsedModule { (name, deps) } + + pub fn attach_doc_and_module_comments(&mut self) { + // Module Comments + self.ast.docs = self + .extra + .module_comments + .iter() + .map(|span| { + Comment::from((span, self.code.as_str())) + .content + .to_string() + }) + .collect(); + + // Order definitions to avoid dissociating doc comments from them + let mut definitions: Vec<_> = self.ast.definitions.iter_mut().collect(); + definitions.sort_by(|a, b| a.location().start.cmp(&b.location().start)); + + // Doc Comments + let mut doc_comments = self.extra.doc_comments.iter().peekable(); + for def in &mut definitions { + let docs: Vec<&str> = + comments_before(&mut doc_comments, def.location().start, &self.code); + if !docs.is_empty() { + let doc = docs.join("\n"); + def.put_doc(doc); + } + + if let Definition::DataType(DataType { constructors, .. }) = def { + for constructor in constructors { + let docs: Vec<&str> = + comments_before(&mut doc_comments, constructor.location.start, &self.code); + if !docs.is_empty() { + let doc = docs.join("\n"); + constructor.put_doc(doc); + } + + for argument in constructor.arguments.iter_mut() { + let docs: Vec<&str> = + comments_before(&mut doc_comments, argument.location.start, &self.code); + if !docs.is_empty() { + let doc = docs.join("\n"); + argument.put_doc(doc); + } + } + } + } + } + } } pub struct ParsedModules(HashMap); @@ -168,7 +220,7 @@ pub struct CheckedModule { pub input_path: PathBuf, pub kind: ModuleKind, pub ast: TypedModule, - // pub extra: ModuleExtra, + pub extra: ModuleExtra, } impl CheckedModule { From ac0d180c5c05200effad2d4ad9b6cf74d91746eb Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 23:22:47 +0100 Subject: [PATCH 09/18] Apply suggestions from clippy. --- crates/project/src/docs.rs | 17 +++++++---------- crates/project/src/lib.rs | 4 ++-- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/crates/project/src/docs.rs b/crates/project/src/docs.rs index f7ed3a1a..7e960a38 100644 --- a/crates/project/src/docs.rs +++ b/crates/project/src/docs.rs @@ -10,7 +10,7 @@ use pulldown_cmark as markdown; use serde::Serialize; use serde_json as json; use std::{ - path::PathBuf, + path::{Path, PathBuf}, sync::Arc, time::{Duration, SystemTime}, }; @@ -75,7 +75,7 @@ struct SearchIndex { /// The documentation is built using template files located at the root of this crate. /// With the documentation, we also build a client-side search index to ease navigation /// across multiple modules. -pub fn generate_all(root: &PathBuf, config: &Config, modules: Vec<&CheckedModule>) -> Vec { +pub fn generate_all(root: &Path, config: &Config, modules: Vec<&CheckedModule>) -> Vec { let timestamp = new_timestamp(); let modules_links = generate_modules_links(&modules); @@ -243,7 +243,7 @@ fn generate_static_assets(search_indexes: Vec) -> Vec { } fn generate_readme( - root: &PathBuf, + root: &Path, config: &Config, modules: &Vec, timestamp: &Duration, @@ -414,13 +414,10 @@ struct DocTypeConstructorArg { impl DocTypeConstructorArg { fn from_record_constructor_arg(arg: &RecordConstructorArg>) -> Option { - match &arg.label { - None => None, - Some(label) => Some(DocTypeConstructorArg { - label: label.clone(), - documentation: arg.doc.as_deref().map(render_markdown).unwrap_or_default(), - }), - } + arg.label.as_ref().map(|label| DocTypeConstructorArg { + label: label.clone(), + documentation: arg.doc.as_deref().map(render_markdown).unwrap_or_default(), + }) } } diff --git a/crates/project/src/lib.rs b/crates/project/src/lib.rs index 159fe320..5f7ad8e4 100644 --- a/crates/project/src/lib.rs +++ b/crates/project/src/lib.rs @@ -107,7 +107,7 @@ where }); self.read_source_files()?; - let destination = destination.unwrap_or(self.root.join("doc")); + let destination = destination.unwrap_or_else(|| self.root.join("doc")); let mut parsed_modules = self.parse_sources()?; for (_, module) in parsed_modules.iter_mut() { module.attach_doc_and_module_comments(); @@ -120,7 +120,7 @@ where docs::generate_all(&self.root, &self.config, checked_modules.values().collect()); for file in doc_files { let path = destination.join(file.path); - fs::create_dir_all(&path.parent().unwrap())?; + fs::create_dir_all(path.parent().unwrap())?; fs::write(&path, file.content)?; } From e1065e892abf24e7f4ae422ddca94d2e7be966a7 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 23:41:46 +0100 Subject: [PATCH 10/18] Support module constants in docs. --- crates/lang/src/format.rs | 12 +-- crates/project/src/docs.rs | 154 +++++++++++++++++++++++++------------ 2 files changed, 106 insertions(+), 60 deletions(-) diff --git a/crates/lang/src/format.rs b/crates/lang/src/format.rs index 7b7f6732..f91592d7 100644 --- a/crates/lang/src/format.rs +++ b/crates/lang/src/format.rs @@ -386,17 +386,9 @@ impl<'comments> Formatter<'comments> { } } - pub fn docs_const_expr<'a>( - &mut self, - public: bool, - name: &'a str, - value: &'a TypedConstant, - ) -> Document<'a> { + pub fn docs_const_expr<'a>(&mut self, name: &'a str, value: &'a TypedConstant) -> Document<'a> { let mut printer = tipo::pretty::Printer::new(); - - pub_(public) - .append("const ") - .append(name) + name.to_doc() .append(": ") .append(printer.print(&value.tipo())) .append(" = ") diff --git a/crates/project/src/docs.rs b/crates/project/src/docs.rs index 7e960a38..7bec74ca 100644 --- a/crates/project/src/docs.rs +++ b/crates/project/src/docs.rs @@ -62,14 +62,6 @@ struct DocLink { path: String, } -#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)] -struct SearchIndex { - doc: String, - title: String, - content: String, - url: String, -} - /// Generate documentation files for a given project. /// /// The documentation is built using template files located at the root of this crate. @@ -110,14 +102,9 @@ fn generate_module( .sorted() .collect(); - functions.iter().for_each(|function| { - search_indexes.push(SearchIndex { - doc: module.name.to_string(), - title: function.name.to_string(), - content: format!("{}\n{}", function.signature, function.documentation), - url: format!("{}.html#{}", module.name, function.name), - }) - }); + functions + .iter() + .for_each(|function| search_indexes.push(SearchIndex::from_function(module, function))); // Types let types: Vec = module @@ -127,43 +114,25 @@ fn generate_module( .flat_map(DocType::from_definition) .sorted() .collect(); - types.iter().for_each(|type_info| { - let constructors = type_info - .constructors - .iter() - .map(|constructor| { - let arguments = constructor - .arguments - .iter() - .map(|argument| format!("{}\n{}", argument.label, argument.documentation)) - .join("\n"); - format!( - "{}\n{}\n{}", - constructor.definition, constructor.documentation, arguments - ) - }) - .join("\n"); - search_indexes.push(SearchIndex { - doc: module.name.to_string(), - title: type_info.name.to_string(), - content: format!( - "{}\n{}\n{}", - type_info.definition, type_info.documentation, constructors, - ), - url: format!("{}.html#{}", module.name, type_info.name), - }) - }); + + types + .iter() + .for_each(|type_info| search_indexes.push(SearchIndex::from_type(module, type_info))); // Constants - // TODO + let constants: Vec = module + .ast + .definitions + .iter() + .flat_map(DocConstant::from_definition) + .sorted() + .collect(); + constants + .iter() + .for_each(|constant| search_indexes.push(SearchIndex::from_constant(module, constant))); // Module - search_indexes.push(SearchIndex { - doc: module.name.to_string(), - title: module.name.to_string(), - content: String::new(), - url: format!("{}.html", module.name), - }); + search_indexes.push(SearchIndex::from_module(module)); let template = ModuleTemplate { aiken_version: VERSION, @@ -177,7 +146,7 @@ fn generate_module( project_version: &config.version.to_string(), functions, types, - constants: vec![], + constants, timestamp: timestamp.as_secs().to_string(), }; @@ -283,6 +252,71 @@ fn generate_modules_links(modules: &Vec<&CheckedModule>) -> Vec { modules_links } +#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)] +struct SearchIndex { + doc: String, + title: String, + content: String, + url: String, +} + +impl SearchIndex { + fn from_function(module: &CheckedModule, function: &DocFunction) -> Self { + SearchIndex { + doc: module.name.to_string(), + title: function.name.to_string(), + content: format!("{}\n{}", function.signature, function.documentation), + url: format!("{}.html#{}", module.name, function.name), + } + } + + fn from_type(module: &CheckedModule, type_info: &DocType) -> Self { + let constructors = type_info + .constructors + .iter() + .map(|constructor| { + let arguments = constructor + .arguments + .iter() + .map(|argument| format!("{}\n{}", argument.label, argument.documentation)) + .join("\n"); + format!( + "{}\n{}\n{}", + constructor.definition, constructor.documentation, arguments + ) + }) + .join("\n"); + + SearchIndex { + doc: module.name.to_string(), + title: type_info.name.to_string(), + content: format!( + "{}\n{}\n{}", + type_info.definition, type_info.documentation, constructors, + ), + url: format!("{}.html#{}", module.name, type_info.name), + } + } + + fn from_constant(module: &CheckedModule, constant: &DocConstant) -> Self { + SearchIndex { + doc: module.name.to_string(), + title: constant.name.to_string(), + content: format!("{}\n{}", constant.definition, constant.documentation), + url: format!("{}.html#{}", module.name, constant.name), + } + } + + fn from_module(module: &CheckedModule) -> Self { + SearchIndex { + doc: module.name.to_string(), + title: module.name.to_string(), + content: module.ast.docs.iter().join("\n"), + url: format!("{}.html", module.name), + } + } +} + #[derive(PartialEq, Eq, PartialOrd, Ord)] struct DocFunction { name: String, @@ -323,6 +357,26 @@ struct DocConstant { source_url: String, } +impl DocConstant { + fn from_definition(def: &TypedDefinition) -> Option { + match def { + Definition::ModuleConstant(const_def) if const_def.public => Some(DocConstant { + name: const_def.name.clone(), + documentation: const_def + .doc + .as_deref() + .map(render_markdown) + .unwrap_or_default(), + definition: format::Formatter::new() + .docs_const_expr(&const_def.name, &const_def.value) + .to_pretty_string(MAX_COLUMNS), + source_url: "#todo".to_string(), + }), + _ => None, + } + } +} + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] struct DocType { name: String, From e7f729c61b4b693945ad195b7db35d61c7533fc8 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 16 Dec 2022 23:55:09 +0100 Subject: [PATCH 11/18] Define HighlightJS definition for Aiken. --- crates/project/src/docs.rs | 4 ++-- crates/project/templates/_layout.html | 4 ++-- ...hlightjs-gleam.js => highlightjs-aiken.js} | 22 ++++++++++++++----- crates/project/templates/module.html | 8 +++---- 4 files changed, 25 insertions(+), 13 deletions(-) rename crates/project/templates/js/{highlightjs-gleam.js => highlightjs-aiken.js} (82%) diff --git a/crates/project/src/docs.rs b/crates/project/src/docs.rs index 7bec74ca..c99e97a1 100644 --- a/crates/project/src/docs.rs +++ b/crates/project/src/docs.rs @@ -185,8 +185,8 @@ fn generate_static_assets(search_indexes: Vec) -> Vec { }); assets.push(DocFile { - path: PathBuf::from("js/highlightjs-gleam.js"), - content: std::include_str!("../templates/js/highlightjs-gleam.js").to_string(), + path: PathBuf::from("js/highlightjs-aiken.js"), + content: std::include_str!("../templates/js/highlightjs-aiken.js").to_string(), }); assets.push(DocFile { diff --git a/crates/project/templates/_layout.html b/crates/project/templates/_layout.html index fd23a59a..875704b3 100644 --- a/crates/project/templates/_layout.html +++ b/crates/project/templates/_layout.html @@ -252,11 +252,11 @@ - + @@ -121,7 +120,7 @@

    {{ project_name }} - - v{{ project_version }} + v{{ project_version }} - -
    -
    Lucy
    -
    says
    -
    trans
    -
    rights
    -
    now
    -
    - diff --git a/crates/project/templates/css/index.css b/crates/project/templates/css/index.css index 2109ca84..ce9158d0 100644 --- a/crates/project/templates/css/index.css +++ b/crates/project/templates/css/index.css @@ -1,30 +1,8 @@ -@import url("https://fonts.googleapis.com/css2?family=Karla:wght@400;700&family=Ubuntu+Mono&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Nunito+Sans&family=Ubuntu+Mono&display=swap"); :root { - /* Colours */ - --black: #2a2020; - --hard-black: #000; - --pink: #ffaff3; - --hot-pink: #d900b8; - --white: #fff; - --pink-white: #fff8fe; - --mid-grey: #dfe2e5; - --light-grey: #f5f5f5; - --boi-blue: #a6f0fc; - - /* Derived colours */ - --text: var(--black); - --background: var(--white); - --accented-background: var(--pink-white); - --code-border: var(--pink); - --code-background: var(--light-grey); - --table-border: var(--mid-grey); - --table-background: var(--pink-white); - --links: var(--hot-pink); - --accent: var(--pink); - /* Sizes */ - --content-width: 680px; + --search-width: 680px; --header-height: 60px; --hash-offset: calc(var(--header-height) * 1.67); --sidebar-width: 240px; @@ -35,10 +13,28 @@ --sidebar-toggle-size: 33px; --search-height: 4rem; + /* Colors */ + --color-text: #4c4f69; + --color-text-accent: #e6e9ef; + --color-inline-code: #ea76cb; + --color-link: #dc8a78; + --color-link-accent: #dd7878; + --color-background: #eff1f5; + --color-background-sidebar: #e6e9ef; + --color-background-accent: #8839ef; + --color-border-accent: #ea76cb; + --color-table-header-background: #bcc0cc; + --color-table-header-text: #4c4f69; + --color-table-background: #e6e9ef; + --color-table-border: #ea76cb; + --color-code-background: #dce0e8; + /* etc */ - --shadow: 0 0 0 1px rgba(50, 50, 93, 0.075), 0 0 1px #e9ecef, - 0 2px 4px -2px rgba(138, 141, 151, 0.6); --nav-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.1); + --shadow: + 0 0 0 1px rgba(50, 50, 93, 0.075), + 0 0 1px #e9ecef, + 0 2px 4px -2px rgba(138, 141, 151, 0.6); } * { @@ -49,12 +45,14 @@ body, html { padding: 0; margin: 0; - font-family: "Karla", sans-serif; + font-family: "Nunito Sans", sans-serif; font-size: 17px; line-height: 1.4; position: relative; min-height: 100vh; word-break: break-word; + background-color: var(--color-background); + color: var(--color-text); } html { @@ -64,7 +62,7 @@ html { a, a:visited { - color: var(--links); + color: var(--color-link); text-decoration: none; } @@ -128,7 +126,7 @@ pre, code { font-family: "Ubuntu Mono", monospace; line-height: 1.2; - background-color: var(--code-background); + background-color: var(--color-code-background); } pre { @@ -144,11 +142,12 @@ code.hljs { background: transparent; } +td code, p code { margin: 0 2px; border-radius: 3px; padding: 0 0.2em; - color: var(--inline-code); + color: var(--color-inline-code); } /* Page layout */ @@ -161,7 +160,7 @@ p code { margin-left: var(--sidebar-width); padding: calc(var(--header-height) + var(--gap)) var(--gap) 0 var(--gap); width: calc(100% - var(--sidebar-width)); - max-width: var(--content-width); + max-width: 100%; } .content img { @@ -173,9 +172,8 @@ p code { .page-header { box-shadow: var(--nav-shadow); height: var(--header-height); - color: black; - color: var(--hard-black); - background-color: var(--pink); + color: var(--color-text-accent); + background-color: var(--color-background-accent); display: flex; padding: var(--small-gap) var(--gap); position: fixed; @@ -194,8 +192,7 @@ p code { .page-header a, .page-header a:visited { - color: black; - color: var(--hard-black); + color: var(--color-text-accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -216,14 +213,12 @@ p code { } .page-header .sidebar-toggle { - color: white; - color: var(--white); + color: var(--color-background); margin: 0 var(--small-gap) 0 0; } .page-header .search-nav-button { - color: white; - color: var(--white); + color: var(--color-background); margin: 0 var(--small-gap) 0 0; } @@ -278,7 +273,7 @@ p code { } .module-name { - color: var(--hard-black); + color: var(--color-text); margin: 0 0 var(--gap); font-weight: 700; } @@ -286,27 +281,31 @@ p code { /* Sidebar */ .sidebar { - background-color: var(--background); + background-color: var(--color-background-sidebar); font-size: 0.95rem; max-height: calc(100vh - var(--header-height)); overflow-y: auto; overscroll-behavior: contain; padding-top: var(--gap); - padding-bottom: calc(3 * var(--gap)); + padding-bottom: var(--gap); padding-left: var(--gap); position: fixed; top: var(--header-height); transition: transform 0.5s ease; width: var(--sidebar-width); z-index: 100; + height: 100%; + display: flex; + flex-direction: column; } .sidebar h2 { margin: 0; + color: var(--color-link-accent); } .sidebar h3.modules-prefix { - color: var(--pink); + color: var(--color-link); margin-bottom: 0; } @@ -326,7 +325,7 @@ p code { } .sidebar .sidebar-toggle { - color: var(--pink); + color: var(--color-link); font-size: calc(0.8 * var(--sidebar-toggle-size)); } @@ -337,9 +336,11 @@ body.drawer-open .label-closed { .display-controls { display: flex; - flex-wrap: wrap; - margin-top: var(--small-gap); - padding-right: var(--gap); + margin-top: auto; +} + +.display-controls svg.icon { + color: var(--color-text); } .display-controls .control { @@ -365,8 +366,8 @@ body.drawer-open .label-closed { display: flex; } -.label .icon { - margin: 0 0.28rem; +.label .icon + .icon { + margin-left: 0.5rem; } /* Module members (types, functions) */ @@ -377,7 +378,7 @@ body.drawer-open .label-closed { .module-member-kind { font-size: 2rem; - color: var(--text); + color: var(--color-text); } .member { @@ -389,9 +390,10 @@ body.drawer-open .label-closed { display: flex; align-items: center; justify-content: space-between; - border-left: 4px solid var(--accent); + border-left: 4px solid var(--color-border-accent); padding: var(--small-gap) var(--gap); - background-color: var(--accented-background); + color: var(--color-text-accent); + background-color: var(--color-background-accent); } .member-name h2 { @@ -401,7 +403,7 @@ body.drawer-open .label-closed { } .member-name h2 a { - color: var(--text); + color: var(--color-text-accent); } .member-source { @@ -473,59 +475,16 @@ table { table td, table th { padding: 6px 13px; - border: 1px solid var(--table-border); + border: 1px solid var(--color-table-border); +} + +table th { + background-color: var(--color-table-header-background); + color: var(--color-table-header-text); } table tr:nth-child(2n) { - background-color: var(--table-background); -} - -/* Footer */ - -.pride { - width: 100%; - display: none; - flex-direction: row; - position: absolute; - bottom: 0; - z-index: 100; -} - -.show-pride .pride { - display: flex; -} - -.show-pride .sidebar { - margin-bottom: var(--gap); -} - -.pride div { - flex: 1; - text-align: center; - padding: var(--tiny-gap); -} - -.pride .white { - background-color: var(--white); -} -.pride .pink { - background-color: var(--pink); -} -.pride .blue { - background-color: var(--boi-blue); -} - -.pride-button { - position: absolute; - right: 2px; - bottom: 2px; - opacity: 0.2; - font-size: 0.9rem; -} - -.pride-button { - text-decoration: none; - cursor: default; + background-color: var(--color-table-background); } /* Icons */ @@ -556,119 +515,28 @@ body.prewrap-on pre { /* Dark Theme Option */ body.theme-dark { - /* Colour palette adapted from: - * https://github.com/dustypomerleau/yarra-valley - */ + /* Colors */ + --color-text: #cdd6f4; + --color-text-accent: #11111b; + --color-inline-code: #f5c2e7; + --color-link: #f5e0dc; + --color-link-accent: #f2cdcd; + --color-background: #1e1e2e; + --color-background-sidebar: #313244; + --color-background-accent: #cba6f7; + --color-border-accent: #f5c2e7; + --color-table-header-background: #11111b; + --color-table-header-text: #cdd6f4; + --color-table-background: #181825; + --color-table-border: #6c7086; + --color-code-background: #11111b; - --argument-atom: #c651e5; - --class-module: #ff89b5; - --comment: #7e818b; - --escape: #7cdf89; - --function-call: #abb8c0; - --function-definition: #8af899; - --interpolation-regex: #ee37aa; - --keyword-operator: #ff9d35; - --number-boolean: #f14360; - --object: #99c2eb; - --punctuation: #4ce7ff; - --string: #aecc00; - - --inline-code: #ff9d35; - - --bg: #292d3e; - --bg-tint-1: #3e4251; - --bg-tint-2: #535664; - --bg-tint-3: #696c77; - --bg-tint-4: #7e818b; - --bg-shade-1: #242837; - --bg-shade-2: #202431; - --bg-shade-3: #1c1f2b; - --bg-mono-1: #33384d; - --bg-mono-2: #3d435d; - --bg-mono-3: #474e6c; - --bg-mono-4: #51597b; - - --fg: #cac0a9; - --fg-tint-1: #fdf2d8; - --fg-tint-2: #fdf3dc; - --fg-tint-3: #fdf5e0; - --fg-shade-1: #e3d8be; - --fg-shade-2: #cac0a9; - --fg-shade-3: #b1a894; - --fg-shade-4: #97907f; - - --orange-shade-1: #e58d2f; - --orange-shade-2: #cc7d2a; - --orange-shade-3: #b26d25; - - --taupe-mono-1: #fdf1d4; - --taupe-mono-2: #fce9bc; - --taupe-mono-3: #fbe1a3; - - /* Theme Overrides */ - - --accent: var(--pink); - --accented-background: var(--bg-shade-1); - --background: var(--bg); - --code-background: var(--bg-shade-2); - --table-background: var(--bg-mono-1); - --hard-black: var(--taupe-mono-1); - --links: var(--pink); - --text: var(--taupe-mono-1); - - --shadow: 0 0 0 1px rgba(50, 50, 93, 0.075), 0 0 1px var(--fg-shade-3), - 0 2px 4px -2px rgba(138, 141, 151, 0.2); + /* etc */ --nav-shadow: 0 0 5px 5px rgba(0, 0, 0, 0.1); -} - -body.theme-dark { - background-color: var(--bg); - color: var(--fg-shade-1); -} - -body.theme-dark .page-header { - background-color: var(--bg-mono-1); -} - -body.theme-dark .page-header h2 { - color: var(--fg-shade-1); -} - -body.theme-dark .page-header a, -body.theme-dark .page-header a:visited { - color: var(--pink); -} - -body.theme-dark .page-header .sidebar-toggle { - color: var(--fg-shade-1); -} -body.theme-dark .page-header .search-nav-button { - color: var(--fg-shade-1); -} - -body.theme-dark #project-version select, -body.theme-dark .control { - color: var(--fg-shade-1); -} - -body.theme-dark .module-name { - color: var(--taupe-mono-1); -} - -body.theme-dark .pride { - color: var(--bg-shade-3); -} - -body.theme-dark .pride .white { - background-color: var(--fg-shade-1); -} - -body.theme-dark .pride .pink { - background-color: var(--argument-atom); -} - -body.theme-dark .pride .blue { - background-color: var(--punctuation); + --shadow: + 0 0 0 1px rgba(50, 50, 93, 0.075), + 0 0 1px var(--fg-shade-3), + 0 2px 4px -2px rgba(138, 141, 151, 0.2); } /* Medium and larger displays */ @@ -768,7 +636,7 @@ body.theme-dark .pride .blue { .search-input-wrap { position: absolute; width: 100%; - max-width: calc(var(--content-width) - var(--gap) - var(--gap)); + max-width: calc(var(--search-width) - var(--gap) - var(--gap)); height: 100% !important; border-radius: 0; box-shadow: none; @@ -783,7 +651,7 @@ body.theme-dark .pride .blue { padding: 0.5rem 1rem; font-size: 16px; background-color: transparent; - color: var(--text); + color: var(--color-text); border-top: 0; border-right: 0; border-bottom: 0; @@ -795,7 +663,7 @@ body.theme-dark .pride .blue { .search-input { padding: 1rem; font-size: 14px; - background-color: transparent; + background-color: var(--color-background); transition: padding-left linear 200ms; } } @@ -804,10 +672,6 @@ body.theme-dark .pride .blue { outline: 0; } -.search-input:focus + .search-label .search-icon { - color: var(--pink); -} - .search-label { position: absolute; right: 0; @@ -828,7 +692,7 @@ body.theme-dark .pride .blue { width: 1.2rem; height: 1.2rem; align-self: center; - color: var(--text); + color: var(--color-text); } .search-results { @@ -838,7 +702,8 @@ body.theme-dark .pride .blue { width: 100%; max-height: calc(100% - var(--search-height)); overflow-y: auto; - background-color: var(--background); + color: var(--color-text); + background-color: var(--color-background); border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); @@ -847,7 +712,7 @@ body.theme-dark .pride .blue { @media (min-width: 919px) { .search-results { top: 100%; - width: calc(var(--content-width) - var(--gap) - var(--gap)); + width: calc(var(--search-width) - var(--gap) - var(--gap)); max-height: calc(100vh - 200%) !important; } } @@ -943,24 +808,26 @@ body.theme-dark .pride .blue { width: 1rem; height: 1rem; margin-right: 0.5rem; - color: var(--pink); + color: var(--color-link-accent); flex-shrink: 0; } .search-result-doc .search-result-doc-title { overflow: auto; + color: var(--color-link-accent); } .search-result-section { margin-left: 1.5rem; word-wrap: break-word; + color: var(--color-link-accent) } .search-result-rel-url { display: block; margin-left: 1.5rem; overflow: hidden; - color: var(--text); + color: var(--color-text); text-overflow: ellipsis; white-space: nowrap; font-size: 9px !important; @@ -978,7 +845,7 @@ body.theme-dark .pride .blue { padding-bottom: 0.5rem; padding-left: 1rem; margin-left: 0.5rem; - color: var(--text); + color: var(--color-text); word-wrap: break-word; border-left: 1px solid; border-left-color: #eeebee; @@ -1032,7 +899,7 @@ body.theme-dark .pride .blue { display: flex; width: 3.5rem; height: 3.5rem; - background-color: var(--background); + background-color: var(--color-background); border: 1px solid rgba(114, 83, 237, 0.3); border-radius: 1.75rem; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); @@ -1069,13 +936,13 @@ body.theme-dark .pride .blue { @media (min-width: 919px) { .search-active .search-input-wrap { - width: calc(var(--content-width) - var(--gap) - var(--gap)); + width: calc(var(--search-width) - var(--gap) - var(--gap)); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); } } .search-active .search-input { - background-color: var(--background); + background-color: var(--color-background); } @media (min-width: 919px) { diff --git a/crates/project/templates/favicon.svg b/crates/project/templates/favicon.svg new file mode 100644 index 00000000..bb04fa41 --- /dev/null +++ b/crates/project/templates/favicon.svg @@ -0,0 +1,3 @@ + + + From 1178fa3f01d499051489008795e8a3b2f5936090 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 17 Dec 2022 03:19:39 +0100 Subject: [PATCH 15/18] Add source repository to config & docs. --- crates/project/src/config.rs | 27 ++++++++++++++- crates/project/src/docs.rs | 48 +++++++++++++++++++++------ crates/project/templates/_layout.html | 8 ++--- 3 files changed, 67 insertions(+), 16 deletions(-) diff --git a/crates/project/src/config.rs b/crates/project/src/config.rs index 4acc18db..1aaba868 100644 --- a/crates/project/src/config.rs +++ b/crates/project/src/config.rs @@ -1,4 +1,4 @@ -use std::{fs, io, path::PathBuf}; +use std::{fmt::Display, fs, io, path::PathBuf}; use serde::Deserialize; @@ -8,6 +8,31 @@ pub struct Config { pub version: String, #[serde(default)] pub description: String, + pub repository: Option, +} + +#[derive(Deserialize)] +pub struct Repository { + pub user: String, + pub project: String, + pub platform: Platform, +} + +#[derive(Deserialize)] +pub enum Platform { + Github, + Gitlab, + Bitbucket, +} + +impl Display for Platform { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> { + match *self { + Platform::Github => f.write_str("github"), + Platform::Gitlab => f.write_str("gitlab"), + Platform::Bitbucket => f.write_str("bitbucket"), + } + } } impl Config { diff --git a/crates/project/src/docs.rs b/crates/project/src/docs.rs index eecf87be..3ab8c46b 100644 --- a/crates/project/src/docs.rs +++ b/crates/project/src/docs.rs @@ -1,4 +1,7 @@ -use crate::{config::Config, module::CheckedModule}; +use crate::{ + config::{Config, Repository}, + module::CheckedModule, +}; use aiken_lang::{ ast::{Definition, RecordConstructor, RecordConstructorArg, TypedDefinition}, format, @@ -33,13 +36,13 @@ struct ModuleTemplate<'a> { module_name: String, project_name: &'a str, project_version: &'a str, - links: &'a Vec, modules_prefix: String, modules: &'a Vec, functions: Vec, types: Vec, constants: Vec, documentation: String, + source: &'a DocLink, timestamp: String, } @@ -51,10 +54,10 @@ struct PageTemplate<'a> { page_title: &'a str, project_name: &'a str, project_version: &'a str, - links: &'a Vec, modules_prefix: String, modules: &'a Vec, content: String, + source: &'a DocLink, timestamp: &'a str, } @@ -64,6 +67,12 @@ struct DocLink { path: String, } +impl DocLink { + pub fn is_empty(&self) -> bool { + self.name.is_empty() + } +} + /// Generate documentation files for a given project. /// /// The documentation is built using template files located at the root of this crate. @@ -73,6 +82,21 @@ pub fn generate_all(root: &Path, config: &Config, modules: Vec<&CheckedModule>) let timestamp = new_timestamp(); let (modules_prefix, modules_links) = generate_modules_links(&modules); + let source = match &config.repository { + None => DocLink { + name: String::new(), + path: String::new(), + }, + Some(Repository { + user, + project, + platform, + }) => DocLink { + name: format!("{user}/{project}"), + path: format!("https://{platform}.com/{user}/{project}"), + }, + }; + let mut output_files: Vec = vec![]; let mut search_indexes: Vec = vec![]; @@ -81,6 +105,7 @@ pub fn generate_all(root: &Path, config: &Config, modules: Vec<&CheckedModule>) config, module, (&modules_prefix, &modules_links), + &source, ×tamp, ); search_indexes.extend(indexes); @@ -92,6 +117,7 @@ pub fn generate_all(root: &Path, config: &Config, modules: Vec<&CheckedModule>) root, config, (&modules_prefix, &modules_links), + &source, ×tamp, )); @@ -102,6 +128,7 @@ fn generate_module( config: &Config, module: &CheckedModule, (modules_prefix, modules): (&str, &Vec), + source: &DocLink, timestamp: &Duration, ) -> (Vec, DocFile) { let mut search_indexes = vec![]; @@ -147,7 +174,6 @@ fn generate_module( let module = ModuleTemplate { aiken_version: VERSION, breadcrumbs: to_breadcrumbs(&module.name), - links: &vec![], documentation: render_markdown(&module.ast.docs.iter().join("\n")), modules_prefix: modules_prefix.to_string(), modules, @@ -158,6 +184,7 @@ fn generate_module( functions, types, constants, + source, timestamp: timestamp.as_secs().to_string(), }; @@ -231,6 +258,7 @@ fn generate_readme( root: &Path, config: &Config, (modules_prefix, modules): (&str, &Vec), + source: &DocLink, timestamp: &Duration, ) -> DocFile { let path = PathBuf::from("index.html"); @@ -240,13 +268,13 @@ fn generate_readme( let template = PageTemplate { aiken_version: VERSION, breadcrumbs: ".", - links: &vec![], modules_prefix: modules_prefix.to_string(), modules, project_name: &config.name, page_title: &config.name, project_version: &config.version.to_string(), content: render_markdown(&content), + source, timestamp: ×tamp.as_secs().to_string(), }; @@ -559,10 +587,10 @@ fn find_modules_prefix(modules: &[DocLink]) -> String { #[test] fn find_modules_prefix_test() { - assert_eq!(find_modules_prefix(&vec![]), "".to_string()); + assert_eq!(find_modules_prefix(&[]), "".to_string()); assert_eq!( - find_modules_prefix(&vec![DocLink { + find_modules_prefix(&[DocLink { name: "aiken/list".to_string(), path: String::new() }]), @@ -570,7 +598,7 @@ fn find_modules_prefix_test() { ); assert_eq!( - find_modules_prefix(&vec![DocLink { + find_modules_prefix(&[DocLink { name: "my_module".to_string(), path: String::new() }]), @@ -578,7 +606,7 @@ fn find_modules_prefix_test() { ); assert_eq!( - find_modules_prefix(&vec![ + find_modules_prefix(&[ DocLink { name: "aiken/list".to_string(), path: String::new() @@ -592,7 +620,7 @@ fn find_modules_prefix_test() { ); assert_eq!( - find_modules_prefix(&vec![ + find_modules_prefix(&[ DocLink { name: "aiken/list".to_string(), path: String::new() diff --git a/crates/project/templates/_layout.html b/crates/project/templates/_layout.html index 355d7162..8f243315 100644 --- a/crates/project/templates/_layout.html +++ b/crates/project/templates/_layout.html @@ -174,12 +174,10 @@ - {% if !links.is_empty() %} -

    Links

    + {% if !source.is_empty() %} +

    Source code

    {% endif %} From a34d7d4dbb12a19c6508a659e19599c5eaa28781 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 17 Dec 2022 11:54:39 +0100 Subject: [PATCH 16/18] Revert 71e71ff Redundant with the `kind: ModuleKind` field already. --- crates/project/src/module.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/crates/project/src/module.rs b/crates/project/src/module.rs index 01bffdda..2c722e6b 100644 --- a/crates/project/src/module.rs +++ b/crates/project/src/module.rs @@ -223,15 +223,6 @@ pub struct CheckedModule { pub extra: ModuleExtra, } -impl CheckedModule { - pub fn is_library(&self) -> bool { - self.ast.definitions().any(|def| match def { - Definition::Fn(func_def) => VALIDATOR_NAMES.contains(&func_def.name.as_str()), - _ => false, - }) - } -} - #[derive(Debug, Clone)] pub struct CheckedModules(HashMap); From 579030db36abecd812795e14b6f517f26846ed56 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 17 Dec 2022 12:13:51 +0100 Subject: [PATCH 17/18] Highlight current module in the sidebar. --- crates/project/src/docs.rs | 15 +++++++++++++++ crates/project/templates/_layout.html | 8 +++++++- crates/project/templates/css/index.css | 11 +++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/project/src/docs.rs b/crates/project/src/docs.rs index 3ab8c46b..a030ff7a 100644 --- a/crates/project/src/docs.rs +++ b/crates/project/src/docs.rs @@ -46,6 +46,15 @@ struct ModuleTemplate<'a> { timestamp: String, } +impl<'a> ModuleTemplate<'a> { + pub fn is_current_module(&self, module: &DocLink) -> bool { + match module.path.split(".html").next() { + None => false, + Some(name) => self.module_name == name, + } + } +} + #[derive(Template)] #[template(path = "page.html")] struct PageTemplate<'a> { @@ -61,6 +70,12 @@ struct PageTemplate<'a> { timestamp: &'a str, } +impl<'a> PageTemplate<'a> { + pub fn is_current_module(&self, _module: &DocLink) -> bool { + false + } +} + #[derive(PartialEq, Eq, PartialOrd, Ord, Clone)] struct DocLink { name: String, diff --git a/crates/project/templates/_layout.html b/crates/project/templates/_layout.html index 8f243315..f8c8611e 100644 --- a/crates/project/templates/_layout.html +++ b/crates/project/templates/_layout.html @@ -187,7 +187,13 @@ {% endif %} diff --git a/crates/project/templates/css/index.css b/crates/project/templates/css/index.css index ce9158d0..2b2c42fc 100644 --- a/crates/project/templates/css/index.css +++ b/crates/project/templates/css/index.css @@ -324,6 +324,17 @@ p code { margin-bottom: 4px; } +.sidebar ul li a > strong { + font-weight: 900; + color: var(--color-link); +} + +.sidebar ul li a > strong::before { + font-size: 0.75em; + content: 'ᐅ '; + padding-right: 0.1rem; +} + .sidebar .sidebar-toggle { color: var(--color-link); font-size: calc(0.8 * var(--sidebar-toggle-size)); From 202678e21eeb3758ed37a3db093fb749ee6a7744 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 17 Dec 2022 12:45:48 +0100 Subject: [PATCH 18/18] Improve rendering of type-signatures in docs - [x] Display function arguments using a newline-multiline strategy when the signature gets too long. For example: ``` union_with ( left left: AssocList , right right: AssocList , with with: fn(key, value, value) -> value ) -> AssocList ``` - [x] Show type-aliases as type-aliases in signatures; provided they've been specified as type annotations. Otherwise, fallback to the inferred type. - [x] Do not show argument names in signatures, but show labels when they're present. This reflects more the original intent behind labels (which are meant as public-facing documentation). --- crates/lang/src/format.rs | 174 ++++++++++++++++++++++++++----------- crates/project/src/docs.rs | 1 + 2 files changed, 124 insertions(+), 51 deletions(-) diff --git a/crates/lang/src/format.rs b/crates/lang/src/format.rs index f91592d7..da68f7d9 100644 --- a/crates/lang/src/format.rs +++ b/crates/lang/src/format.rs @@ -18,6 +18,7 @@ use crate::{ }; const INDENT: isize = 2; +const DOCS_MAX_COLUMNS: isize = 80; pub fn pretty(writer: &mut String, module: UntypedModule, extra: ModuleExtra, src: &str) { let intermediate = Intermediate { @@ -347,6 +348,7 @@ impl<'comments> Formatter<'comments> { } => name .to_doc() .append(wrap_args( + false, args.iter() .map(|a| (self.constant_call_arg(a), a.label.is_some())), )) @@ -362,6 +364,7 @@ impl<'comments> Formatter<'comments> { .append(".") .append(name.as_str()) .append(wrap_args( + false, args.iter() .map(|a| (self.constant_call_arg(a), a.label.is_some())), )) @@ -380,6 +383,7 @@ impl<'comments> Formatter<'comments> { Constant::Tuple { elements, .. } => "#" .to_doc() .append(wrap_args( + false, elements.iter().map(|e| (self.const_expr(e), false)), )) .group(), @@ -451,15 +455,19 @@ impl<'comments> Formatter<'comments> { .. } => "fn" .to_doc() - .append(wrap_args(args.iter().map(|t| (self.annotation(t), false)))) + .append(wrap_args( + false, + args.iter().map(|t| (self.annotation(t), false)), + )) .group() .append(" ->") .append(break_("", " ").append(self.annotation(retrn)).nest(INDENT)), Annotation::Var { name, .. } => name.to_doc(), - Annotation::Tuple { elems, .. } => "#" - .to_doc() - .append(wrap_args(elems.iter().map(|t| (self.annotation(t), false)))), + Annotation::Tuple { elems, .. } => "#".to_doc().append(wrap_args( + false, + elems.iter().map(|t| (self.annotation(t), false)), + )), } .group() } @@ -519,7 +527,10 @@ impl<'comments> Formatter<'comments> { .append(keyword) .append(" ") .append(name) - .append(wrap_args(args.iter().map(|e| (self.fn_arg(e), false)))); + .append(wrap_args( + false, + args.iter().map(|e| (self.fn_arg(e), false)), + )); // Add return annotation let head = match return_annotation { @@ -550,7 +561,7 @@ impl<'comments> Formatter<'comments> { return_annotation: Option<&'a Annotation>, body: &'a UntypedExpr, ) -> Document<'a> { - let args = wrap_args(args.iter().map(|e| (self.fn_arg(e), false))).group(); + let args = wrap_args(false, args.iter().map(|e| (self.fn_arg(e), false))).group(); let body = match body { UntypedExpr::When { .. } => self.expr(body).force_break(), _ => self.expr(body), @@ -780,7 +791,10 @@ impl<'comments> Formatter<'comments> { UntypedExpr::Tuple { elems, .. } => "#" .to_doc() - .append(wrap_args(elems.iter().map(|e| (self.wrap_expr(e), false)))) + .append(wrap_args( + false, + elems.iter().map(|e| (self.wrap_expr(e), false)), + )) .group(), }; commented(document, comments) @@ -844,6 +858,7 @@ impl<'comments> Formatter<'comments> { _ => name .append(wrap_args( + false, args.iter().map(|a| (self.pattern_call_arg(a), is_record)), )) .group(), @@ -885,6 +900,7 @@ impl<'comments> Formatter<'comments> { _ => self .expr(fun) .append(wrap_args( + false, args.iter() .map(|a| (self.call_arg(a, needs_curly), needs_curly)), )) @@ -932,7 +948,9 @@ impl<'comments> Formatter<'comments> { let spread_doc = "..".to_doc().append(self.expr(&spread.base)); let arg_docs = args.iter().map(|a| (self.record_update_arg(a), true)); let all_arg_docs = once((spread_doc, true)).chain(arg_docs); - constructor_doc.append(wrap_args(all_arg_docs)).group() + constructor_doc + .append(wrap_args(false, all_arg_docs)) + .group() } pub fn bin_op<'a>( @@ -1018,6 +1036,7 @@ impl<'comments> Formatter<'comments> { // x |> fun(_, 2, 3) self.expr(fun).append( wrap_args( + false, args.iter() .skip(1) .map(|a| (self.call_arg(a, false), false)), @@ -1026,8 +1045,9 @@ impl<'comments> Formatter<'comments> { ) } else { // x |> fun(1, _, 3) - self.expr(fun) - .append(wrap_args(args.iter().map(|a| (self.call_arg(a, false), false))).group()) + self.expr(fun).append( + wrap_args(false, args.iter().map(|a| (self.call_arg(a, false), false))).group(), + ) } } @@ -1047,7 +1067,7 @@ impl<'comments> Formatter<'comments> { } _ => self.expr(fun).append( - wrap_args(args.iter().map(|a| (self.call_arg(a, false), false))).group(), + wrap_args(false, args.iter().map(|a| (self.call_arg(a, false), false))).group(), ), }, @@ -1091,29 +1111,34 @@ impl<'comments> Formatter<'comments> { constructor .name .to_doc() - .append(wrap_args(constructor.arguments.iter().map( - |RecordConstructorArg { - label, - annotation, - location, - .. - }| { - let arg_comments = self.pop_comments(location.start); + .append(wrap_args( + false, + constructor.arguments.iter().map( + |RecordConstructorArg { + label, + annotation, + location, + .. + }| { + let arg_comments = self.pop_comments(location.start); - let arg = match label { - Some(l) => l.to_doc().append(": ").append(self.annotation(annotation)), - None => self.annotation(annotation), - }; + let arg = match label { + Some(l) => { + l.to_doc().append(": ").append(self.annotation(annotation)) + } + None => self.annotation(annotation), + }; - ( - commented( - self.doc_comments(location.start).append(arg).group(), - arg_comments, - ), - label.is_some(), - ) - }, - ))) + ( + commented( + self.doc_comments(location.start).append(arg).group(), + arg_comments, + ), + label.is_some(), + ) + }, + ), + )) .group() }; @@ -1247,30 +1272,72 @@ impl<'comments> Formatter<'comments> { &mut self, name: &'a str, args: &'a [TypedArg], + return_annotation: &'a Option, return_type: Arc, ) -> Document<'a> { - let mut printer = tipo::pretty::Printer::new(); - name.to_doc() - .append(self.docs_fn_args(args, &mut printer)) - .append(" -> ".to_doc()) - .append(printer.print(&return_type)) + let head = name + .to_doc() + .append(self.docs_fn_args(false, args)) + .append(" -> "); + + let tail = self.type_or_annotation(return_annotation, &return_type); + + let doc = head.append(tail.clone()).group(); + + // Wrap arguments on multi-lines if they are lengthy. + if doc + .clone() + .to_pretty_string(DOCS_MAX_COLUMNS) + .contains('\n') + { + let head = name + .to_doc() + .append(self.docs_fn_args(true, args)) + .append(" -> "); + head.append(tail).group() + } else { + doc + } } // Will always print the types, even if they were implicit in the original source - pub fn docs_fn_args<'a>( + pub fn docs_fn_args<'a>(&mut self, multiline: bool, args: &'a [TypedArg]) -> Document<'a> { + if multiline { + line().nest(INDENT).append(wrap_args( + true, + args.iter() + .map(|e| (self.docs_fn_arg(e).append(line()), false)), + )) + } else { + wrap_args(false, args.iter().map(|e| (self.docs_fn_arg(e), false))) + } + } + + fn docs_fn_arg<'a>(&mut self, arg: &'a Arg>) -> Document<'a> { + self.docs_fn_arg_name(&arg.arg_name) + .append(self.type_or_annotation(&arg.annotation, &arg.tipo)) + .group() + } + + fn docs_fn_arg_name<'a>(&mut self, arg_name: &'a ArgName) -> Document<'a> { + match arg_name { + ArgName::Named { .. } | ArgName::Discard { .. } => "".to_doc(), + ArgName::LabeledDiscard { label, .. } | ArgName::NamedLabeled { label, .. } => { + label.to_doc().append(": ") + } + } + } + + // Display type-annotation when available, or fallback to inferred type. + fn type_or_annotation<'a>( &mut self, - args: &'a [TypedArg], - printer: &mut tipo::pretty::Printer, + annotation: &'a Option, + type_info: &Arc, ) -> Document<'a> { - wrap_args(args.iter().map(|arg| { - ( - arg.arg_name - .to_doc() - .append(": ".to_doc().append(printer.print(&arg.tipo))) - .group(), - false, - ) - })) + match annotation { + Some(a) => self.annotation(a), + None => tipo::pretty::Printer::new().print(type_info), + } } fn wrap_expr<'a>(&mut self, expr: &'a UntypedExpr) -> Document<'a> { @@ -1403,7 +1470,10 @@ impl<'comments> Formatter<'comments> { Pattern::Tuple { elems, .. } => "#" .to_doc() - .append(wrap_args(elems.iter().map(|e| (self.pattern(e), false)))) + .append(wrap_args( + false, + elems.iter().map(|e| (self.pattern(e), false)), + )) .group(), Pattern::List { elements, tail, .. } => { @@ -1559,7 +1629,7 @@ impl<'a> Documentable<'a> for &'a BinOp { } } -pub fn wrap_args<'a, I>(args: I) -> Document<'a> +pub fn wrap_args<'a, I>(multiline: bool, args: I) -> Document<'a> where I: IntoIterator, bool)>, { @@ -1575,6 +1645,8 @@ where let (open_broken, open_unbroken, close) = if curly { (" {", " { ", "}") + } else if multiline { + ("( ", "( ", ")") } else { ("(", "(", ")") }; diff --git a/crates/project/src/docs.rs b/crates/project/src/docs.rs index a030ff7a..4517ed03 100644 --- a/crates/project/src/docs.rs +++ b/crates/project/src/docs.rs @@ -410,6 +410,7 @@ impl DocFunction { .docs_fn_signature( &func_def.name, &func_def.arguments, + &func_def.return_annotation, func_def.return_type.clone(), ) .to_pretty_string(MAX_COLUMNS),