about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--users/Profpatsch/blog/default.nix83
-rw-r--r--users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md123
2 files changed, 168 insertions, 38 deletions
diff --git a/users/Profpatsch/blog/default.nix b/users/Profpatsch/blog/default.nix
index e3d32947c9e8..a272f0f446a1 100644
--- a/users/Profpatsch/blog/default.nix
+++ b/users/Profpatsch/blog/default.nix
@@ -27,12 +27,12 @@ let
     {
       route = [ "notes" "preventing-oom" ];
       name = "Preventing out-of-memory (OOM) errors on Linux";
-      page = renderNote "preventing-oom" ./notes/preventing-oom.md;
+      page = markdownToHtml "preventing-oom" ./notes/preventing-oom.md;
     }
     {
       route = [ "notes" "rust-string-conversions" ];
       name = "Converting between different String types in Rust";
-      page = renderNote "rust-string-conversions" ./notes/rust-string-conversions.md;
+      page = markdownToHtml "rust-string-conversions" ./notes/rust-string-conversions.md;
     }
   ];
 
@@ -44,7 +44,7 @@ let
     }
     {
       name = "netencode";
-      description = "A human-readble nested data exchange format inspired by netstrings and bencode.";
+      description = ''A human-readble nested data exchange format inspired by <a href="https://en.wikipedia.org/wiki/Netstring">netstrings</a> and <a href="https://en.wikipedia.org/wiki/Bencode">bencode</a>.'';
       link = depotCgitLink { relativePath = "users/Profpatsch/netencode/README.md"; };
     }
     {
@@ -54,8 +54,20 @@ let
     }
   ];
 
-  # convert a note to html via lowdown
-  renderNote = name: note: depot.nix.runExecline "${name}.html" {} [
+  posts = [
+    {
+      date = "2017-05-04";
+      title = "Ligature Emulation in Emacs";
+      subtitle = "It’s not pretty, but the results are";
+      description = "How to set up ligatures using <code>prettify-symbols-mode</code> and the Hasklig/FiraCode fonts.";
+      page = markdownToHtml "2017-05-04-ligature-emluation-in-emacs" ./posts/2017-05-04-ligature-emulation-in-emacs.md;
+      route = [ "posts" "2017-05-04-ligature-emluation-in-emacs" ];
+      tags = ["emacs"];
+    }
+  ];
+
+  # convert a markdown file to html via lowdown
+  markdownToHtml = name: note: depot.nix.runExecline "${name}.html" {} [
     "importas" "out" "out"
     bins.lowdown "-s" "-Thtml" "-o" "$out" note
   ];
@@ -65,14 +77,19 @@ let
     (map (x@{route, ...}: x // { route = mkRoute route; }))
   ];
 
+  # all posts with `route` converted to an absolute path
+  postsFullRoute = lib.pipe posts [
+    (map (x@{route, ...}: x // { route = mkRoute route; }))
+  ];
+
   # a cdb from route to a netencoded version of data for each route
-  router = lib.pipe notesFullRoute [
+  router = lib.pipe (notesFullRoute ++ postsFullRoute) [
     (map (x: {
       name = x.route;
       value = depot.users.Profpatsch.netencode.gen.dwim x;
     }))
     lib.listToAttrs
-    (cdbMake "notes-router")
+    (cdbMake "router")
   ];
 
   # Create a link to the given source file/directory, given the relative path in the depot repo.
@@ -107,21 +124,7 @@ let
       </ul>
     '';
 
-  notes-index  = runExeclineStdout "notes-index" {
-    stdin = depot.users.Profpatsch.netencode.gen.dwim notesFullRoute;
-  } [
-    "withstdinas" "-in" "TEMPLATE_DATA"
-    "pipeline" [
-      bins.printf ''
-        <ul>
-        {{#.}}
-          <li><a href="{{route}}">{{name}}</a></li>
-        {{/.}}
-        </ul>
-      ''
-    ]
-    depot.users.Profpatsch.netencode.netencode-mustache
-  ];
+  notes-index = pkgs.writeText "notes-index.html" notes-index-html;
 
   # A simple mustache-inspired string interpolation combinator
   # that takes an object and a template (a function from o to string)
@@ -150,22 +153,20 @@ let
     </dl>
   '';
 
-  projects-index = runExeclineStdout "projects-index" {
-    stdin = depot.users.Profpatsch.netencode.gen.dwim projects;
-  } [
-    "withstdinas" "-in" "TEMPLATE_DATA"
-    "pipeline" [
-      bins.printf ''
-        <dl>
-        {{#.}}
-          <dt><a href="{{link}}">{{name}}</a></dt>
-          <dd>{{{description}}}</dd>
-        {{/.}}
-        </dl>
-      ''
-    ]
-    depot.users.Profpatsch.netencode.netencode-mustache
-  ];
+  projects-index = pkgs.writeText "projects-index.html" projects-index-html;
+
+  posts-index-html =
+  let o = postsFullRoute;
+  in ''
+    <dl>
+    ${scope o (o: ''
+      <dt>${str o.date} <a href="${str o.route}">${esc o.title}</a></dt>
+      <dd>${html o.description}</dd>
+    '')}
+    </dl>
+  '';
+
+  posts-index = pkgs.writeText "projects-index.html" posts-index-html;
 
   arglibNetencode = val: depot.nix.writeExecline "arglib-netencode" { } [
     "export" "ARGLIB_NETENCODE" (depot.users.Profpatsch.netencode.gen.dwim val)
@@ -201,6 +202,11 @@ let
           "export" "serve-file" projects-index
           depot.users.Profpatsch.netencode.env-splice-record
         ]
+      "ifelse" [ bins.test "$path" "=" "/posts" ]
+        [ "export" "content-type" "text/html"
+          "export" "serve-file" posts-index
+          depot.users.Profpatsch.netencode.env-splice-record
+        ]
       # TODO: ignore potential query arguments. See 404 message
       "pipeline" [ router-lookup "$path" ]
       depot.users.Profpatsch.netencode.record-splice-env
@@ -334,6 +340,7 @@ in depot.nix.utils.drvTargets {
     notes-index-html
     projects-index
     projects-index-html
+    posts-index-html
     router-lookup
     ;
 
diff --git a/users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md b/users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md
new file mode 100644
index 000000000000..ba80888badd8
--- /dev/null
+++ b/users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md
@@ -0,0 +1,123 @@
+title: Ligature Emulation in Emacs
+date: 2017-05-04
+
+Monday was (yet another)
+[NixOS hackathon][hackathon] at [OpenLab Augsburg][ola].
+[Maximilian][mhuber] was there and to my amazement
+he got working ligatures in his Haskell files in Emacs! Ever since Hasklig
+updated its format to use ligatures and private Unicode code points a while ago,
+the hack I had used in my config stopped working.
+
+Encouraged by that I decided to take a look on Tuesday. Long story short, I was
+able to [get it working in a pretty satisfying way][done].
+
+[hackathon]: https://www.meetup.com/Munich-NixOS-Meetup/events/239077247/
+[mhuber]: https://github.com/maximilianhuber
+[ola]: https://openlab-augsburg.de
+[done]: https://github.com/i-tu/Hasklig/issues/84#issuecomment-298803495
+
+What’s left to do is package it into a module and push to melpa.
+
+
+### elisp still sucks, but it’s bearable, sometimes
+
+I’m the kind of person who, when trying to fix something elisp related, normally
+gives up two hours later and three macro calls deep. Yes, homoiconic,
+non-lexically-scoped, self-rewriting code is not exactly my fetish.
+This time the task and the library (`prettify-symbols-mode`) were simple enough
+for that to not happen.
+
+Some interesting technical trivia:
+
+- elisp literal character syntax is `?c`. `?\t` is the tab character
+- You join characters by `(string c1 c2 c3 ...)`
+- [dash.el][dash] is pretty awesome and does what a functional programmer
+  expects. Also, Rainbow Dash.
+- Hasklig and FiraCode multi-column symbols actually [only occupy one column, on
+  the far right of the glyph][glyph]. `my-correct-symbol-bounds` fixes emacs’
+  rendering in that case.
+
+
+[dash]: https://github.com/magnars/dash.el
+[glyph]: https://github.com/tonsky/FiraCode/issues/211#issuecomment-239082368
+
+
+## Appendix A
+
+For reference, here’s the complete code as it stands now. Feel free to paste
+into your config; let’s make it [MIT][mit]. Maybe link to this site, in case there are
+updates.
+
+[mit]: https://opensource.org/licenses/MIT
+
+```elisp
+ (defun my-correct-symbol-bounds (pretty-alist)
+    "Prepend a TAB character to each symbol in this alist,
+this way compose-region called by prettify-symbols-mode
+will use the correct width of the symbols
+instead of the width measured by char-width."
+    (mapcar (lambda (el)
+              (setcdr el (string ?\t (cdr el)))
+              el)
+            pretty-alist))
+
+  (defun my-ligature-list (ligatures codepoint-start)
+    "Create an alist of strings to replace with
+codepoints starting from codepoint-start."
+    (let ((codepoints (-iterate '1+ codepoint-start (length ligatures))))
+      (-zip-pair ligatures codepoints)))
+
+  ; list can be found at https://github.com/i-tu/Hasklig/blob/master/GlyphOrderAndAliasDB#L1588
+  (setq my-hasklig-ligatures
+    (let* ((ligs '("&&" "***" "*>" "\\\\" "||" "|>" "::"
+                   "==" "===" "==>" "=>" "=<<" "!!" ">>"
+                   ">>=" ">>>" ">>-" ">-" "->" "-<" "-<<"
+                   "<*" "<*>" "<|" "<|>" "<$>" "<>" "<-"
+                   "<<" "<<<" "<+>" ".." "..." "++" "+++"
+                   "/=" ":::" ">=>" "->>" "<=>" "<=<" "<->")))
+      (my-correct-symbol-bounds (my-ligature-list ligs #Xe100))))
+
+  ;; nice glyphs for haskell with hasklig
+  (defun my-set-hasklig-ligatures ()
+    "Add hasklig ligatures for use with prettify-symbols-mode."
+    (setq prettify-symbols-alist
+          (append my-hasklig-ligatures prettify-symbols-alist))
+    (prettify-symbols-mode))
+
+  (add-hook 'haskell-mode-hook 'my-set-hasklig-ligatures)
+```
+
+## Appendix B (Update 1): FiraCode integration
+
+I also created a mapping for [FiraCode][fira]. You need to grab the [additional
+symbol font][symbol] that adds (most) ligatures to the unicode private use area.
+Consult your system documentation on how to add it to your font cache.
+Next add `"Fira Code"` and `"Fira Code Symbol"` to your font preferences. Symbol
+only contains the additional characters, so you need both.
+
+If you are on NixOS, the font package should be on the main branch shortly, [I
+added a package][symbol-pkg].
+
+[fira]: https://github.com/tonsky/FiraCode/
+[symbol]: https://github.com/tonsky/FiraCode/issues/211#issuecomment-239058632
+[symbol-pkg]: https://github.com/NixOS/nixpkgs/pull/25517
+
+Here’s the mapping adjusted for FiraCode:
+
+```elisp
+  (setq my-fira-code-ligatures
+    (let* ((ligs '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\"
+                  "{-" "[]" "::" ":::" ":=" "!!" "!=" "!==" "-}"
+                  "--" "---" "-->" "->" "->>" "-<" "-<<" "-~"
+                  "#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_("
+                  ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*"
+                  "/**" "/=" "/==" "/>" "//" "///" "&&" "||" "||="
+                  "|=" "|>" "^=" "$>" "++" "+++" "+>" "=:=" "=="
+                  "===" "==>" "=>" "=>>" "<=" "=<<" "=/=" ">-" ">="
+                  ">=>" ">>" ">>-" ">>=" ">>>" "<*" "<*>" "<|" "<|>"
+                  "<$" "<$>" "<!--" "<-" "<--" "<->" "<+" "<+>" "<="
+                  "<==" "<=>" "<=<" "<>" "<<" "<<-" "<<=" "<<<" "<~"
+                  "<~~" "</" "</>" "~@" "~-" "~=" "~>" "~~" "~~>" "%%"
+                  "x" ":" "+" "+" "*")))
+      (my-correct-symbol-bounds (my-ligature-list ligs #Xe100))))
+```