about summary refs log tree commit diff
path: root/pkgs/profpatsch
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2021-05-18 19:38:38 +0200
committerProfpatsch <mail@profpatsch.de>2021-05-18 19:39:11 +0200
commit4c9515ceb43f90700d1e376233a6c44ce8a15f11 (patch)
tree991d731494707aef251e79bf6794d41a5498ef6d /pkgs/profpatsch
parent35d235889532a57325a7f3ef2f5bcbdf41184167 (diff)
pkgs/profpatsch: init text-letter
A simple text letter formatter (A4) for printing.
Diffstat (limited to 'pkgs/profpatsch')
-rw-r--r--pkgs/profpatsch/default.nix2
-rw-r--r--pkgs/profpatsch/text-letter.nix25
-rw-r--r--pkgs/profpatsch/text-letter.rs131
3 files changed, 158 insertions, 0 deletions
diff --git a/pkgs/profpatsch/default.nix b/pkgs/profpatsch/default.nix
index 61530859..732eabc6 100644
--- a/pkgs/profpatsch/default.nix
+++ b/pkgs/profpatsch/default.nix
@@ -260,6 +260,8 @@ in rec {
     printenv
     ;
 
+  text-letter = import ./text-letter.nix { inherit pkgs rust-deps writeRustSimple writeExecline getBins; };
+
   inherit (import ./netencode { inherit pkgs writeRustSimpleLib writeRustSimple el-semicolon el-exec; })
     netencode-rs
     netencode-rs-tests
diff --git a/pkgs/profpatsch/text-letter.nix b/pkgs/profpatsch/text-letter.nix
new file mode 100644
index 00000000..d9ee9ef5
--- /dev/null
+++ b/pkgs/profpatsch/text-letter.nix
@@ -0,0 +1,25 @@
+{ pkgs, rust-deps, writeRustSimple, writeExecline, getBins }:
+
+let
+  bins = getBins pkgs.coreutils [ "date" "cat" ];
+
+  mustache-interpol = writeRustSimple "mustache-interpol" {
+    dependencies = [
+      rust-deps.mustache
+      rust-deps.toml
+      rust-deps.regex
+      rust-deps.lazy_static
+    ];
+  } (./text-letter.rs);
+
+  text-letter = writeExecline "write-letter" {} [
+    "pipeline" [ bins.cat "/home/philip/kot/work/pa/krankenkasse/2021-05-18-tk-anschreiben-assurance-maladie.toml" ]
+    mustache-interpol
+  ];
+
+in {
+   inherit
+     mustache-interpol
+     text-letter
+     ;
+}
diff --git a/pkgs/profpatsch/text-letter.rs b/pkgs/profpatsch/text-letter.rs
new file mode 100644
index 00000000..55921adc
--- /dev/null
+++ b/pkgs/profpatsch/text-letter.rs
@@ -0,0 +1,131 @@
+//! Reads a toml file on stdin describing a simple letter format,
+//! outputs a text formatting of the file, which can be piped to lp
+//! and should be viable to use on A4 paper with one of these windowed envelopes.
+//! Might depend on the printer.
+//!
+//! ```
+//! cat letter.toml | ./text-letter | lp -h localhost -d printer-name -
+//! ```
+extern crate mustache;
+extern crate toml;
+extern crate regex;
+extern crate lazy_static;
+
+
+use std::io::{Read, Write};
+
+struct Letter {
+    current_city: String,
+    from_address: String,
+    to_address: String,
+    content: String,
+    date: Date
+}
+
+struct Date {
+    year: String,
+    month: String,
+    day: String,
+}
+
+
+lazy_static::lazy_static!{
+    static ref date_regex: regex::bytes::Regex = regex::bytes::Regex::new(r"^([0-9]{4})-([0-9]{2})-([0-9]{2})$").unwrap();
+}
+
+fn parse_date(s: &str) -> Option<Date> {
+    date_regex.captures(s.as_bytes()).map(|c| Date {
+        year: String::from_utf8(c.get(1).unwrap().as_bytes().to_vec()).unwrap(),
+        month: String::from_utf8(c.get(2).unwrap().as_bytes().to_vec()).unwrap(),
+        day: String::from_utf8(c.get(3).unwrap().as_bytes().to_vec()).unwrap(),
+    })
+}
+
+fn parse_letter_toml(input: &str) -> Letter {
+    let v : toml::Value = toml::from_str(input).expect("could not parse letter TOML");
+    let get = |field: &str| -> &str {
+        v.get(field).expect(&format!("field {} is missing in letter TOML", field))
+          .as_str().expect(&format!("field {} must be a string", field))
+    };
+    assert_eq!(get("type"), "letter", "type must be `letter`");
+    assert_eq!(get("version"), "0.0.1", "version must be `0.0.1`");
+
+    Letter {
+        current_city: get("current-city").to_owned(),
+        from_address: get("from-address").trim_right().to_owned(),
+        to_address: get("to-address").trim_right().to_owned(),
+        content: get("content").trim_right().to_owned(),
+        date: parse_date(get("date")).expect("field `date` needs to be a date like yyyy-mm-dd"),
+    }
+}
+
+fn main() {
+    let mut letter = String::new();
+    std::io::stdin().read_to_string(&mut letter).expect("stdin has to be an utf-8 string");
+    let letter = parse_letter_toml(&letter);
+    let from_address_one_line = letter.from_address.replace("\n", ", ");
+
+    fn indent4(s: String) -> String {
+        let mut res = String::from("    ");
+        res.push_str(&s.replace("\n", "\n    "));
+        res
+    }
+    fn indent2(s: String) -> String {
+        let mut res = String::from("  ");
+        res.push_str(&s.replace("\n", "\n  "));
+        res
+    }
+
+    let template = mustache::compile_str(r###"
+{{{date}}}
+
+
+
+
+
+
+
+
+
+{{{from_address_one_line}}}
+
+{{{an}}}
+{{{to_address}}}
+
+
+
+
+
+
+
+
+
+{{content}}
+"###
+    ).expect("the template is malformed");
+
+
+    let data : std::collections::HashMap<String, mustache::Data> =
+        [("an", indent4("An:".to_string())),
+         ("from_address_one_line", indent4(from_address_one_line)),
+         ("to_address", indent4(letter.to_address)),
+         ("content", letter.content),
+         ("date", format!(
+             "{}, den {}.{}.{}",
+             letter.current_city,
+             letter.date.day,
+             letter.date.month,
+             letter.date.year
+         ))
+        ][..].into_iter().cloned()
+        .map(|(k,v)| (k.to_owned(), mustache::Data::String(v))).collect();
+    let data = mustache::Data::Map(data);
+    let res = template.render_data_to_string(
+        &data
+    ).expect("could not render template");
+
+    // give a slight margin
+    let res = indent2(res);
+
+    std::io::stdout().write_all(&res.as_bytes()).unwrap()
+}