diff options
-rw-r--r-- | users/Profpatsch/blog/default.nix | 83 | ||||
-rw-r--r-- | users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md | 123 |
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)))) +``` |