commit 59af7e0d30f2744583a55f038b2a680a48020274
parent 3fcc8f79543a1bb32d1b84080fa7d3388ac041e2
Author: lash <dev@holbrook.no>
Date: Sun, 21 Jul 2024 22:44:39 +0100
Add remaining output fields in output
Set published and update in export
Add dates, contents
Add authors
Add categories
Fix slash escape in guid fs cache
Temporarily fix bufwriter ring write with manual buffer size
Remove commented code, add back categories to output
Diffstat:
6 files changed, 314 insertions(+), 31 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -38,7 +38,6 @@ dependencies = [
[[package]]
name = "atom_syndication"
version = "0.12.3"
-source = "git+git://holbrook.no/contrib/atom_syndication?rev=9985c1610b2b819f5bd2f7a719567ee0b5419b85#9985c1610b2b819f5bd2f7a719567ee0b5419b85"
dependencies = [
"chrono",
"derive_builder",
diff --git a/Cargo.toml b/Cargo.toml
@@ -28,9 +28,9 @@ atom_syndication = "^0.12"
#features = ["serialize"]
[patch.crates-io]
-#atom_syndication = { path = "/home/lash/src/contrib/atom_syndication" }
+atom_syndication = { path = "/home/lash/src/contrib/atom_syndication" }
#atom_syndication = { git = "git://holbrook.no/contrib/atom_syndication", rev="fab6f733f6481ecfcbd6a76074f1038c79c854ae" } #branch="lash/entry-to-xml"
-atom_syndication = { git = "git://holbrook.no/contrib/atom_syndication", rev="9985c1610b2b819f5bd2f7a719567ee0b5419b85" } #branch="lash/entry-fromstr"
+#atom_syndication = { git = "git://holbrook.no/contrib/atom_syndication", rev="9985c1610b2b819f5bd2f7a719567ee0b5419b85" } #branch="lash/entry-fromstr"
[dev-dependencies]
tempfile = "3.3.0"
diff --git a/src/io/fs.rs b/src/io/fs.rs
@@ -44,14 +44,20 @@ impl Cache for FsCache {
fn open(&mut self, id: String) -> &mut dyn Write {
let p: &Path;
let fp: PathBuf;
- let s: &str;
+ let mut s: String;
+ let mut ids: String;
let mut f: File;
if !self.files.contains_key(&id) {
p = Path::new(self.dir.as_path());
- fp = p.join(id.clone());
- s = fp.to_str().unwrap();
- f = File::create(s).unwrap();
+
+ ids = id.clone();
+ ids = ids.replace("/", "%2F");
+ ids = ids.replace("\\", "%5C");
+
+ fp = p.join(ids);
+ s = String::from(fp.to_str().unwrap());
+ f = File::create(s.as_str()).unwrap();
self.files.insert(id.clone(), f);
}
return self.files.get_mut(&id).unwrap();
diff --git a/src/lib.rs b/src/lib.rs
@@ -14,6 +14,12 @@ use rs_sha512::Sha512Hasher;
use chrono::Local;
use atom_syndication::Feed as OutFeed;
use atom_syndication::Entry as OutEntry;
+use atom_syndication::TextType as OutTextType;
+use atom_syndication::Text as OutText;
+use atom_syndication::Content as OutContent;
+use atom_syndication::Person as OutPerson;
+use atom_syndication::Category as OutCategory;
+use atom_syndication::FixedDateTime;
use itertools::Itertools;
mod meta;
@@ -228,20 +234,112 @@ impl SequencerEntry {
o.digest += id_part as u64;
o
}
+
+ /// TODO: get size heuristics from already written values (either that or replace underlying
+ /// in-memory writer implementation with something that doesnt wrap on flush.
+ fn to_writer(&self, v: Vec<u8>) -> BufWriter<Vec<u8>> {
+ BufWriter::with_capacity(10241024, v)
+ }
}
+/// TODO: split out field translations to separate module
impl Into<Vec<u8>> for SequencerEntry {
fn into(self) -> Vec<u8> {
let mut out_entry: OutEntry;
let mut b: Vec<u8>;
let mut w: BufWriter<Vec<u8>>;
+ let o: &SequencerEntry;
+
+ o = &self;
+ b = Vec::new();
+ w = o.to_writer(b);
out_entry = OutEntry::default();
out_entry.set_id(self.entry.id);
out_entry.set_title(self.entry.title.unwrap().content);
- b = Vec::new();
- w = BufWriter::new(b);
+ let mut d = FixedDateTime::parse_from_rfc2822(self.entry.published.unwrap().to_rfc2822().as_str()).unwrap();
+ out_entry.set_published(Some(d.clone()));
+
+ match self.entry.updated {
+ Some(v) => {
+ d = FixedDateTime::parse_from_rfc2822(v.to_rfc2822().as_str()).unwrap();
+ out_entry.set_updated(d.clone());
+ },
+ None => {},
+ }
+
+ match self.entry.summary {
+ Some(v) => {
+ let text_out: OutText;
+ let summary_out_type: OutTextType;
+ let summary_subtype = String::from(v.content_type.subty().as_str());
+ if summary_subtype.contains("xhtml") {
+ summary_out_type = OutTextType::Xhtml;
+ } else if summary_subtype.contains("html") {
+ summary_out_type = OutTextType::Html;
+ } else {
+ summary_out_type = OutTextType::Text;
+ }
+ text_out = OutText{
+ value: v.content,
+ r#type: summary_out_type,
+ base: None,
+ lang: None,
+ };
+ out_entry.set_summary(Some(text_out));
+ },
+ None => {},
+ }
+
+ match self.entry.content {
+ Some(v) => {
+ let mut content_out = OutContent::default();
+ content_out.content_type = Some(String::from(v.content_type.as_str()));
+ match v.src {
+ Some(vv) => {
+ content_out.src = Some(vv.href);
+ },
+ None => {},
+ };
+ match v.body {
+ Some(vv) => {
+ content_out.value = Some(vv);
+ },
+ None => {},
+ };
+ out_entry.set_content(Some(content_out));
+ },
+ None => {},
+ }
+
+ for v in self.entry.authors {
+ let o = OutPerson{
+ name: v.name,
+ uri: v.uri,
+ email: v.email,
+ };
+ out_entry.authors.push(o);
+ }
+
+ for v in self.entry.contributors {
+ let o = OutPerson{
+ name: v.name,
+ uri: v.uri,
+ email: v.email,
+ };
+ out_entry.contributors.push(o);
+ }
+
+ for v in self.entry.categories {
+ let o = OutCategory {
+ term: v.term,
+ scheme: v.scheme,
+ label: v.label,
+ };
+ out_entry.categories.push(o);
+ }
+
w = out_entry.write_to(w).unwrap();
b = Vec::from(w.buffer());
b
diff --git a/src/tests.rs b/src/tests.rs
@@ -8,7 +8,7 @@ use feed_rs::model::Text;
use mediatype::MediaTypeBuf;
use chrono::DateTime;
use tempfile::NamedTempFile;
-use tempfile::TempDir;
+use tempfile::tempdir;
use atom_syndication::Entry as OutEntry;
use quick_xml::Reader as XMLReader;
use quick_xml::events::Event as XMLEvent;
@@ -68,7 +68,6 @@ fn test_entry_guard() {
});
- //src.published = Some(DateTime::<Utc>::default());
src.published = Some(DateTime::parse_from_rfc3339("2024-06-25T20:46:00+02:00").unwrap().into());
r = seq.add(src);
assert!(r);
@@ -120,7 +119,7 @@ fn test_feed_all() {
let feed = fs.get("testdata/test.atom.xml", None).unwrap();
let mut seq = Sequencer::new();
r = seq.add_from(feed);
- assert_eq!(r, 15);
+ assert_eq!(r, 16);
}
#[test]
@@ -131,12 +130,12 @@ fn test_feed_mix() {
let mut feed = fs.get("testdata/test.atom.xml", None).unwrap();
let mut seq = Sequencer::new();
r = seq.add_from(feed);
- assert_eq!(r, 15);
+ assert_eq!(r, 16);
feed = fs.get("testdata/test2.xml", None).unwrap();
r = seq.add_from(feed);
assert_eq!(r, 10);
- assert_eq!(seq.by_ref().count(), 25);
- assert_eq!(seq.count(), 25);
+ assert_eq!(seq.by_ref().count(), 26);
+ assert_eq!(seq.count(), 26);
}
#[test]
@@ -146,7 +145,6 @@ fn test_feed_write() {
let fs = FsFeed{};
let f: NamedTempFile;
let mut fr: File;
- //let mut b: [0; 10240];
let feed = fs.get("testdata/test.atom.xml", None).unwrap();
let mut seq = Sequencer::new();
@@ -154,12 +152,8 @@ fn test_feed_write() {
f = NamedTempFile::new().unwrap();
fr = f.reopen().unwrap();
r = seq.write_to(f).unwrap();
- assert_eq!(r, 15);
-// let mut b = String::new();
-// fr.seek(SeekFrom::Start(0));
-// fr.read_to_string(&mut b);
-// println!("{:?}", b);
- assert_eq!(fr.metadata().unwrap().len(), 2521);
+ assert_eq!(r, 16);
+ assert_eq!(fr.metadata().unwrap().len(), 519536);
}
#[test]
@@ -167,25 +161,24 @@ fn test_feed_write() {
fn test_feed_write_extcache() {
let r: usize;
let fs = FsFeed{};
- let d: TempDir;
let f: NamedTempFile;
let fr: File;
let mut cache: FsCache;
- d = TempDir::new().unwrap();
+ let d = tempdir().unwrap();
cache = FsCache::new(d.into_path());
let feed = fs.get("testdata/test.atom.xml", None).unwrap();
let mut seq = Sequencer::new();
seq = seq.with_cache(&mut cache);
- seq.add_from(feed);
+ seq.add_from(feed);
f = NamedTempFile::new().unwrap();
fr = f.reopen().unwrap();
r = seq.write_to(f).unwrap();
- assert_eq!(r, 15);
- assert_eq!(fr.metadata().unwrap().len(), 2521);
+ assert_eq!(r, 16);
+ assert_eq!(fr.metadata().unwrap().len(), 519536);
}
#[test]
@@ -195,7 +188,6 @@ fn test_sequence_order() {
let mut entry: Entry;
let mut s: String;
let mut r: Vec<u8>;
- //let mut r: OutEntry;
entry = Entry::default();
entry.id = String::from("y");
@@ -257,5 +249,3 @@ fn test_sequence_order() {
r = seq.next().unwrap();
check_xml_title(r, "clyde");
}
-
-
diff --git a/testdata/test.atom.xml b/testdata/test.atom.xml
@@ -1,5 +1,195 @@
<?xml version="1.0" encoding="utf-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom"><title>man bytes gnu</title><link href="/" rel="alternate"></link><link href="feeds/all.atom.xml" rel="self"></link><id>/</id><updated>2024-06-25T21:58:00+02:00</updated><entry><title>Secrets in the shell</title><link href="clortho.html" rel="alternate"></link><published>2024-06-25T20:46:00+02:00</published><updated>2024-06-25T21:58:00+02:00</updated><author><name>Louis Holbrook</name></author><id>tag:None,2024-06-25:clortho.html</id><summary type="html"><p class="first last">A key value store at your fingertips</p>
+<feed xmlns="http://www.w3.org/2005/Atom"><title>man bytes gnu</title><link href="/" rel="alternate"></link><link href="feeds/all.atom.xml" rel="self"></link><id>/</id><updated>2024-07-07T21:03:40+02:00</updated><entry><title>Support Your Local Viewer</title><link href="local-markdown.html" rel="alternate"></link><published>2024-07-07T21:03:40+02:00</published><updated>2024-07-07T21:03:40+02:00</updated><author><name>Louis Holbrook</name></author><id>tag:None,2024-07-07:local-markdown.html</id><summary type="html"><p class="first last">Bash script to render and spawn a viewer for markdown files</p>
+</summary><content type="html"><p>Markdown is the fast-food of document formats.</p>
+<p>That doesn't change the fact that it's everywhere.</p>
+<p>So much everywhere, in fact, that it's kind of puzzling there is not a dedicated tool around to view it.</p>
+<div class="section" id="pinning-down-markdown">
+<h2>Pinning down markdown</h2>
+<p>There is no shortage of applications that <em>can</em> render markdown. Among the alternatives are free code editors like <a class="reference external" href="https://atom-editor.cc/">Atom</a> or <a class="reference external" href="https://plugins.geany.org/markdown.html">Geany</a>, the browser plugin <a class="reference external" href="https://chromewebstore.google.com/detail/markdown-viewer/ckkdlimhmcjmikdlpkmbgfkaikojcbjk">Markdown Viewer</a> and even a dedicated markdown editor like <a class="reference external" href="https://github.com/marktext/marktext">Marktext</a>, <a class="reference external" href="https://github.com/retext-project/retext">retext</a> and <a class="reference external" href="https://ghostwriter.kde.org/">ghostwriter</a>.</p>
+<p>And of course, there exist SaaS offerings such as <a class="reference external" href="https://hackmd.io">hackmd</a>. But seeing as those are not alternatives for offline use, we don't concern ourselves with those here.</p>
+<p>But what is the equivalent of <a class="reference external" href="https://github.com/muennich/sxiv">sxiv</a> or <a class="reference external" href="https://feh.finalrewind.org">feh</a> for Markdown?</p>
+<p>Honestly, I couldn't find any such thing. If there is, I'd <a class="reference external" href="https://holbrook.no/msg">love to know</a>.</p>
+<p>Fortunately, there is a perfectly reasonable workaround.</p>
+</div>
+<div class="section" id="step-by-step">
+<h2>Step by step</h2>
+<p>After all, it is in the spirit of *nixes to use a choice of tools who <em>does one thing and does it well</em>.</p>
+<p>So, no matter how bizarre it feels, it may make sense that a lurid format like <em>Markdown</em> should be treated in a separate step to produce a more well-established - and less ambiguous - format.</p>
+<p>I asked a related question on <a class="reference external" href="https://tex.stackexchange.com/questions/341899/latex-to-markdown-converter">Stackexchange</a> long ago, and there the <tt class="docutils literal">pandoc</tt> tool came up as a solution.</p>
+<p>And it turns out it works beautifully in this case aswell.</p>
+<p>Consider the following script:</p>
+<div class="highlight"><pre><span></span><span class="nv">t</span><span class="o">=</span><span class="k">$(</span>mktemp<span class="w"> </span>--suffix<span class="o">=</span>.html<span class="k">)</span>
+<span class="m">2</span>&gt;<span class="p">&amp;</span><span class="m">1</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="nv">$t</span>
+pandoc<span class="w"> </span>-f<span class="w"> </span>gfm<span class="w"> </span>-t<span class="w"> </span>html<span class="w"> </span>-M<span class="w"> </span>document-css<span class="o">=</span><span class="nb">false</span><span class="w"> </span>--standalone<span class="w"> </span><span class="nv">$1</span><span class="w"> </span>&gt;<span class="w"> </span><span class="nv">$t</span><span class="w"> </span><span class="m">2</span>&gt;<span class="w"> </span>/dev/null
+w3m<span class="w"> </span><span class="nv">$t</span>
+</pre></div>
+<p>Quite simply, we generate a standalone html file in <tt class="docutils literal">tmpfs</tt>, which in turn is read and renderered by a web browser.</p>
+</div>
+<div class="section" id="browsing-browsers">
+<h2>Browsing browsers</h2>
+<p>No appreciation for <a class="reference external" href="https://w3m.sourceforge.net">w3m</a>, eh? Instead want that fuzzy feel of comforting colors, smooth scroll and fancy fonts?</p>
+<p>I can understand. I used to suffer that affliction, too.</p>
+<p>But nonetheless; it's an important point. For example, what if I wanted to use <a class="reference external" href="https://lynx.browser.org">lynx</a> or <a class="reference external" href="https://fanglingsu.github.io/vimb">vimb</a> instead? Choosing the browser to view with should definitely be the caller's call.</p>
+<p>Is there a canonical way of doing that in Linux.</p>
+<p>Kind of.</p>
+<p>Let's review a couple of the options.</p>
+<div class="section" id="the-environmental-solution">
+<h3>The environmental solution</h3>
+<p>Some applications honor the <tt class="docutils literal">$BROWSER</tt> environment variable. So let's cover for that:</p>
+<div class="highlight"><pre><span></span><span class="nv">browser</span><span class="o">=</span><span class="si">${</span><span class="nv">BROWSER</span><span class="k">:-</span><span class="nv">w3m</span><span class="si">}</span>
+<span class="nv">t</span><span class="o">=</span><span class="k">$(</span>mktemp<span class="w"> </span>--suffix<span class="o">=</span>.html<span class="k">)</span>
+pandoc<span class="w"> </span>-f<span class="w"> </span>gfm<span class="w"> </span>-t<span class="w"> </span>html<span class="w"> </span>-M<span class="w"> </span>document-css<span class="o">=</span><span class="nb">false</span><span class="w"> </span>--standalone<span class="w"> </span><span class="nv">$1</span><span class="w"> </span>&gt;<span class="w"> </span><span class="nv">$t</span><span class="w"> </span><span class="m">2</span>&gt;<span class="w"> </span>/dev/null
+<span class="nv">$browser</span><span class="w"> </span><span class="nv">$t</span>
+</pre></div>
+<p>Now, viewing the markdown file <tt class="docutils literal">README.md</tt> with <tt class="docutils literal">lynx</tt> is as easy as:</p>
+<div class="highlight"><pre><span></span><span class="gp">$ </span><span class="nv">BROWSER</span><span class="o">=</span><span class="k">$(</span>which<span class="w"> </span>lynx<span class="k">)</span><span class="w"> </span>bash<span class="w"> </span>wmd.sh<span class="w"> </span>README.md
+</pre></div>
+</div>
+<div class="section" id="the-cross-solution">
+<h3>The cross solution</h3>
+<p>So, have you heard about the Cross Desktop Group? <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a> These are the guys you should be sending a thought of gratitude every time you intuitively look in your <tt class="docutils literal"><span class="pre">~/.config</span></tt> or <tt class="docutils literal"><span class="pre">~/.local</span></tt> folder for application data. And if you're a <strong>HUIf</strong> <a class="footnote-reference" href="#footnote-2" id="footnote-reference-2">[2]</a> coder, chances are you have seen the string <tt class="docutils literal">xdg</tt> in some function call somewhere.</p>
+<p>These days they go by the name <a class="reference external" href="https://www.freedesktop.org/">Free Desktop Group</a>, and among other things they have negotiated something particularly useful to us in this particular case.</p>
+<p>To launch programs in a desktop environment in Linux, a <a class="reference external" href="https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html">Desktop Entry Specification</a> file format <a class="footnote-reference" href="#footnote-3" id="footnote-reference-3">[3]</a> has been defined - appropriately suffixed <tt class="docutils literal">.desktop</tt>.</p>
+<p>Take a look at a random <tt class="docutils literal">*.desktop</tt> file in <tt class="docutils literal">/usr/share/applications</tt> (your most likely default <tt class="docutils literal">$XDG_DATA_DIRS</tt> location, where xdg searches for desktop files). Every one will contain an top-level <tt class="docutils literal">Exec=</tt> entry.</p>
+<p>For example, my <tt class="docutils literal">feh.desktop</tt> entry has <tt class="docutils literal">Exec=feh <span class="pre">--start-at</span> %u</tt> which means find <tt class="docutils literal">feh</tt> in <tt class="docutils literal">$PATH</tt> and execute it with the <tt class="docutils literal"><span class="pre">--start-at</span></tt> switch and one single <em>url</em> as argument:</p>
+<div class="highlight"><pre><span></span><span class="k">[Desktop Entry]</span>
+<span class="na">Name</span><span class="o">=</span><span class="s">Feh</span>
+<span class="na">Name[en_US]</span><span class="o">=</span><span class="s">feh</span>
+<span class="na">GenericName</span><span class="o">=</span><span class="s">Image viewer</span>
+<span class="na">GenericName[en_US]</span><span class="o">=</span><span class="s">Image viewer</span>
+<span class="na">Comment</span><span class="o">=</span><span class="s">Image viewer and cataloguer</span>
+<span class="na">Exec</span><span class="o">=</span><span class="s">feh --start-at %u</span>
+<span class="na">Terminal</span><span class="o">=</span><span class="s">false</span>
+<span class="na">Type</span><span class="o">=</span><span class="s">Application</span>
+<span class="na">Icon</span><span class="o">=</span><span class="s">feh</span>
+<span class="na">Categories</span><span class="o">=</span><span class="s">Graphics</span><span class="c1">;2DGraphics;Viewer;</span>
+<span class="na">MimeType</span><span class="o">=</span><span class="s">image/bmp</span><span class="c1">;image/gif;image/jpeg;image/jpg;image/pjpeg;image/png;image/tiff;image/webp;image/x-bmp;image/x-pcx;image/x-png;image/x-portable-anymap;image/x-portable-bitmap;image/x-portable-graymap;image/x-portable-pixmap;image/x-tga;image/x-xbitmap;image/heic;</span>
+<span class="na">NoDisplay</span><span class="o">=</span><span class="s">true</span>
+</pre></div>
+<p>Covering this case in our script:</p>
+<div class="highlight"><pre><span></span><span class="nv">fallbackbrowsercmd</span><span class="o">=</span>w3m
+<span class="nv">browsercmd</span><span class="o">=</span>
+<span class="c1"># if browser env exists, then</span>
+<span class="c1"># try handle it as a desktop entry</span>
+<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$BROWSER</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="c1"># find the xdg paths</span>
+<span class="w"> </span><span class="nv">XDG_DATA_DIRS</span><span class="o">=</span><span class="si">${</span><span class="nv">XDG_DATA_DIRS</span><span class="k">:-</span><span class="p">/usr/share</span><span class="si">}</span>
+<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$XDG_DATA_HOME</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">XDG_DATA_DIRS</span><span class="o">=</span><span class="nv">$XDG_DATA_HOME</span>:<span class="nv">$XDG_DATA_DIRS</span>
+<span class="w"> </span><span class="k">fi</span>
+<span class="w"> </span><span class="c1"># split on &quot;:&quot; and try dirs one by one</span>
+<span class="w"> </span><span class="c1"># use first matching browser desktop entry</span>
+<span class="w"> </span><span class="nv">_ifs</span><span class="o">=</span><span class="nv">$IFS</span>
+<span class="w"> </span><span class="nv">IFS</span><span class="o">=</span>:
+<span class="w"> </span><span class="nv">dirs</span><span class="o">=(</span><span class="s2">&quot;</span><span class="nv">$XDG_DATA_DIRS</span><span class="s2">&quot;</span><span class="o">)</span>
+<span class="w"> </span><span class="k">for</span><span class="w"> </span>d<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nv">$dirs</span><span class="p">;</span><span class="w"> </span><span class="k">do</span>
+<span class="w"> </span><span class="nv">s</span><span class="o">=</span><span class="nv">$BROWSER</span>.desktop
+<span class="w"> </span><span class="nv">a</span><span class="o">=</span><span class="nv">$d</span>/applications/<span class="nv">$BROWSER</span>.desktop
+<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-f<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$a</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">browsercmd</span><span class="o">=</span><span class="s2">&quot;gtk-launch </span><span class="nv">$s</span><span class="s2">&quot;</span>
+<span class="w"> </span><span class="k">fi</span>
+<span class="w"> </span><span class="k">done</span>
+<span class="w"> </span><span class="nv">IFS</span><span class="o">=</span>
+<span class="k">fi</span>
+<span class="c1"># if no browser set or could not be found in xdg,</span>
+<span class="c1"># then try the browser env var as command, or</span>
+<span class="c1"># ultimately the static fallback</span>
+<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$browsercmd</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">browsercmd</span><span class="o">=</span><span class="si">${</span><span class="nv">BROWSER</span><span class="k">:-</span><span class="nv">$fallbackbrowsercmd</span><span class="si">}</span>
+<span class="k">fi</span>
+<span class="nv">t</span><span class="o">=</span><span class="k">$(</span>mktemp<span class="w"> </span>--suffix<span class="o">=</span>.html<span class="k">)</span>
+pandoc<span class="w"> </span>-f<span class="w"> </span>gfm<span class="w"> </span>-t<span class="w"> </span>html<span class="w"> </span>-M<span class="w"> </span>document-css<span class="o">=</span><span class="nb">false</span><span class="w"> </span>--standalone<span class="w"> </span><span class="nv">$1</span><span class="w"> </span>&gt;<span class="w"> </span><span class="nv">$t</span><span class="w"> </span><span class="m">2</span>&gt;<span class="w"> </span>/dev/null
+<span class="nv">$browsercmd</span><span class="w"> </span><span class="nv">$t</span>
+</pre></div>
+</div>
+<div class="section" id="the-default-solution">
+<h3>The default solution</h3>
+<p>Yes, there is such a thing as &quot;default web browser&quot; in <tt class="docutils literal">XDG</tt>, too.</p>
+<p>Have a look at <tt class="docutils literal"><span class="pre">xdg-settings</span> <span class="pre">--list</span></tt>. On my system, it shows a rather modest output:</p>
+<div class="highlight"><pre><span></span><span class="gp">$ </span>xdg-settings<span class="w"> </span>--list
+<span class="go">Known properties:</span>
+<span class="go"> default-url-scheme-handler Default handler for URL scheme</span>
+<span class="go"> default-web-browser Default web browser</span>
+</pre></div>
+<p>And the default web browser is:</p>
+<div class="highlight"><pre><span></span><span class="gp">$ </span>xdg-settings<span class="w"> </span>get<span class="w"> </span>default-web-browser
+<span class="go">brave-browser.desktop</span>
+</pre></div>
+<p>Yeah, yeah, yeah. Busted. I use graphical browsers, too.</p>
+<p>Now let's add this to the mix, then.</p>
+<div class="highlight"><pre><span></span><span class="nv">fallbackbrowsercmd</span><span class="o">=</span>w3m
+<span class="nv">browsercmd</span><span class="o">=</span>
+<span class="c1"># if browser env var not set, set it with default browser</span>
+<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$BROWSER</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">BROWSER</span><span class="o">=</span><span class="k">$(</span>xdg-settings<span class="w"> </span>get<span class="w"> </span>default-web-browser<span class="k">)</span>
+<span class="w"> </span><span class="nv">BROWSER</span><span class="o">=</span><span class="si">${</span><span class="nv">BROWSER</span><span class="p">%%.*</span><span class="si">}</span>
+<span class="k">fi</span>
+<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$BROWSER</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">XDG_DATA_DIRS</span><span class="o">=</span><span class="si">${</span><span class="nv">XDG_DATA_DIRS</span><span class="k">:-</span><span class="p">/usr/share</span><span class="si">}</span>
+<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$XDG_DATA_HOME</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">XDG_DATA_DIRS</span><span class="o">=</span><span class="nv">$XDG_DATA_HOME</span>:<span class="nv">$XDG_DATA_DIRS</span>
+<span class="w"> </span><span class="k">fi</span>
+<span class="w"> </span><span class="nv">_ifs</span><span class="o">=</span><span class="nv">$IFS</span>
+<span class="w"> </span><span class="nv">IFS</span><span class="o">=</span>:
+<span class="w"> </span><span class="nv">dirs</span><span class="o">=(</span><span class="s2">&quot;</span><span class="nv">$XDG_DATA_DIRS</span><span class="s2">&quot;</span><span class="o">)</span>
+<span class="w"> </span><span class="k">for</span><span class="w"> </span>d<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nv">$dirs</span><span class="p">;</span><span class="w"> </span><span class="k">do</span>
+<span class="w"> </span><span class="nv">s</span><span class="o">=</span><span class="nv">$BROWSER</span>.desktop
+<span class="w"> </span><span class="nv">a</span><span class="o">=</span><span class="nv">$d</span>/applications/<span class="nv">$BROWSER</span>.desktop
+<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-f<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$a</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">browsercmd</span><span class="o">=</span><span class="s2">&quot;gtk-launch </span><span class="nv">$s</span><span class="s2">&quot;</span>
+<span class="w"> </span><span class="k">fi</span>
+<span class="w"> </span><span class="k">done</span>
+<span class="w"> </span><span class="nv">IFS</span><span class="o">=</span>
+<span class="k">fi</span>
+<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$browsercmd</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
+<span class="w"> </span><span class="nv">browsercmd</span><span class="o">=</span><span class="si">${</span><span class="nv">BROWSER</span><span class="k">:-</span><span class="nv">$fallbackbrowsercmd</span><span class="si">}</span>
+<span class="k">fi</span>
+<span class="nv">t</span><span class="o">=</span><span class="k">$(</span>mktemp<span class="w"> </span>--suffix<span class="o">=</span>.html<span class="k">)</span>
+pandoc<span class="w"> </span>-f<span class="w"> </span>gfm<span class="w"> </span>-t<span class="w"> </span>html<span class="w"> </span>-M<span class="w"> </span>document-css<span class="o">=</span><span class="nb">false</span><span class="w"> </span>--standalone<span class="w"> </span><span class="nv">$1</span><span class="w"> </span>&gt;<span class="w"> </span><span class="nv">$t</span><span class="w"> </span><span class="m">2</span>&gt;<span class="w"> </span>/dev/null
+<span class="nv">$browsercmd</span><span class="w"> </span><span class="nv">$t</span>
+</pre></div>
+</div>
+</div>
+<div class="section" id="naming-the-executioner">
+<h2>Naming the executioner</h2>
+<p>So now we have a markdown viewer. And it can be as lean or as heavy as you want it to be. It's all to the browser you choose.</p>
+<p>To make it accessible, map the script as a command alias in your <tt class="docutils literal">.profile</tt> or <tt class="docutils literal">.bashrc</tt> and you have the viewer at your fingertips.</p>
+<p>I call mine <tt class="docutils literal">wmd</tt>:</p>
+<div class="highlight"><pre><span></span><span class="nb">alias</span><span class="w"> </span><span class="nv">wmd</span><span class="o">=</span><span class="s2">&quot;bash </span><span class="nv">$HOME</span><span class="s2">/scripts/markdown.sh&quot;</span>
+</pre></div>
+<p>And voilá:</p>
+<div class="highlight"><pre><span></span><span class="gp">$ </span><span class="nb">export</span><span class="w"> </span><span class="nv">BROWSER</span><span class="o">=</span>lynx
+<span class="gp">$ </span>wmd<span class="w"> </span>README.md
+</pre></div>
+<!-- -->
+<blockquote>
+<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>Or X Desktop Group, as they were originally called.</td></tr>
+</tbody>
+</table>
+</blockquote>
+<!-- -->
+<blockquote>
+<table class="docutils footnote" frame="void" id="footnote-2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#footnote-reference-2">[2]</a></td><td>Human User Interface. Don't bother looking - I made it up. As the cause of AI, robots and machines inevitably will become appropriated by the woke intersectionality complex, the terminology is probably going to need such distictions.</td></tr>
+</tbody>
+</table>
+</blockquote>
+<!-- -->
+<blockquote>
+<table class="docutils footnote" frame="void" id="footnote-3" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#footnote-reference-3">[3]</a></td><td>Actually the format is <a class="reference external" href="https://en.wikipedia.org/wiki/INI_file">ini</a>. The standard is rather in the file naming, really.</td></tr>
+</tbody>
+</table>
+</blockquote>
+</div>
+</content><category term="Offlining"></category><category term="bash"></category><category term="markdown"></category><category term="pandoc"></category><category term="vimb"></category><category term="w3m"></category><category term="lynx"></category><category term="xdg"></category></entry><entry><title>Secrets in the shell</title><link href="clortho.html" rel="alternate"></link><published>2024-06-25T20:46:00+02:00</published><updated>2024-06-25T21:58:00+02:00</updated><author><name>Louis Holbrook</name></author><id>tag:None,2024-06-25:clortho.html</id><summary type="html"><p class="first last">A key value store at your fingertips</p>
</summary><content type="html"><p>Ever since I started using the <a class="reference external" href="https://www.passwordstore.org/">pass</a> CLI as my password manager, I've found myself putting all sorts of stuff in there; usernames, email, urls, crypto addresses, api keys, you name it.</p>
<p>It makes total sense that some of these items are in there. For example, I store the url to a service together with the password, usually accompanied by the username and the email used <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a>. No password recoveries needed.</p>
<p>However, at some point I also started putting in things like crypto addresses, or even token smart contract addresses in there.</p>