blog-deployment

build artifacts for my blog
git clone git://jeskin.net/blog-deployment.git
Log | Files | Refs

commit 21239af944892dba793bc2b638ae1a56b1515af6
Author: Jon Eskin <eskinjp@gmail.com>
Date:   Wed,  7 Sep 2022 02:52:43 -0400

clean

Diffstat:
A404.html | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aabout/index.html | 258+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablog/clp.html | 1113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablog/clp/index.html | 374+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablog/getting-started-with-cosmopolitan-libc/index.html | 421+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablog/grep-fzf-clp/index.html | 294+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablog/index.html | 277+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ablog/index.xml | 46++++++++++++++++++++++++++++++++++++++++++++++
Acategories/index.html | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acategories/index.xml | 11+++++++++++
Afavicon.ico | 0
Aimages/favicon.png | 0
Aindex.html | 236+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aindex.xml | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arobots.txt | 2++
Asitemap.xml | 28++++++++++++++++++++++++++++
Atags/index.html | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atags/index.xml | 11+++++++++++
18 files changed, 3857 insertions(+), 0 deletions(-)

diff --git a/404.html b/404.html @@ -0,0 +1,232 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>404</title> +<meta name="title" content="404 Page not found" /> +<meta name="description" content="Jon Eskin&#39;s Personal Blog" /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="404 Page not found" /> +<meta property="og:description" content="Jon Eskin&#39;s Personal Blog" /> +<meta property="og:type" content="website" /> +<meta property="og:url" content="https://jeskin.net/404.html" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="404 Page not found"/> +<meta name="twitter:description" content="Jon Eskin&#39;s Personal Blog"/> + + + +<meta itemprop="name" content="404 Page not found"> +<meta itemprop="description" content="Jon Eskin&#39;s Personal Blog"> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> +<h1>404</h1> +<h2>ʕノ•ᴥ•ʔノ ︵ ┻━┻</h2> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/about/index.html b/about/index.html @@ -0,0 +1,258 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>About | Jon Eskin&#39;s Blog</title> +<meta name="title" content="About" /> +<meta name="description" content="Hello! +I&rsquo;m a stay at home dad tinkering with software at night. +I&rsquo;m interested in tooling, web &amp; mobile development, and systems programming. +You can find some projects I&rsquo;ve worked on in the page footer. If you&rsquo;d like to contact me, my email is eskinjp at gmail dot com." /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="About" /> +<meta property="og:description" content="Hello! +I&rsquo;m a stay at home dad tinkering with software at night. +I&rsquo;m interested in tooling, web &amp; mobile development, and systems programming. +You can find some projects I&rsquo;ve worked on in the page footer. If you&rsquo;d like to contact me, my email is eskinjp at gmail dot com." /> +<meta property="og:type" content="article" /> +<meta property="og:url" content="https://jeskin.net/about/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="article:section" content="" /> +<meta property="article:published_time" content="2022-07-15T04:20:38-04:00" /> +<meta property="article:modified_time" content="2022-07-15T04:20:38-04:00" /><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="About"/> +<meta name="twitter:description" content="Hello! +I&rsquo;m a stay at home dad tinkering with software at night. +I&rsquo;m interested in tooling, web &amp; mobile development, and systems programming. +You can find some projects I&rsquo;ve worked on in the page footer. If you&rsquo;d like to contact me, my email is eskinjp at gmail dot com."/> + + + +<meta itemprop="name" content="About"> +<meta itemprop="description" content="Hello! +I&rsquo;m a stay at home dad tinkering with software at night. +I&rsquo;m interested in tooling, web &amp; mobile development, and systems programming. +You can find some projects I&rsquo;ve worked on in the page footer. If you&rsquo;d like to contact me, my email is eskinjp at gmail dot com."><meta itemprop="datePublished" content="2022-07-15T04:20:38-04:00" /> +<meta itemprop="dateModified" content="2022-07-15T04:20:38-04:00" /> +<meta itemprop="wordCount" content="49"><meta itemprop="image" content="https://jeskin.net/images/share.png"/> +<meta itemprop="keywords" content="" /> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> + +<content> + <p>Hello!</p> +<p>I&rsquo;m a stay at home dad tinkering with software at night.</p> +<p>I&rsquo;m interested in tooling, web &amp; mobile development, and systems programming.</p> +<p>You can find some projects I&rsquo;ve worked on in the page footer. If you&rsquo;d like to contact me, my email is eskinjp at gmail dot com.</p> + +</content> +<p> + +</p> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/blog/clp.html b/blog/clp.html @@ -0,0 +1,1112 @@ +<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="date" content="2022-07-16T04:33:41-04:00"> +<meta name="draft" content="true"><style>body { + max-width: 980px; + outline: 1300px solid #fff; + margin: 16px auto; +} + +body .markdown-body +{ + padding: 45px; +} + +@font-face { + font-family: fontawesome-mini; + src: url(data:font/woff;charset=utf-8;base64,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) format('woff'); +} + +.markdown-body { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + color: #333333; + overflow: hidden; + font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; + font-size: 16px; + line-height: 1.6; + word-wrap: break-word; +} + +.markdown-body a { + background: transparent; +} + +.markdown-body a:active, +.markdown-body a:hover { + outline: 0; +} + +.markdown-body b, +.markdown-body strong { + font-weight: bold; +} + +.markdown-body mark { + background: #ff0; + color: #000; + font-style: italic; + font-weight: bold; +} + +.markdown-body sub, +.markdown-body sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +.markdown-body sup { + top: -0.5em; +} +.markdown-body sub { + bottom: -0.25em; +} + +.markdown-body h1 { + font-size: 2em; + margin: 0.67em 0; +} + +.markdown-body img { + border: 0; +} + +.markdown-body hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +.markdown-body pre { + overflow: auto; +} + +.markdown-body code, +.markdown-body kbd, +.markdown-body pre, +.markdown-body samp { + font-family: monospace, monospace; + font-size: 1em; +} + +.markdown-body input { + color: inherit; + font: inherit; + margin: 0; +} + +.markdown-body html input[disabled] { + cursor: default; +} + +.markdown-body input { + line-height: normal; +} + +.markdown-body input[type="checkbox"] { + box-sizing: border-box; + padding: 0; +} + +.markdown-body table { + border-collapse: collapse; + border-spacing: 0; +} + +.markdown-body td, +.markdown-body th { + padding: 0; +} + +.markdown-body .codehilitetable, +.markdown-body .highlighttable { + border: 0; + border-spacing: 0; +} + +.markdown-body .codehilitetable tr, +.markdown-body .highlighttable { + border: 0; +} + +.markdown-body .codehilitetable pre, +.markdown-body .codehilitetable div.codehilite, +.markdown-body .highlighttable pre, +.markdown-body .highlighttable div.highlight { + margin: 0; +} + +.markdown-body .linenos, +.markdown-body .code, +.markdown-body .codehilitetable td, +.markdown-body .highlighttable td { + border: 0; + padding: 0; +} + +.markdown-body td:not(.linenos) .linenodiv { + padding: 0 !important; +} + +.markdown-body .code { + width: 100%; +} + +.markdown-body .linenos div pre, +.markdown-body .linenodiv pre, +.markdown-body .linenodiv { + border: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-border-top-left-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + -moz-border-radius-topleft: 3px; + -moz-border-radius-bottomleft: 3px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +} + +.markdown-body .code div pre, +.markdown-body .code div { + border: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +.markdown-body * { + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.markdown-body input { + font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; + line-height: 1.4; +} + +.markdown-body a { + color: #4183c4; + text-decoration: none; +} + +.markdown-body a:hover, +.markdown-body a:focus, +.markdown-body a:active { + text-decoration: underline; +} + +.markdown-body hr { + height: 0; + margin: 15px 0; + overflow: hidden; + background: transparent; + border: 0; + border-bottom: 1px solid #ddd; +} + +.markdown-body hr:before, +.markdown-body hr:after { + display: table; + content: " "; +} + +.markdown-body hr:after { + clear: both; +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + margin-top: 15px; + margin-bottom: 15px; + line-height: 1.1; +} + +.markdown-body h1 { + font-size: 30px; +} + +.markdown-body h2 { + font-size: 21px; +} + +.markdown-body h3 { + font-size: 16px; +} + +.markdown-body h4 { + font-size: 14px; +} + +.markdown-body h5 { + font-size: 12px; +} + +.markdown-body h6 { + font-size: 11px; +} + +.markdown-body blockquote { + margin: 0; +} + +.markdown-body ul, +.markdown-body ol { + padding: 0; + margin-top: 0; + margin-bottom: 0; +} + +.markdown-body ol ol, +.markdown-body ul ol { + list-style-type: lower-roman; +} + +.markdown-body ul ul ol, +.markdown-body ul ol ol, +.markdown-body ol ul ol, +.markdown-body ol ol ol { + list-style-type: lower-alpha; +} + +.markdown-body dd { + margin-left: 0; +} + +.markdown-body code, +.markdown-body pre, +.markdown-body samp { + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 12px; +} + +.markdown-body pre { + margin-top: 0; + margin-bottom: 0; +} + +.markdown-body kbd { + background-color: #e7e7e7; + background-image: -moz-linear-gradient(#fefefe, #e7e7e7); + background-image: -webkit-linear-gradient(#fefefe, #e7e7e7); + background-image: linear-gradient(#fefefe, #e7e7e7); + background-repeat: repeat-x; + border-radius: 2px; + border: 1px solid #cfcfcf; + color: #000; + padding: 3px 5px; + line-height: 10px; + font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; + display: inline-block; +} + +.markdown-body>*:first-child { + margin-top: 0 !important; +} + +.markdown-body>*:last-child { + margin-bottom: 0 !important; +} + +.markdown-body .headerlink { + font: normal 400 16px fontawesome-mini; + vertical-align: middle; + margin-left: -16px; + float: left; + display: inline-block; + text-decoration: none; + opacity: 0; + color: #333; +} + +.markdown-body .headerlink:focus { + outline: none; +} + +.markdown-body h1 .headerlink { + margin-top: 0.8rem; +} + +.markdown-body h2 .headerlink, +.markdown-body h3 .headerlink { + margin-top: 0.6rem; +} + +.markdown-body h4 .headerlink { + margin-top: 0.2rem; +} + +.markdown-body h5 .headerlink, +.markdown-body h6 .headerlink { + margin-top: 0; +} + +.markdown-body .headerlink:hover, +.markdown-body h1:hover .headerlink, +.markdown-body h2:hover .headerlink, +.markdown-body h3:hover .headerlink, +.markdown-body h4:hover .headerlink, +.markdown-body h5:hover .headerlink, +.markdown-body h6:hover .headerlink { + opacity: 1; + text-decoration: none; +} + +.markdown-body h1 { + padding-bottom: 0.3em; + font-size: 2.25em; + line-height: 1.2; + border-bottom: 1px solid #eee; +} + +.markdown-body h2 { + padding-bottom: 0.3em; + font-size: 1.75em; + line-height: 1.225; + border-bottom: 1px solid #eee; +} + +.markdown-body h3 { + font-size: 1.5em; + line-height: 1.43; +} + +.markdown-body h4 { + font-size: 1.25em; +} + +.markdown-body h5 { + font-size: 1em; +} + +.markdown-body h6 { + font-size: 1em; + color: #777; +} + +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body pre, +.markdown-body .admonition { + margin-top: 0; + margin-bottom: 16px; +} + +.markdown-body hr { + height: 4px; + padding: 0; + margin: 16px 0; + background-color: #e7e7e7; + border: 0 none; +} + +.markdown-body ul, +.markdown-body ol { + padding-left: 2em; +} + +.markdown-body ul ul, +.markdown-body ul ol, +.markdown-body ol ol, +.markdown-body ol ul { + margin-top: 0; + margin-bottom: 0; +} + +.markdown-body li>p { + margin-top: 16px; +} + +.markdown-body dl { + padding: 0; +} + +.markdown-body dl dt { + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: bold; +} + +.markdown-body dl dd { + padding: 0 16px; + margin-bottom: 16px; +} + +.markdown-body blockquote { + padding: 0 15px; + color: #777; + border-left: 4px solid #ddd; +} + +.markdown-body blockquote>:first-child { + margin-top: 0; +} + +.markdown-body blockquote>:last-child { + margin-bottom: 0; +} + +.markdown-body table { + display: block; + width: 100%; + overflow: auto; + word-break: normal; + word-break: keep-all; +} + +.markdown-body table th { + font-weight: bold; +} + +.markdown-body table th, +.markdown-body table td { + padding: 6px 13px; + border: 1px solid #ddd; +} + +.markdown-body table tr { + background-color: #fff; + border-top: 1px solid #ccc; +} + +.markdown-body table tr:nth-child(2n) { + background-color: #f8f8f8; +} + +.markdown-body img { + max-width: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.markdown-body code, +.markdown-body samp { + padding: 0; + padding-top: 0.2em; + padding-bottom: 0.2em; + margin: 0; + font-size: 85%; + background-color: rgba(0,0,0,0.04); + border-radius: 3px; +} + +.markdown-body code:before, +.markdown-body code:after { + letter-spacing: -0.2em; + content: "\00a0"; +} + +.markdown-body pre>code { + padding: 0; + margin: 0; + font-size: 100%; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; +} + +.markdown-body .codehilite, +.markdown-body .highlight { + margin-bottom: 16px; +} + +.markdown-body .codehilite pre, +.markdown-body .highlight pre, +.markdown-body pre { + padding: 16px; + overflow: auto; + font-size: 85%; + line-height: 1.45; + background-color: #f7f7f7; + border-radius: 3px; +} + +.markdown-body .codehilite pre, +.markdown-body .highlight pre { + margin-bottom: 0; + word-break: normal; +} + +.markdown-body pre { + word-wrap: normal; +} + +.markdown-body pre code { + display: inline; + max-width: initial; + padding: 0; + margin: 0; + overflow: initial; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; +} + +.markdown-body pre code:before, +.markdown-body pre code:after { + content: normal; +} + +/* Admonition */ +.markdown-body .admonition { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + position: relative; + border-radius: 3px; + border: 1px solid #e0e0e0; + border-left: 6px solid #333; + padding: 10px 10px 10px 30px; +} + +.markdown-body .admonition table { + color: #333; +} + +.markdown-body .admonition p { + padding: 0; +} + +.markdown-body .admonition-title { + font-weight: bold; + margin: 0; +} + +.markdown-body .admonition>.admonition-title { + color: #333; +} + +.markdown-body .attention>.admonition-title { + color: #a6d796; +} + +.markdown-body .caution>.admonition-title { + color: #d7a796; +} + +.markdown-body .hint>.admonition-title { + color: #96c6d7; +} + +.markdown-body .danger>.admonition-title { + color: #c25f77; +} + +.markdown-body .question>.admonition-title { + color: #96a6d7; +} + +.markdown-body .note>.admonition-title { + color: #d7c896; +} + +.markdown-body .admonition:before, +.markdown-body .attention:before, +.markdown-body .caution:before, +.markdown-body .hint:before, +.markdown-body .danger:before, +.markdown-body .question:before, +.markdown-body .note:before { + font: normal normal 16px fontawesome-mini; + -moz-osx-font-smoothing: grayscale; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + line-height: 1.5; + color: #333; + position: absolute; + left: 0; + top: 0; + padding-top: 10px; + padding-left: 10px; +} + +.markdown-body .admonition:before { + content: "\f056\00a0"; + color: 333; +} + +.markdown-body .attention:before { + content: "\f058\00a0"; + color: #a6d796; +} + +.markdown-body .caution:before { + content: "\f06a\00a0"; + color: #d7a796; +} + +.markdown-body .hint:before { + content: "\f05a\00a0"; + color: #96c6d7; +} + +.markdown-body .danger:before { + content: "\f057\00a0"; + color: #c25f77; +} + +.markdown-body .question:before { + content: "\f059\00a0"; + color: #96a6d7; +} + +.markdown-body .note:before { + content: "\f040\00a0"; + color: #d7c896; +} + +.markdown-body .admonition::after { + content: normal; +} + +.markdown-body .attention { + border-left: 6px solid #a6d796; +} + +.markdown-body .caution { + border-left: 6px solid #d7a796; +} + +.markdown-body .hint { + border-left: 6px solid #96c6d7; +} + +.markdown-body .danger { + border-left: 6px solid #c25f77; +} + +.markdown-body .question { + border-left: 6px solid #96a6d7; +} + +.markdown-body .note { + border-left: 6px solid #d7c896; +} + +.markdown-body .admonition>*:first-child { + margin-top: 0 !important; +} + +.markdown-body .admonition>*:last-child { + margin-bottom: 0 !important; +} + +/* progress bar*/ +.markdown-body .progress { + display: block; + width: 300px; + margin: 10px 0; + height: 24px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background-color: #ededed; + position: relative; + box-shadow: inset -1px 1px 3px rgba(0, 0, 0, .1); +} + +.markdown-body .progress-label { + position: absolute; + text-align: center; + font-weight: bold; + width: 100%; margin: 0; + line-height: 24px; + color: #333; + text-shadow: 1px 1px 0 #fefefe, -1px -1px 0 #fefefe, -1px 1px 0 #fefefe, 1px -1px 0 #fefefe, 0 1px 0 #fefefe, 0 -1px 0 #fefefe, 1px 0 0 #fefefe, -1px 0 0 #fefefe, 1px 1px 2px #000; + -webkit-font-smoothing: antialiased !important; + white-space: nowrap; + overflow: hidden; +} + +.markdown-body .progress-bar { + height: 24px; + float: left; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + background-color: #96c6d7; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .1); + background-size: 30px 30px; + background-image: -webkit-linear-gradient( + 135deg, rgba(255, 255, 255, .4) 27%, + transparent 27%, + transparent 52%, rgba(255, 255, 255, .4) 52%, + rgba(255, 255, 255, .4) 77%, + transparent 77%, transparent + ); + background-image: -moz-linear-gradient( + 135deg, + rgba(255, 255, 255, .4) 27%, transparent 27%, + transparent 52%, rgba(255, 255, 255, .4) 52%, + rgba(255, 255, 255, .4) 77%, transparent 77%, + transparent + ); + background-image: -ms-linear-gradient( + 135deg, + rgba(255, 255, 255, .4) 27%, transparent 27%, + transparent 52%, rgba(255, 255, 255, .4) 52%, + rgba(255, 255, 255, .4) 77%, transparent 77%, + transparent + ); + background-image: -o-linear-gradient( + 135deg, + rgba(255, 255, 255, .4) 27%, transparent 27%, + transparent 52%, rgba(255, 255, 255, .4) 52%, + rgba(255, 255, 255, .4) 77%, transparent 77%, + transparent + ); + background-image: linear-gradient( + 135deg, + rgba(255, 255, 255, .4) 27%, transparent 27%, + transparent 52%, rgba(255, 255, 255, .4) 52%, + rgba(255, 255, 255, .4) 77%, transparent 77%, + transparent + ); +} + +.markdown-body .progress-100plus .progress-bar { + background-color: #a6d796; +} + +.markdown-body .progress-80plus .progress-bar { + background-color: #c6d796; +} + +.markdown-body .progress-60plus .progress-bar { + background-color: #d7c896; +} + +.markdown-body .progress-40plus .progress-bar { + background-color: #d7a796; +} + +.markdown-body .progress-20plus .progress-bar { + background-color: #d796a6; +} + +.markdown-body .progress-0plus .progress-bar { + background-color: #c25f77; +} + +.markdown-body .candystripe-animate .progress-bar{ + -webkit-animation: animate-stripes 3s linear infinite; + -moz-animation: animate-stripes 3s linear infinite; + animation: animate-stripes 3s linear infinite; +} + +@-webkit-keyframes animate-stripes { + 0% { + background-position: 0 0; + } + + 100% { + background-position: 60px 0; + } +} + +@-moz-keyframes animate-stripes { + 0% { + background-position: 0 0; + } + + 100% { + background-position: 60px 0; + } +} + +@keyframes animate-stripes { + 0% { + background-position: 0 0; + } + + 100% { + background-position: 60px 0; + } +} + +.markdown-body .gloss .progress-bar { + box-shadow: + inset 0 4px 12px rgba(255, 255, 255, .7), + inset 0 -12px 0 rgba(0, 0, 0, .05); +} + +/* MultiMarkdown Critic Blocks */ +.markdown-body .critic_mark { + background: #ff0; +} + +.markdown-body .critic_delete { + color: #c82829; + text-decoration: line-through; +} + +.markdown-body .critic_insert { + color: #718c00 ; + text-decoration: underline; +} + +.markdown-body .critic_comment { + color: #8e908c; + font-style: italic; +} + +.markdown-body .headeranchor { + font: normal normal 16px fontawesome-mini; + line-height: 1; + display: inline-block; + text-decoration: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.headeranchor:before { + content: '\e157'; +} + +.markdown-body .task-list-item { + list-style-type: none; +} + +.markdown-body .task-list-item+.task-list-item { + margin-top: 3px; +} + +.markdown-body .task-list-item input { + margin: 0 4px 0.25em -20px; + vertical-align: middle; +} + +.markdown-body diagram-div, .markdown-body div.uml-sequence-diagram, .markdown-body, div.uml-flowchart { + overflow: auto; +} + +/* Media */ +@media only screen and (min-width: 480px) { + .markdown-body { + font-size:14px; + } +} + +@media only screen and (min-width: 768px) { + .markdown-body { + font-size:16px; + } +} + +@media print { + .markdown-body * { + background: transparent !important; + color: black !important; + filter:none !important; + -ms-filter: none !important; + } + + .markdown-body { + font-size:12pt; + max-width:100%; + outline:none; + border: 0; + } + + .markdown-body a, + .markdown-body a:visited { + text-decoration: underline; + } + + .markdown-body .headeranchor-link { + display: none; + } + + .markdown-body a[href]:after { + content: " (" attr(href) ")"; + } + + .markdown-body abbr[title]:after { + content: " (" attr(title) ")"; + } + + .markdown-body .ir a:after, + .markdown-body a[href^="javascript:"]:after, + .markdown-body a[href^="#"]:after { + content: ""; + } + + .markdown-body pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; + } + + .markdown-body pre, + .markdown-body blockquote { + border: 1px solid #999; + padding-right: 1em; + page-break-inside: avoid; + } + + .markdown-body .progress, + .markdown-body .progress-bar { + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; + } + + .markdown-body .progress { + border: 1px solid #ddd; + } + + .markdown-body .progress-bar { + height: 22px; + border-right: 1px solid #ddd; + } + + .markdown-body tr, + .markdown-body img { + page-break-inside: avoid; + } + + .markdown-body img { + max-width: 100% !important; + } + + .markdown-body p, + .markdown-body h2, + .markdown-body h3 { + orphans: 3; + widows: 3; + } + + .markdown-body h2, + .markdown-body h3 { + page-break-after: avoid; + } +} +</style><style>/*GitHub*/ +.highlight {background-color:#fff;color:#333333;} +.highlight .hll {background-color:#ffffcc;} +.highlight .c{color:#999988;font-style:italic} +.highlight .err{color:#a61717;background-color:#e3d2d2} +.highlight .k{font-weight:bold} +.highlight .o{font-weight:bold} +.highlight .cm{color:#999988;font-style:italic} +.highlight .cp{color:#999999;font-weight:bold} +.highlight .c1{color:#999988;font-style:italic} +.highlight .cs{color:#999999;font-weight:bold;font-style:italic} +.highlight .gd{color:#000000;background-color:#ffdddd} +.highlight .ge{font-style:italic} +.highlight .gr{color:#aa0000} +.highlight .gh{color:#999999} +.highlight .gi{color:#000000;background-color:#ddffdd} +.highlight .go{color:#888888} +.highlight .gp{color:#555555} +.highlight .gs{font-weight:bold} +.highlight .gu{color:#800080;font-weight:bold} +.highlight .gt{color:#aa0000} +.highlight .kc{font-weight:bold} +.highlight .kd{font-weight:bold} +.highlight .kn{font-weight:bold} +.highlight .kp{font-weight:bold} +.highlight .kr{font-weight:bold} +.highlight .kt{color:#445588;font-weight:bold} +.highlight .m{color:#009999} +.highlight .s{color:#dd1144} +.highlight .n{color:#333333} +.highlight .na{color:teal} +.highlight .nb{color:#0086b3} +.highlight .nc{color:#445588;font-weight:bold} +.highlight .no{color:teal} +.highlight .ni{color:purple} +.highlight .ne{color:#990000;font-weight:bold} +.highlight .nf{color:#990000;font-weight:bold} +.highlight .nn{color:#555555} +.highlight .nt{color:navy} +.highlight .nv{color:teal} +.highlight .ow{font-weight:bold} +.highlight .w{color:#bbbbbb} +.highlight .mf{color:#009999} +.highlight .mh{color:#009999} +.highlight .mi{color:#009999} +.highlight .mo{color:#009999} +.highlight .sb{color:#dd1144} +.highlight .sc{color:#dd1144} +.highlight .sd{color:#dd1144} +.highlight .s2{color:#dd1144} +.highlight .se{color:#dd1144} +.highlight .sh{color:#dd1144} +.highlight .si{color:#dd1144} +.highlight .sx{color:#dd1144} +.highlight .sr{color:#009926} +.highlight .s1{color:#dd1144} +.highlight .ss{color:#990073} +.highlight .bp{color:#999999} +.highlight .vc{color:teal} +.highlight .vg{color:teal} +.highlight .vi{color:teal} +.highlight .il{color:#009999} +.highlight .gc{color:#999;background-color:#EAF2F5} +</style><title>"How I scored a 10x speedup in terminal syntax highlighting"</title></head><body><article class="markdown-body"><p><em>This blog post describes the development of <code>clp</code>, a command line tool +to highlight source files. The source code is available on <a href="https://github.com/jpe90/clp">Github</a> and +<a href="https://git.sr.ht/~eskin/clp">Sourcehut</a>, and the repositories contain links to homebrew, AUR, and ubuntu PPA installers.</em></p> +<p>I like to develop software from the command line, so I often explore codebases +by running a ripgrep piped to FZF, with a file previewer to show search +results, like in the following script:</p> +<div class="highlight"><pre>#!/bin/sh + +rg --line-number --no-heading --color=always --smart-case &quot;$@&quot; | fzf -d &#39;:&#39; -n 2.. --ansi --no-sort --preview-window &#39;right:60%:+{2}-/2&#39; --preview &#39;bat --style=numbers --color=always --highlight-line {2} {1}&#39; +</pre></div> + +<p>Ocassionally I&rsquo;ve noticed that the previewer chokes on large files. After it +happened a few times, I got curious enough to poke around and see what was +going on.</p> +<p>It turns out that the preview tool used above, bat, can take up to several +seconds to parse and display large source files. When I work in a large project +with lots of large files, this can lead to noticeable hiccups.</p> +<p>Bat has a lot of features, but I only use it as a previewer for FZF. I wondered +if there was another program that could highlight source code more quickly. I +found several, but they had far less extensive language support. Bat +uses the Rust library [Syntect] for highlighting, which allows it to use any +Sublime syntax definition for highlighting. All the programs I found either had +fast execution or wide language support, but not both.</p> +<h1 id="filling-the-void">Filling the void<a class="headerlink" href="#filling-the-void" title="Permanent link"></a></h1> +<p>A side effect of being very easily distracted is that you occasionally learn +useful things. For example, I learned about using PEG lexers to highlight +source code by spelunking in the internals of the +<a href="https://github.com/martanne/vis">Vis editor</a>. Vis upstreams its lexers from +the <a href="https://github.com/orbitalquark/scintillua">Scintillua</a> project, which +currently maintains grammars for around 150 languages.</p> +<p>I found some code on the <a href="https://github.com/martanne/vis/issues/601">Vis issue tracker</a>. I dropped that code into a file and ran a quick benchmark to </p> +<h1 id="more-lexers">more lexers<a class="headerlink" href="#more-lexers" title="Permanent link"></a></h1> +<pre><code>- scintillua is very open to new lexers- no restrictions +- orbitalquark is very helpful and responsive +</code></pre> +<h1 id="call-for-contributions">call for contributions<a class="headerlink" href="#call-for-contributions" title="Permanent link"></a></h1> +<p>The most surprising thing about my project was how much I learned by completing +it. I started the project with <em>very</em> little working knowledge of C, Lua, and +Autotools, and walked away with much more concrete understanding of not only +those but also package managers,</p> +<p>fzf &ndash;margin 5% &ndash;padding 5% &ndash;border &ndash;preview &lsquo;cat {}&rsquo; \ +&ndash;color bg:#222222,preview-bg:#333333</p> +<p>rg &ndash;line-number &ndash;no-heading &ndash;color=always &ndash;smart-case &ldquo;$@&rdquo; | fzf -d &lsquo;:&rsquo; -n 2.. &ndash;ansi &ndash;no-sort &ndash;preview-window &lsquo;right:60%:+{2}-/2&rsquo; &ndash;preview &lsquo;clp {1}&rsquo;</p></article></body></html> +\ No newline at end of file diff --git a/blog/clp/index.html b/blog/clp/index.html @@ -0,0 +1,374 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>Fast Command Line Syntax Highlighting with clp | Jon Eskin&#39;s Blog</title> +<meta name="title" content="Fast Command Line Syntax Highlighting with clp" /> +<meta name="description" content="clp&rsquo;s source code and installation instructions are available on Github and Sourcehut. It’s a work in progress hobby project, so expect bugs and quirks. +clp is a program that writes files to stdout with syntax highlighting. I built it to quickly fill fzf&rsquo;s preview window. +It&rsquo;s similar to bat but is simpler, faster, and easier to add languages that don&rsquo;t have existing Sublime syntax definitions. +When the --preview option is set in fzf, the preview command is kicked off in an external process and the results are displayed in the preview window, which in this case is clp." /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="Fast Command Line Syntax Highlighting with clp" /> +<meta property="og:description" content="clp&rsquo;s source code and installation instructions are available on Github and Sourcehut. It’s a work in progress hobby project, so expect bugs and quirks. +clp is a program that writes files to stdout with syntax highlighting. I built it to quickly fill fzf&rsquo;s preview window. +It&rsquo;s similar to bat but is simpler, faster, and easier to add languages that don&rsquo;t have existing Sublime syntax definitions. +When the --preview option is set in fzf, the preview command is kicked off in an external process and the results are displayed in the preview window, which in this case is clp." /> +<meta property="og:type" content="article" /> +<meta property="og:url" content="https://jeskin.net/blog/clp/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="article:section" content="blog" /> +<meta property="article:published_time" content="2022-07-28T05:59:41-04:00" /> +<meta property="article:modified_time" content="2022-07-28T05:59:41-04:00" /><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="Fast Command Line Syntax Highlighting with clp"/> +<meta name="twitter:description" content="clp&rsquo;s source code and installation instructions are available on Github and Sourcehut. It’s a work in progress hobby project, so expect bugs and quirks. +clp is a program that writes files to stdout with syntax highlighting. I built it to quickly fill fzf&rsquo;s preview window. +It&rsquo;s similar to bat but is simpler, faster, and easier to add languages that don&rsquo;t have existing Sublime syntax definitions. +When the --preview option is set in fzf, the preview command is kicked off in an external process and the results are displayed in the preview window, which in this case is clp."/> + + + +<meta itemprop="name" content="Fast Command Line Syntax Highlighting with clp"> +<meta itemprop="description" content="clp&rsquo;s source code and installation instructions are available on Github and Sourcehut. It’s a work in progress hobby project, so expect bugs and quirks. +clp is a program that writes files to stdout with syntax highlighting. I built it to quickly fill fzf&rsquo;s preview window. +It&rsquo;s similar to bat but is simpler, faster, and easier to add languages that don&rsquo;t have existing Sublime syntax definitions. +When the --preview option is set in fzf, the preview command is kicked off in an external process and the results are displayed in the preview window, which in this case is clp."><meta itemprop="datePublished" content="2022-07-28T05:59:41-04:00" /> +<meta itemprop="dateModified" content="2022-07-28T05:59:41-04:00" /> +<meta itemprop="wordCount" content="850"><meta itemprop="image" content="https://jeskin.net/images/share.png"/> +<meta itemprop="keywords" content="" /> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> + +<h1>Fast Command Line Syntax Highlighting with clp</h1> +<p> + <i> + <time datetime='2022-07-28' pubdate> + 28 Jul, 2022 + </time> + </i> +</p> + +<content> + <p><em>clp&rsquo;s source code and installation instructions are available on <a href="https://github.com/jpe90/clp">Github</a> and <a href="https://sr.ht/~eskin/clp/">Sourcehut</a>. It’s a work in progress hobby project, so expect bugs and quirks.</em></p> +<p>clp is a program that writes files to stdout with syntax highlighting. I built it to quickly fill fzf&rsquo;s preview window.</p> +<p>It&rsquo;s similar to <a href="https://github.com/sharkdp/bat">bat</a> but is simpler, faster, and easier to add languages that don&rsquo;t have existing Sublime syntax definitions.</p> +<p>When the --preview option is set in fzf, the preview command is kicked off in an external process and the results are displayed in the preview window, which in this case is clp.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>fzf --preview <span style="color:#e6db74">&#39;clp {}&#39;</span></span></span></code></pre></div> +<p>Here&rsquo;s what we see when we execute the command:</p> +<p><img src="https://github.com/jpe90/images/raw/master/fzf_clp.png" alt="fzf_clp"></p> +<p>clp obtains syntax highlighting information from <a href="http://www.inf.puc-rio.br/~roberto/docs/peg.pdf">Parsing Expressing Grammar (PEG)</a> lexers provided by <a href="https://orbitalquark.github.io/scintillua/">Scintillua</a>.</p> +<p>The implementation is very simple; here&rsquo;s how clp works:</p> +<ul> +<li>shepherd input files to their respective lexer based on checks for filetype extension, MIME type, and more (thanks to Vis contributor Ian Nomar, who was hugely helpful in ironing out kinks in this project)</li> +<li>lex the input file and produce a list of tokens</li> +<li>iterate over the list of tokens: +<ul> +<li>for each token, it look up an ANSI color escape sequence corresponding to each token type, write it to stdout, and then write out the text that yielded the token to stdout</li> +</ul> +</li> +</ul> +<p>I hacked in an option to highlight line a line as well, since that&rsquo;s nice for file previewing.</p> +<p>Here&rsquo;s a performance comparison to similar programs taken from my machine, measuring the time it takes to highlight the <a href="https://sqlite.org/amalgamation.html">sqlite3 amalgamation</a> using <a href="https://github.com/sharkdp/hyperfine">hyperfine</a>:</p> +<table> +<thead> +<tr> +<th style="text-align:left">Command</th> +<th style="text-align:left">Mean [ms]</th> +<th style="text-align:left">Min [ms]</th> +<th style="text-align:left">Max [ms]</th> +<th style="text-align:left">Relative</th> +</tr> +</thead> +<tbody> +<tr> +<td style="text-align:left"><code>clp sqlite3.c</code></td> +<td style="text-align:left">212.7 ± 0.9</td> +<td style="text-align:left">211.5</td> +<td style="text-align:left">214.7</td> +<td style="text-align:left">1.00</td> +</tr> +<tr> +<td style="text-align:left"><code>bat --color=always sqlite3.c</code></td> +<td style="text-align:left">3178.0 ± 109.6</td> +<td style="text-align:left">3128.6</td> +<td style="text-align:left">3488.7</td> +<td style="text-align:left"><strong>14.94 ± 0.52</strong></td> +</tr> +<tr> +<td style="text-align:left"><code>source-highlight sqlite3.c</code></td> +<td style="text-align:left">4276.2 ± 12.6</td> +<td style="text-align:left">4259.6</td> +<td style="text-align:left">4297.7</td> +<td style="text-align:left"><strong>20.10 ± 0.11</strong></td> +</tr> +</tbody> +</table> +<p><img src="https://github.com/jpe90/images/raw/master/median.png" alt="median"></p> +<p>It&rsquo;s a pretty nice performance increase. It can also highlight around 150 programming languages, markup languages, input files, configuration files, and types of program output.</p> +<p>clp is currently limited to 16 colors; since the program itself can run on any system with a C99 compiler, I figured I&rsquo;d keep its default configuration very basic so it can run in any 16 color terminal emulator out of the box.</p> +<p>Down the line I would like to make clp more easily theme-able and add some built-in themes. I&rsquo;d also like to improve the aesthetics of line highlighting.</p> +<p>When I started the project, I had very little knowledge of Lua, Autotools, and C. Working on it was a very fun and satisfying way to get more familiar with all of them.</p> +<p>Overall, I&rsquo;m happy with how clp is coming along and am excited to add more. It&rsquo;s fast, supports a ton of languages, is easily extendable, and very portable to boot.</p> +<p>Contributions are welcome, and if you&rsquo;d like to add a lexer, you should submit it upstream to Scintillua. If it isn&rsquo;t accepted there, I will merge pretty much any lexer that does not try to mine for Bitcoin.</p> +<p><em>clp&rsquo;s source code and installation instructions are available on <a href="https://github.com/jpe90/clp">Github</a> and <a href="https://sr.ht/~eskin/clp/">Sourcehut</a></em></p> +<p><em>Update 8/20</em></p> +<h3 id="adding-color-themes">Adding color themes</h3> +<p>I&rsquo;ve added the ability to change clp&rsquo;s colors by selecting different built-in color themes or creating your own.</p> +<p>To change your theme, create a configuration file in <code>~/.config/clp/clprc.lua</code> to override the system default. It should look like this:</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span>clprc <span style="color:#f92672">=</span> {} +</span></span><span style="display:flex;"><span>clprc.theme <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;ansi-16&#34;</span> +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">return</span> clprc</span></span></code></pre></div> +<p>The value of <code>clprc.theme</code> is the name of a colorscheme that <code>clp</code> will later <code>require</code>. The following themes are available out of the box:</p> +<h3 id="3-bit-ansi-theme">3-bit ANSI theme</h3> +<ul> +<li><code>ansi-16</code></li> +</ul> +<h3 id="truecolor-themes">Truecolor themes</h3> +<ul> +<li><code>material</code></li> +<li><code>codedark</code></li> +<li><code>github_dark</code></li> +<li><code>github_light</code></li> +<li><code>gruvbox</code></li> +<li><code>tokyonight</code></li> +<li><code>sonokai</code></li> +<li><code>everforest</code></li> +</ul> +<p>The ANSI theme is enabled by default; it uses 16 color ANSI codes and should work on both light or dark terminals. The truecolors themes were exported from vim using <a href="https://github.com/jpe90/export-colorscheme.nvim">export-colorscheme.nvim</a>, which is a little neovim plugin I wrote recently.</p> +<p>You can create your own themes in <code>~/.config/clp/themes/</code>. Like with <code>clprc.lua</code>, these should be Lua modules. Here&rsquo;s the definition of <code>ansi-16</code>:</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span><span style="color:#66d9ef">local</span> M <span style="color:#f92672">=</span> {} +</span></span><span style="display:flex;"><span>M.theme <span style="color:#f92672">=</span> { +</span></span><span style="display:flex;"><span> [<span style="color:#e6db74">&#39;comment&#39;</span>] <span style="color:#f92672">=</span> {color<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;cyan&#34;</span>}, +</span></span><span style="display:flex;"><span> [<span style="color:#e6db74">&#39;keyword&#39;</span>] <span style="color:#f92672">=</span> {color<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;blue&#34;</span>}, +</span></span><span style="display:flex;"><span> [<span style="color:#e6db74">&#39;number&#39;</span>] <span style="color:#f92672">=</span> {color<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;red&#34;</span>}, +</span></span><span style="display:flex;"><span> [<span style="color:#e6db74">&#39;string&#39;</span>] <span style="color:#f92672">=</span> {color<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;green&#34;</span>}, +</span></span><span style="display:flex;"><span> [<span style="color:#e6db74">&#39;preprocessor&#39;</span>] <span style="color:#f92672">=</span> {color<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;magenta&#34;</span>}, +</span></span><span style="display:flex;"><span> [<span style="color:#e6db74">&#39;type&#39;</span>] <span style="color:#f92672">=</span> {color<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;yellow&#34;</span>}, +</span></span><span style="display:flex;"><span>} +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">return</span> M</span></span></code></pre></div> +<p>The table keys on the left correspond to lexical tokens picked up by the lexer, and the right specifies the color assigned to that token when the text is written to stdout.</p> +<p>When the right hand value is a Lua object like above, <code>clp</code> will use 16 color ANSI codes to highlight the token.</p> +<p>To use truecolor, the right hand value should be a string in the form <code>&quot;#RRGGBB&quot;</code> using hex values, like here:</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-lua" data-lang="lua"><span style="display:flex;"><span>[<span style="color:#e6db74">&#39;comment&#39;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;#6a9955&#34;</span>,</span></span></code></pre></div> +<p>This will cause <code>clp</code> to emit 24 bit color codes upon encountering the token. This means it will only render if the terminal being used <a href="https://github.com/termstandard/colors#fully-supporting">supports truecolor.</a></p> +<p>Throw a bunch of these definitions in a lua file in <code>~/.config/clp/themes/</code>, then set <code>clprc.theme</code> to the name of the file (not including the file extension), and you should be good to go!</p> +<h3 id="acknowledgements">Acknowledgements</h3> +<p>Many thanks to:</p> +<ul> +<li>Marc André Tanner &amp; contributors for Vis</li> +<li>Rich Felker for musl libc&rsquo;s awesome configure script and makefile</li> +<li>orbitalquark for Scintillua</li> +<li>Ian Nomar and Christopher Wellons for contributions &amp; suggestions</li> +</ul> + +</content> +<p> + +</p> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/blog/getting-started-with-cosmopolitan-libc/index.html b/blog/getting-started-with-cosmopolitan-libc/index.html @@ -0,0 +1,421 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>Getting Started with Cosmopolitan Libc | Jon Eskin&#39;s Blog</title> +<meta name="title" content="Getting Started with Cosmopolitan Libc" /> +<meta name="description" content="I recently learned a little bit about Cosmopolitan Libc in order to make a portable executable of clp, a small program written for POSIX systems. +I had a little bit of trouble getting started at first, so I thought it might be useful to write up what I learned. +In this blog post I&rsquo;ll share some of my notes on the basics of Cosmopolitan and demonstrate a couple approaches to building software with it." /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="Getting Started with Cosmopolitan Libc" /> +<meta property="og:description" content="I recently learned a little bit about Cosmopolitan Libc in order to make a portable executable of clp, a small program written for POSIX systems. +I had a little bit of trouble getting started at first, so I thought it might be useful to write up what I learned. +In this blog post I&rsquo;ll share some of my notes on the basics of Cosmopolitan and demonstrate a couple approaches to building software with it." /> +<meta property="og:type" content="article" /> +<meta property="og:url" content="https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="article:section" content="blog" /> +<meta property="article:published_time" content="2022-09-04T05:59:22-04:00" /> +<meta property="article:modified_time" content="2022-09-04T05:59:22-04:00" /><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="Getting Started with Cosmopolitan Libc"/> +<meta name="twitter:description" content="I recently learned a little bit about Cosmopolitan Libc in order to make a portable executable of clp, a small program written for POSIX systems. +I had a little bit of trouble getting started at first, so I thought it might be useful to write up what I learned. +In this blog post I&rsquo;ll share some of my notes on the basics of Cosmopolitan and demonstrate a couple approaches to building software with it."/> + + + +<meta itemprop="name" content="Getting Started with Cosmopolitan Libc"> +<meta itemprop="description" content="I recently learned a little bit about Cosmopolitan Libc in order to make a portable executable of clp, a small program written for POSIX systems. +I had a little bit of trouble getting started at first, so I thought it might be useful to write up what I learned. +In this blog post I&rsquo;ll share some of my notes on the basics of Cosmopolitan and demonstrate a couple approaches to building software with it."><meta itemprop="datePublished" content="2022-09-04T05:59:22-04:00" /> +<meta itemprop="dateModified" content="2022-09-04T05:59:22-04:00" /> +<meta itemprop="wordCount" content="1667"><meta itemprop="image" content="https://jeskin.net/images/share.png"/> +<meta itemprop="keywords" content="" /> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> + +<h1>Getting Started with Cosmopolitan Libc</h1> +<p> + <i> + <time datetime='2022-09-04' pubdate> + 04 Sep, 2022 + </time> + </i> +</p> + +<content> + <p>I recently learned a little bit about <a href="https://justine.lol/cosmopolitan/index.html">Cosmopolitan Libc</a> in order to make a portable executable of <a href="https://jeskin.net/blog/clp/">clp</a>, a small program written for POSIX systems.</p> +<p>I had a little bit of trouble getting started at first, so I thought it might be useful to write up what I learned.</p> +<p>In this blog post I&rsquo;ll share some of my notes on the basics of Cosmopolitan and demonstrate a couple approaches to building software with it.</p> +<ul> +<li><a href="#introduction-to-cosmopolitan-libc" title="Introduction to Cosmopolitan Libc">Introduction to Cosmopolitan Libc</a></li> +<li><a href="#building-programs-with-the-prebuilt-amalgamation" title="Building Programs with the Prebuilt Amalgamation">Building Programs with the Prebuilt Amalgamation</a></li> +<li><a href="#building-programs-inside-the-hermetic-monorepo" title="Building Programs Inside the Hermetic Monorepo">Building Programs Inside the Hermetic Monorepo</a></li> +<li><a href="#shortcut-for-portable-lua-programs" title="Shortcut for Portable Lua Programs">Shortcut for Portable Lua Programs</a></li> +</ul> +<h3 id="introduction-to-cosmopolitan-libc">Introduction to Cosmopolitan Libc</h3> +<p>Cosmopolitan is a C library. When you compile your C program and link it, your executable will be:</p> +<ul> +<li> +<p><strong>Runnable anywhere</strong>: it can be moved to a Linux, Mac OS X, Windows NT, FreeBSD, OpenBSD, and NetBSD and it will run.</p> +</li> +<li> +<p><strong>Single-file</strong>: Cosmo can package up everything your program needs to run inside a single executable zip file. You won&rsquo;t need to script installers to move files to platform-specific locations.</p> +</li> +<li> +<p><strong>Statically linked</strong>: all dependencies including libc are self contained in each executable.</p> +</li> +</ul> +<p>Cosmo&rsquo;s <strong>executables are tiny</strong>- far smaller than you&rsquo;d see for comparable from Rust or Go.</p> +<p>Binaries currently <strong>only target x86</strong>. They also run out of the box on Apple Silicon and Windows ARM thanks to their built in x86_64 emulation, and you can use explicit x86_64 emulation elsewhere.</p> +<p>GUI programs are not in a workable state or even an officially stated goal, although they are <a href="https://github.com/jart/cosmopolitan/issues/35">being explored</a>.</p> +<p>Build-once run-anywhere is achieved by the <strong>Actually Portable Executable (APE)</strong> format. Executables built by Cosmopolitan are interpreted by Windows as <a href="https://en.wikipedia.org/wiki/Portable_Executable">Portable Executables</a>, and on Unix they are interpreted as a shell script without a shebang line.</p> +<p>Now let&rsquo;s take a look at how we can use Cosmopolitan to build programs.</p> +<h3 id="building-programs-with-the-prebuilt-amalgamation">Building Programs with the Prebuilt Amalgamation</h3> +<p>The simplest way to build APE programs is to use GCC and link the <a href="https://justine.lol/cosmopolitan/cosmopolitan.zip">prebuilt library</a>.</p> +<p>An example of this approach can be seen in <a href="https://github.com/jpe90/hello-cosmo">this makefile project</a> consisting of two files:</p> +<p><em>hello.c</em></p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>() { +</span></span><span style="display:flex;"><span> printf(<span style="color:#e6db74">&#34;hello world</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>); +</span></span><span style="display:flex;"><span>} +</span></span></code></pre></div><p><em>Makefile</em> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>CC<span style="color:#f92672">=</span>gcc +</span></span><span style="display:flex;"><span>OBJCOPY<span style="color:#f92672">=</span>objcopy +</span></span><span style="display:flex;"><span>BASEURL<span style="color:#f92672">=</span>https://worker.jart.workers.dev +</span></span><span style="display:flex;"><span>AMALGAMATION<span style="color:#f92672">=</span>cosmopolitan-amalgamation-2.0.zip +</span></span><span style="display:flex;"><span>LIBCOSMO_SHA256_EXPECTED<span style="color:#f92672">=</span><span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>2228cd5924c001b2d8c8efcc9ddacaab354ba4c99a3e0c8858098e2c3f2e3fdb +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>hello.com: libcosmo hello.c +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">$(</span>CC<span style="color:#66d9ef">)</span> -g -Os -static -fno-pie -no-pie -nostdlib -nostdinc <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> -fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -o <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> hello.com.dbg hello.c -Wl,--gc-sections -fuse-ld<span style="color:#f92672">=</span>bfd -Wl,--gc-sections <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> -Wl,-T,libcosmo/ape.lds -include libcosmo/cosmopolitan.h <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> libcosmo/crt.o libcosmo/ape-no-modify-self.o <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span> libcosmo/cosmopolitan.a +</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">$(</span>OBJCOPY<span style="color:#66d9ef">)</span> -S -O binary hello.com.dbg hello.com +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>libcosmo: <span style="color:#66d9ef">$(</span>AMALGAMATION<span style="color:#66d9ef">)</span> +</span></span><span style="display:flex;"><span> @libcosmo_sha256_actual<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>sha256sum <span style="color:#66d9ef">$(</span>AMALGAMATION<span style="color:#66d9ef">)</span> | cut -d <span style="color:#e6db74">&#39; &#39;</span> -f 1<span style="color:#e6db74">`</span>; <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>echo <span style="color:#e6db74">&#34;expected sha256sum: </span><span style="color:#66d9ef">$(</span>LIBCOSMO_SHA256_EXPECTED<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">&amp;&amp;</span> echo <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span><span style="color:#e6db74">&#34;actual sha256sum: </span>$$<span style="color:#e6db74">libcosmo_sha256_actual&#34;</span>; <span style="color:#66d9ef">if</span> <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$$<span style="color:#e6db74">libcosmo_sha256_actual&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>LIBCOSMO_SHA256_EXPECTED<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span> echo <span style="color:#ae81ff">\ +</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span><span style="color:#e6db74">&#34;checksums match&#34;</span>; <span style="color:#66d9ef">else</span> echo <span style="color:#e6db74">&#34;checksums don&#39;t match, aborting&#34;</span> <span style="color:#f92672">&amp;&amp;</span> exit 1; <span style="color:#66d9ef">fi</span>; +</span></span><span style="display:flex;"><span> unzip -d libcosmo <span style="color:#66d9ef">$(</span>AMALGAMATION<span style="color:#66d9ef">)</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span><span style="color:#66d9ef">$(</span>AMALGAMATION<span style="color:#66d9ef">)</span>: +</span></span><span style="display:flex;"><span> wget <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>BASEURL<span style="color:#66d9ef">)</span><span style="color:#e6db74">/</span><span style="color:#66d9ef">$(</span>AMALGAMATION<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span> +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>clean: +</span></span><span style="display:flex;"><span> rm -f hello.com.dbg hello.com +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>distclean: clean +</span></span><span style="display:flex;"><span> rm -rf cosmopolitan* libcosmo</span></span></code></pre></div></p> +<p>You might notice that hello.c does not contain a <code>#include &lt;stdio.h&gt;</code> line to provide the header for printf. Ordinarily, the c compiler would search the system headers for this file, which would provide the function declaration for <code>printf</code>, and then the linker would find the definition in the system standard library.</p> +<p>In this case, the Makefile does not search the system headers because of the <code>-nostdinc</code> flag, and it doesn&rsquo;t link the system standard library because of the <code>-nostdlib</code> flag.</p> +<p>Instead, the makefile specifies an include for <code>cosmopolitan.h</code>, which provides declarations for all libc functions including <code>printf</code>, while the function definitions are provided by <code>cosmopolitan.a</code>.</p> +<p>Because of the <code>-nostdinc</code> flag, if we added the include line to <code>hello.c</code>, we would get an error:</p> +<pre tabindex="0"><code>hello.c:1:19: error: no include path in which to search for stdio.h + 1 | #include &lt;stdio.h&gt; +</code></pre><p>As you might imagine, this will cause issues when you&rsquo;re trying to port existing code written against the standard library. In some cases, there&rsquo;s quite a few of them- too many to remove by hand. And we can&rsquo;t just remove the <code>-nostdinc</code> flag, otherwise the compiler would find conflicting function declarations.</p> +<p>A workaround is to create a folder in your project, fill it empty files that have names of all the system headers your code is looking for, and include that folder in the build path.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span><span style="color:#f92672">--- +</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span> Makefile | 2 +- +</span></span><span style="display:flex;"><span> header_stubs/stdio.h | 0 +</span></span><span style="display:flex;"><span> hello.c | 2 ++ +</span></span><span style="display:flex;"><span> 3 files changed, 3 insertions(+), 1 deletion(-) +</span></span><span style="display:flex;"><span> create mode 100644 header_stubs/stdio.h +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span>diff --git a/Makefile b/Makefile +</span></span><span style="display:flex;"><span>index 4bd867d..f7d3623 100644 +</span></span><span style="display:flex;"><span><span style="color:#f92672">--- a/Makefile +</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+++ b/Makefile +</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span><span style="color:#75715e">@@ -10,7 +10,7 @@ hello.com: libcosmo hello.c +</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span> hello.com.dbg hello.c -Wl,--gc-sections -fuse-ld=bfd -Wl,--gc-sections \ +</span></span><span style="display:flex;"><span> -Wl,-T,libcosmo/ape.lds -include libcosmo/cosmopolitan.h \ +</span></span><span style="display:flex;"><span> libcosmo/crt.o libcosmo/ape-no-modify-self.o \ +</span></span><span style="display:flex;"><span><span style="color:#f92672">- libcosmo/cosmopolitan.a +</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+ libcosmo/cosmopolitan.a -Iheader_stubs/ +</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span> $(OBJCOPY) -S -O binary hello.com.dbg hello.com +</span></span><span style="display:flex;"><span> +</span></span><span style="display:flex;"><span> libcosmo: $(AMALGAMATION) +</span></span><span style="display:flex;"><span>diff --git a/header_stubs/stdio.h b/header_stubs/stdio.h +</span></span><span style="display:flex;"><span>new file mode 100644 +</span></span><span style="display:flex;"><span>index 0000000..e69de29 +</span></span><span style="display:flex;"><span>diff --git a/hello.c b/hello.c +</span></span><span style="display:flex;"><span>index d07c467..11f7c99 100644 +</span></span><span style="display:flex;"><span><span style="color:#f92672">--- a/hello.c +</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+++ b/hello.c +</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span><span style="color:#75715e">@@ -1,3 +1,5 @@ +</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#a6e22e">+#include &lt;stdio.h&gt; +</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+ +</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span> int main() { +</span></span><span style="display:flex;"><span> printf(&#34;hello world\n&#34;); +</span></span><span style="display:flex;"><span> } +</span></span><span style="display:flex;"><span><span style="color:#f92672">-- +</span></span></span></code></pre></div><p>This way the includes specified by the source code are found, but they&rsquo;re replaced with empty content during preprocessing. This is what you want, since the declarations that the includes usually contain are already provided by <code>cosmopolitan.h</code>.</p> +<p>I think building with the prebuilt amalgamation makes sense for small projects with few dependencies. It keeps the size of the source repository small and builds quickly.</p> +<p>I was able to build <code>clp</code> with this approach by forking <a href="https://github.com/ahgamut/lua/tree/cosmopolitan">another project</a> which built Lua using the amalgamation prior to its inclusion in the hermetic monorepo. You can see the result <a href="https://github.com/jpe90/clp-prebuilt-cosmo/tree/clp">here</a>.</p> +<p>Without that fork existing, I wouldn&rsquo;t have been able to compile clp this way. If your projects require non-trivial external dependencies, you&rsquo;ll really need to know what you&rsquo;re doing to get it to build.</p> +<p>Luckily for me, there&rsquo;s a different option that provides additional batteries.</p> +<h3 id="building-programs-inside-the-hermetic-monorepo">Building Programs Inside the Hermetic Monorepo</h3> +<p>Another way to build APE programs is to use the <a href="https://github.com/jart/cosmopolitan">hermetic monorepo</a>. You&rsquo;ll only need make installed on your system to build it; it uses a vendored GCC to bootstrap itself.</p> +<p>The repository is managed with an interconnected system of makefiles which is documented <a href="https://github.com/jart/cosmopolitan/blob/master/Makefile#L99-L230">within the main Makefile</a> that you use for building.</p> +<p>In addition to providing core system functionality, the repository contains many programs, utilities, libraries, including the <a href="https://redbean.dev">redbean single file web server</a>, a <a href="https://justine.lol/blinkenlights/">command line debugger</a>, an <a href="https://justine.lol/nesemu1.html">nes emulator that runs in a terminal</a>, implementations of sed, awk, and make, and much more. The code in all these projects is tailored to Cosmopolitan, which is nice because it makes it easier to yoink from them compared to external code that might need some finangling.</p> +<p>For quick and dirty programs, you can drop a C file inside <a href="https://github.com/jart/cosmopolitan/tree/master/examples">the examples folder</a> and it&rsquo;ll get picked up and built inside <code>o/examples</code>. That can be nice for trying out ideas or getting up and running quickly.</p> +<p>For more involved projects, or for adding re-usable libraries, you will probably want to add a third_party module.</p> +<p>Third_party modules follow repository-wide conventions where they include Makefiles that declare their source files, header files, dependencies on other packages, and more.</p> +<p>To add a third_party module, you&rsquo;ll want to study the <a href="https://github.com/jart/cosmopolitan/tree/master/examples/package">example library package</a> and some of the programs packaged in the repository. You can also check out <a href="https://github.com/jpe90/cosmopolitan/tree/clp">my fork</a>, where I added a clp third_party.</p> +<p>I&rsquo;d love to give a detailed breakdown of how to properly write a makefile for a third party, but I pretty much just copied sed&rsquo;s, changed stuff, and hacked in some extras.</p> +<p>Maintaining a personal fork of the monorepo and adding your own packages to it looks like a good way to manage projects. The repository appears designed to be modular and extensible, so upstream changes seem unlikely to break your code. If you want to core parts of the monorepo for a single package, you could always do so on another branch.</p> +<p>Using the hermetic monorepo might seem like overkill for a tiny program. It&rsquo;s pretty big repository, and the initial build can be kind of long. On the other hand, the executables it produces are tiny, iterative builds are quick, it gives nice options for tuning build output, and in general it makes maintainence easier.</p> +<p>There&rsquo;s another option for building software that I think is worth mentioning.</p> +<h3 id="shortcut-for-portable-lua-programs">Shortcut for Portable Lua Programs</h3> +<p>Here&rsquo;s a quick demonstration of how to package portable Lua programs. In this section we&rsquo;ll build the Lua interpreter, copy it to the base of the repository, zip up a lua file into the executable, and configure it to run the lua file when the file is run.</p> +<p>First, grab the monorepo if you haven&rsquo;t already.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git clone https://github.com/jart/cosmopolitan.git +</span></span><span style="display:flex;"><span>cd cosmopolitan +</span></span></code></pre></div><p>From this point on, all commands should be run from the base of the repository.</p> +<p>Build the Lua interpreter, and copy it to the base of the repo.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>build/bootstrap/make.com -j<span style="color:#66d9ef">$(</span>nproc<span style="color:#66d9ef">)</span> o//third_party/lua +</span></span><span style="display:flex;"><span>cp o//third_party/lua/lua.com . +</span></span></code></pre></div><p>Next, make a <code>.lua</code> folder and build the <code>zip.com</code> program.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir -p .lua +</span></span><span style="display:flex;"><span>build/bootstrap/make.com -j<span style="color:#66d9ef">$(</span>nproc<span style="color:#66d9ef">)</span> o//third_party/zip +</span></span></code></pre></div><p>Now create a file <code>mymodule.lua</code> inside <code>.lua</code> by pasting the following text into your shell.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>printf %s <span style="color:#e6db74">&#39;local mymodule = {} +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">function mymodule.hello() +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> print(&#34;Hello World!&#34;) +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">end +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">return mymodule&#39;</span> &gt; .lua/mymodule.lua +</span></span></code></pre></div><p>Next create a file <code>.args</code> in the base of the repository by again pasting the following text into your shell.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>printf %s <span style="color:#e6db74">&#39;-l +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">mymodule +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">-e +</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">require&#34;mymodule&#34;.hello()&#39;</span> &gt; .args +</span></span></code></pre></div><p>This file will tell be loaded by the modified interpreter and the arguments will be presented to the interpreter as if they came from the command line.</p> +<p>Finally, we&rsquo;ll use the <code>zip.com</code> program to load a <code>.lua</code> directory containing your lua files and the <code>.args</code> file which launches your program into the Lua interpreter binary.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>./o/third_party/zip/zip.com -r lua.com .lua/ +</span></span><span style="display:flex;"><span>./o/third_party/zip/zip.com -r lua.com .args +</span></span></code></pre></div><p>Now if you run <code>lua.com</code>, the program will run the lua file and print &ldquo;Hello World!&rdquo; as if you had run it with <code>lua.com -l mymodule -e 'require&quot;mymodule&quot;.hello()'</code>.</p> +<p>You can read more about these in the <code>/.args</code> and the <code>/.lua/...</code> sections of <a href="https://redbean.dev/#specials">redbean&rsquo;s documenation</a>; just be aware that not all of redbean&rsquo;s functionality is available to the Lua interpreter out of the box.</p> +<h3 id="wrap-up">Wrap Up</h3> +<p>That covers most of what I figured out on my own while playing around with Cosmopolitan.</p> +<p>If you want to see what other people have done, check out some of the projects here: <a href="https://github.com/shmup/awesome-cosmopolitan">https://github.com/shmup/awesome-cosmopolitan</a></p> +<h3 id="acknowledgements">Acknowledgements</h3> +<p>Thanks to <a href="https://justine.lol">Justine Tunney</a> for guidance on porting clp.</p> + +</content> +<p> + +</p> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/blog/grep-fzf-clp/index.html b/blog/grep-fzf-clp/index.html @@ -0,0 +1,294 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>CLI Workflow with Grep, Fzf, and Clp | Jon Eskin&#39;s Blog</title> +<meta name="title" content="CLI Workflow with Grep, Fzf, and Clp" /> +<meta name="description" content="Introduction grep, ag, and ripgrep search file contents for text that matches regular expressions. The previous links show some of their more advanced options. +fzf is an interactive Unix filter. You can feed it anything from stdin (files, previously entered commands, etc) and it displays the results on the screen along with a prompt. When you type into the prompt, fzf filters the list. +When combined, they can substantially speed up a CLI workflow." /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="CLI Workflow with Grep, Fzf, and Clp" /> +<meta property="og:description" content="Introduction grep, ag, and ripgrep search file contents for text that matches regular expressions. The previous links show some of their more advanced options. +fzf is an interactive Unix filter. You can feed it anything from stdin (files, previously entered commands, etc) and it displays the results on the screen along with a prompt. When you type into the prompt, fzf filters the list. +When combined, they can substantially speed up a CLI workflow." /> +<meta property="og:type" content="article" /> +<meta property="og:url" content="https://jeskin.net/blog/grep-fzf-clp/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="article:section" content="blog" /> +<meta property="article:published_time" content="2022-08-02T05:50:00-04:00" /> +<meta property="article:modified_time" content="2022-08-02T05:50:00-04:00" /><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="CLI Workflow with Grep, Fzf, and Clp"/> +<meta name="twitter:description" content="Introduction grep, ag, and ripgrep search file contents for text that matches regular expressions. The previous links show some of their more advanced options. +fzf is an interactive Unix filter. You can feed it anything from stdin (files, previously entered commands, etc) and it displays the results on the screen along with a prompt. When you type into the prompt, fzf filters the list. +When combined, they can substantially speed up a CLI workflow."/> + + + +<meta itemprop="name" content="CLI Workflow with Grep, Fzf, and Clp"> +<meta itemprop="description" content="Introduction grep, ag, and ripgrep search file contents for text that matches regular expressions. The previous links show some of their more advanced options. +fzf is an interactive Unix filter. You can feed it anything from stdin (files, previously entered commands, etc) and it displays the results on the screen along with a prompt. When you type into the prompt, fzf filters the list. +When combined, they can substantially speed up a CLI workflow."><meta itemprop="datePublished" content="2022-08-02T05:50:00-04:00" /> +<meta itemprop="dateModified" content="2022-08-02T05:50:00-04:00" /> +<meta itemprop="wordCount" content="576"><meta itemprop="image" content="https://jeskin.net/images/share.png"/> +<meta itemprop="keywords" content="" /> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> + +<h1>CLI Workflow with Grep, Fzf, and Clp</h1> +<p> + <i> + <time datetime='2022-08-02' pubdate> + 02 Aug, 2022 + </time> + </i> +</p> + +<content> + <h3 id="introduction">Introduction</h3> +<p><a href="https://tldr.ostera.io/grep">grep</a>, <a href="https://tldr.ostera.io/ag">ag</a>, and <a href="https://www.mankier.com/1/rg">ripgrep</a> search file contents for text that matches regular expressions. The previous links show some of their more advanced options.</p> +<p>fzf is an interactive Unix filter. You can feed it anything from stdin (files, previously entered commands, etc) and it displays the results on the screen along with a prompt. When you type into the prompt, fzf filters the list.</p> +<p>When combined, they can substantially speed up a CLI workflow.</p> +<h3 id="fzf-overview">fzf overview</h3> +<p>The command &ldquo;fzf&rdquo; on its own populates the list with all files in the current directory and its subfolders.</p> +<p>If you&rsquo;ve installed fzf from a distribution package manager, pressing <a href="https://wiki.archlinux.org/title/fzf#Shells">Ctrl+r</a> at a shell prompt populates the list with show your command history.</p> +<p>As you type into the prompt, fzf narrows the results by fuzzy matching (e.g. typing &ldquo;vcaa&rdquo; matches <code><span style="color:red">v</span>im ~/.<span style="color:red">c</span>onfig/<span style="color:red">a</span>erc/<span style="color:red">a</span>erc.conf</code>). I find this very useful for digging up infrequently used commands involving git, ssh, or the system clipboard.</p> +<p>The --preview option will kick off a program in a subprocess and display its output <a href="https://github.com/junegunn/fzf#preview-window">in a tiled window</a>.</p> +<p>The following command uses <a href="https://jeskin.net/blog/clp/">clp</a> to fill the preview window. clp takes a file and writes it to stdout with syntax highlighting. fzf will provide the filename for each result, feed it to clp, and display the output in the righthand pane.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>fzf --preview <span style="color:#e6db74">&#39;clp {}&#39;</span></span></span></code></pre></div> +<p><img src="https://github.com/jpe90/images/raw/master/fzf_clp.png" alt="fzf_clp"></p> +<p>You can scroll the preview window by holding shift pressing up/down, or by using your mouse wheel.</p> +<h3 id="combination">Combination</h3> +<p>You can combine fzf and grep tool such as grep with fzf with a Unix pipe. Let&rsquo;s see how that works.</p> +<p>We&rsquo;ll start by grepping for the the word &ldquo;time&rdquo;, chosen for just for demonstrative purposes:</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>grep --recursive --line-number --binary-files<span style="color:#f92672">=</span>without-match <span style="color:#e6db74">&#34;time&#34;</span> .</span></span></code></pre></div> +<p>Here&rsquo;s grep&rsquo;s output, run in the <a href="https://harelang.org">Hare programming language&rsquo;s</a> source directory:</p> +<p><img src="https://github.com/jpe90/images/raw/master/grep.png" alt="grep"></p> +<p>We can tell fzf to pick apart the output; we state that it&rsquo;s colon delimited and that we want to pass the first column (the filename) to clp: +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>grep --recursive --line-number --binary-files<span style="color:#f92672">=</span>without-match <span style="color:#e6db74">&#34;time&#34;</span> . | fzf --delimiter<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;:&#39;</span> --preview <span style="color:#e6db74">&#39;clp {1}&#39;</span></span></span></code></pre></div></p> +<p><img src="https://github.com/jpe90/images/raw/master/fzf_grep.png" alt="fzf_grep"></p> +<p>Observe that the second column of grep&rsquo;s output contains the line number of the match.</p> +<p>We can tell fzf to center the output of the preview window on the matched line and tell clp to highlight the line with the -h flag.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>grep --recursive --line-number --binary-files<span style="color:#f92672">=</span>without-match <span style="color:#e6db74">&#34;time&#34;</span> . | fzf --delimiter<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;:&#39;</span> -n 2.. --preview-window <span style="color:#e6db74">&#39;+{2}-/2&#39;</span> --preview <span style="color:#e6db74">&#39;clp -h {2} {1}&#39;</span></span></span></code></pre></div> +<p><img src="https://github.com/jpe90/images/raw/master/fzf_clp_line2.png" alt="fzf_clp_line"></p> +<p>Finally, we can bind a key to open the file in a text editor and jump to the location of the matched line. When we quit the editor, we&rsquo;ll be right back where we were in fzf.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>grep --recursive --line-number --binary-files<span style="color:#f92672">=</span>without-match <span style="color:#e6db74">&#34;time&#34;</span> . | fzf --delimiter<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;:&#39;</span> -n 2.. --preview-window <span style="color:#e6db74">&#39;+{2}-/2&#39;</span> --preview <span style="color:#e6db74">&#39;clp -h {2} {1}&#39;</span> --bind <span style="color:#e6db74">&#39;ctrl-o:execute(vim +{2} {1} &lt; /dev/tty)&#39;</span></span></span></code></pre></div> +<p>Note that you can trivially swap out grep for ag or ripgrep and it&rsquo;ll work just fine.</p> +<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ag --color --line-number <span style="color:#e6db74">&#34;time&#34;</span> | fzf --delimiter<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;:&#39;</span> -n 2.. --preview-window <span style="color:#e6db74">&#39;+{2}-/2&#39;</span> --preview <span style="color:#e6db74">&#39;clp -h {2} {1}&#39;</span> --bind <span style="color:#e6db74">&#39;ctrl-o:execute(vim +{2} {1} &lt; /dev/tty)&#39;</span></span></span></code></pre></div> +<p>The command has grown pretty long. I tend to throw everything after the first pipe in a script on my path and pipe grep commands to that instead.</p> +<p>I use this script often; it&rsquo;s handy for quickly jumping back and forth between fzf and your editor to make a series of quick edits.</p> +<p><a href="https://asciinema.org/a/gUeDIEoyDzIhHuMbtFXZLDY3M"><img src="https://asciinema.org/a/gUeDIEoyDzIhHuMbtFXZLDY3M.svg" alt="asciicast"></a></p> +<!-- raw HTML omitted --> +<p>In conclusion, we&rsquo;ve seen that this approach provides editor agnostic searching and file previewing. Having grep at your fingertips allows you to effortlessly make elaborate searches without the constraints of editor plugins.</p> + +</content> +<p> + +</p> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/blog/index.html b/blog/index.html @@ -0,0 +1,277 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>Blogs | Jon Eskin&#39;s Blog</title> +<meta name="title" content="Blogs" /> +<meta name="description" content="Jon Eskin&#39;s Personal Blog" /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="Blogs" /> +<meta property="og:description" content="Jon Eskin&#39;s Personal Blog" /> +<meta property="og:type" content="website" /> +<meta property="og:url" content="https://jeskin.net/blog/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="Blogs"/> +<meta name="twitter:description" content="Jon Eskin&#39;s Personal Blog"/> + + + +<meta itemprop="name" content="Blogs"> +<meta itemprop="description" content="Jon Eskin&#39;s Personal Blog"> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <link rel="alternate" type="application/rss+xml" href="https://jeskin.net/blog/index.xml" title="Jon Eskin's Blog" /> + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> +<content> + + <ul class="blog-posts"> + + <li> + <span> + <i> + <time datetime='2022-09-04' pubdate> + 04 Sep, 2022 + </time> + </i> + </span> + <a href="https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/">Getting Started with Cosmopolitan Libc</a> + </li> + + <li> + <span> + <i> + <time datetime='2022-08-02' pubdate> + 02 Aug, 2022 + </time> + </i> + </span> + <a href="https://jeskin.net/blog/grep-fzf-clp/">CLI Workflow with Grep, Fzf, and Clp</a> + </li> + + <li> + <span> + <i> + <time datetime='2022-07-28' pubdate> + 28 Jul, 2022 + </time> + </i> + </span> + <a href="https://jeskin.net/blog/clp/">Fast Command Line Syntax Highlighting with clp</a> + </li> + + </ul> + + <small> + <div> + + </div> + </small> + +</content> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/blog/index.xml b/blog/index.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> + <channel> + <title>Blogs on Jon Eskin&#39;s Blog</title> + <link>https://jeskin.net/blog/</link> + <description>Recent content in Blogs on Jon Eskin&#39;s Blog</description> + <generator>Hugo -- gohugo.io</generator> + <language>en-US</language> + <copyright>Copyright © 2022, Jon Eskin.</copyright> + <lastBuildDate>Sun, 04 Sep 2022 05:59:22 -0400</lastBuildDate><atom:link href="https://jeskin.net/blog/index.xml" rel="self" type="application/rss+xml" /> + <item> + <title>Getting Started with Cosmopolitan Libc</title> + <link>https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/</link> + <pubDate>Sun, 04 Sep 2022 05:59:22 -0400</pubDate> + + <guid>https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/</guid> + <description>I recently learned a little bit about Cosmopolitan Libc in order to make a portable executable of clp, a small program written for POSIX systems. +I had a little bit of trouble getting started at first, so I thought it might be useful to write up what I learned. +In this blog post I&amp;rsquo;ll share some of my notes on the basics of Cosmopolitan and demonstrate a couple approaches to building software with it.</description> + </item> + + <item> + <title>CLI Workflow with Grep, Fzf, and Clp</title> + <link>https://jeskin.net/blog/grep-fzf-clp/</link> + <pubDate>Tue, 02 Aug 2022 05:50:00 -0400</pubDate> + + <guid>https://jeskin.net/blog/grep-fzf-clp/</guid> + <description>Introduction grep, ag, and ripgrep search file contents for text that matches regular expressions. The previous links show some of their more advanced options. +fzf is an interactive Unix filter. You can feed it anything from stdin (files, previously entered commands, etc) and it displays the results on the screen along with a prompt. When you type into the prompt, fzf filters the list. +When combined, they can substantially speed up a CLI workflow.</description> + </item> + + <item> + <title>Fast Command Line Syntax Highlighting with clp</title> + <link>https://jeskin.net/blog/clp/</link> + <pubDate>Thu, 28 Jul 2022 05:59:41 -0400</pubDate> + + <guid>https://jeskin.net/blog/clp/</guid> + <description>clp&amp;rsquo;s source code and installation instructions are available on Github and Sourcehut. It’s a work in progress hobby project, so expect bugs and quirks. +clp is a program that writes files to stdout with syntax highlighting. I built it to quickly fill fzf&amp;rsquo;s preview window. +It&amp;rsquo;s similar to bat but is simpler, faster, and easier to add languages that don&amp;rsquo;t have existing Sublime syntax definitions. +When the --preview option is set in fzf, the preview command is kicked off in an external process and the results are displayed in the preview window, which in this case is clp.</description> + </item> + + </channel> +</rss> diff --git a/categories/index.html b/categories/index.html @@ -0,0 +1,248 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>Categories | Jon Eskin&#39;s Blog</title> +<meta name="title" content="Categories" /> +<meta name="description" content="Jon Eskin&#39;s Personal Blog" /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="Categories" /> +<meta property="og:description" content="Jon Eskin&#39;s Personal Blog" /> +<meta property="og:type" content="website" /> +<meta property="og:url" content="https://jeskin.net/categories/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="Categories"/> +<meta name="twitter:description" content="Jon Eskin&#39;s Personal Blog"/> + + + +<meta itemprop="name" content="Categories"> +<meta itemprop="description" content="Jon Eskin&#39;s Personal Blog"> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <link rel="alternate" type="application/rss+xml" href="https://jeskin.net/categories/index.xml" title="Jon Eskin's Blog" /> + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> +<content> + + <h3 style="margin-bottom:0">Filtering for "Categories"</h3> + <small> + <a href="/blog">Remove filter</a> + </small> + + <ul class="blog-posts"> + + <li> + No posts yet + </li> + + </ul> + + +</content> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/categories/index.xml b/categories/index.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> + <channel> + <title>Categories on Jon Eskin&#39;s Blog</title> + <link>https://jeskin.net/categories/</link> + <description>Recent content in Categories on Jon Eskin&#39;s Blog</description> + <generator>Hugo -- gohugo.io</generator> + <language>en-US</language> + <copyright>Copyright © 2022, Jon Eskin.</copyright><atom:link href="https://jeskin.net/categories/index.xml" rel="self" type="application/rss+xml" /> + </channel> +</rss> diff --git a/favicon.ico b/favicon.ico Binary files differ. diff --git a/images/favicon.png b/images/favicon.png Binary files differ. diff --git a/index.html b/index.html @@ -0,0 +1,236 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta name="generator" content="Hugo 0.101.0" /> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>Jon Eskin&#39;s Blog</title> +<meta name="title" content="Jon Eskin&#39;s Blog" /> +<meta name="description" content="Jon Eskin&#39;s Personal Blog" /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="" /> +<meta property="og:description" content="Jon Eskin&#39;s Personal Blog" /> +<meta property="og:type" content="website" /> +<meta property="og:url" content="https://jeskin.net/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content=""/> +<meta name="twitter:description" content="Jon Eskin&#39;s Personal Blog"/> + + + +<meta itemprop="name" content=""> +<meta itemprop="description" content="Jon Eskin&#39;s Personal Blog"> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <link rel="alternate" type="application/rss+xml" href="https://jeskin.net/index.xml" title="Jon Eskin's Blog" /> + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> +<p>Hi! I like to work on open source stuff and write about things I find interesting.</p> +<p><a href="https://github.com/jpe90">Github</a></p> +<p><a href="mailto:eskinjp@gmail.com">Contact me</a></p> + + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/index.xml b/index.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> + <channel> + <title>Jon Eskin&#39;s Blog</title> + <link>https://jeskin.net/</link> + <description>Recent content on Jon Eskin&#39;s Blog</description> + <generator>Hugo -- gohugo.io</generator> + <language>en-US</language> + <copyright>Copyright © 2022, Jon Eskin.</copyright> + <lastBuildDate>Sun, 04 Sep 2022 05:59:22 -0400</lastBuildDate><atom:link href="https://jeskin.net/index.xml" rel="self" type="application/rss+xml" /> + <item> + <title>Getting Started with Cosmopolitan Libc</title> + <link>https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/</link> + <pubDate>Sun, 04 Sep 2022 05:59:22 -0400</pubDate> + + <guid>https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/</guid> + <description>I recently learned a little bit about Cosmopolitan Libc in order to make a portable executable of clp, a small program written for POSIX systems. +I had a little bit of trouble getting started at first, so I thought it might be useful to write up what I learned. +In this blog post I&amp;rsquo;ll share some of my notes on the basics of Cosmopolitan and demonstrate a couple approaches to building software with it.</description> + </item> + + <item> + <title>CLI Workflow with Grep, Fzf, and Clp</title> + <link>https://jeskin.net/blog/grep-fzf-clp/</link> + <pubDate>Tue, 02 Aug 2022 05:50:00 -0400</pubDate> + + <guid>https://jeskin.net/blog/grep-fzf-clp/</guid> + <description>Introduction grep, ag, and ripgrep search file contents for text that matches regular expressions. The previous links show some of their more advanced options. +fzf is an interactive Unix filter. You can feed it anything from stdin (files, previously entered commands, etc) and it displays the results on the screen along with a prompt. When you type into the prompt, fzf filters the list. +When combined, they can substantially speed up a CLI workflow.</description> + </item> + + <item> + <title>Fast Command Line Syntax Highlighting with clp</title> + <link>https://jeskin.net/blog/clp/</link> + <pubDate>Thu, 28 Jul 2022 05:59:41 -0400</pubDate> + + <guid>https://jeskin.net/blog/clp/</guid> + <description>clp&amp;rsquo;s source code and installation instructions are available on Github and Sourcehut. It’s a work in progress hobby project, so expect bugs and quirks. +clp is a program that writes files to stdout with syntax highlighting. I built it to quickly fill fzf&amp;rsquo;s preview window. +It&amp;rsquo;s similar to bat but is simpler, faster, and easier to add languages that don&amp;rsquo;t have existing Sublime syntax definitions. +When the --preview option is set in fzf, the preview command is kicked off in an external process and the results are displayed in the preview window, which in this case is clp.</description> + </item> + + <item> + <title>About</title> + <link>https://jeskin.net/about/</link> + <pubDate>Fri, 15 Jul 2022 04:20:38 -0400</pubDate> + + <guid>https://jeskin.net/about/</guid> + <description>Hello! +I&amp;rsquo;m a stay at home dad tinkering with software at night. +I&amp;rsquo;m interested in tooling, web &amp;amp; mobile development, and systems programming. +You can find some projects I&amp;rsquo;ve worked on in the page footer. If you&amp;rsquo;d like to contact me, my email is eskinjp at gmail dot com.</description> + </item> + + </channel> +</rss> diff --git a/robots.txt b/robots.txt @@ -0,0 +1,2 @@ +User-Agent: * +Sitemap: https://jeskin.net/sitemap.xml diff --git a/sitemap.xml b/sitemap.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" + xmlns:xhtml="http://www.w3.org/1999/xhtml"> + <url> + <loc>https://jeskin.net/</loc> + <lastmod>2022-09-04T05:59:22-04:00</lastmod> + <priority>0</priority> + </url><url> + <loc>https://jeskin.net/blog/</loc> + <lastmod>2022-09-04T05:59:22-04:00</lastmod> + </url><url> + <loc>https://jeskin.net/blog/getting-started-with-cosmopolitan-libc/</loc> + <lastmod>2022-09-04T05:59:22-04:00</lastmod> + </url><url> + <loc>https://jeskin.net/blog/grep-fzf-clp/</loc> + <lastmod>2022-08-02T05:50:00-04:00</lastmod> + </url><url> + <loc>https://jeskin.net/blog/clp/</loc> + <lastmod>2022-07-28T05:59:41-04:00</lastmod> + </url><url> + <loc>https://jeskin.net/about/</loc> + <lastmod>2022-07-15T04:20:38-04:00</lastmod> + </url><url> + <loc>https://jeskin.net/categories/</loc> + </url><url> + <loc>https://jeskin.net/tags/</loc> + </url> +</urlset> diff --git a/tags/index.html b/tags/index.html @@ -0,0 +1,248 @@ +<!DOCTYPE html> +<html lang="en-US"> + +<head> + <meta http-equiv="X-Clacks-Overhead" content="GNU Terry Pratchett" /> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> +<link rel="shortcut icon" href="https://jeskin.net/images/favicon.png" /> +<title>Tags | Jon Eskin&#39;s Blog</title> +<meta name="title" content="Tags" /> +<meta name="description" content="Jon Eskin&#39;s Personal Blog" /> +<meta name="keywords" content="" /> + + +<meta property="og:title" content="Tags" /> +<meta property="og:description" content="Jon Eskin&#39;s Personal Blog" /> +<meta property="og:type" content="website" /> +<meta property="og:url" content="https://jeskin.net/tags/" /><meta property="og:image" content="https://jeskin.net/images/share.png"/><meta property="og:site_name" content="Jon Eskin&#39;s Blog" /> + + + + +<meta name="twitter:card" content="summary_large_image"/> +<meta name="twitter:image" content="https://jeskin.net/images/share.png"/> + +<meta name="twitter:title" content="Tags"/> +<meta name="twitter:description" content="Jon Eskin&#39;s Personal Blog"/> + + + +<meta itemprop="name" content="Tags"> +<meta itemprop="description" content="Jon Eskin&#39;s Personal Blog"> +<meta name="referrer" content="no-referrer-when-downgrade" /> + + <link rel="alternate" type="application/rss+xml" href="https://jeskin.net/tags/index.xml" title="Jon Eskin's Blog" /> + <style> + body { + font-family: Verdana, sans-serif; + margin: auto; + padding: 20px; + max-width: 720px; + text-align: left; + background-color: #fff; + word-wrap: break-word; + overflow-wrap: break-word; + line-height: 1.5; + color: #444; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #222; + } + + a { + color: #3273dc; + + } + + .title { + text-decoration: none; + border: 0; + } + + .title span { + font-weight: 400; + } + + nav a { + margin-right: 10px; + } + + textarea { + width: 100%; + font-size: 16px; + } + + input { + font-size: 16px; + } + + content { + line-height: 1.6; + } + + table { + width: 100%; + } + + img { + max-width: 100%; + } + + code { + padding: 2px 5px; + background-color: #f2f2f2; + } + + pre code { + color: #222; + display: block; + padding: 20px; + white-space: pre-wrap; + font-size: 14px; + } + + div.highlight pre { + background-color: initial; + color: initial; + } + + div.highlight code { + background-color: unset; + color: unset; + } + + blockquote { + border-left: 1px solid #999; + color: #222; + padding-left: 20px; + font-style: italic; + } + + footer { + padding: 25px; + text-align: center; + } + + .helptext { + color: #777; + font-size: small; + } + + .errorlist { + color: #eba613; + font-size: small; + } + + + ul.blog-posts { + list-style-type: none; + padding: unset; + } + + ul.blog-posts li { + display: flex; + } + + ul.blog-posts li span { + flex: 0 0 130px; + } + + ul.blog-posts li a:visited { + color: #8b6fcb; + } + + @media (prefers-color-scheme: dark) { + body { + background-color: #333; + color: #ddd; + } + + h1, + h2, + h3, + h4, + h5, + h6, + strong, + b { + color: #eee; + } + + a { + color: #8cc2dd; + } + + code { + background-color: #777; + } + + pre code { + color: #ddd; + } + + blockquote { + color: #ccc; + } + + textarea, + input { + background-color: #252525; + color: #ddd; + } + + .helptext { + color: #aaa; + } + } + +</style> + +</head> + +<body> + <header><a href="/" class="title"> + <h2>Jon Eskin&#39;s Blog</h2> +</a> +<nav><a href="/">Home</a> + + +<a href="/blog">Blog</a> +<a href="https://git.jeskin.net">Git</a> + +</nav> +</header> + <main> +<content> + + <h3 style="margin-bottom:0">Filtering for "Tags"</h3> + <small> + <a href="/blog">Remove filter</a> + </small> + + <ul class="blog-posts"> + + <li> + No posts yet + </li> + + </ul> + + +</content> + + </main> + <footer></footer> + + +</body> + +</html> diff --git a/tags/index.xml b/tags/index.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> + <channel> + <title>Tags on Jon Eskin&#39;s Blog</title> + <link>https://jeskin.net/tags/</link> + <description>Recent content in Tags on Jon Eskin&#39;s Blog</description> + <generator>Hugo -- gohugo.io</generator> + <language>en-US</language> + <copyright>Copyright © 2022, Jon Eskin.</copyright><atom:link href="https://jeskin.net/tags/index.xml" rel="self" type="application/rss+xml" /> + </channel> +</rss>