commit 362c6156dbf8d8cb402215b241898dfbc96ad4fd
parent 71f2b6bd4568ec40a795a2ebba824f52d511f2ed
Author: Demonstrandum <moi@knutsen.co>
Date:   Sat, 10 Oct 2020 21:27:24 +0100
Allow input from stdin.
Diffstat:
7 files changed, 99 insertions(+), 44 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -83,7 +83,7 @@ dependencies = [
 
 [[package]]
 name = "seam"
-version = "0.1.2"
+version = "0.1.3"
 dependencies = [
  "chrono",
  "colored",
diff --git a/Cargo.toml b/Cargo.toml
@@ -4,7 +4,7 @@ description = "Symbolic Expressions As Markup."
 keywords = ["markup", "lisp", "macro", "symbolic-expression", "sexp"]
 license-file = "LICENSE"
 homepage = "https://git.knutsen.co/seam"
-version = "0.1.2"
+version = "0.1.3"
 authors = ["Demonstrandum <moi@knutsen.co>"]
 edition = "2018"
 
diff --git a/README.md b/README.md
@@ -21,6 +21,40 @@ client.
  - HTML
  - CSS
 
+### Using The Binary
+
+Providing you have installed `seam` with
+```sh
+cargo install seam
+```
+
+You may use it by doing
+```sh
+seam test.sex --html > test.html
+```
+
+`test.sex` contains your symbolic-expressions, which is used to generate
+HTML, saved in `test.html`.
+
+Likewise, you may do
+```sh
+cat test.sex | seam --html > test.html
+```
+or
+```sh
+seam --html <<< "(p Hello World)"
+#stdout:
+#   <!DOCTYPE html>
+#   <html>
+#   <head></head>
+#   <body>
+#   <p>Hello World</p>
+#   <!-- Generated by SEAM, from symbolic-expressions into HTML. -->
+#   </body>
+#   </html>
+```
+
+
 ## TODO
  - Caching or checking time-stamps as to not regenerate unmodified source files.
  - HTML object `style="..."` object should handle s-expressions well, (e.g. `(p :style (:color red :border none) Hello World)`)
@@ -35,13 +69,3 @@ client.
    `(+ 1 2)` with Chez-Scheme LISP, and places the result in the source
    (i.e. `3`).
 
-### Using The Binary
-
-(Providing you have cloned this repo, and `cd`'d into it)
-
-```console
-cargo run test.sex --html > test.html
-```
-
-`test.sex` contains your symbolic-expressions, which is used to generate
-HTML, saved in `test.html`.
diff --git a/src/bin.rs b/src/bin.rs
@@ -1,7 +1,7 @@
 use seam;
 use seam::assemble::MarkupDisplay;
 
-use std::env;
+use std::{io, env};
 use std::path::PathBuf;
 use std::error::Error;
 
@@ -22,6 +22,7 @@ fn main() -> Result<(), Box<dyn Error>> {
 
     let mut files = Vec::new();
     let mut target = "";
+    let mut from_stdin = false;
 
     for arg in args {
         if arg.chars().nth(0) == Some('-') {
@@ -38,6 +39,9 @@ fn main() -> Result<(), Box<dyn Error>> {
                         major, minor, tiny).bold());
                     std::process::exit(0);
                 },
+                "" => {
+                    from_stdin = true;
+                },
                 _ => argument_fatal(
                     format!("Unknown argument (`-{}').", opt))
             }
@@ -50,10 +54,23 @@ fn main() -> Result<(), Box<dyn Error>> {
     }
 
     if files.is_empty() {
-        argument_fatal("No input files given.");
+        from_stdin = true;
     }
     if target.is_empty() {
-        argument_fatal("No such target exists / no target given.");
+        argument_fatal("No such target format exists / \
+                        no target format given.");
+    }
+
+    if from_stdin {
+        let mut stdin = io::stdin();
+        let tree = match seam::parse_stream(&mut stdin) {
+            Ok(tree) => tree,
+            Err(e) =>  {
+                eprintln!("{}", e);
+                std::process::exit(1)
+            }
+        };
+        print_generated(tree, target);
     }
 
     for file in files {
@@ -68,33 +85,38 @@ fn main() -> Result<(), Box<dyn Error>> {
         eprintln!("{}", &tree
             .iter().fold(String::new(),
             |acc, s| acc + "\n" + &s.to_string()));
-        let result = match target {
-            "html" => {
-                let fmt = seam::assemble::html::HTMLFormatter::new(tree);
-                fmt.document()
-            },
-            "xml"  => {
-                let fmt = seam::assemble::xml::XMLFormatter::new(tree);
-                fmt.document()
-            },
-            "css" => {
-                let fmt = seam::assemble::css::CSSFormatter::new(tree);
-                fmt.document()
-            },
-            _ => {
-                argument_fatal(
-                    format!("Target `{}', does not exist.", target))
-            }
-        };
-        match result {
-            Ok(generated) => print!("{}", generated),
-            Err(e) => {
-                eprintln!("{}", e);
-                std::process::exit(1)
-            }
-        }
+        print_generated(tree, target);
     }
 
 
     Ok(())
 }
+
+fn print_generated(tree : seam::parse::ParseTree, target : &str) {
+    let result = match target {
+    "html" => {
+        let fmt = seam::assemble::html::HTMLFormatter::new(tree);
+        fmt.document()
+    },
+    "xml"  => {
+        let fmt = seam::assemble::xml::XMLFormatter::new(tree);
+        fmt.document()
+    },
+    "css" => {
+        let fmt = seam::assemble::css::CSSFormatter::new(tree);
+        fmt.document()
+    },
+    _ => {
+        argument_fatal(
+            format!("Target `{}', does not exist.", target))
+    }};
+
+    match result {
+        Ok(generated) => print!("{}", generated),
+        Err(e) => {
+            eprintln!("{}", e);
+            std::process::exit(1)
+        }
+    }
+}
+
diff --git a/src/lib.rs b/src/lib.rs
@@ -2,11 +2,12 @@ pub mod parse;
 pub mod assemble;
 
 use parse::{expander, parser, lexer};
+pub use parse::parse_stream;
 
 use std::error::Error;
 use std::{fs, path::Path};
 
-pub const VERSION : (u8, u8, u8) = (0, 1, 2);
+pub const VERSION : (u8, u8, u8) = (0, 1, 3);
 
 pub fn parse<P: AsRef<Path>>(string : String, source : Option<P>)
     -> Result<parser::ParseTree, Box<dyn Error>> {
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
@@ -4,8 +4,16 @@ pub mod lexer;
 
 pub mod parser;
 
-use parser::ParseTree;
-use std::{fs, path::Path, error::Error};
+pub use parser::ParseTree;
+use std::{fs, path::Path, io, error::Error};
+
+pub fn parse_stream(stream : &mut impl io::Read) -> Result<ParseTree, Box<dyn Error>> {
+    let mut contents = String::new();
+    stream.read_to_string(&mut contents)?;
+    let tokens = lexer::lex(contents, Option::<&Path>::None)?;
+    let tree = parser::parse_stream(tokens)?;
+    Ok(tree)
+}
 
 pub fn parse_file(path : &Path) -> Result<ParseTree, Box<dyn Error>> {
     let contents = fs::read_to_string(&path)?;
diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs
@@ -46,7 +46,7 @@ impl Display for Site {
         if let Some(source) = &self.source {
             write!(f, "{}:", source)?;
         } else {
-            write!(f, "no-file:")?;
+            write!(f, "<stdin>:")?;
         }
         write!(f, "{}:{})", self.line, self.bytes_from_start + 1)
     }