Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From sidoc-0.1.0 To sidoc-0.1.1
2024-11-07
| ||
09:13 | change log. check-in: ef4f5138fd user: jan tags: trunk | |
08:53 | Update crate metadata. Happy pedantic clippy. check-in: c84ce1ad85 user: jan tags: trunk, sidoc-0.1.1 | |
2024-11-06
| ||
18:42 | Happy pedantic clippy. check-in: c1d63406c5 user: jan tags: trunk | |
2022-09-29
| ||
18:48 | Move repo. Clippy. check-in: 98b35525c4 user: jan tags: trunk | |
2020-09-12
| ||
13:56 | Ignore gitignore. check-in: 4bf4749324 user: jan tags: trunk, sidoc-0.1.0 | |
13:54 | Move from temporary repository. check-in: b274896be6 user: jan tags: trunk | |
Changes to .efiles.
1 | Cargo.toml | > > > | > > > > | 1 2 3 4 5 6 7 8 9 10 | Cargo.toml README.md www/index.md www/changelog.md src/err.rs src/lib.rs src/builder.rs src/doc.rs src/render.rs tests/*.rs |
Changes to .fossil-settings/ignore-glob.
1 | .*.swp | < | 1 2 3 | .*.swp Cargo.lock target |
Changes to Cargo.toml.
1 2 | [package] name = "sidoc" | | < | > > | | > > > > > > > | > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | [package] name = "sidoc" version = "0.1.1" edition = "2021" license = "0BSD" # https://crates.io/category_slugs categories = [ "template-engine" ] keywords = [ "text", "document", "html" ] repository = "https://repos.qrnch.tech/pub/sidoc" description = "Generate structured/scoped indented documents." exclude = [ ".fossil-settings", ".efiles", ".fslckout", "www", "bacon.toml", "rustfmt.toml" ] # https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section [badges] maintenance = { status = "passively-maintained" } [dependencies] [lints.clippy] all = { level = "warn", priority = -1 } pedantic = { level = "warn", priority = -1 } nursery = { level = "warn", priority = -1 } cargo = { level = "warn", priority = -1 } |
Added README.md.
> > > > | 1 2 3 4 | # sidoc Template engine designed to generate indented documents. |
Added bacon.toml.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | # This is a configuration file for the bacon tool # # Complete help on configuration: https://dystroy.org/bacon/config/ # # You may check the current default at # https://github.com/Canop/bacon/blob/main/defaults/default-bacon.toml default_job = "clippy-all" [jobs.check] command = ["cargo", "check", "--color", "always"] need_stdout = false [jobs.check-all] command = ["cargo", "check", "--all-targets", "--color", "always"] need_stdout = false # Run clippy on the default target [jobs.clippy] command = [ "cargo", "clippy", "--color", "always", ] need_stdout = false # Run clippy on all targets # To disable some lints, you may change the job this way: # [jobs.clippy-all] # command = [ # "cargo", "clippy", # "--all-targets", # "--color", "always", # "--", # "-A", "clippy::bool_to_int_with_if", # "-A", "clippy::collapsible_if", # "-A", "clippy::derive_partial_eq_without_eq", # ] # need_stdout = false [jobs.clippy-all] command = [ "cargo", "clippy", "--all-targets", "--color", "always", ] need_stdout = false # This job lets you run # - all tests: bacon test # - a specific test: bacon test -- config::test_default_files # - the tests of a package: bacon test -- -- -p config [jobs.test] command = [ "cargo", "test", "--color", "always", "--", "--color", "always", # see https://github.com/Canop/bacon/issues/124 ] need_stdout = true [jobs.nextest] command = [ "cargo", "nextest", "run", "--color", "always", "--hide-progress-bar", "--failure-output", "final" ] need_stdout = true analyzer = "nextest" [jobs.doc] command = ["cargo", "doc", "--color", "always", "--no-deps"] need_stdout = false # If the doc compiles, then it opens in your browser and bacon switches # to the previous job [jobs.doc-open] command = ["cargo", "doc", "--color", "always", "--no-deps", "--open"] need_stdout = false on_success = "back" # so that we don't open the browser at each change # You can run your application and have the result displayed in bacon, # if it makes sense for this crate. # Don't forget the `--color always` part or the errors won't be # properly parsed. [jobs.run] command = [ "cargo", "run", "--color", "always", # put launch parameters for your program behind a `--` separator ] need_stdout = true allow_warnings = true background = true # Run your long-running application (eg server) and have the result displayed in bacon. # For programs that never stop (eg a server), `background` is set to false # to have the cargo run output immediately displayed instead of waiting for # program's end. # 'on_change_strategy' is set to `kill_then_restart` to have your program restart # on every change (an alternative would be to use the 'F5' key manually in bacon). # If you often use this job, it makes sense to override the 'r' key by adding # a binding `r = job:run-long` at the end of this file . [jobs.run-long] command = [ "cargo", "run", "--color", "always", # put launch parameters for your program behind a `--` separator ] need_stdout = true allow_warnings = true background = false on_change_strategy = "kill_then_restart" # This parameterized job runs the example of your choice, as soon # as the code compiles. # Call it as # bacon ex -- my-example [jobs.ex] command = ["cargo", "run", "--color", "always", "--example"] need_stdout = true allow_warnings = true # You may define here keybindings that would be specific to # a project, for example a shortcut to launch a specific job. # Shortcuts to internal functions (scrolling, toggling, etc.) # should go in your personal global prefs.toml file instead. [keybindings] # alt-m = "job:my-job" c = "job:clippy-all" # comment this to have 'c' run clippy on only the default target |
Changes to src/builder.rs.
1 2 3 4 5 6 7 8 9 10 11 | use crate::{Doc, Error, Node}; /// Constructor for `Doc` objects. pub struct Builder { nodes: Vec<Node>, scope_stack: Vec<Option<String>> } impl Builder { /// Create a new `Doc` builder context. pub fn new() -> Self { | > > | < < < > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | use crate::{Doc, Error, Node}; /// Constructor for `Doc` objects. #[derive(Default)] pub struct Builder { nodes: Vec<Node>, scope_stack: Vec<Option<String>> } impl Builder { /// Create a new `Doc` builder context. #[must_use] pub fn new() -> Self { Self::default() } /// Begin a scope, pushing an optional scope terminator to the internal scope /// stack. /// /// If the scope generated using a terminator line, that line will appended /// to the document when the scope is closed using the `exit()` method. #[allow(clippy::needless_pass_by_value)] pub fn scope<L: ToString, K: ToString>( &mut self, begin_line: L, term_line: Option<K> ) -> &mut Self { self.nodes.push(Node::BeginScope(begin_line.to_string())); if let Some(ln) = term_line { self.scope_stack.push(Some(ln.to_string())); } else { self.scope_stack.push(None); } self } /// Leave a previously entered scope. /// /// If the `scope()` call that created the current scope /// /// # Panics /// The scope stack must not be empty. pub fn exit(&mut self) -> &mut Self { if let Some(s) = self.scope_stack.pop().unwrap() { self.nodes.push(Node::EndScope(Some(s))); } else { self.nodes.push(Node::EndScope(None)); } self } /// Leave previously entered scope, adding a line passed by the caller rather /// than the scope stack. /// /// # Panics /// The scope stack must not be empty. #[allow(clippy::needless_pass_by_value)] pub fn exit_line<L: ToString>(&mut self, line: L) -> &mut Self { let _ = self.scope_stack.pop().unwrap(); self.nodes.push(Node::EndScope(Some(line.to_string()))); self } /// Add a new line at current scope. #[allow(clippy::needless_pass_by_value)] pub fn line<L: ToString>(&mut self, line: L) -> &mut Self { self.nodes.push(Node::Line(line.to_string())); self } /// Add a named optional reference. /// /// References are placeholders for other documents. An optional reference /// means that this reference does not need to be resolved by the renderer. #[allow(clippy::needless_pass_by_value)] pub fn optref<N: ToString>(&mut self, name: N) -> &mut Self { self.nodes.push(Node::OptRef(name.to_string())); self } /// Add a named required reference. /// /// References are placeholders for other documents. A required reference /// must be resolved by the renderer or it will return an error to its /// caller. #[allow(clippy::needless_pass_by_value)] pub fn reqref<N: ToString>(&mut self, name: N) -> &mut Self { self.nodes.push(Node::ReqRef(name.to_string())); self } /// Generate a `Doc` object from this document. /// /// The document must be properly nested before calling this function, /// meaning all scopes it opened must be closed. /// /// # Errors /// [`Error::BadNesting`] means one or more scopes are still open. pub fn build(self) -> Result<Doc, Error> { if self.scope_stack.is_empty() { Ok(Doc { nodes: self.nodes }) } else { Err(Error::BadNesting(format!( "{} scope(s) remaining", self.scope_stack.len() ))) } } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/doc.rs.
1 2 3 4 5 6 7 8 9 | use crate::Node; /// A "Doc" represents a set of lines and references to other Doc's. pub struct Doc { pub(crate) nodes: Vec<Node> } impl Doc { pub fn new() -> Self { | > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | use crate::Node; /// A "Doc" represents a set of lines and references to other Doc's. #[derive(Default)] pub struct Doc { pub(crate) nodes: Vec<Node> } impl Doc { #[must_use] pub fn new() -> Self { Self::default() } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/err.rs.
1 2 3 4 5 6 7 8 9 10 11 12 | use std::fmt; #[derive(Debug)] pub enum Error { BadRef(String), BadNesting(String) } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | use std::fmt; #[derive(Debug)] pub enum Error { BadRef(String), BadNesting(String) } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::BadRef(s) => write!(f, "Bad reference error; {s}"), Self::BadNesting(s) => write!(f, "Bad nesting error; {s}") } } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/render.rs.
|
| | < > < | < | | | > > > > > > > > > > > > > | < | < | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | use std::{collections::HashMap, sync::Arc}; use crate::{Doc, Error, Node}; #[allow(clippy::module_name_repetitions)] pub struct RenderContext { ichar: char, iwidth: usize, dict: HashMap<String, Arc<Doc>> } impl Default for RenderContext { fn default() -> Self { Self { ichar: ' ', iwidth: 2, dict: HashMap::new() } } } impl RenderContext { /// Create a new render context object. #[must_use] pub fn new() -> Self { Self::default() } /// Add a shared `Doc` document to the render context. #[allow(clippy::needless_pass_by_value)] pub fn doc<N: ToString>(&mut self, id: N, doc: Arc<Doc>) { self.dict.insert(id.to_string(), Arc::clone(&doc)); } /// Render a root `Doc`, resolving all references. /// /// # Errors /// [`Error::BadRef`] means a referenced document does not exist. pub fn render(&self, name: &str) -> Result<String, Error> { struct IterNode<'a> { lst: &'a Vec<Node>, idx: usize } let mut iterstack = Vec::new(); let mut out = String::new(); let mut indent: usize = 0; // Generate single indent string let istr = self.ichar.to_string().repeat(self.iwidth); if let Some(dict) = self.dict.get(name) { iterstack.push(IterNode { lst: &dict.nodes, idx: 0 }); } else { return Err(Error::BadRef(format!("Missing root document '{name}'"))); } 'outer: while let Some(mut it) = iterstack.pop() { while it.idx < it.lst.len() { match &it.lst[it.idx] { Node::BeginScope(s) => { let is = istr.repeat(indent); out.push_str(&is); out.push_str(s); out.push('\n'); indent += 1; } Node::EndScope(s) => { indent -= 1; if let Some(s) = s { let is = istr.repeat(indent); out.push_str(&is); out.push_str(s); out.push('\n'); } } Node::Line(s) => { let is = istr.repeat(indent); out.push_str(&is); out.push_str(s); out.push('\n'); } Node::OptRef(name) => { if let Some(dict) = self.dict.get(name) { iterstack.push(IterNode { lst: it.lst, idx: it.idx + 1 |
︙ | ︙ | |||
96 97 98 99 100 101 102 | }); iterstack.push(IterNode { lst: &dict.nodes, idx: 0 }); continue 'outer; | < > | | < | < | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | }); iterstack.push(IterNode { lst: &dict.nodes, idx: 0 }); continue 'outer; } return Err(Error::BadRef(format!( "Missing required document '{name}'" ))); } } it.idx += 1; } } Ok(out) } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Added www/changelog.md.
> > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Change Log ⚠️ indicates a breaking change. ## [Unreleased] [Details](/vdiff?from=sidoc-0.1.0&to=trunk) ### Added - Derive `Default` on `Doc` and `RenderContext` ### Changed ### Removed --- ## [0.1.0] - 2020-09-12 Initial release |
Added www/index.md.
> > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # sidoc Template engine designed to generate indented documents. ## Change log The details of changes can always be found in the timeline, but for a high-level view of changes between released versions there's a manually maintained [Change Log](./changelog.md). ## Project Status sidoc is passively maintained. It will receive updates and fixes and needed, but is currently considered to be feature complete. |