Compare commits
No commits in common. "08ae603106743119c511d7be7a3e79f78b5de7c2" and "7a2c19af66c45911353133b096f08f094e308670" have entirely different histories.
08ae603106
...
7a2c19af66
28 changed files with 318 additions and 513 deletions
32
docs/external/graphviz.nml
vendored
32
docs/external/graphviz.nml
vendored
|
@ -1,32 +0,0 @@
|
|||
@import ../template.nml
|
||||
%<make_doc({"External Tools"}, "Graphviz", "Graphvis")>%
|
||||
|
||||
# Graphs from graphviz
|
||||
|
||||
[graph]
|
||||
digraph {
|
||||
bgcolor=transparent;
|
||||
|
||||
filelist [color=green, label="File List"];
|
||||
doclist [color=green, label="Document List"];
|
||||
iscached [shape=diamond, color=red, label="Cached?"];
|
||||
parse [color=white, label=Parse];
|
||||
compile [color=white, label=Compile];
|
||||
cache [shape=box, color=blue, label=Cache];
|
||||
|
||||
edge [color=gray]
|
||||
filelist -> iscached;
|
||||
iscached -> cache[dir=both];
|
||||
iscached -> doclist[label="+"];
|
||||
|
||||
iscached -> parse[label="No"];
|
||||
parse -> compile;
|
||||
compile -> cache[label="+"];
|
||||
compile -> doclist[label="+"];
|
||||
|
||||
buildnav [color=white, label="Build Navigation"];
|
||||
doclist -> buildnav;
|
||||
output [color=white, label="Output"];
|
||||
buildnav -> output;
|
||||
}
|
||||
[/graph]
|
5
docs/external/latex.nml
vendored
5
docs/external/latex.nml
vendored
|
@ -1,5 +1,8 @@
|
|||
@import ../template.nml
|
||||
%<make_doc({"External Tools"}, "LaTeX", "LaTeX")>%
|
||||
@compiler.output = latex.html
|
||||
@nav.title = LaTeX
|
||||
@nav.category = External Tools
|
||||
@html.page_title = Documentation | LaTeX
|
||||
|
||||
@LaTeX = $|[kind=inline, caption=LaTeX]\LaTeX|$
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
@import template.nml
|
||||
%<make_doc({}, "Index", "Index")>%
|
||||
@compiler.output = index.html
|
||||
@nav.title = Documentation
|
||||
@html.page_title = Documentation | Index
|
||||
|
||||
# Welcome to the NML documentation!
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
@import ../template.nml
|
||||
%<make_doc({"Lua"}, "Lua", "Lua Basics")>%
|
||||
@compiler.output = lua.html
|
||||
@nav.title = Lua
|
||||
@nav.category = Lua
|
||||
@html.page_title = Documentation | Lua
|
||||
|
||||
# Running lua code
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
@import ../template.nml
|
||||
%<make_doc({"Styles"}, "Basic", "Basic Styles")>%
|
||||
@compiler.output = basic.html
|
||||
@nav.title = Basic
|
||||
@nav.category = Styles
|
||||
@html.page_title = Documentation | Basic Styles
|
||||
|
||||
# Basic styles
|
||||
## Bold
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
@import ../template.nml
|
||||
%<make_doc({"Styles"}, "User-Defined", "User-Defined Styles")>%
|
||||
@compiler.output = user-defined.html
|
||||
@nav.title = User-Defined
|
||||
@nav.category = Styles
|
||||
@html.page_title = Documentation | User-Defined Styles
|
||||
|
||||
# TODO
|
||||
|
|
|
@ -6,22 +6,3 @@
|
|||
\definecolor{__color1}{HTML}{d5d5d5} \\
|
||||
\everymath{\color{__color1}\displaystyle}
|
||||
@tex.main.block_prepend = \color{__color1}
|
||||
|
||||
@<
|
||||
function make_doc(categories, title, page_title)
|
||||
-- Navigation
|
||||
nml.variable.insert("nav.title", title)
|
||||
if categories[1] ~= nil
|
||||
then
|
||||
nml.variable.insert("nav.category", categories[1])
|
||||
if categories[2] ~= nil
|
||||
then
|
||||
nml.variable.insert("nav.subcategory", categories[2])
|
||||
end
|
||||
end
|
||||
|
||||
-- HTML
|
||||
nml.variable.insert("html.page_title", "NML | " .. page_title)
|
||||
nml.variable.insert("compiler.output", page_title .. ".html")
|
||||
end
|
||||
>@
|
||||
|
|
|
@ -38,24 +38,6 @@ impl Compiler {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sanitizes text for a [`Target`]
|
||||
pub fn sanitize<S: AsRef<str>>(target: Target, str: S) -> String {
|
||||
match target {
|
||||
Target::HTML => str
|
||||
.as_ref()
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace("\"", """),
|
||||
_ => todo!("Sanitize not implemented"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a reference name
|
||||
pub fn refname<S: AsRef<str>>(target: Target, str: S) -> String {
|
||||
Self::sanitize(target, str).replace(' ', "_")
|
||||
}
|
||||
|
||||
/// Inserts or get a reference id for the compiled document
|
||||
///
|
||||
/// # Parameters
|
||||
|
@ -92,6 +74,18 @@ impl Compiler {
|
|||
self.cache.as_ref().map(RefCell::borrow_mut)
|
||||
}
|
||||
|
||||
pub fn sanitize<S: AsRef<str>>(target: Target, str: S) -> String {
|
||||
match target {
|
||||
Target::HTML => str
|
||||
.as_ref()
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace("\"", """),
|
||||
_ => todo!("Sanitize not implemented"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header(&self, document: &dyn Document) -> String {
|
||||
pub fn get_variable_or_error(
|
||||
document: &dyn Document,
|
||||
|
@ -115,11 +109,8 @@ impl Compiler {
|
|||
result += "<!DOCTYPE HTML><html><head>";
|
||||
result += "<meta charset=\"UTF-8\">";
|
||||
if let Some(page_title) = get_variable_or_error(document, "html.page_title") {
|
||||
result += format!(
|
||||
"<title>{}</title>",
|
||||
Compiler::sanitize(self.target(), page_title.to_string())
|
||||
)
|
||||
.as_str();
|
||||
result += format!("<title>{}</title>", Compiler::sanitize(self.target(), page_title.to_string()))
|
||||
.as_str();
|
||||
}
|
||||
|
||||
if let Some(css) = document.get_variable("html.css") {
|
||||
|
@ -129,7 +120,7 @@ impl Compiler {
|
|||
)
|
||||
.as_str();
|
||||
}
|
||||
result += r#"</head><body><div class="layout">"#;
|
||||
result += r#"</head><body><div id="layout">"#;
|
||||
|
||||
// TODO: TOC
|
||||
// TODO: Author, Date, Title, Div
|
||||
|
@ -157,7 +148,7 @@ impl Compiler {
|
|||
let header = self.header(document);
|
||||
|
||||
// Body
|
||||
let mut body = r#"<div class="content">"#.to_string();
|
||||
let mut body = r#"<div id="content">"#.to_string();
|
||||
for i in 0..borrow.len() {
|
||||
let elem = &borrow[i];
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ impl NavEntry {
|
|||
let mut result = String::new();
|
||||
match target {
|
||||
Target::HTML => {
|
||||
result += r#"<div class="navbar"><ul>"#;
|
||||
result += r#"<div id="navbar"><ul>"#;
|
||||
|
||||
fn process(
|
||||
target: Target,
|
||||
|
|
|
@ -544,7 +544,8 @@ impl RegexRule for CodeRule {
|
|||
reports
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||
let mut bindings = vec![];
|
||||
bindings.push((
|
||||
"push_inline".to_string(),
|
||||
|
@ -646,7 +647,7 @@ impl RegexRule for CodeRule {
|
|||
.unwrap(),
|
||||
));
|
||||
|
||||
Some(bindings)
|
||||
bindings
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,5 +80,5 @@ impl RegexRule for CommentRule {
|
|||
return reports;
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -371,5 +371,5 @@ impl RegexRule for GraphRule {
|
|||
}
|
||||
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -178,5 +178,5 @@ impl RegexRule for ImportRule {
|
|||
return result;
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -171,5 +171,5 @@ impl RegexRule for LinkRule {
|
|||
}
|
||||
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -337,5 +337,5 @@ impl Rule for ListRule
|
|||
}
|
||||
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@ use ariadne::Fmt;
|
|||
use ariadne::Label;
|
||||
use ariadne::Report;
|
||||
use ariadne::ReportKind;
|
||||
use mlua::Function;
|
||||
use mlua::Lua;
|
||||
use regex::Captures;
|
||||
use regex::Match;
|
||||
use regex::Regex;
|
||||
|
@ -520,7 +518,9 @@ impl RegexRule for MediaRule {
|
|||
reports
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -150,5 +150,5 @@ impl Rule for ParagraphRule {
|
|||
}
|
||||
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ impl RegexRule for RawRule {
|
|||
reports
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||
let mut bindings = vec![];
|
||||
|
||||
bindings.push((
|
||||
|
@ -270,7 +270,7 @@ impl RegexRule for RawRule {
|
|||
.unwrap(),
|
||||
));
|
||||
|
||||
Some(bindings)
|
||||
bindings
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ use ariadne::Fmt;
|
|||
use ariadne::Label;
|
||||
use ariadne::Report;
|
||||
use ariadne::ReportKind;
|
||||
use mlua::Function;
|
||||
use mlua::Lua;
|
||||
use regex::Captures;
|
||||
use regex::Match;
|
||||
use regex::Regex;
|
||||
|
@ -207,5 +205,7 @@ impl RegexRule for ReferenceRule {
|
|||
reports
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,5 +275,5 @@ impl RegexRule for ScriptRule {
|
|||
}
|
||||
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -38,14 +38,11 @@ impl Element for Section {
|
|||
fn as_referenceable(&self) -> Option<&dyn ReferenceableElement> { Some(self) }
|
||||
fn compile(&self, compiler: &Compiler, _document: &dyn Document) -> Result<String, String> {
|
||||
match compiler.target() {
|
||||
Target::HTML => {
|
||||
Ok(format!(
|
||||
r#"<h{0} id="{1}">{2}</h{0}>"#,
|
||||
Target::HTML => Ok(format!(
|
||||
"<h{0}>{1}</h{0}>",
|
||||
self.depth,
|
||||
Compiler::refname(compiler.target(), self.title.as_str()),
|
||||
Compiler::sanitize(compiler.target(), self.title.as_str())
|
||||
))
|
||||
},
|
||||
)),
|
||||
Target::LATEX => Err("Unimplemented compiler".to_string()),
|
||||
}
|
||||
}
|
||||
|
@ -59,27 +56,11 @@ impl ReferenceableElement for Section {
|
|||
fn compile_reference(
|
||||
&self,
|
||||
compiler: &Compiler,
|
||||
_document: &dyn Document,
|
||||
document: &dyn Document,
|
||||
reference: &super::reference::Reference,
|
||||
_refid: usize,
|
||||
refid: usize,
|
||||
) -> Result<String, String> {
|
||||
match compiler.target() {
|
||||
Target::HTML => {
|
||||
let caption = reference.caption().map_or(
|
||||
format!(
|
||||
"({})",
|
||||
Compiler::sanitize(compiler.target(), self.title.as_str())
|
||||
),
|
||||
|cap| cap.clone(),
|
||||
);
|
||||
|
||||
Ok(format!(
|
||||
"<a class=\"section-ref\" href=\"#{}\">{caption}</a>",
|
||||
Compiler::refname(compiler.target(), self.title.as_str())
|
||||
))
|
||||
}
|
||||
_ => todo!(""),
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,7 +235,7 @@ impl RegexRule for SectionRule {
|
|||
return result;
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||
let mut bindings = vec![];
|
||||
|
||||
bindings.push((
|
||||
|
@ -299,6 +280,6 @@ impl RegexRule for SectionRule {
|
|||
.unwrap(),
|
||||
));
|
||||
|
||||
Some(bindings)
|
||||
bindings
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,5 +183,5 @@ impl RegexRule for StyleRule
|
|||
}
|
||||
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -430,7 +430,7 @@ impl RegexRule for TexRule {
|
|||
}
|
||||
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -61,7 +61,7 @@ impl Rule for TextRule {
|
|||
panic!("Text cannot match");
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||
let mut bindings = vec![];
|
||||
bindings.push((
|
||||
"push".to_string(),
|
||||
|
@ -83,6 +83,6 @@ impl Rule for TextRule {
|
|||
.unwrap(),
|
||||
));
|
||||
|
||||
Some(bindings)
|
||||
bindings
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,109 +1,78 @@
|
|||
use crate::document::document::Document;
|
||||
use crate::document::variable::BaseVariable;
|
||||
use crate::document::variable::PathVariable;
|
||||
use crate::document::variable::Variable;
|
||||
use crate::lua::kernel::CTX;
|
||||
use crate::parser::parser::Parser;
|
||||
use crate::parser::parser::ReportColors;
|
||||
use crate::parser::rule::RegexRule;
|
||||
use crate::parser::source::Source;
|
||||
use crate::parser::source::Token;
|
||||
use ariadne::Fmt;
|
||||
use ariadne::Label;
|
||||
use ariadne::Report;
|
||||
use ariadne::ReportKind;
|
||||
use mlua::Function;
|
||||
use mlua::Lua;
|
||||
use mlua::{Function, Lua};
|
||||
use regex::Regex;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum VariableKind {
|
||||
Regular,
|
||||
Path,
|
||||
}
|
||||
|
||||
impl FromStr for VariableKind {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"regular" | "" => Ok(VariableKind::Regular),
|
||||
"path" | "'" => Ok(VariableKind::Path),
|
||||
_ => Err(format!("Uknnown variable kind: `{s}`")),
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::{document::document::Document, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token}}};
|
||||
use ariadne::{Report, Fmt, Label, ReportKind};
|
||||
use crate::document::variable::{BaseVariable, PathVariable, Variable};
|
||||
use std::{ops::Range, rc::Rc};
|
||||
|
||||
pub struct VariableRule {
|
||||
re: [Regex; 1],
|
||||
kinds: Vec<(String, String)>,
|
||||
kinds: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl VariableRule {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()],
|
||||
kinds: vec![("".into(), "Regular".into()), ("'".into(), "Path".into())],
|
||||
}
|
||||
re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()],
|
||||
kinds: vec![
|
||||
("".into(), "Regular".into()),
|
||||
("'".into(), "Path".into())
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_variable(
|
||||
&self,
|
||||
colors: &ReportColors,
|
||||
location: Token,
|
||||
kind: usize,
|
||||
name: String,
|
||||
value: String,
|
||||
) -> Result<Rc<dyn Variable>, String> {
|
||||
match self.kinds[kind].0.as_str() {
|
||||
"" => Ok(Rc::new(BaseVariable::new(location, name, value))),
|
||||
"'" => {
|
||||
match std::fs::canonicalize(value.as_str()) // TODO: not canonicalize
|
||||
pub fn make_variable(&self, colors: &ReportColors, location: Token, kind: usize, name: String, value: String) -> Result<Rc<dyn Variable>, String>
|
||||
{
|
||||
match self.kinds[kind].0.as_str()
|
||||
{
|
||||
"" => {
|
||||
Ok(Rc::new(BaseVariable::new(location, name, value)))
|
||||
}
|
||||
"'" => {
|
||||
match std::fs::canonicalize(value.as_str()) // TODO: not canonicalize
|
||||
{
|
||||
Ok(path) => Ok(Rc::new(PathVariable::new(location, name, path))),
|
||||
Err(e) => Err(format!("Unable to canonicalize path `{}`: {}",
|
||||
value.fg(colors.highlight),
|
||||
e.to_string()))
|
||||
}
|
||||
}
|
||||
_ => panic!("Unhandled variable kind"),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Unhandled variable kind")
|
||||
}
|
||||
}
|
||||
|
||||
// Trim and check variable name for validity
|
||||
pub fn validate_name<'a>(
|
||||
colors: &ReportColors,
|
||||
original_name: &'a str,
|
||||
) -> Result<&'a str, String> {
|
||||
let name = original_name.trim_start().trim_end();
|
||||
if name.contains("%") {
|
||||
return Err(format!("Name cannot contain '{}'", "%".fg(colors.info)));
|
||||
}
|
||||
return Ok(name);
|
||||
}
|
||||
// Trim and check variable name for validity
|
||||
pub fn validate_name<'a>(colors: &ReportColors, original_name: &'a str) -> Result<&'a str, String>
|
||||
{
|
||||
let name = original_name.trim_start().trim_end();
|
||||
if name.contains("%")
|
||||
{
|
||||
return Err(format!("Name cannot contain '{}'",
|
||||
"%".fg(colors.info)));
|
||||
}
|
||||
return Ok(name);
|
||||
}
|
||||
|
||||
pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result<String, String> {
|
||||
pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result<String, String>
|
||||
{
|
||||
let mut escaped = 0usize;
|
||||
let mut result = String::new();
|
||||
for c in original_value.trim_start().trim_end().chars() {
|
||||
if c == '\\' {
|
||||
escaped += 1
|
||||
} else if c == '\n' {
|
||||
if c == '\\' { escaped += 1 }
|
||||
else if c == '\n' {
|
||||
match escaped {
|
||||
0 => return Err("Unknown error wile capturing variable".to_string()),
|
||||
// Remove '\n'
|
||||
1 => {}
|
||||
1 => {},
|
||||
// Insert '\n'
|
||||
_ => {
|
||||
result.push(c);
|
||||
(0..escaped - 2).for_each(|_| result.push('\\'));
|
||||
(0..escaped-2).for_each(|_| result.push('\\'));
|
||||
}
|
||||
}
|
||||
escaped = 0;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
(0..escaped).for_each(|_| result.push('\\'));
|
||||
escaped = 0;
|
||||
result.push(c);
|
||||
|
@ -112,7 +81,7 @@ impl VariableRule {
|
|||
(0..escaped).for_each(|_| result.push('\\'));
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RegexRule for VariableRule {
|
||||
|
@ -120,306 +89,233 @@ impl RegexRule for VariableRule {
|
|||
|
||||
fn regexes(&self) -> &[Regex] { &self.re }
|
||||
|
||||
fn on_regex_match<'a>(
|
||||
&self,
|
||||
_: usize,
|
||||
parser: &dyn Parser,
|
||||
document: &'a dyn Document,
|
||||
token: Token,
|
||||
matches: regex::Captures,
|
||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
||||
fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: regex::Captures) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>
|
||||
{
|
||||
let mut result = vec![];
|
||||
// [Optional] variable kind
|
||||
let var_kind = match matches.get(1) {
|
||||
// [Optional] variable kind
|
||||
let var_kind = match matches.get(1)
|
||||
{
|
||||
Some(kind) => {
|
||||
// Find kind
|
||||
let r = self
|
||||
.kinds
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_i, (ref char, ref _name))| char == kind.as_str());
|
||||
// Find kind
|
||||
let r = self.kinds.iter().enumerate().find(|(_i, (ref char, ref _name))| {
|
||||
char == kind.as_str() });
|
||||
|
||||
// Unknown kind specified
|
||||
if r.is_none() {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), kind.start())
|
||||
.with_message("Unknown variable kind")
|
||||
.with_label(
|
||||
Label::new((token.source(), kind.range()))
|
||||
.with_message(format!(
|
||||
"Variable kind `{}` is unknown",
|
||||
kind.as_str().fg(parser.colors().highlight)
|
||||
))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.with_help(format!(
|
||||
"Leave empty for regular variables. Available variable kinds:{}",
|
||||
self.kinds.iter().skip(1).fold(
|
||||
"".to_string(),
|
||||
|acc, (char, name)| {
|
||||
acc + format!(
|
||||
"\n - `{}` : {}",
|
||||
char.fg(parser.colors().highlight),
|
||||
name.fg(parser.colors().info)
|
||||
)
|
||||
.as_str()
|
||||
}
|
||||
)
|
||||
))
|
||||
.finish(),
|
||||
);
|
||||
// Unknown kind specified
|
||||
if r.is_none()
|
||||
{
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), kind.start())
|
||||
.with_message("Unknown variable kind")
|
||||
.with_label(
|
||||
Label::new((token.source(), kind.range()))
|
||||
.with_message(format!("Variable kind `{}` is unknown",
|
||||
kind.as_str().fg(parser.colors().highlight)))
|
||||
.with_color(parser.colors().error))
|
||||
.with_help(format!("Leave empty for regular variables. Available variable kinds:{}",
|
||||
self.kinds.iter().skip(1).fold("".to_string(), |acc, (char, name)| {
|
||||
acc + format!("\n - `{}` : {}",
|
||||
char.fg(parser.colors().highlight),
|
||||
name.fg(parser.colors().info)).as_str()
|
||||
})))
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
r.unwrap().0
|
||||
r.unwrap().0
|
||||
}
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let var_name = match matches.get(2) {
|
||||
Some(name) => match VariableRule::validate_name(&parser.colors(), name.as_str()) {
|
||||
Ok(var_name) => var_name,
|
||||
Err(msg) => {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!(
|
||||
"Variable name `{}` is not allowed. {msg}",
|
||||
name.as_str().fg(parser.colors().highlight)
|
||||
))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.finish(),
|
||||
);
|
||||
let var_name = match matches.get(2)
|
||||
{
|
||||
Some(name) => {
|
||||
match VariableRule::validate_name(&parser.colors(), name.as_str())
|
||||
{
|
||||
Ok(var_name) => var_name,
|
||||
Err(msg) => {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!("Variable name `{}` is not allowed. {msg}",
|
||||
name.as_str().fg(parser.colors().highlight)))
|
||||
.with_color(parser.colors().error))
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
},
|
||||
_ => panic!("Unknown variable name"),
|
||||
};
|
||||
return result;
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => panic!("Unknown variable name")
|
||||
};
|
||||
|
||||
let var_value = match matches.get(3) {
|
||||
Some(value) => match VariableRule::validate_value(&parser.colors(), value.as_str()) {
|
||||
Ok(var_value) => var_value,
|
||||
Err(msg) => {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), value.start())
|
||||
.with_message("Invalid variable value")
|
||||
.with_label(
|
||||
Label::new((token.source(), value.range()))
|
||||
.with_message(format!(
|
||||
"Variable value `{}` is not allowed. {msg}",
|
||||
value.as_str().fg(parser.colors().highlight)
|
||||
))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.finish(),
|
||||
);
|
||||
let var_value = match matches.get(3)
|
||||
{
|
||||
Some(value) => {
|
||||
match VariableRule::validate_value(&parser.colors(), value.as_str())
|
||||
{
|
||||
Ok(var_value) => var_value,
|
||||
Err(msg ) => {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), value.start())
|
||||
.with_message("Invalid variable value")
|
||||
.with_label(
|
||||
Label::new((token.source(), value.range()))
|
||||
.with_message(format!("Variable value `{}` is not allowed. {msg}",
|
||||
value.as_str().fg(parser.colors().highlight)))
|
||||
.with_color(parser.colors().error))
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
},
|
||||
_ => panic!("Invalid variable value"),
|
||||
};
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Invalid variable value")
|
||||
};
|
||||
|
||||
match self.make_variable(
|
||||
&parser.colors(),
|
||||
token.clone(),
|
||||
var_kind,
|
||||
var_name.to_string(),
|
||||
var_value,
|
||||
) {
|
||||
Ok(variable) => document.add_variable(variable),
|
||||
Err(msg) => {
|
||||
let m = matches.get(0).unwrap();
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), m.start())
|
||||
.with_message("Unable to create variable")
|
||||
.with_label(
|
||||
Label::new((token.source(), m.start() + 1..m.end()))
|
||||
.with_message(format!(
|
||||
"Unable to create variable `{}`. {}",
|
||||
var_name.fg(parser.colors().highlight),
|
||||
msg
|
||||
))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.finish(),
|
||||
);
|
||||
match self.make_variable(&parser.colors(), token.clone(), var_kind, var_name.to_string(), var_value)
|
||||
{
|
||||
Ok(variable) => document.add_variable(variable),
|
||||
Err(msg) => {
|
||||
let m = matches.get(0).unwrap();
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), m.start())
|
||||
.with_message("Unable to create variable")
|
||||
.with_label(
|
||||
Label::new((token.source(), m.start()+1 .. m.end() ))
|
||||
.with_message(format!("Unable to create variable `{}`. {}",
|
||||
var_name.fg(parser.colors().highlight),
|
||||
msg))
|
||||
.with_color(parser.colors().error))
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||
let mut bindings = vec![];
|
||||
bindings.push((
|
||||
"insert".to_string(),
|
||||
lua.create_function(|_, (name, value): (String, String)| {
|
||||
CTX.with_borrow(|ctx| {
|
||||
ctx.as_ref().map(|ctx| {
|
||||
let var = Rc::new(BaseVariable::new(ctx.location.clone(), name, value));
|
||||
ctx.document.add_variable(var);
|
||||
})
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.unwrap(),
|
||||
));
|
||||
bindings.push((
|
||||
"get".to_string(),
|
||||
lua.create_function(|_, name: String| {
|
||||
let mut value: Option<String> = None;
|
||||
CTX.with_borrow(|ctx| {
|
||||
ctx.as_ref().map(|ctx| {
|
||||
if let Some(var) = ctx.document.get_variable(name.as_str())
|
||||
{
|
||||
value = Some(var.to_string());
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
Ok(value)
|
||||
})
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
Some(bindings)
|
||||
}
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
||||
pub struct VariableSubstitutionRule {
|
||||
pub struct VariableSubstitutionRule
|
||||
{
|
||||
re: [Regex; 1],
|
||||
}
|
||||
|
||||
impl VariableSubstitutionRule {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
re: [Regex::new(r"%(.*?)%").unwrap()],
|
||||
}
|
||||
re: [Regex::new(r"%(.*?)%").unwrap()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RegexRule for VariableSubstitutionRule {
|
||||
fn name(&self) -> &'static str { "Variable Substitution" }
|
||||
impl RegexRule for VariableSubstitutionRule
|
||||
{
|
||||
fn name(&self) -> &'static str { "Variable Substitution" }
|
||||
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
fn regexes(&self) -> &[regex::Regex] { &self.re }
|
||||
|
||||
fn on_regex_match<'a>(
|
||||
&self,
|
||||
_index: usize,
|
||||
parser: &dyn Parser,
|
||||
document: &'a dyn Document<'a>,
|
||||
token: Token,
|
||||
matches: regex::Captures,
|
||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
||||
fn on_regex_match<'a>(&self, _index: usize, parser: &dyn Parser, document: &'a dyn Document<'a>, token: Token, matches: regex::Captures) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
||||
let mut result = vec![];
|
||||
|
||||
let variable = match matches.get(1) {
|
||||
Some(name) => {
|
||||
// Empty name
|
||||
if name.as_str().is_empty() {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Empty variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), matches.get(0).unwrap().range()))
|
||||
.with_message(format!("Missing variable name for substitution"))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.finish(),
|
||||
);
|
||||
let variable = match matches.get(1)
|
||||
{
|
||||
Some(name) => {
|
||||
// Empty name
|
||||
if name.as_str().is_empty()
|
||||
{
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Empty variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), matches.get(0).unwrap().range()))
|
||||
.with_message(format!("Missing variable name for substitution"))
|
||||
.with_color(parser.colors().error))
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
// Leading spaces
|
||||
else if name.as_str().trim_start() != name.as_str() {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!("Variable names contains leading spaces"))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.with_help("Remove leading spaces")
|
||||
.finish(),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
// Leading spaces
|
||||
else if name.as_str().trim_start() != name.as_str()
|
||||
{
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!("Variable names contains leading spaces"))
|
||||
.with_color(parser.colors().error))
|
||||
.with_help("Remove leading spaces")
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
// Trailing spaces
|
||||
else if name.as_str().trim_end() != name.as_str() {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!(
|
||||
"Variable names contains trailing spaces"
|
||||
))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.with_help("Remove trailing spaces")
|
||||
.finish(),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
// Trailing spaces
|
||||
else if name.as_str().trim_end() != name.as_str()
|
||||
{
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!("Variable names contains trailing spaces"))
|
||||
.with_color(parser.colors().error))
|
||||
.with_help("Remove trailing spaces")
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Invalid name
|
||||
match VariableRule::validate_name(&parser.colors(), name.as_str()) {
|
||||
Err(msg) => {
|
||||
match VariableRule::validate_name(&parser.colors(), name.as_str())
|
||||
{
|
||||
Err(msg) =>
|
||||
{
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(msg)
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.finish(),
|
||||
);
|
||||
.with_message("Invalid variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(msg)
|
||||
.with_color(parser.colors().error))
|
||||
.finish());
|
||||
|
||||
return result;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// Get variable
|
||||
match document.get_variable(name.as_str()) {
|
||||
None => {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Unknown variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!(
|
||||
"Unable to find variable with name: `{}`",
|
||||
name.as_str().fg(parser.colors().highlight)
|
||||
))
|
||||
.with_color(parser.colors().error),
|
||||
)
|
||||
.finish(),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
Some(var) => var,
|
||||
}
|
||||
}
|
||||
_ => panic!("Unknown error"),
|
||||
};
|
||||
match document.get_variable(name.as_str())
|
||||
{
|
||||
None => {
|
||||
result.push(
|
||||
Report::build(ReportKind::Error, token.source(), name.start())
|
||||
.with_message("Unknown variable name")
|
||||
.with_label(
|
||||
Label::new((token.source(), name.range()))
|
||||
.with_message(format!("Unable to find variable with name: `{}`",
|
||||
name.as_str().fg(parser.colors().highlight)))
|
||||
.with_color(parser.colors().error))
|
||||
.finish());
|
||||
return result;
|
||||
}
|
||||
Some(var) => var,
|
||||
}
|
||||
},
|
||||
_ => panic!("Unknown error")
|
||||
};
|
||||
|
||||
variable.parse(token, parser, document);
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||
// TODO
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
||||
}
|
||||
|
|
|
@ -34,18 +34,15 @@ impl Kernel {
|
|||
|
||||
for rule in parser.rules()
|
||||
{
|
||||
if let Some(bindings) = rule.lua_bindings(&lua)
|
||||
let table = lua.create_table().unwrap();
|
||||
let name = rule.name().to_lowercase();
|
||||
|
||||
for (fun_name, fun) in rule.lua_bindings(&lua)
|
||||
{
|
||||
let table = lua.create_table().unwrap();
|
||||
let name = rule.name().to_lowercase();
|
||||
|
||||
for (fun_name, fun) in bindings
|
||||
{
|
||||
table.set(fun_name, fun).unwrap();
|
||||
}
|
||||
|
||||
nml_table.set(name, table).unwrap();
|
||||
table.set(fun_name, fun).unwrap();
|
||||
}
|
||||
|
||||
nml_table.set(name, table).unwrap();
|
||||
}
|
||||
lua.globals().set("nml", nml_table).unwrap();
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ pub trait Rule {
|
|||
match_data: Option<Box<dyn Any>>,
|
||||
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>);
|
||||
/// Export bindings to lua
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>>;
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>;
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for dyn Rule {
|
||||
|
@ -89,7 +89,7 @@ pub trait RegexRule {
|
|||
matches: regex::Captures,
|
||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>;
|
||||
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>>;
|
||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>;
|
||||
}
|
||||
|
||||
impl<T: RegexRule> Rule for T {
|
||||
|
@ -144,7 +144,7 @@ impl<T: RegexRule> Rule for T {
|
|||
);
|
||||
}
|
||||
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
||||
self.lua_bindings(lua)
|
||||
}
|
||||
}
|
||||
|
|
52
style.css
52
style.css
|
@ -2,19 +2,9 @@ body {
|
|||
background-color: #1b1b1d;
|
||||
color: #c5c5c5;
|
||||
font-family: sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 99ch;
|
||||
max-width: 90ch;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Styles */
|
||||
|
@ -39,18 +29,13 @@ a.inline-code {
|
|||
}
|
||||
|
||||
/* Navbar */
|
||||
.navbar {
|
||||
display: none;
|
||||
|
||||
#navbar {
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: max(calc((100vw - 99ch) / 2 - 15vw), 24ch);
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
margin-right: 1em;
|
||||
|
||||
width: max(16vw, 20ch);
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
overscroll-behavior-y: contain;
|
||||
|
||||
|
@ -61,53 +46,44 @@ a.inline-code {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media (min-width: 130ch) {
|
||||
.navbar {
|
||||
display: block;
|
||||
}
|
||||
.container {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
#navbar a {
|
||||
color: #ffb454;
|
||||
|
||||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.navbar li {
|
||||
#navbar li {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-left: 1em;
|
||||
margin-left: 0em;
|
||||
}
|
||||
|
||||
.navbar ul {
|
||||
#navbar ul {
|
||||
margin-left: 0em;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.navbar summary{
|
||||
#navbar summary{
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navbar summary::marker,
|
||||
.navbar summary::-webkit-details-marker{
|
||||
#navbar summary::marker,
|
||||
#navbar summary::-webkit-details-marker{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar summary:focus{
|
||||
#navbar summary:focus{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.navbar summary:focus-visible{
|
||||
#navbar summary:focus-visible{
|
||||
outline: 1px dotted #000;
|
||||
}
|
||||
|
||||
.navbar summary:before {
|
||||
#navbar summary:before {
|
||||
content: "+";
|
||||
color: #ffb454;
|
||||
float: left;
|
||||
|
@ -115,7 +91,7 @@ a.inline-code {
|
|||
width: 1em;
|
||||
}
|
||||
|
||||
.navbar details[open] > summary:before {
|
||||
#navbar details[open] > summary:before {
|
||||
content: "–";
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue