<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
 xmlns:content="http://purl.org/rss/1.0/modules/content/"
 xmlns:wfw="http://wellformedweb.org/CommentAPI/"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:atom="http://www.w3.org/2005/Atom"
 xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
 xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
 xmlns:georss="http://www.georss.org/georss"
 xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
 xmlns:media="http://search.yahoo.com/mrss/">
<channel>
<atom:link href="https://merrick.luois.me/rss.xml" rel="self" type="application/rss+xml" />
<title>Uncharted</title>
<link>https://merrick.luois.me</link>
<description><![CDATA[Uncharted]]></description>
<language>en</language>
<lastBuildDate>Sat, 15 Aug 2026 13:53:22 +0800</lastBuildDate>
<generator>Emacs 31.0.91 org-publish-rss.el 0.6</generator>
<item>
<title>在 Mac 上更好的使用 Emacs 快捷键</title>
<link>https://merrick.luois.me/posts/better-emacs-keymap-on-mac.html</link>
<pubDate>Wed, 10 Sep 2014 23:20:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/better-emacs-keymap-on-mac.html</guid>
<description>
<![CDATA[<div id="outline-container-在-mac-上更好的使用-emacs-快捷键" class="outline-2">
<h2 id="在-mac-上更好的使用-emacs-快捷键">在 Mac 上更好的使用 Emacs 快捷键</h2>
<div class="outline-text-2" id="text-在-mac-上更好的使用-emacs-快捷键">
<p>
不太记得自己为啥学了 Emacs，大概是最开始听说作为程序员 Emacs 和 Vim 至少得会用一个，然后觉得 Vim 各种要按 Esc 傻傻的，所以就安心学习了 Emacs 的快捷键。不过要说作为一个 Android 开发者（虽说你强行要在 Emacs 中开发也不是不行，但是代价太大，我反正是放弃了），还是得用到 IDE，不过好在的是，各种好用的 IDE 都是支持修改快捷键的，而且也早有大神们做好了各种 Emacs 的 Keymap 供我们使用（吐槽：不论是 Eclipse 还是 Intellij 自带的 Emacs 布局都不好用）。
</p>

<p>
现在回到标题，其实 Mac（OS X whatever）对 Emacs 爱好者可谓又爱又狠，爱的是，大部分编辑文本的地方都能用基本的 Emacs 光标移动等快捷键，恨的是这个可恶的 Option 按钮，他完全没办法作为 Meta 键使用，让我每次都按 ESC？你等等，我先去跳个楼。不过好在的是 Emacs 爱好者们都遇到了这个问题，于是就有了解决方案。
</p>

<p>
大部分的解决方案都是使用 Ukulele 这个软件重新编辑键盘布局，大致操作就是新建一个键盘布局，然后按住 Option 键，把所有键值都清掉，保存并放在~/Library/KeyboardLayout/中，最后到语言和输入法中选择这个键盘布局就搞定啦。还有一点要提一下的是，大部分的中文输入法都支持选择键盘布局，所以以后也可以保持在中文输入法状态下搬砖啦。
</p>

<p>
另外上面的手动方法可能比较麻烦，大致介绍以下原理，这个[网站](<a href="http://wordherd.com/keyboards/">http://wordherd.com/keyboards/</a>)可以直接下载改好的键盘布局文件，直接放进去就能用了。
</p>

<p>
最后祝大家敲键盘愉快，小指头健康~
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>开始使用 Spacemacs</title>
<link>https://merrick.luois.me/posts/start-use-spacemacs.html</link>
<pubDate>Sat, 12 Dec 2015 23:18:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/start-use-spacemacs.html</guid>
<description>
<![CDATA[<div id="outline-container-开始使用-spacemacs" class="outline-2">
<h2 id="开始使用-spacemacs">开始使用 Spacemacs</h2>
<div class="outline-text-2" id="text-开始使用-spacemacs">
<p>
虽说上一篇 Blog 已经是在很久之前，但是上篇刚说了不爱用 vim 的快捷键，现在就开始用 spacemacs 貌似有些奇怪=。=
</p>

<p>
我为什么开始使用 vim 的 keybinding 呢，说来话长，一切都要从坑爹的 Xcode 说起&hellip;（省略对 Xcode 的 1w 字吐槽）总之因为 Xcode 无法支持 Emacs 的 keybinding（别说 Karabiner，这玩意儿影响太多东西），然后自带的 keybinding 效率实在太低，于是我不得不开始使用 XVim，然后在背叛 Emacs 的道路上越走越远（强力推荐 Chrome 的插件 cVim）。
</p>

<p>
但是我不得不说，spacemacs 确实相当的好用，之前也有试过 oh-my-emacs 等等配置，然后自己也乱七八糟配过一些，都谈不上好用，而且还有一些相当麻烦的问题，虽说 spacemacs 问题也不不少，好在最后都找到了解决方案，下面就来记录一下配置时遇到的一些小问题。
</p>
</div>
</div>
<div id="outline-container-安装-spacemacs" class="outline-2">
<h2 id="安装-spacemacs">安装 spacemacs</h2>
<div class="outline-text-2" id="text-安装-spacemacs">
<p>
参见[官方文档](<a href="https://github.com/syl20bnr/spacemacs">https://github.com/syl20bnr/spacemacs</a>)，就不再赘述
</p>

<p>
装好之后，打开 Emacs，
</p>

<p>
<code>find-file ~/.spacemacs</code>
</p>
</div>
</div>
<div id="outline-container-emacs-behind-proxy" class="outline-2">
<h2 id="emacs-behind-proxy">Emacs behind proxy</h2>
<div class="outline-text-2" id="text-emacs-behind-proxy">
<p>
要想正常使用软件，第一件事就是配好代理，Emacs 里面的包管理，shell，都是需要代理的，所以第一步就是要配好代理
</p>

<p>
在 <code>dotspacemacs/user-init()</code> 中
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">url-proxy-services</span>
      <span style="color: #531ab6; font-weight: bold;">'</span>((<span style="color: #3548cf;">"no_proxy"</span> . <span style="color: #3548cf;">"^</span><span style="color: #721045; font-weight: bold;">\\</span><span style="color: #00663f; font-weight: bold;">(</span><span style="color: #3548cf;">localhost</span><span style="color: #721045; font-weight: bold;">\\</span><span style="color: #00663f; font-weight: bold;">|</span><span style="color: #3548cf;">10.*</span><span style="color: #721045; font-weight: bold;">\\</span><span style="color: #00663f; font-weight: bold;">)</span><span style="color: #3548cf;">"</span>)
        (<span style="color: #3548cf;">"http"</span> . <span style="color: #3548cf;">"proxy_host:port"</span>)
        (<span style="color: #3548cf;">"https"</span> . <span style="color: #3548cf;">"proxy_host:port"</span>)))
</code></pre>
</div>

<p>
C-x，C-e and you are good to go.
这里需要一个 http 的代理，如果用 shadowsocks 转一下就好。
</p>
</div>
</div>
<div id="outline-container-fonts" class="outline-2">
<h2 id="fonts">Fonts</h2>
<div class="outline-text-2" id="text-fonts">
<p>
字体不对简直不想写代码，所以先配好字体
</p>

<p>
英文字体
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">setq-default</span> dotspacemacs-default-font <span style="color: #531ab6; font-weight: bold;">'</span>(<span style="color: #3548cf;">"Essential PragmataPro"</span>
                                          <span style="color: #8f0075; font-weight: bold;">:size</span> 14
                                          <span style="color: #8f0075; font-weight: bold;">:weight</span> normal
                                          <span style="color: #8f0075; font-weight: bold;">:width</span> normal
                                          <span style="color: #8f0075; font-weight: bold;">:powerline-scale</span> 1.1))
</code></pre>
</div>

<p>
中文字体
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">dolist</span> (charset <span style="color: #531ab6; font-weight: bold;">'</span>(kana han symbol cjk-misc bopomofo))
  (<span style="color: #0000b0;">set-fontset-font</span> (<span style="color: #0000b0;">frame-parameter</span> nil <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">font</span>)
                    charset (<span style="color: #0000b0;">font-spec</span> <span style="color: #8f0075; font-weight: bold;">:family</span> <span style="color: #3548cf;">"Source Han Sans SC"</span>
                                       <span style="color: #8f0075; font-weight: bold;">:size</span> 13)))
</code></pre>
</div>
</div>
</div>
<div id="outline-container-fish-in-emacs" class="outline-2">
<h2 id="fish-in-emacs">Fish in Emacs</h2>
<div class="outline-text-2" id="text-fish-in-emacs">
<p>
接下来是比较麻烦的部分，至于为什么要在 Emacs 中用 Fish，没办法，Emacs 党就是喜欢 one to rule them all。
</p>

<p>
首先安装 spacemacs 提供的 shell layer 并配置一下默认 shell
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #7b435c;">shell</span> <span style="color: #8f0075; font-weight: bold;">:variables</span>
       shell-default-term-shell <span style="color: #3548cf;">"/usr/local/bin/fish"</span>
       shell-default-height 30
       shell-default-position <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">bottom</span>)
</code></pre>
</div>

<p>
然后打开 ansi-term，你会发现几个问题：
</p>

<ol class="org-ol">
<li>prompt 下面会多出一个回车符号，在 <code>dotspacemacs/user-init()</code> 里加入</li>
</ol>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #7b435c;">add-hook</span> <span style="color: #531ab6; font-weight: bold;">'</span>term-mode-hook
          (<span style="color: #531ab6; font-weight: bold;">lambda</span> ()
            (<span style="color: #7b435c;">toggle-truncate-lines</span>)
            (<span style="color: #7b435c;">make-local-variable</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #005e8b;">transient-mark-mode</span>)
            (<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">transient-mark-mode</span> nil)))
</code></pre>
</div>

<ol class="org-ol">
<li><p>
prompt title 显示问题
</p>

<p>
<code>find-file ~/.config/fish/config.fish</code>
</p></li>
</ol>

<p>
加上
</p>

<div class="org-src-container">
<pre class="src src-fish"><code><span style="color: #531ab6; font-weight: bold;">function</span> <span style="color: #721045;">fish_title</span>
    <span style="color: #531ab6; font-weight: bold;">true</span>
<span style="color: #531ab6; font-weight: bold;">end</span>
</code></pre>
</div>

<ol class="org-ol">
<li>fish 的自动提示出现时，会显示一个 4m 并换行，同样在 <code>dotspacemacs/user-init()</code> 中</li>
</ol>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">system-uses-terminfo</span> nil)
</code></pre>
</div>

<p>
暂且到另一个 terminal 中，如果 emacs 是用 Homebrew 安装的，执行以下命令
</p>
<div class="org-src-container">
<pre class="src src-shell"><code>tic -o ~/.terminfo /usr/local/share/emacs/24.5/etc/e/eterm-color.ti
</code></pre>
</div>

<p>
其他安装方法，请自行找到类似目录
</p>
</div>
</div>
<div id="outline-container-kotlin-mode" class="outline-2">
<h2 id="kotlin-mode">kotlin-mode</h2>
<div class="outline-text-2" id="text-kotlin-mode">
<p>
目前 kotlin 官方并没有支持 Emacs，只在 github 上搜到了两个 repo，[这个]()以及[这个]()，目前没有发现有什么区别。
</p>

<p>
参照 spacemacs 自定义 layer 的方法并使用以上两个中任意一个即可获得 kotlin 代码的语法高亮显示。
</p>
</div>
</div>
<div id="outline-container-magit" class="outline-2">
<h2 id="magit">magit</h2>
<div class="outline-text-2" id="text-magit">
<p>
magit 的安装非常简单，安装 spacemacs 自带的 git layer 即可，唯一的问题是文档中提到的默认将 magit-status 的 buffer 打开全屏的设置方法失效了，经过一番查询后，现在需要一个第三方的 extesion 才能实现。
</p>

<p>
这个在.spacemacs 中搜索一下加在对应位置即可
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">setq</span> dotspacemacs-additional-packages<span style="color: #531ab6; font-weight: bold;">'</span>(fullframe))
</code></pre>
</div>

<p>
<code>dotspacemacs/user-config()</code> 中
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #7b435c; font-style: italic;">fullframe</span> magit-status magit-mode-quit-window)
</code></pre>
</div>

<p>
重新同步 packages 即可。
</p>
</div>
</div>
<div id="outline-container-todo" class="outline-2">
<h2 id="todo">!TODO</h2>
<div class="outline-text-2" id="text-todo">
<ol class="org-ol">
<li>补充链接</li>
</ol>
</div>
</div>
<div id="outline-container-history" class="outline-2">
<h2 id="history">History</h2>
<div class="outline-text-2" id="text-history">
<p>
2015.12.12 initial version
2015.12.13 kotlin-mode 和 magit
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>The Ultimate Emacs Entry</title>
<link>https://merrick.luois.me/posts/the-ultimate-emacs-entry.html</link>
<pubDate>Sun, 21 Aug 2016 23:16:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/the-ultimate-emacs-entry.html</guid>
<description>
<![CDATA[<div id="outline-container-the-ultimate-emacs-entry" class="outline-2">
<h2 id="the-ultimate-emacs-entry">The Ultimate Emacs Entry</h2>
<div class="outline-text-2" id="text-the-ultimate-emacs-entry">
<p>
最近对于工具有点疯魔（写不出代码只好折腾下工具了
</p>
</div>
</div>
<div id="outline-container-at-first" class="outline-2">
<h2 id="at-first">At first</h2>
<div class="outline-text-2" id="text-at-first">
<p>
Emacs 作为一个 Lisp Machine，启动时间虽说比其他操作系统快得多，但是由于经常会无意间被关机，导致大家对其启动速度印象深刻。虽说 <code>emacs --daemon</code> 可以部分解决这个问题，但还是无法拯救喜欢乱按 space-q-q 的我（spacemacs 用户），在这样的情况下呢，启动慢已经不是最让我烦心的事了，由于 <code>emacs --daemon</code>, 所以大部分的东西我都会用 <code>emacscliet -c</code> 来当作编辑器，如果 daemon 不小心被我自己干掉了，那么这些操作全部会中断。又得手动 <code>emacs --daemon</code> ，总之一个字，烦！
</p>
</div>
</div>
<div id="outline-container-so" class="outline-2">
<h2 id="so">So</h2>
<div class="outline-text-2" id="text-so">
<p>
于是就有了这么一个脚本
</p>

<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #595959; font-style: italic;">#</span><span style="color: #595959; font-style: italic;">!/bin/</span><span style="color: #531ab6; font-weight: bold;">sh</span><span style="color: #595959; font-style: italic;">
</span><span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">making fcitx working in emacs
</span><span style="color: #005e8b;">client</span>=<span style="color: #3548cf;">"emacsclient"</span>
<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">I dont want to start a new frame if there is one
</span><span style="color: #005e8b;">frame_count</span>=<span style="color: #8f0075; font-weight: bold;">`emacsclient -e '(true-frame-count)' 2&gt;/dev/null || </span><span style="color: #8f0075; font-weight: bold;">echo</span><span style="color: #8f0075; font-weight: bold;"> -1`</span>
<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">start server if not started
</span><span style="color: #531ab6; font-weight: bold;">if</span> [ $<span style="color: #005e8b;">frame_count</span> -lt 0 ]; <span style="color: #531ab6; font-weight: bold;">then</span>
    <span style="color: #005e8b;">LC_CTYPE</span>=zh_CN.UTF-8 emacs --daemon
    <span style="color: #005e8b;">client</span>=<span style="color: #3548cf;">"</span><span style="color: #0000b0;">$</span><span style="color: #005e8b;">client</span><span style="color: #3548cf;"> -c"</span>
    <span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-weight: bold; font-style: italic;">make</span><span style="color: #595959; font-style: italic;"> frame if no param coming
</span><span style="color: #531ab6; font-weight: bold;">elif</span> [ $<span style="color: #005e8b;">frame_count</span> -lt 1 ]; <span style="color: #531ab6; font-weight: bold;">then</span>
    <span style="color: #005e8b;">client</span>=<span style="color: #3548cf;">"</span><span style="color: #0000b0;">$</span><span style="color: #005e8b;">client</span><span style="color: #3548cf;"> -c"</span>
<span style="color: #531ab6; font-weight: bold;">fi</span>
$<span style="color: #005e8b;">client</span> $<span style="color: #005e8b;">@</span> 2&gt;/dev/null
<span style="color: #8f0075; font-weight: bold;">```
and in emacs init script:

```</span>
(defun true-frame-count()
  (length
   (remove-if
    (lambda(f) (string-equal (terminal-name f) <span style="color: #3548cf;">"initial_terminal"</span>))
    (frame-list))))
</code></pre>
</div>

<p>
因为如果以 &ndash;daemon 模式启动，就会有这样一个叫做 initial<sub>terminal</sub> 的 frame 强行说自己 visible。
</p>

<p>
and in i3 config:
</p>

<div class="org-src-container">
<pre class="src src-conf"><code><span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">emacs
</span>focus_on_window_activation focus
</code></pre>
</div>
</div>
</div>
<div id="outline-container-sec" class="outline-2">
<h2 id="sec"><span class="todo TODO">TODO</span> </h2>
<div class="outline-text-2" id="text-sec">
<p>
大概会看看用 Automator 怎么在 OSX 哦不，是 macOS 上实现类似的功能。（改名字真好玩，反正改名字的人不用搜索）。
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>using kwm</title>
<link>https://merrick.luois.me/posts/using-kwm.html</link>
<pubDate>Tue, 08 Nov 2016 23:04:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/using-kwm.html</guid>
<description>
<![CDATA[<div id="outline-container-using-kwm" class="outline-2">
<h2 id="using-kwm">using kwm</h2>
<div class="outline-text-2" id="text-using-kwm">
<p>
前一段时间也算是好好的折腾了一下 Linux 桌面，然后深深地“迷上”了 i3，不过由于在水果本子上安装 Linux 不太顺利（懒）。
</p>

<p>
所以工作的大部分时间还是用着先进系统，不停需要切换到鼠标点点点点点点点点点真的是很烦人，更不提先进系统上那先进的 Window 系统（每次切到 App 会把所有的窗口都拉到前面来）了。
</p>

<p>
之前也有测试过各种试图在先进系统上模拟 i3 的应用，比如 amethyst、slate 等等，怎么说呢&amp;#x2026;都&amp;#x2026;不好用&amp;#x2026;包括者别要说到的 kwm 之前也已经试过，当时相当不稳定，而且功能也不太全，不过这次尝试之后发现已经能用了，基本能有 1／3 用 i3 的时候那么爽了&amp;#x2026;
</p>

<p>
[GitHub](<a href="https://github.com/koekeishiya/kwm">https://github.com/koekeishiya/kwm</a>) 上非常详细的，最简单的当然是
</p>

<div class="org-src-container">
<pre class="src src-shell"><code>brew install koekeishiya/kwm/kwm
</code></pre>
</div>

<p>
启动/管理的最简单方法是用 [homebrew-services](<a href="https://github.com/Homebrew/homebrew-services">https://github.com/Homebrew/homebrew-services</a>):
</p>
<div class="org-src-container">
<pre class="src src-shell"><code>brew servies start/stop/restart kwm
</code></pre>
</div>

<p>
然后你就会发现你所有的 Window 开始跳来跳去了！Don't Panic!
</p>

<p>
在 Github 仓库里也有提供一个[example](<a href="https://github.com/koekeishiya/kwm/tree/master/examples">https://github.com/koekeishiya/kwm/tree/master/examples</a>) config, 不过好像现在的是简化版，大概是想让用户自行配置比较好吧，我这里是之前版本留下的比较完整的 [example](<a href="https://gist.github.com/merrickluo/b27fd1b69729d6e4bb8397a9a394b1ba">https://gist.github.com/merrickluo/b27fd1b69729d6e4bb8397a9a394b1ba</a>) 和我自己的一些修改，里面基本所有的选项都有注释。
</p>

<p>
所有可用的选项在[这里](<a href="https://koekeishiya.github.io/kwm/kwmc.html">https://koekeishiya.github.io/kwm/kwmc.html</a>)。
</p>

<p>
一些概念：
</p>

<blockquote>
<p>
space = i3 workspace
</p>

<p>
window = i3 window
</p>

<p>
display = 显示器
</p>
</blockquote>

<p>
然后下面是我自己用到的常用按键配置:
cmd+ctrl 当做 i3 的 mod
alt+ctrl 当作 i3 的 shift+mod
</p>
</div>
</div>
<div id="outline-container-同一个-space-下切换焦点" class="outline-2">
<h2 id="同一个-space-下切换焦点">同一个 space 下切换焦点</h2>
<div class="outline-text-2" id="text-同一个-space-下切换焦点">
<div class="org-src-container">
<pre class="src src-shell"><code>kwmc bindsym cmd+ctrl-h window -f west
kwmc bindsym cmd+ctrl-l window -f east
kwmc bindsym cmd+ctrl-j window -f south
kwmc bindsym cmd+ctrl-k window -f north
</code></pre>
</div>
</div>
</div>
<div id="outline-container-同一个-space-下交换焦点-window-的位置" class="outline-2">
<h2 id="同一个-space-下交换焦点-window-的位置">同一个 space 下交换焦点 window 的位置</h2>
<div class="outline-text-2" id="text-同一个-space-下交换焦点-window-的位置">
<div class="org-src-container">
<pre class="src src-shell"><code>kwmc bindsym ctrl+alt-h window -s west
kwmc bindsym ctrl+alt-j window -s south
kwmc bindsym ctrl+alt-k window -s north
kwmc bindsym ctrl+alt-l window -s east
</code></pre>
</div>
</div>
</div>
<div id="outline-container-切换-space基本跟-mission-control-一样不过没有动画important" class="outline-2">
<h2 id="切换-space基本跟-mission-control-一样不过没有动画important">切换 space，基本跟 Mission Control 一样，不过没有动画（important！）</h2>
<div class="outline-text-2" id="text-切换-space基本跟-mission-control-一样不过没有动画important">
<div class="org-src-container">
<pre class="src src-nil"><code>kwmc bindsym ctrl-1 space -fExperimental 1
kwmc bindsym ctrl-2 space -fExperimental 2
kwmc bindsym ctrl-3 space -fExperimental 3
kwmc bindsym ctrl-4 space -fExperimental 4
</code></pre>
</div>

<p>
需要注意的是这个功能会把 Mission Control 搞坏
</p>
</div>
</div>
<div id="outline-container-启动-prefix类似-i3-的自定义-mode在-prefix-状态下所有快捷键有另外的用途" class="outline-2">
<h2 id="启动-prefix类似-i3-的自定义-mode在-prefix-状态下所有快捷键有另外的用途">启动 prefix，类似 i3 的自定义 mode，在 prefix 状态下，所有快捷键有另外的用途</h2>
<div class="outline-text-2" id="text-启动-prefix类似-i3-的自定义-mode在-prefix-状态下所有快捷键有另外的用途">
<div class="org-src-container">
<pre class="src src-nil"><code>// Activate prefix mode
kwmc bindsym cmd+ctrl+q mode activate prefix
</code></pre>
</div>
</div>
</div>
<div id="outline-container-切换焦点到不同的显示器" class="outline-2">
<h2 id="切换焦点到不同的显示器">切换焦点到不同的显示器</h2>
<div class="outline-text-2" id="text-切换焦点到不同的显示器">
<div class="org-src-container">
<pre class="src src-nil"><code>kwmc bindsym cmd+ctrl+1 display -f 0
kwmc bindsym cmd+ctrl+2 display -f 1
</code></pre>
</div>
</div>
</div>
<div id="outline-container-轻量调整窗口宽度" class="outline-2">
<h2 id="轻量调整窗口宽度">轻量调整窗口宽度</h2>
<div class="outline-text-2" id="text-轻量调整窗口宽度">
<div class="org-src-container">
<pre class="src src-shell"><code>kwmc bindsym prefix-h window -c reduce 0.05
kwmc bindsym prefix-l window -c expand 0.05
</code></pre>
</div>
</div>
</div>
<div id="outline-container-让-kwm-识别-emacs-为普通窗口" class="outline-2">
<h2 id="让-kwm-识别-emacs-为普通窗口">让 kwm 识别 Emacs 为普通窗口</h2>
<div class="outline-text-2" id="text-让-kwm-识别-emacs-为普通窗口">
<div class="org-src-container">
<pre class="src src-shell"><code>kwmc rule <span style="color: #005e8b;">owner</span>=<span style="color: #3548cf;">"Emacs"</span> <span style="color: #005e8b;">properties</span>={<span style="color: #005e8b;">role</span>=<span style="color: #3548cf;">"AXStandardWindow"</span>}
</code></pre>
</div>
</div>
</div>
<div id="outline-container-有些需要-float-的窗口" class="outline-2">
<h2 id="有些需要-float-的窗口">有些需要 float 的窗口</h2>
<div class="outline-text-2" id="text-有些需要-float-的窗口">
<div class="org-src-container">
<pre class="src src-shell"><code>kwmc rule <span style="color: #005e8b;">properties</span>={<span style="color: #005e8b;">float</span>=<span style="color: #3548cf;">"true"</span>} <span style="color: #005e8b;">owner</span>=<span style="color: #3548cf;">"App Store"</span>
kwmc rule <span style="color: #005e8b;">properties</span>={<span style="color: #005e8b;">float</span>=<span style="color: #3548cf;">"true"</span>} <span style="color: #005e8b;">owner</span>=<span style="color: #3548cf;">"System Preferences"</span>
</code></pre>
</div>

<p>
可根据需求酌情添加
</p>
</div>
</div>
<div id="outline-container-差点忘了最重要的随时随地启动-iterm2" class="outline-2">
<h2 id="差点忘了最重要的随时随地启动-iterm2">差点忘了最重要的：随时随地启动 iTerm2</h2>
<div class="outline-text-2" id="text-差点忘了最重要的随时随地启动-iterm2">
<div class="org-src-container">
<pre class="src src-shell"><code>kwmc bindsym cmd-return exec open -na /Applications/iTerm2.app
</code></pre>
</div>
</div>
</div>
<div id="outline-container-重启和重新加载配置" class="outline-2">
<h2 id="重启和重新加载配置">重启和重新加载配置</h2>
<div class="outline-text-2" id="text-重启和重新加载配置">
<div class="org-src-container">
<pre class="src src-shell"><code>kwmc bindsym cmd+alt+ctrl-q quit
kwmc bindsym cmd+alt+ctrl-r config reload
</code></pre>
</div>

<p>
这里上面一个命令虽然说是退出，但是因为我们是以 daemon 模式启动的，所以它会自动重启，我一般用这种方式来更新配置，因为下面一个命令按了之后 UI 没有反应，不知道有没有生效&amp;#x2026;
</p>

<p>
根据我这一两个星期的使用，大量使用的快捷键大概就这些了。
</p>
</div>
</div>
<div id="outline-container-problems" class="outline-2">
<h2 id="problems">Problems</h2>
<div class="outline-text-2" id="text-problems">
<p>
虽说现在已经到可用的程度，不过问题还是有一些的，比如有时候窗口跳来跳去，有些藏在后台的窗口会影响布局等&amp;#x2026;但是一般这种情况按下重启的快捷键也就好了&amp;#x2026;
</p>

<p>
现在拖后腿的反倒是用了 cVim 的 Chrome 呢，感觉不久后我又会启动一波 Firefox 体验活动了&amp;#x2026;
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>Shadowsocks Openwrt Setup</title>
<link>https://merrick.luois.me/posts/shadowsocks-openwrt-setup.html</link>
<pubDate>Wed, 14 Mar 2018 22:31:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/shadowsocks-openwrt-setup.html</guid>
<description>
<![CDATA[<div id="outline-container-shadowsocks-openwrt-setup" class="outline-2">
<h2 id="shadowsocks-openwrt-setup">Shadowsocks Openwrt Setup</h2>
<div class="outline-text-2" id="text-shadowsocks-openwrt-setup">
<p>
正常来讲我本来不想写一篇 "Yet another Shadowsocks installation guide"，不过前几天升级路由发现又得编译一次然后之前的工具又不见了的时候，又得到 Google
"翻箱倒柜"找编译步骤，不如记下来顺便发一下吧。
</p>
</div>
</div>
<div id="outline-container-编译环境" class="outline-2">
<h2 id="编译环境">编译环境</h2>
<div class="outline-text-2" id="text-编译环境">
<p>
到 <a href="https://downloads.openwrt.org/">Openwrt</a> 找到路由器对应的 SDK 下载条目，我路由器是 WNDR4300，版本是 lede
17.01.4，SDK 名字是
<code>lede-sdk-17.01.4-ar71xx-nand_gcc-5.4.0_musl-1.1.16.Linux-x86_64.tar.xz</code>
之所以先看名字是想确定 gcc 的版本，据经验来看，使用其他版本的 gcc 编译会很惨（此处省略 200 字抱怨）。
</p>

<p>
由于这时候还没有翻墙，所以编译最好在一个墙外的 VPS 上搞定。（安装 docker 这种步骤就先跳过了）。
</p>

<p>
#+NAME prepare gcc
</p>
<div class="org-src-container">
<pre class="src src-shell"><code>docker run -it --name lede gcc:5.4 bash

<span style="color: #005f5f; font-weight: bold;">cd</span> /usr/src
<span style="color: #005f5f; font-weight: bold;">curl</span> $<span style="color: #005e8b;">SDK_URL</span> -O
tar xvf $<span style="color: #005e8b;">SDK_FILENAME</span>
<span style="color: #005f5f; font-weight: bold;">mv</span> $<span style="color: #005e8b;">SDK_DIR</span> lede-sdk
<span style="color: #005f5f; font-weight: bold;">cd</span> lede-sdk
</code></pre>
</div>
</div>
</div>
<div id="outline-container-编译" class="outline-2">
<h2 id="编译">编译</h2>
<div class="outline-text-2" id="text-编译">
<p>
这两位 <a href="https://github.com/shadowsocks/openwrt-shadowsocks">openwrt-shadowsocks</a> &amp; <a href="https://github.com/shadowsocks/luci-app-shadowsocks">luci-app-shadowsocks</a>
</p>

<div class="org-src-container">
<pre class="src src-shell" id="orgddaca96"><code><span style="color: #005f5f; font-weight: bold;">git</span> clone https://github.com/shadowsocks/openwrt-feeds.git package/feeds
<span style="color: #005f5f; font-weight: bold;">git</span> clone https://github.com/shadowsocks/openwrt-shadowsocks.git package/shadowsocks-libev


<span style="color: #005f5f; font-weight: bold;">git</span> clone https://github.com/shadowsocks/luci-app-shadowsocks.git package/luci-app-shadowsocks

pushd package/luci-app-shadowsocks/tools/po2lmo
<span style="color: #005f5f; font-weight: bold;">make</span> &amp;&amp; <span style="color: #005f5f; font-weight: bold;">make</span> install
popd

<span style="color: #005f5f; font-weight: bold;">make</span> menuconfig

<span style="color: #005f5f; font-weight: bold;">make</span> package/shadowsocks-libev/compile <span style="color: #005e8b;">V</span>=99
<span style="color: #005f5f; font-weight: bold;">make</span> package/luci-app-shadowsocks/compile <span style="color: #005e8b;">V</span>=99
</code></pre>
</div>
</div>
</div>
<div id="outline-container-打包" class="outline-2">
<h2 id="打包">打包</h2>
<div class="outline-text-2" id="text-打包">
<div class="org-src-container">
<pre class="src src-shell" id="orga7ecf33"><code><span style="color: #005f5f; font-weight: bold;">mkdir</span> ipks

<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">&#26377;&#20123;&#26159;&#19981;&#38656;&#35201;&#30340;&#65292;&#19981;&#36807;&#25042;&#24471;&#33457;&#26102;&#38388;&#21435;&#25490;&#38500;&#20102;
</span><span style="color: #005f5f; font-weight: bold;">cp</span> bin/packages/mips_24kc/base/*.ipk ipks/
<span style="color: #005f5f; font-weight: bold;">cp</span> bin/packages/mips_24kc/packages/*.ipk ipks/
<span style="color: #005f5f; font-weight: bold;">cp</span> bin/targets/ar71xx/nand/pacakges/*.ipk ipks/

tar cvf notimportant.tar ipks

<span style="color: #531ab6; font-weight: bold;">exit</span>

docker <span style="color: #005f5f; font-weight: bold;">cp</span> lede:/usr/src/lede-sdk/notimportant.tar ./
</code></pre>
</div>
</div>
</div>
<div id="outline-container-安装" class="outline-2">
<h2 id="安装">安装</h2>
<div class="outline-text-2" id="text-安装">
<div class="org-src-container">
<pre class="src src-shell" id="orgb38858e"><code>scp notimportant.tar root@lede:/tmp/

ssh root@lede
<span style="color: #005f5f; font-weight: bold;">cd</span> /tmp
tar xvf notimportant.tar
<span style="color: #005f5f; font-weight: bold;">cd</span> ipks
opkg install *.ipk

opkg update
opkg install iptables-mod-tproxy
</code></pre>
</div>
</div>
</div>
<div id="outline-container-dns-和-chnroutes" class="outline-2">
<h2 id="dns-和-chnroutes">DNS 和 chnroutes</h2>
<div class="outline-text-2" id="text-dns-和-chnroutes">
<p>
这里用的是 <a href="https://github.com/felixonmars/dnsmasq-china-list">dnsmasq-china-list</a>
</p>

<div class="org-src-container">
<pre class="src src-shell" id="org58f4b05"><code><span style="color: #005f5f; font-weight: bold;">git</span> clone https://github.com/felixonmars/dnsmasq-china-list.git
<span style="color: #005f5f; font-weight: bold;">cd</span> dnsmasq-china-list
scp *.conf root@lede:~/

ssh root@lede
<span style="color: #005f5f; font-weight: bold;">mkdir</span> /etc/dnsmasq.conf.d
<span style="color: #005f5f; font-weight: bold;">mv</span> *.conf /etc/dnsmasq.conf.d/

<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">opkg install vim
</span>vim /etc/dnsmasq.conf
<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">insert conf-dir=/etc/dnsmasq.conf.d/
</span>
opkg remove dnsmasq &amp;&amp; opkg install dnsmasq-full
/etc/init.d/dnsmasq restart
</code></pre>
</div>

<p>
然后再配置一个没有污染的 DNS，最好在 luci 里面，方便修改。
</p>

<p>
最后是 <a href="https://github.com/shadowsocks/luci-app-shadowsocks/wiki/use-crontab-to-update-the-ignore.list">chnroutes</a>
</p>

<div class="org-src-container">
<pre class="src src-shell" id="orgba651c1"><code>vim /usr/bin/update-ignore-list

<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">insert
</span><span style="color: #595959; font-style: italic;">#</span><span style="color: #595959; font-style: italic;">!/bin/sh
</span>
<span style="color: #8f0075; font-weight: bold;">set</span> -e -o pipefail

wget -O- <span style="color: #3548cf;">'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest'</span> | <span style="color: #3548cf;">\</span>
    awk -F<span style="color: #3548cf;">\|</span> <span style="color: #3548cf;">'/CN\|ipv4/ { printf("%s/%d\n", $4, 32-log($5)/log(2)) }'</span> &gt; <span style="color: #3548cf;">\</span>
    /tmp/ignore.list

<span style="color: #005f5f; font-weight: bold;">mv</span> /tmp/ignore.list /etc/

<span style="color: #531ab6; font-weight: bold;">if</span> pidof ss-redir&gt;/dev/null; <span style="color: #531ab6; font-weight: bold;">then</span>
    /etc/init.d/shadowsocks rules
<span style="color: #531ab6; font-weight: bold;">fi</span>

<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">end
</span>
<span style="color: #005f5f; font-weight: bold;">chmod</span> +x /usr/bin/update-ignore-list

update-ignore-list

crontab -e
30 4 * * 0 /usr/bin/update-ignore-list &gt;&gt; /var/log/update_ignore_list.log
</code></pre>
</div>

<p>
Note to self： 下次最好升级之前先弄好。
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>用 Emacs 进行代码重构</title>
<link>https://merrick.luois.me/posts/refactoring-with-emacs.html</link>
<pubDate>Sat, 04 Aug 2018 23:01:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/refactoring-with-emacs.html</guid>
<description>
<![CDATA[<div id="outline-container-用-emacs-进行代码重构" class="outline-2">
<h2 id="用-emacs-进行代码重构">用 Emacs 进行代码重构</h2>
<div class="outline-text-2" id="text-用-emacs-进行代码重构">
<p>
首先要解释一下这里提到的重构主要是指变量名、方法名的修改，并不涉及到任何代码优化的部分（Emacs can't help you with that ）。
</p>

<p>
作为一名（前）Android 开发者，对于这部分基本是属于被 Intellj IDEA (
Android Studio) 惯坏了，右键点点就帮你换好了，顺便还帮你提前检查了可能出现的编译错误。当然这也是受益于 Java 是个静态语言，所以当我的主要工作转移到
Emacs 写 js（没错） 之后。虽然没办法用到这么方便的工具了，但是也让我学会了更加通用的办法，是好事（F91 语气）。
</p>
</div>
</div>
<div id="outline-container-当前文件的查找替换-httpsgithubcomvictorhgeieditiedit" class="outline-2">
<h2 id="当前文件的查找替换-httpsgithubcomvictorhgeieditiedit">当前文件的“查找替换”： <a href="https://github.com/victorhge/iedit">iedit</a></h2>
<div class="outline-text-2" id="text-当前文件的查找替换-httpsgithubcomvictorhgeieditiedit">
<p>
最常见的情况是当前编辑的文件中有需要修改的变量名，比如说一个 typo，由于自动补全工具的强大（比如说我在用的<a href="http://company-mode.github.io/">company-mode</a>），如果你写错一次，那么多半这个
typo 基本就会到处都是了。
</p>

<p>
最容易想到的办法是使用 <code>(replace-string)</code> 查找替换，不过这样的局限性也很强。一是不够直观，二是在手动输入查找替换字符串中难免再次出错导致需要再来一瓶。
</p>

<p>
而使用 iedit ，只需要选中需要修改的字符串并执行 <code>(iedit-mode): C-;</code> ，当前
Buffer 所有的相同字符串都会高亮：
</p>


<figure id="org01ae8c6">
<img src="https://assets.luois.me/refactoring-with-emacs/iedit-highlight.png" alt="iedit-highlight.png">

</figure>

<p>
这时候修改高亮的字符串，其他的字符串也会同步修改。
</p>


<figure id="orge8c42df">
<img src="https://assets.luois.me/refactoring-with-emacs/iedit-changed.png" alt="iedit-changed.png">

</figure>

<p>
这个过程中随时都能看到全局的变化，也不容易再次犯错。
</p>

<p>
如果你觉得这样还不够清晰，也可以使用下文提到的 ivy-occur + wgrep 的方式修改，将搜索的范围限定到当前文件即可。
</p>
</div>
</div>
<div id="outline-container-局部变量替换-httpwwwgnuorgsoftwareemacsmanualhtmlnodeemacsnarrowinghtmlnarrowing" class="outline-2">
<h2 id="局部变量替换-httpwwwgnuorgsoftwareemacsmanualhtmlnodeemacsnarrowinghtmlnarrowing">局部变量替换 <a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/Narrowing.html">narrowing</a></h2>
<div class="outline-text-2" id="text-局部变量替换-httpwwwgnuorgsoftwareemacsmanualhtmlnodeemacsnarrowinghtmlnarrowing">
<p>
有些时候需要替换的是一个函数内部局部变量的名字，但是其他函数里面也有同名的变量我不想修改，这时候只用 iedit 的话就有点麻烦了，不过 Emacs 内置的 narrow 功能就派上了用场，需要注意的是这个功能默认是被禁用了，因为新手如果不小心按到快捷键会不知道发生了什么。第一次使用时 Emacs 弹出警告按下 y 即可。
</p>

<p>
简单来说， <code>narrow</code> 就是指限定当前编辑的区域，如果你按下 <code>M-x</code> 并输入
narrow&lt;Tab&gt; 会看到自动补全的三个方法分别是：
</p>

<ol class="org-ol">
<li><code>narrow-to-defun (C-x n d)</code></li>
</ol>
<p>
这个方法一般只在 emacs-lisp-mode 有用，将当前编辑区域限定为当前的 <code>(defun ())</code> 区域。
</p>

<ol class="org-ol">
<li><code>narrow-to-page (C-x n p)</code></li>
</ol>
<p>
将当前编辑区域限定为当前的 page(?)，关于 Page 相关的定义我还没有完全理解，根据我的
use case 基本跟 <code>widen</code> 的功能一致。
</p>

<ol class="org-ol">
<li><code>narrow-to-region (C-x n n)</code></li>
</ol>
<p>
这个是我最常用到的，先选定一个区域然后将编辑区域限定为选定的区域。
</p>

<p>
当然还有恢复到完整显示的方法 <code>widen (C-x n w)</code> 。
</p>

<p>
处于 narrow 状态时，不管你怎么修改当前区域的内容都不会影响到文件的其余部分，所以就愉快的用 iedit 改掉局部变量的名字吧。
</p>
</div>
</div>
<div id="outline-container-项目的查找替换-httpsgithubcombbatsovprojectileprojectile-httpsgithubcomabo-aboswiperivy-httpsgithubcommhayashi1120emacs-wgrepwgrep" class="outline-2">
<h2 id="项目的查找替换-httpsgithubcombbatsovprojectileprojectile-httpsgithubcomabo-aboswiperivy-httpsgithubcommhayashi1120emacs-wgrepwgrep">项目的查找替换 <a href="https://github.com/bbatsov/projectile">projectile</a> &amp; <a href="https://github.com/abo-abo/swiper">ivy</a> &amp; <a href="https://github.com/mhayashi1120/Emacs-wgrep">wgrep</a></h2>
<div class="outline-text-2" id="text-项目的查找替换-httpsgithubcombbatsovprojectileprojectile-httpsgithubcomabo-aboswiperivy-httpsgithubcommhayashi1120emacs-wgrepwgrep">
<p>
最惨烈的情况当然是一个项目里多个文件里面都需要修改，（包括但不限于 leader 对你起的变量名不满意（x 等情况）。这里就需要一些额外的工具，包括和 ivy 。如果你还没用过
projectile 的话，建议花一点时间熟悉。另外 ivy 并不是必须的，不过非常推荐。
</p>

<p>
首先查找用 ivy 提供的 <code>counsel-rg</code> 配合 projectile
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">projectile-smart-search</span>()
  (<span style="color: #531ab6; font-weight: bold;">interactive</span>)
  (<span style="color: #531ab6; font-weight: bold;">let</span> ((text (<span style="color: #7b435c;">substring-no-properties</span> (<span style="color: #531ab6; font-weight: bold;">or</span> (<span style="color: #7b435c;">thing-at-point</span> <span style="color: #531ab6; font-weight: bold;">'</span>symbol) <span style="color: #3548cf;">""</span>))))
    (<span style="color: #531ab6; font-weight: bold;">if</span> (<span style="color: #7b435c;">projectile-project-p</span>)
        (<span style="color: #7b435c; font-style: italic;">counsel-rg</span> text (<span style="color: #005e8b;">projectile-project-root</span>))
      (<span style="color: #7b435c; font-style: italic;">counsel-rg</span> text))))
</code></pre>
</div>

<blockquote>
<p>
Tips: text 部分的作用是将光标位置所在的单词直接当成搜索字符串，不过这不重要。
</p>
</blockquote>


<p>
当搜索结果出现在 minibuffer 之后，执行 <code>(ivy-occur): C-x C-o</code> 将所有查找结果在另一个 buffer 显示。
</p>


<figure id="org166d380">
<img src="https://assets.luois.me/refactoring-with-emacs/ivy-occur.png" alt="ivy-occur.png">

</figure>

<p>
如图的情况，假定我现在需要将 struct <code>EmacsRime</code> 改名为 <code>ERime</code> , 而另一个类型
<code>EmacsRimeCandidates</code> 不需要修改。我需要做的是将光标移动到 <code>EmacsRimeCandidates</code> 行执行
<code>(ivy-occur-delete-candidate): C-d</code> ，保证剩下的都是需要修改的：
</p>


<figure id="org244c6f2">
<img src="https://assets.luois.me/refactoring-with-emacs/ivy-occur-modified.png" alt="ivy-occur-modified.png">

</figure>

<p>
使用 <code>(ivy-wgrep-change-to-wgrep-mode): w</code> 切换到 <code>wgrep-mode</code> 使用 <code>iedit</code>
完成修改。按下 <code>C-c C-c</code> 保存即可。
</p>


<figure id="org6e107ee">
<img src="https://assets.luois.me/refactoring-with-emacs/ivy-occur-changed.png" alt="ivy-occur-changed.png">

</figure>

<blockquote>
<p>
Tips: 使用 <code>C-x s</code> 可以一次性保存所有修改过的 buffer。
</p>
</blockquote>
</div>
</div>
<div id="outline-container-通用性" class="outline-2">
<h2 id="通用性">通用性</h2>
<div class="outline-text-2" id="text-通用性">
<p>
虽然这边举例都是用修改代码来说明，不过这并不意味着这些工具只能在编写代码时有用。比如我需要将本文中的 Emacs 全部替换为 Vim，我需要的操作仅仅是：
</p>

<ol class="org-ol">
<li>移动光标到其中一个 Emacs</li>
<li><code>C-;</code></li>
<li><code>M-d</code></li>
<li>Vim</li>
<li><code>C-;</code></li>
</ol>
</div>
</div>
<div id="outline-container-references" class="outline-2">
<h2 id="references">References</h2>
<div class="outline-text-2" id="text-references">
</div>
<div id="outline-container-httpsoremacscom20150127my-refactoring-workflowhttpsoremacscom20150127my-refactoring-workflow" class="outline-3">
<h3 id="httpsoremacscom20150127my-refactoring-workflowhttpsoremacscom20150127my-refactoring-workflow"><a href="https://oremacs.com/2015/01/27/my-refactoring-workflow/">https://oremacs.com/2015/01/27/my-refactoring-workflow/</a></h3>
</div>
</div>
]]>
</description></item>
<item>
<title>Roam Capture Workflow in Doom Emacs</title>
<link>https://merrick.luois.me/posts/roam-capture-workflow-in-doom-emacs.html</link>
<pubDate>Thu, 23 Apr 2020 22:44:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/roam-capture-workflow-in-doom-emacs.html</guid>
<description>
<![CDATA[<div id="outline-container-roam-capture-workflow-in-doom-emacs" class="outline-2">
<h2 id="roam-capture-workflow-in-doom-emacs">Roam Capture Workflow in Doom Emacs</h2>
<div class="outline-text-2" id="text-roam-capture-workflow-in-doom-emacs">
<p>
I don&rsquo;t take much notes before, until I recently discovered <a href="https://github.com/jethrokuan/org-roam">org-roam</a>, I tried to learn some note taking workflow in org-mode before, but none of them work out, it&rsquo;s hard to manage all things in a tree if you are not so organized :). org-roam&rsquo;s back link feature is much easier to work with, I can put random stuff in and some tags I think is good, and it&rsquo;s automatically organized like a wiki.
</p>

<p>
Anyway, I&rsquo;m still learning and here is how I use it when I want to capture some web page into the roam graph.
</p>
</div>
</div>
<div id="outline-container-setup-roam-protocol" class="outline-2">
<h2 id="setup-roam-protocol">Setup Roam Protocol</h2>
<div class="outline-text-2" id="text-setup-roam-protocol">
<p>
org-roam <a href="https://org-roam.readthedocs.io/en/latest/roam_protocol/">supports org-protocol</a>, so you need to setup org-protocol and roam beforehand, luckily, <a href="https://github.com/hlissner/doom-emacs">doom-emacs</a> setup this nicely for me, all I have to do is change the <code>$doomdir/init.el</code> like this:
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(org                <span style="color: #595959; font-style: italic;">; </span><span style="color: #595959; font-style: italic;">organize your plain life in plain text
</span>  +dragndrop         <span style="color: #595959; font-style: italic;">; </span><span style="color: #595959; font-style: italic;">drag &amp; drop files/images into org buffers
</span>  +hugo              <span style="color: #595959; font-style: italic;">; </span><span style="color: #595959; font-style: italic;">use Emacs for hugo blogging
</span>  +roam
  +journal
  <span style="color: #595959; font-style: italic;">;;</span><span style="color: #595959; font-style: italic;">+jupyter         ; ipython/jupyter support for babel
</span>  <span style="color: #595959; font-style: italic;">;;</span><span style="color: #595959; font-style: italic;">+pandoc          ; export-with-pandoc support
</span>  <span style="color: #595959; font-style: italic;">;;</span><span style="color: #595959; font-style: italic;">+pomodoro        ; be fruitful with the tomato technique
</span>  <span style="color: #595959; font-style: italic;">;;</span><span style="color: #595959; font-style: italic;">+present)          ; using org-mode for presentations</span>
</code></pre>
</div>

<p>
Of course, only the <code>roam</code> part is necessary.
</p>

<p>
And a desktop file <code>$HOME/.local/share/applications/org-capture.desktop</code> to handle <code>org-protocol://</code> links.
</p>

<div class="org-src-container">
<pre class="src src-nil"><code>[Desktop Entry]
Name=Org Capture
GenericName=Text Editor
Comment=Edit text
MimeType=x-scheme-handler/org-protocol;
Exec=emacsclient -a emacs -c -F '((name . "doom-capture") (transient . t))' %u
Icon=emacs
Type=Application
Terminal=false
Categories=Development;TextEditor;
StartupWMClass=Emacs
Keywords=Text;Editor;
</code></pre>
</div>

<p>
The name for the new frame is for identify in window manager, and the transient is for close the new frame after capture is done. Since I&rsquo;m using awesome wm, so I didn&rsquo;t setup the frame size.
</p>

<p>
Then follow the guide in <a href="https://org-roam.readthedocs.io/en/latest/roam_protocol/">org-roam documents</a>, add a bookmarklet with following content:
</p>

<div class="org-src-container">
<pre class="src src-javascript"><code>javascript:location.href =
<span style="color: #3548cf;">'org-protocol://roam-ref?template=r&amp;ref='</span>
+ encodeURIComponent(location.href)
+ <span style="color: #3548cf;">'&amp;title='</span>
+ encodeURIComponent(document.title)
</code></pre>
</div>

<p>
or if with Firefox and <a href="https://github.com/tridactyl/tridactyl">tridactyl</a>, add a shortcut in <code>$HOME/.tridactylrc</code>:
</p>

<div class="org-src-container">
<pre class="src src-vimrc"><code>bind ;r js javascript:location.href = 'org-protocol:/roam-ref?template=r&amp;ref=' + encodeURIComponent(location.href) + '&amp;title=' + encodeURIComponent(document.title)
</code></pre>
</div>

<p>
Now when I press ;r in any site, an emacs frame opens up, with title and <code>#ROAM_KEY</code> ready, I can just put my note and thoughts about it and hit C-c C-c.
</p>
</div>
</div>
<div id="outline-container-more-space-for-notes" class="outline-2">
<h2 id="more-space-for-notes">More space for notes</h2>
<div class="outline-text-2" id="text-more-space-for-notes">
<p>
roam-capture buffer opens in a popup buffer in doom emacs, by default it&rsquo;s too small for taking notes, so I added a popup rule to increase it.
</p>

<p>
in <code>$doomdir/config.el</code>
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #7b435c;">set-popup-rule!</span> <span style="color: #3548cf;">"^CAPTURE"</span> <span style="color: #8f0075; font-weight: bold;">:side</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">bottom</span> <span style="color: #8f0075; font-weight: bold;">:size</span> 0.90 <span style="color: #8f0075; font-weight: bold;">:select</span> t <span style="color: #8f0075; font-weight: bold;">:ttl</span> nil)
</code></pre>
</div>
</div>
</div>
<div id="outline-container-optimize-for-awesome-wm" class="outline-2">
<h2 id="optimize-for-awesome-wm">Optimize for awesome wm</h2>
<div class="outline-text-2" id="text-optimize-for-awesome-wm">
<p>
As I said above, I&rsquo;m using awesome wm, like many tiling wm user, I place my Emacs window in a specific tag, the first one, for me, and Firefox in a specific tag, and it&rsquo;s the second for me. But this is not very convenient for capture workflow, every time I press <code>;r</code> in Firefox, the emacs frame is opened in the first tag, so I need to switch to it and take notes, since the name of the capture frame is fixed <code>doom-capture</code>, so I just exclude it from the rule.
</p>

<div class="org-src-container">
<pre class="src src-lua"><code>ruled.client.append_rule {
    id         = <span style="color: #3548cf;">"emacs"</span>,
    rule   = {
        class = <span style="color: #3548cf;">"Emacs"</span>,
    },
    except = { name = <span style="color: #3548cf;">"doom-capture"</span>},
    properties = {
        tag = <span style="color: #3548cf;">'1'</span>
    }
}
</code></pre>
</div>

<p>
It&rsquo;s working for me pretty well, I take more notes in two weeks than last 4 years, and my tabs in Firefox is much less since I actually read them. Although it&rsquo;s not the only thing org-roam offers, but it&rsquo;s a good start.
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>Speedup aur Package Install by 1000%</title>
<link>https://merrick.luois.me/posts/speedup-aur-package-install-by-1000.html</link>
<pubDate>Thu, 30 Apr 2020 19:34:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/speedup-aur-package-install-by-1000.html</guid>
<description>
<![CDATA[<div id="outline-container-speedup-aur-package-install-by-1000" class="outline-2">
<h2 id="speedup-aur-package-install-by-1000">Speedup aur Package Install by 1000%</h2>
<div class="outline-text-2" id="text-speedup-aur-package-install-by-1000">
<p>
And&hellip; of course this is a click-bait title, This will only speedup the compress time when packaging the package, not the whole build time 🙂️.
</p>

<p>
One night in a peaceful Telegram group, a member starts complaining about aur packages install is too slow, and the <code>xz</code> process is only consuming one core. This leads to a meaningful discussion about how aur works and how to speed up the build, but I&rsquo;ll skip the first part by now, if you are interested, just follow <a href="https://wiki.archlinux.org/index.php/Makepkg">Makepkg</a> page on Arch Wiki.
</p>

<p>
In short, aur is using makepkg to build the package and then install it with pacman, and there is a <code>/etc/makepkg.conf</code> we can tweak to make it works better.
</p>
</div>
</div>
<div id="outline-container-zstd" class="outline-2">
<h2 id="zstd">zstd</h2>
<div class="outline-text-2" id="text-zstd">
<p>
Another thing pop up in the discussion is <a href="https://github.com/facebook/zstd">zstd</a>, pacman <a href="https://www.archlinux.org/news/now-using-zstandard-instead-of-xz-for-package-compression/">switches to zstd from xz</a> on Friday, Dec 27, 2019, and claims it had a 1300% speedup. Since we can also use it in makepkg now, so it&rsquo;s a great time to switch.
Just change one line in <code>/etc/makepkg.conf</code> to make it use zstd.
</p>

<div class="org-src-container">
<pre class="src src-diff"><code><span style="color: #aa2222; background-color: #ffd8d5;">-</span><span style="color: #8f1313; background-color: #ffd8d5;"> PKGEXT='.pkg.tar.xz'
</span>+ PKGEXT='.pkg.tar.zst'
</code></pre>
</div>
</div>
</div>
<div id="outline-container-multithread" class="outline-2">
<h2 id="multithread">Multithread</h2>
<div class="outline-text-2" id="text-multithread">
<p>
The main complain is <code>xz</code> is only using one thread when there are 8/16 available. It&rsquo;s because the commands is not setup to use multi-thread by default. we can change it as documented in the <a href="https://wiki.archlinux.org/index.php/Makepkg">Makepkg</a> wiki page.
This change can change zstd to use multi-thread (similar to <code>xz</code>).
</p>

<div class="org-src-container">
<pre class="src src-diff"><code><span style="color: #aa2222; background-color: #ffd8d5;">-</span><span style="color: #8f1313; background-color: #ffd8d5;"> COMPRESSZST=(zstd -c -z -q -)
</span>+ COMPRESSZST=(zstd -c -z -q - --threads=0)
</code></pre>
</div>
</div>
</div>
<div id="outline-container-use-tmpfs" class="outline-2">
<h2 id="use-tmpfs">Use tmpfs</h2>
<div class="outline-text-2" id="text-use-tmpfs">
<p>
If you have spare memory, you can also use it for speed up build. This is also documented in the <a href="https://wiki.archlinux.org/index.php/Makepkg">Makepkg</a> wiki page.
Just uncomment one line in <code>/etc/makepkg.conf</code>
</p>

<div class="org-src-container">
<pre class="src src-diff"><code><span style="color: #aa2222; background-color: #ffd8d5;">-</span><span style="color: #8f1313; background-color: #ffd8d5;"> #BUILDDIR=/tmp/makepkg
</span>+ BUILDDIR=/tmp/makepkg
</code></pre>
</div>
</div>
</div>
<div id="outline-container-conclusion" class="outline-2">
<h2 id="conclusion">Conclusion</h2>
<div class="outline-text-2" id="text-conclusion">
<p>
These steps should give you a 1000%+ speedup with aur package compressing(according to <a href="https://www.archlinux.org/news/now-using-zstandard-instead-of-xz-for-package-compression/">Robin Broda</a>). I have so many times starring at aur package install stuck at <code>Compressing Package</code> step, but never thought of how to optimize it.  #TodayILearned
</p>
</div>
</div>
<div id="outline-container-history" class="outline-2">
<h2 id="history">History</h2>
<div class="outline-text-2" id="text-history">
<ul class="org-ul">
<li>2020-04-30 add title explanation.</li>
</ul>
</div>
</div>
]]>
</description></item>
<item>
<title>Replacing GPG private keys</title>
<link>https://merrick.luois.me/posts/replacing-gpg-private-keys.html</link>
<pubDate>Sun, 10 May 2020 22:47:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/replacing-gpg-private-keys.html</guid>
<description>
<![CDATA[<div id="outline-container-replacing-gpg-private-keys" class="outline-2">
<h2 id="replacing-gpg-private-keys">Replacing GPG private keys</h2>
<div class="outline-text-2" id="text-replacing-gpg-private-keys">
<p>
<a href="https://keybase.io/blog/keybase-joins-zoom">Keybase is acquired by Zoom</a> on May 7, 2020.
</p>

<p>
Although I don&rsquo;t have any evidence why Zoom is not trustworthy, I just don&rsquo;t. I deleted my account immediately after I saw the news. Since my private keys are all generated by keybase cli and have been synced with it, so I think it&rsquo;s a good idea to replace them as well.
</p>

<p>
I currently only use gpg key with pass, git commit sign, an <code>.authinfo.gpg</code> file used by emacs, and a <code>.mailpass.gpg</code> file used by <code>mbsync</code>.
</p>
</div>
</div>
<div id="outline-container-generate-new-keys" class="outline-2">
<h2 id="generate-new-keys">Generate new keys.</h2>
<div class="outline-text-2" id="text-generate-new-keys">
<p>
This is pretty straightforward, just run <code>gpg --full-gen-key</code> and follow the instructions, I&rsquo;m using RSA and RSA with 4096 bits keysize and no expire options.
</p>

<p>
Do this twice to generate two keys, one for personal use, and one for sign git commits for work.
</p>

<p>
Find out the &lt;new-key-id&gt; with <code>gpg --list-secret-keys</code>.
</p>
</div>
</div>
<div id="outline-container-re-encrypt-the-password-store" class="outline-2">
<h2 id="re-encrypt-the-password-store">Re-encrypt the password store.</h2>
<div class="outline-text-2" id="text-re-encrypt-the-password-store">
<p>
First check for <code>.gpg-id</code> file in the password store directory, if it exists, it should contain the old gpg key-id, just remove it. The just run a <code>pass init</code> with newly generated key to re-encrypt all password files in it.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #005f5f; font-weight: bold;">cd</span> .password-store
<span style="color: #005f5f; font-weight: bold;">rm</span> .gpg-id
pass init &lt;new-key-id&gt;
</code></pre>
</div>

<p>
references: <a href="https://askubuntu.com/questions/929307/how-to-change-the-gpg-key-of-the-pass-password-store">pgp - How to change the gpg key of the pass password store - Ask Ubuntu</a>
</p>
</div>
</div>
<div id="outline-container-change-git-commit-signing-key" class="outline-2">
<h2 id="change-git-commit-signing-key">Change git commit signing key.</h2>
<div class="outline-text-2" id="text-change-git-commit-signing-key">
<p>
I have multiple git config with <code>gitdir:</code> config, just update all <code>.gitconfig</code> files, replacing the old key id with the new one. If only one git config is used, it can also be changed in terminal.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #005f5f; font-weight: bold;">git</span> config user.signingkey &lt;new-key-id&gt;
</code></pre>
</div>

<p>
Get a public key export by running
</p>

<div class="org-src-container">
<pre class="src src-shell"><code>gpg --export --armor &lt;new-key-id&gt; | pbcopy
</code></pre>
</div>

<blockquote>
<p>
<code>pbcopy</code> is a wrapper I use for save stdout to clipboard.
</p>
<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #595959; font-style: italic;">#</span><span style="color: #595959; font-style: italic;">!/bin/</span><span style="color: #531ab6; font-weight: bold;">bash</span><span style="color: #595959; font-style: italic;">
</span><span style="color: #531ab6; font-weight: bold;">if</span> [[ $(uname) == <span style="color: #3548cf;">"Darwin"</span> ]]; <span style="color: #531ab6; font-weight: bold;">then</span>
    /usr/bin/pbcopy
<span style="color: #531ab6; font-weight: bold;">else</span>
    xclip -i -sel c -f |xclip -i -sel p
<span style="color: #531ab6; font-weight: bold;">fi</span>
</code></pre>
</div>
</blockquote>

<p>
Then go to GitHub/GitLab or any other service needed, add the new pubkey and remove the old key from GPG Key Settings.
</p>
</div>
</div>
<div id="outline-container-other-files-encrypted-with-gpg" class="outline-2">
<h2 id="other-files-encrypted-with-gpg">Other files encrypted with gpg.</h2>
<div class="outline-text-2" id="text-other-files-encrypted-with-gpg">
<p>
Just do a decrypt and encrypt.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code>gpg --decrypt -o authinfo.txt .authinfo.gpg
gpg --encrypt -o .authinfo.gpg --default-key &lt;new-key-id&gt; authinfo.txt
<span style="color: #005f5f; font-weight: bold;">rm</span> authinfo.txt

gpg --decrypt -o mailpass.txt .mailpass.gpg
gpg --encrypt -o .mailpass.gpg --default-key &lt;new-key-id&gt; mailpass.txt
<span style="color: #005f5f; font-weight: bold;">rm</span> mailpass.txt
</code></pre>
</div>
</div>
</div>
<div id="outline-container-remove-the-old-gpg-key" class="outline-2">
<h2 id="remove-the-old-gpg-key">Remove the old gpg key.</h2>
<div class="outline-text-2" id="text-remove-the-old-gpg-key">
<p>
Backup keys in case of something missing from the above steps.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code>gpg --export --armor &lt;old-key-id&gt; &gt; old_pubkey.asc
gpg --export-secret-keys --armor &lt;old-key-id&gt; &gt; old_privkey.asc
gpg --delete-secret-and-public-key &lt;old-key-id&gt;
</code></pre>
</div>

<p>
There will be a lot of popups, just hit delete 🙂️.
</p>
</div>
</div>
<div id="outline-container-conclusion" class="outline-2">
<h2 id="conclusion">Conclusion</h2>
<div class="outline-text-2" id="text-conclusion">
<p>
It&rsquo;s quite easy I&rsquo;d say, definitely easier than replacing an Email address or phone number. Be safe.
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>无人生还和黄金时代</title>
<link>https://merrick.luois.me/posts/and-then-there-were-none-and-golden-age.html</link>
<pubDate>Sun, 24 May 2020 19:37:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/and-then-there-were-none-and-golden-age.html</guid>
<description>
<![CDATA[<div id="outline-container-无人生还和黄金时代" class="outline-2">
<h2 id="无人生还和黄金时代">无人生还和黄金时代</h2>
<div class="outline-text-2" id="text-无人生还和黄金时代">
<p>
这周末突然有了读书的感觉，于是动手把两本开到一半的书读完了，想起自己久来也没有中文写作的练习了，就写一点读后感权当日记。
</p>
</div>
</div>
<div id="outline-container-and-then-there-were-none" class="outline-2">
<h2 id="and-then-there-were-none"><a href="https://www.amazon.cn/dp/B00T2NGQW2">《无人生还》</a>by阿加莎・克里斯蒂娜</h2>
<div class="outline-text-2" id="text-and-then-there-were-none">
<p>
Kindle给这本推理小说的副标题是"全球销量第一的侦探小说，古典推理的不朽名作！", 虽然不知道准不准确，不过就我的水平来看还算是精彩的，阿加莎克里斯蒂娜的推理小说特点就是“暴风雪山庄”，所以凶手必定是在出现的人物之中，所以说猜凶手和手法就是阅读这类小说的最大乐趣了。
</p>

<details id="org7b817d4">
<summary id="org713bea3">
<p>
Warning：接下来的内容包含剧透，如果还未读过请勿轻易展开。
</p>
</summary>
<p>
由于这本书鼎鼎大名，名字差不多也算是剧透，我一开始就知道上岛的人肯定是一个都没活下来。
</p>

<p>
刚开始我以为跟东方列车谋杀案类似，这是个人都是同一个案件的“凶手”，联手害死了某个人而引来了复仇，不过故事刚刚展开，“凶手”就公开了每位“受害者”的罪行，十个人几乎没有任何交集。那么从一个上帝视角来说，“凶手”一定就是一位正义感非常强的人了，所以我的“嫌疑人”一直锁定在法官和基督教徒里面。
</p>

<p>
不过由于我看书的毛病（看得太快），忽略了中间法官和医生的交流那一段，忽略了一些假死的细节，最后还是被骗到了。
</p>
</details>
</div>
</div>
<div id="outline-container-golden-age" class="outline-2">
<h2 id="golden-age"><a href="https://www.amazon.cn/dp/B00DNX7Y1E">《黄金时代》</a>by王小波</h2>
<div class="outline-text-2" id="text-golden-age">
<p>
黄金时代是王小波先生的几篇小说合集，其中的《革命时期的爱情》、《似水流年》我大概已经看过好几遍了，不过这次来看合集也还是看得津津有味。
</p>

<p>
我摘选了一些自觉比较有意思的段落放在这里。跟上面不同，这里完全没有剧透也不会影响阅读。
</p>

<p>
“我自己也没兴趣”。
</p>
<blockquote>
<p>
“配种站吗？我找郭主任。不！我什么都不送……我自己也没兴趣……我们公的母的都有。郭二，我们要去了。现在不是节气，只能看看样子了。刚才接电话的是谁？”
</p>
</blockquote>

<p>
伟大的诗人。
</p>
<blockquote>
<p>
现在我是诗人。虽然没发表过一行诗，但是正因为如此，我更伟大。
</p>
</blockquote>

<p>
经历过的一切。
</p>
<blockquote>
<p>
似水流年是一个人所有的一切，只有这个东西，才真正归你所有。其余的一切，都是片刻的欢娱和不幸，转眼间就已跑到那似水流年里去了。我所认识的人，都不珍视自己的似水流年。他们甚至不知道，自己还有这么一件东西，所以一个个像丢了魂一样。
</p>
</blockquote>

<p>
生孩子没屁眼。
</p>
<blockquote>
<p>
出这主意的那位首长，后来生了个孩子没屁眼，是我妈动手术给孩子做了个人工肛门。这个故事告诉我们，随着医学的发展，干点缺德事不要紧，生孩子没屁眼可以做人工肛门，怕什么？
</p>
</blockquote>

<p>
亩产十万斤。
</p>
<blockquote>
<p>
假设有一头猪，在一般饲养条件下每天只能长八两的话，本发明能让它长到一斤半，其法是用一斤花生油，加鸡蛋黄两个对它做肌肉注射。据说这样喂出的猪不光肥胖，肉质还十分细嫩。当时我就想到了这个发明虽好，但还不是尽善尽美。应该再打点酱油和料酒进去，使它不等挨刀子就变成一根巨大的广东香肠。
</p>
</blockquote>

<p>
KPI。
</p>
<blockquote>
<p>
指标这种东西，是一切浪漫情调的死敌。假如有上级下达指标令我每周和老婆做爱三次的话，我就会把自己阉掉。
</p>
</blockquote>

<p>
我看到的不是我想看到的。
</p>
<blockquote>
<p>
虽然有确凿的证据说明在这个炉筒里什么都没有，但是我仍然相信假如不是我哥哥踢开了挡门的树粧，而是我自己爬了进去，情况就会有所不同。
</p>
</blockquote>

<p>
原始的时代。
</p>
<blockquote>
<p>
等到六七年的武斗发展到了动枪时，我离开了“拿起笔做刀枪”回家去了。有人可能会说我胆小，但我决不承认。因为用大刀长矛投石机战斗，显然需要更多的勇气。就以我们院为例，自从动了枪，就没有打死过一个人。这一点丝毫不足为怪，因为在历史上也是刀矛杀掉的比枪炮多得多。原子弹造出来已经有四十多年了，除了在日本发了两回利市,还没有炸死过一个人。
</p>
</blockquote>

<p>
别觉得自己老。
</p>
<blockquote>
<p>
我只有四十岁,人生的道路还相当漫长。我不能总是心怀厌倦吧。
</p>
</blockquote>

<p>
倘若王小波先生能活到现在，我大概也能当一回脑残粉吧。
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>Introducing Burmese</title>
<link>https://merrick.luois.me/posts/introducing-burmese.html</link>
<pubDate>Tue, 27 Jul 2021 10:57:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/introducing-burmese.html</guid>
<description>
<![CDATA[<div id="outline-container-introducing-burmese" class="outline-2">
<h2 id="introducing-burmese">Introducing Burmese</h2>
<div class="outline-text-2" id="text-introducing-burmese">

<figure id="orga5c5016">
<img src="https://assets.luois.me/introducing-burmese/showcase.gif" alt="showcase.gif">

</figure>

<p>
Annimated cat on the screen that relaxes your eyes and mind.
</p>
</div>
</div>
<div id="outline-container-but-why" class="outline-2">
<h2 id="but-why">But Why?</h2>
<div class="outline-text-2" id="text-but-why">
<p>
About 2 years ago, I found this awesome <a href="https://addons.mozilla.org/en-US/firefox/addon/a-n-i-m-a-t-e-d-kitty-cat/">Firefox theme</a>, I&rsquo;m astonished, because who doesn&rsquo;t like a cat wagging his tail on their screen? But the extension is somewhat outdated, cat looks blurry on hidpi screens, and I also want it on my emacs! So why not?
</p>

<p>
Then I extracted the images from the extension, converted to png and svg (didn&rsquo;t remember how, should have taken notes). And dragged them into Xcode since I was using a macbook back then.
</p>

<p>
Then time passed, I mainly use my desktop running Linux (I use <del>Arch</del> Gentoo BTW), I totally forgot this cat (sorry) for almost 2 years, until I opened it again on my macbook last Monday, I was thinking, damn, I needed it on my desktop too.
</p>
</div>
</div>
<div id="outline-container-choose-a-stack" class="outline-2">
<h2 id="choose-a-stack">Choose a stack</h2>
<div class="outline-text-2" id="text-choose-a-stack">
<p>
It&rsquo;s a rather simple application, which, just rendering images, change it every 1/10 seconds, in another word, a frame animation. But in order to display nicely on the desktop, it needs some unordinary features.
</p>

<ul class="org-ul">
<li>window needs to be transparent, so it looks nice.</li>
<li>better if we can click through it so it won&rsquo;t block the mouse events for the application underneath.</li>
</ul>

<p>
These two requirements sounds easy enough, and can simply implemented with the cocoa version, but I find them very challenging for its <del>cross platform</del> implementation.
</p>

<p>
First come to mind is to use electron, I tried that 2 years ago but had some issue about transparency and I don&rsquo;t really like electron that much. So I decide to try other frameworks.
</p>
</div>
<div id="outline-container-rust" class="outline-3">
<h3 id="rust">Rust</h3>
<div class="outline-text-3" id="text-rust">
<p>
I&rsquo;m not a fan of rust, but I do like its toolchain, <code>cargo</code> and <code>rustup</code> is simple to run and setup, save me some time to worry about Makefile or gcc. And also for this simple app, I don&rsquo;t need to learn much about rust to get it done.
</p>
</div>
</div>
<div id="outline-container-sdl2" class="outline-3">
<h3 id="sdl2">sdl2</h3>
<div class="outline-text-3" id="text-sdl2">
<p>
First I wanted to try some &ldquo;light&rdquo; frameworks, <a href="https://www.libsdl.org/">Simple DirectMedia Layer</a> is a light-weight, cross-platform library mostly used for game development, but it should display a image quite easily.
</p>

<p>
BUT, I can&rsquo;t get it to draw a transparent pixel and the top window, either macos nor linux(i3). I have tried to set <code>BlendMode</code> and set window opacity, remove the hint for not using compositor on linux, none of them works, and I don&rsquo;t want to waste 4 more hours on it, so pass.
</p>
</div>
</div>
<div id="outline-container-gtk3" class="outline-3">
<h3 id="gtk3">gtk3</h3>
<div class="outline-text-3" id="text-gtk3">
<p>
Rust has a nicely maintained <a href="https://gtk-rs.org/">gtk binding</a>, as a &ldquo;living on the edge&rdquo; type of guy, I tried the gtk4 version first, but it seems lack a lot nice API gtk3 have, so I settled with gtk3.
</p>
</div>
</div>
</div>
<div id="outline-container-implementation" class="outline-2">
<h2 id="implementation">Implementation</h2>
<div class="outline-text-2" id="text-implementation">
<p>
Creating an animation is really easy with the <code>PixbufSimpleAnim</code> API, and it handles svg out of box.
</p>

<div class="org-src-container">
<pre class="src src-rust"><code><span style="color: #531ab6; font-weight: bold;">let</span> <span style="color: #005e8b;">anime</span> = <span style="color: #005f5f; font-weight: bold;">PixbufSimpleAnim</span>::new(<span style="color: #005f5f; font-weight: bold;">WIDTH</span>, <span style="color: #005f5f; font-weight: bold;">HEIGHT</span>, <span style="color: #000000;">10.0</span>);
<span style="color: #531ab6; font-weight: bold;">for</span> <span style="color: #005e8b;">i</span> <span style="color: #531ab6; font-weight: bold;">in</span> <span style="color: #000000;">1</span>..<span style="color: #000000;">22</span> {
    <span style="color: #531ab6; font-weight: bold;">let</span> <span style="color: #005e8b;">data</span> = <span style="color: #005f5f; font-weight: bold;">Cats</span>::get(&amp;<span style="color: #8f0075; font-weight: bold;">format</span>!(<span style="color: #3548cf;">"svg_cat{}.svg"</span>, i)).unwrap();
    <span style="color: #531ab6; font-weight: bold;">let</span> <span style="color: #005e8b;">buffer</span> = <span style="color: #005f5f; font-weight: bold;">ByteBuffer</span>::from_bytes(&amp;data);
    <span style="color: #531ab6; font-weight: bold;">let</span> <span style="color: #005e8b;">pixbuf</span> = <span style="color: #005f5f; font-weight: bold;">Pixbuf</span>::from_read(buffer).unwrap();
    anime.add_frame(&amp;pixbuf);
}
anime.set_loop(<span style="color: #0000b0;">true</span>);
</code></pre>
</div>

<p>
I wanted the images bundled in the binary, so <a href="https://github.com/pyros2097/rust-embed">rust-embed</a> comes to help.
</p>

<div class="org-src-container">
<pre class="src src-rust"><code><span style="color: #a0132f;">#[derive(RustEmbed)]</span>
<span style="color: #a0132f;">#[folder = "cats"]</span>
<span style="color: #531ab6; font-weight: bold;">struct</span> <span style="color: #005f5f; font-weight: bold;">Cats</span>;
</code></pre>
</div>

<p>
And we need gtk to use the compositor so it can show transparent pixels.
</p>

<div class="org-src-container">
<pre class="src src-rust"><code><span style="color: #531ab6; font-weight: bold;">let</span> <span style="color: #005e8b;">screen</span> = win.screen().unwrap();
win.set_visual(screen.rgba_visual().as_ref());
</code></pre>
</div>

<p>
The rest of the code is just passing some params to create and display the window, that&rsquo;s it.
</p>

<p>
<a href="https://gitlab.com/merrickluo/burmese">The repo</a> is at <a href="https://gitlab.com/">Gitlab</a>, please try it out!
</p>

<blockquote>
<p>
All credits goes to the author of the <a href="https://addons.mozilla.org/en-US/firefox/addon/a-n-i-m-a-t-e-d-kitty-cat/">Firefox theme</a>!
</p>
</blockquote>
</div>
</div>
]]>
</description></item>
<item>
<title>Pipewire fixed my USB speaker</title>
<link>https://merrick.luois.me/posts/pipewire-fixed-my-usb-speaker.html</link>
<pubDate>Mon, 13 Sep 2021 19:24:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/pipewire-fixed-my-usb-speaker.html</guid>
<description>
<![CDATA[<div id="outline-container-pipewire-fixed-my-usb-speaker" class="outline-2">
<h2 id="pipewire-fixed-my-usb-speaker">Pipewire fixed my USB speaker</h2>
<div class="outline-text-2" id="text-pipewire-fixed-my-usb-speaker">
<p>
I only notice <a href="https://pipewire.org">PipeWire</a> from a <del>hot</del> <a href="https://news.ycombinator.com/item?id=28490078">hacker news headline</a> this morning, the top comment mentioned that it can replace PulseAudio caught my attention.
</p>

<p>
I had some struggles with PulseAudio before. The biggest one is that my USB speaker (Sony SRS-HG10) stopped working since I updated my kernel to 5.12. I have tried a lot of fixes, tweaking kernel configs, clean PulseAudio caches, etc. Finally, I gave up and wore a headphone instead.
</p>

<p>
After reading the <a href="https://wiki.archlinux.org/title/PipeWire">ArchWiki page</a> and <a href="https://wiki.gentoo.org/wiki/PipeWire">Gentoo Wiki page</a> about PipeWire I find it&rsquo;s quite easy to replace PulseAudio with it.
</p>

<ul class="org-ul">
<li>Stop PulseAudio from auto spawning.
Edit <code>/etc/pulse/client.conf</code> and un-comment line <code>autospawn = no</code></li>

<li><p>
start PipeWire when X starts.
It&rsquo;s possible to add it to any X start script like <code>.xinirc</code> or <code>.xprofile</code>, I did it in my <code>i3/config</code>
</p>

<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #531ab6; font-weight: bold;">exec</span> --no-startup-id pipewire
</code></pre>
</div></li>
</ul>

<p>
That&rsquo;s it. I restarted i3, opened up a Youtube video. BOOOOOM, everything works.
</p>

<p>
Just to be sure.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code>ps -aux | <span style="color: #005f5f; font-weight: bold;">grep</span> pulse
<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-weight: bold; font-style: italic;">make</span><span style="color: #595959; font-style: italic;"> sure no PulseAudio process running</span>
</code></pre>
</div>

<div class="org-src-container">
<pre class="src src-shell"><code>pactl info | <span style="color: #005f5f; font-weight: bold;">grep</span> <span style="color: #3548cf;">"Server Name"</span>
<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">: Server Name: PulseAudio (on PipeWire 0.3.30)</span>
</code></pre>
</div>

<p>
Open <code>pavucontrol</code> and switch to USB speaker, it works too, congratulations (to me)!
</p>

<p>
There is also <a href="https://bugs.gentoo.org/744622">a ticket</a> in Gentoo bug tracker discussing how to avoid installing PulseAudio entirely. I&rsquo;m looking forward to it.
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>博客主题更新</title>
<link>https://merrick.luois.me/posts/blog-theme-update.html</link>
<pubDate>Thu, 16 Sep 2021 01:35:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/blog-theme-update.html</guid>
<description>
<![CDATA[<div id="outline-container-博客主题更新" class="outline-2">
<h2 id="博客主题更新">博客主题更新</h2>
<div class="outline-text-2" id="text-博客主题更新">
<p>
最近的几篇博客我都在尝试使用英文写，其一是因为大部分的工作、非工作文档需要使用英文编写，其二是因为编程相关的术语较多，而我一向不喜欢这些术语的中文翻译。所以权当练习（？）。
</p>

<p>
之前为了这个还特意把博客分开了中文页面和英文页面，其实是瞎用了 Hugo 的“翻译”功能，并不是非常合适，所以决定更新一下主题，顺便改几个 Bug(?)。
</p>

<p>
博客主题 Repo: <a href="https://github.com/merrickluo/hugo-tailwind-journal">https://github.com/merrickluo/hugo-tailwind-journal</a>
</p>
</div>
</div>
<div id="outline-container-中英文-tag" class="outline-2">
<h2 id="中英文-tag">中英文 tag</h2>
<div class="outline-text-2" id="text-中英文-tag">
<p>
虽然自己的英文写作水平比较低，不过还是希望坚持一下多写一点。由于不再使用 Hugo 的翻译功能，所以给中英文的博客分别打上了标签。
</p>
</div>
</div>
<div id="outline-container-pangujs" class="outline-2">
<h2 id="pangujs">pangu.js</h2>
<div class="outline-text-2" id="text-pangujs">
<p>
我在 Emacs 里一直在使用 <a href="https://github.com/coldnew/pangu-spacing">pangu-spacing</a>， 这次给博客也加上了 <a href="https://github.com/vinta/pangu.js/">pangu.js</a>。
</p>

<p>
不过感觉可能作用有限了，由于在 Org-mode 里不中英文不加上空格，spell-check 会变得相当混乱，所以我现在都把 <code>pangu-spacing-real-insert-separtor</code> 又打开了，以后的博客内容应该都会自带空格。
</p>
</div>
</div>
<div id="outline-container-no-script" class="outline-2">
<h2 id="no-script">no-script</h2>
<div class="outline-text-2" id="text-no-script">
<p>
之前给博客主题添加了一个简单的 Light/Dark Mode 切换按钮，用到了几行 JavaScript，这次在偶然关掉浏览器 JavaScript 的情况下打开之后发现就定在 Dark Mode 了，狠狠的伤害了我自己的眼睛。并且右上角的切换按钮在没有 JavaScript 的情况下也毫无作用。
</p>

<p>
更新后在没有 JavaScript 的情况下，会使用浏览器的 <code>prefers-color-scheme</code> 值设定 Light/Dark Mode，并不再显示切换按钮。
</p>
</div>
</div>
<div id="outline-container-live-section" class="outline-2">
<h2 id="live-section"><span class="todo TODO">TODO</span> Live Section</h2>
<div class="outline-text-2" id="text-live-section">
<p>
下一步准备给博客增加一个 "Live Section"，大概目的是用来放新弄的 Literate Doom Emacs 配置，随时更新，并且发布出来也会让我给配置补充文档增加点动力，参考     <a href="https://tecosaur.github.io/emacs-config/config.html">tecosaur 的配置</a>。
</p>

<p>
或许还有一些其他用处，比如用来更新自己的读书笔记？（说得好像会读书）。
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>Better TSX support w/ Tree-sitter in Doom Emacs</title>
<link>https://merrick.luois.me/posts/better-tsx-support-in-doom-emacs.html</link>
<pubDate>Mon, 25 Oct 2021 22:38:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/better-tsx-support-in-doom-emacs.html</guid>
<description>
<![CDATA[<div id="outline-container-better-tsx-support-w-tree-sitter-in-doom-emacs" class="outline-2">
<h2 id="better-tsx-support-w-tree-sitter-in-doom-emacs">Better TSX support w/ Tree-sitter in Doom Emacs</h2>
<div class="outline-text-2" id="text-better-tsx-support-w-tree-sitter-in-doom-emacs">
<p>
I don&rsquo;t like TypeScript, but for <del>science/torturing myself</del>, I decided to try it in a small side project. Naturally, I need to set up the development environment for it in Emacs. Luckily it&rsquo;s pretty easy to do in Doom Emacs. All I need to do is to enable the <code>javascript</code> and <code>web</code> layer in <code>init.el</code>, but there is a catch (or this article won&rsquo;t exist).
</p>
</div>
</div>
<div id="outline-container-update-2023-04-09" class="outline-2">
<h2 id="update-2023-04-09">Update 2023-04-09</h2>
<div class="outline-text-2" id="text-update-2023-04-09">
<p>
If you are using Emacs 29, you can use the built-in Tree-sitter support for TSX/TS. See <a href="posts/typescript-in-emacs-29.html">Typescript/TSX in (Doom) Emacs 29+</a>.
</p>
</div>
</div>
<div id="outline-container-update-2022-11-23" class="outline-2">
<h2 id="update-2022-11-23">Update 2022-11-23</h2>
<div class="outline-text-2" id="text-update-2022-11-23">
<p>
If you&rsquo;re using emacs 29, feature/tree-sitter just got merged, and you can use the built in
</p>
</div>
</div>
<div id="outline-container-tldr" class="outline-2">
<h2 id="tldr">TLDR;</h2>
<div class="outline-text-2" id="text-tldr">
<p>
View <a href="#the-final-result">The Final Result</a> or use <a href="https://bitbucket.org/mituharu/emacs-mac/src/master/">emacs-mac</a> (if you are using macOS).
</p>
</div>
</div>
<div id="outline-container-the-catch" class="outline-2">
<h2 id="the-catch">The catch</h2>
<div class="outline-text-2" id="text-the-catch">
<p>
I have a desktop with Ryzen 3900X and a MacBook Pro 2019(I know, I&rsquo;m sorry). So this problem didn&rsquo;t occur to me until I opened the project on the Macbook Pro. Emacs <b>lags so much</b> when navigating in the <code>.tsx</code> files. And I remembered that a former colleague was complaining about this a couple of days ago, and I was like: &ldquo;It works for me.&rdquo;. It&rsquo;s not now, so I started digging.
</p>
</div>
</div>
<div id="outline-container-typescript-mode-web-mode" class="outline-2">
<h2 id="typescript-mode-web-mode">typescript-mode &amp; web-mode</h2>
<div class="outline-text-2" id="text-typescript-mode-web-mode">
<p>
Doom Emacs uses a major mode derived from <code>web-mode</code> to handle <code>.tsx</code> files, because <code>typescript-mode</code> <a href="https://github.com/emacs-typescript/typescript.el/issues/4">does not support TSX</a>. I agree with their decision after I read part of the <code>web-mode</code> code, like <a href="https://github.com/fxbois/web-mode/blob/61f057a6baeba6b3595e412ba79b3080dca17dcc/web-mode.el#L8221">this function</a> handles the indentation. A <b>700+</b> lines code function is called just for I press enter in a <code>web-mode</code> buffer. <code>web-mode</code> is a great package and I understand that it has to supports soooo many template languages, but it&rsquo;s just too complicated.
</p>

<p>
In the typescript-mode thread, someone mentioned using typescript-mode + Tree-sitter to handle <code>.tsx</code> files caught my attention. Since I was running Tree-sitter in my configuration for weeks, and it works pretty well. So I tried it.
</p>
</div>
</div>
<div id="outline-container-typescript-mode-tree-sitter" class="outline-2">
<h2 id="typescript-mode-tree-sitter">typescript-mode + Tree-sitter</h2>
<div class="outline-text-2" id="text-typescript-mode-tree-sitter">
<p>
I already configured Tree-sitter in my configuration, copied from a <a href="https://github.com/hlissner/doom-emacs/pull/5401">pending PR</a> from Doom Emacs.
</p>

<ul class="org-ul">
<li>Update: there are <a href="https://github.com/hlissner/doom-emacs/pull/5401/files/eb54017ee5619ecaf9198d18c7fd4c7b7b90a8c5..b4cd659aa4d65c48e46fa7a6d5f6fd6d2c4d5364">another PR</a> working for better Tree-sitter integration to Doom.</li>
</ul>

<p>
<code>packages.el</code>
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">package!</span> tree-sitter
  <span style="color: #8f0075; font-weight: bold;">:ignore</span> (<span style="color: #0000b0;">null</span> (<span style="color: #531ab6; font-weight: bold;">bound-and-true-p</span> <span style="color: #005e8b;">module-file-suffix</span>)))

(<span style="color: #531ab6; font-weight: bold;">package!</span> tree-sitter-langs
  <span style="color: #8f0075; font-weight: bold;">:ignore</span> (<span style="color: #0000b0;">null</span> (<span style="color: #531ab6; font-weight: bold;">bound-and-true-p</span> <span style="color: #005e8b;">module-file-suffix</span>)))
</code></pre>
</div>

<p>
<code>config.el</code>
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">use-package!</span> tree-sitter
  <span style="color: #8f0075; font-weight: bold;">:when</span> (<span style="color: #531ab6; font-weight: bold;">bound-and-true-p</span> <span style="color: #005e8b;">module-file-suffix</span>)
  <span style="color: #8f0075; font-weight: bold;">:hook</span> (<span style="color: #0000b0;">prog-mode</span> . tree-sitter-mode)
  <span style="color: #8f0075; font-weight: bold;">:hook</span> (tree-sitter-after-on . tree-sitter-hl-mode)
  <span style="color: #8f0075; font-weight: bold;">:config</span>
  (<span style="color: #0000b0;">require</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">tree-sitter-langs</span>)
  (global-tree-sitter-mode)
  (<span style="color: #0000b0;">add-hook</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">tree-sitter-after-on-hook</span> <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">tree-sitter-hl-mode</span>)
  (<span style="color: #531ab6; font-weight: bold;">defadvice!</span> doom-tree-sitter-fail-gracefully-a (orig-fn <span style="color: #005f5f; font-weight: bold;">&amp;rest</span> args)
    <span style="color: #2a5045; font-style: italic;">"Don't break with errors when current major mode lacks tree-sitter support."</span>
    <span style="color: #8f0075; font-weight: bold;">:around</span> <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">tree-sitter-mode</span>
    (<span style="color: #531ab6; font-weight: bold;">condition-case</span> e
        (<span style="color: #0000b0;">apply</span> orig-fn args)
      (<span style="color: #0000b0;">error</span>
       (<span style="color: #531ab6; font-weight: bold;">unless</span> (<span style="color: #721045;">string-match-p</span> (<span style="color: #0000b0;">concat</span> <span style="color: #3548cf;">"^Cannot find shared library</span><span style="color: #721045; font-weight: bold;">\\</span><span style="color: #00663f; font-weight: bold;">|</span><span style="color: #3548cf;">"</span>
                                       <span style="color: #3548cf;">"^No language registered</span><span style="color: #721045; font-weight: bold;">\\</span><span style="color: #00663f; font-weight: bold;">|</span><span style="color: #3548cf;">"</span>
                                       <span style="color: #3548cf;">"cannot open shared object file"</span>)
                               (<span style="color: #0000b0;">error-message-string</span> e))
         (<span style="color: #0000b0;">signal</span> (<span style="color: #0000b0;">car</span> e) (<span style="color: #0000b0;">cadr</span> e)))))))
</code></pre>
</div>

<p>
So I added the suggestion from the issue thread in <code>typescript-mode</code>.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">use-package!</span> typescript-mode
  <span style="color: #8f0075; font-weight: bold;">:mode</span> (<span style="color: #3548cf;">"\\.tsx\\'"</span> . typescript-tsx-tree-sitter-mode)
  <span style="color: #8f0075; font-weight: bold;">:config</span>
  (<span style="color: #531ab6; font-weight: bold;">setq</span> typescript-indent-level 2)
  (<span style="color: #531ab6; font-weight: bold;">define-derived-mode</span> <span style="color: #721045;">typescript-tsx-tree-sitter-mode</span> typescript-mode <span style="color: #3548cf;">"TypeScript TSX"</span>))

(<span style="color: #531ab6; font-weight: bold;">after!</span> tree-sitter
  (<span style="color: #7b435c;">add-to-list</span> <span style="color: #531ab6; font-weight: bold;">'</span>tree-sitter-major-mode-language-alist <span style="color: #531ab6; font-weight: bold;">'</span>(typescript-tsx-tree-sitter-mode . tsx)))
</code></pre>
</div>

<p>
And it works! JSX syntax highlighted, <code>lsp-mode</code> works, but(this is the last &ldquo;but&rdquo;; I promise.), since <code>typescript-mode</code> does not support JSX, it doesn&rsquo;t know how to indent the code, of course, you can still manually press <code>tab</code>, but that&rsquo;s not what we want from a &ldquo;smart&rdquo; editor, right?
</p>
</div>
</div>
<div id="outline-container-indentation-a-failed-try" class="outline-2">
<h2 id="indentation-a-failed-try">Indentation: a failed try</h2>
<div class="outline-text-2" id="text-indentation-a-failed-try">
<p>
I started to figure out the indentation. At first, I found this package <a href="https://codeberg.org/FelipeLema/tree-sitter-indent.el">tree-sitter-indent.el</a>, it seems in a fairly early stage, only supports rust right now, it does have some instruction to adding new language support. But it requires some deep knowledge in Tree-sitter and the language parser that I don&rsquo;t have, and I also only want to handle the JSX part, leave the TypeScript part to <code>typescript-mode</code>, so I spent 4h to come up with this&hellip;
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">typescript-tsx-tree-sitter-indent-line</span> ()
  (<span style="color: #531ab6; font-weight: bold;">if-let*</span> ((col (<span style="color: #7b435c; font-style: italic;">typescript-tsx-tree-sitter--proper-indentation</span>))
            (offset (<span style="color: #7b435c;">-</span> (<span style="color: #7b435c;">current-column</span>) (<span style="color: #7b435c;">current-indentation</span>))))
      (<span style="color: #531ab6; font-weight: bold;">progn</span>
        (<span style="color: #7b435c;">indent-line-to</span> <span style="color: #2f3f83;">col</span>)
        (<span style="color: #7b435c;">move-to-column</span> (<span style="color: #7b435c;">+</span> <span style="color: #2f3f83;">offset</span> <span style="color: #2f3f83;">col</span>)))
    (<span style="color: #7b435c; font-style: italic;">typescript-indent-line</span>)))

(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">typescript-tsx-tree-sitter--in-tsx</span> (node-type parent-type)
  (<span style="color: #531ab6; font-weight: bold;">--some?</span> (<span style="color: #721045;">s-starts-with?</span> <span style="color: #3548cf;">"jsx"</span> it)
           (<span style="color: #531ab6; font-weight: bold;">--map</span> (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"%s"</span> it) (<span style="color: #0000b0;">list</span> node-type parent-type))))

(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">typescript-tsx-tree-sitter--proper-indentation</span> ()
  (<span style="color: #531ab6; font-weight: bold;">save-excursion</span>
    (<span style="color: #7b435c;">back-to-indentation</span>)
    (<span style="color: #531ab6; font-weight: bold;">-let*</span> ((node (tree-sitter-node-at-point))
            (parent (tsc-get-parent node))
            (node-type (tsc-node-type node))
            (parent-type (tsc-node-type parent)))
      <span style="color: #595959; font-style: italic;">;; </span><span style="color: #595959; font-style: italic;">only handles jsx related indention
</span>      (<span style="color: #531ab6; font-weight: bold;">when</span> (typescript-tsx-tree-sitter--in-tsx node-type parent-type)
        <span style="color: #595959; font-style: italic;">;; </span><span style="color: #595959; font-style: italic;">(message "current: %s" node-type)
</span>        <span style="color: #595959; font-style: italic;">;; </span><span style="color: #595959; font-style: italic;">(message "parent: %s" parent-type)
</span>        (<span style="color: #531ab6; font-weight: bold;">cond</span>
         ((<span style="color: #531ab6; font-weight: bold;">and</span> (<span style="color: #0000b0;">member</span> node-type <span style="color: #531ab6; font-weight: bold;">'</span>(<span style="color: #3548cf;">"{"</span> <span style="color: #3548cf;">"}"</span>))
               (<span style="color: #0000b0;">eq</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">jsx_expression</span> parent-type))
          (<span style="color: #0000b0;">+</span> (<span style="color: #0000b0;">cdr</span> (tsc-node-start-point (tsc-get-parent parent))) typescript-indent-level))
         ((<span style="color: #0000b0;">eq</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">jsx_expression</span> parent-type)
          nil)
         ((<span style="color: #0000b0;">eq</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">jsx_attribute</span> parent-type)
          (<span style="color: #0000b0;">+</span> (<span style="color: #0000b0;">cdr</span> (tsc-node-start-point (tsc-get-parent parent))) typescript-indent-level))
         ((<span style="color: #0000b0;">eq</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">jsx_expression</span> node-type)
          (<span style="color: #0000b0;">+</span> typescript-indent-level (<span style="color: #0000b0;">cdr</span> (tsc-node-start-point node))))
         ((<span style="color: #0000b0;">member</span> node-type <span style="color: #531ab6; font-weight: bold;">'</span>(<span style="color: #3548cf;">"&gt;"</span> <span style="color: #3548cf;">"/"</span>))
          (<span style="color: #0000b0;">cdr</span> (tsc-node-start-point parent)))
         ((<span style="color: #0000b0;">eq</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">jsx_closing_element</span> parent-type)
          (<span style="color: #0000b0;">cdr</span> (tsc-node-start-point (tsc-get-parent parent))))
         ((<span style="color: #0000b0;">eq</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">jsx_self_closing_element</span> parent-type)
          nil)
         ((<span style="color: #0000b0;">eq</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">jsx_self_closing_element</span> node-type)
          (<span style="color: #0000b0;">+</span> (<span style="color: #0000b0;">cdr</span> (tsc-node-start-point node)) typescript-indent-level))
         (t
          (<span style="color: #0000b0;">+</span> (<span style="color: #0000b0;">cdr</span> (tsc-node-start-point parent)) typescript-indent-level)))))))
</code></pre>
</div>

<p>
It&rsquo;s kind of working, but so much worse than the <code>web-mode</code> version. And I believe I missed lots of use cases.
</p>
</div>
</div>
<div id="outline-container-indentation-with-rjsx-mode" class="outline-2">
<h2 id="indentation-with-rjsx-mode">Indentation with rjsx-mode</h2>
<div class="outline-text-2" id="text-indentation-with-rjsx-mode">
<p>
Before I got frustrated, I started wondering: &ldquo;Why <code>.jsx</code> files&rsquo; indentation works so well?&rdquo;.
</p>

<p>
The answer is <a href="https://github.com/felipeochoa/rjsx-mode">rjsx-mode</a>, it&rsquo;s a lot simpler than web-mode, and of course, does not support TypeScript, but I only want it to handle the indentation. It should be easy, right?
</p>

<p>
The answer is YES! <code>rjsx-mode</code> provides a <code>rjsx-minor-mode</code> which parses JSX syntax into AST, it can then be used in other <code>rjsx-mode</code> function, in this case, <code>rjsx-indent-line</code>. It will probably comes with a performance cost, but I feel it&rsquo;s worth.
</p>
</div>
</div>
<div id="outline-container-the-final-result" class="outline-2">
<h2 id="the-final-result">The Final Result</h2>
<div class="outline-text-2" id="text-the-final-result">
<p>
Here is the working configuration I ended up with, even some bonus &ldquo;electric&rdquo; action from <code>rjsx-mode</code>.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">use-package!</span> typescript-mode
  <span style="color: #8f0075; font-weight: bold;">:mode</span> (<span style="color: #3548cf;">"\\.tsx\\'"</span> . typescript-tsx-tree-sitter-mode)
  <span style="color: #8f0075; font-weight: bold;">:config</span>
  (<span style="color: #531ab6; font-weight: bold;">setq</span> typescript-indent-level 2)

  (<span style="color: #531ab6; font-weight: bold;">define-derived-mode</span> <span style="color: #721045;">typescript-tsx-tree-sitter-mode</span> typescript-mode <span style="color: #3548cf;">"TypeScript TSX"</span>
    (<span style="color: #531ab6; font-weight: bold;">setq-local</span> <span style="color: #005e8b;">indent-line-function</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">rjsx-indent-line</span>))

  (<span style="color: #531ab6; font-weight: bold;">add-hook!</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">typescript-tsx-tree-sitter-mode-local-vars-hook</span>
             <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">+javascript-init-lsp-or-tide-maybe-h</span>
             <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">rjsx-minor-mode</span>)
  (<span style="color: #531ab6; font-weight: bold;">map!</span> <span style="color: #8f0075; font-weight: bold;">:map</span> typescript-tsx-tree-sitter-mode-map
        <span style="color: #3548cf;">"&lt;"</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">rjsx-electric-lt</span>
        <span style="color: #3548cf;">"&gt;"</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">rjsx-electric-gt</span>))

(<span style="color: #531ab6; font-weight: bold;">after!</span> tree-sitter
  (<span style="color: #7b435c;">add-to-list</span> <span style="color: #531ab6; font-weight: bold;">'</span>tree-sitter-major-mode-language-alist <span style="color: #531ab6; font-weight: bold;">'</span>(typescript-tsx-tree-sitter-mode . tsx)))
</code></pre>
</div>
</div>
</div>
<div id="outline-container-emacs-mac" class="outline-2">
<h2 id="emacs-mac">emacs-mac</h2>
<div class="outline-text-2" id="text-emacs-mac">
<p>
All the above is I trying to improve TSX support in Doom Emacs with emacs 28 w/ native-compile on a macbook.
</p>

<p>
A day after that, I&rsquo;m trying out the <a href="https://bitbucket.org/mituharu/emacs-mac/src/master/">emacs-mac</a> port, turns out it can massively improve the Emacs performance on <b>macOS</b>, way much than emacs 28 w/ native-compile. I guess the biggest problem is not web-mode or lisp after all, but I feel it still helps. The rjsx electric magic is fantastic.
</p>
</div>
</div>
<div id="outline-container-more-on-tree-sitter" class="outline-2">
<h2 id="more-on-tree-sitter">More on Tree-sitter</h2>
<div class="outline-text-2" id="text-more-on-tree-sitter">
<p>
There is another take on <a href="https://archive.casouri.cat/note/2021/emacs-tree-sitter/">integrating tree-sitter into emacs core</a>, I hope this can make tsx or in general web development better in Emacs.
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>[Short] podman + docker-compose 的一些坑</title>
<link>https://merrick.luois.me/posts/podman-docker-compose.html</link>
<pubDate>Tue, 29 Mar 2022 11:36:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/podman-docker-compose.html</guid>
<description>
<![CDATA[<div id="outline-container-short-podman-docker-compose-的一些坑" class="outline-2">
<h2 id="short-podman-docker-compose-的一些坑">[Short] podman + docker-compose 的一些坑</h2>
<div class="outline-text-2" id="text-short-podman-docker-compose-的一些坑">
<p>
podman 3.0 的时候<a href="https://www.redhat.com/sysadmin/podman-docker-compose">增加了对 docker-compose 的支持</a>，平时简单用用好像问题不大，今天打算在本地启动一组 <a href="https://git.sr.ht/~cadence/cloudtube">cloudtube</a> 服务时发现坑还是不少，特此记录。
</p>
</div>
</div>
<div id="outline-container-gentoo-with-openrc-限定" class="outline-2">
<h2 id="gentoo-with-openrc-限定">Gentoo with openrc 限定</h2>
<div class="outline-text-2" id="text-gentoo-with-openrc-限定">
</div>
<div id="outline-container-podman-service-rootless" class="outline-3">
<h3 id="podman-service-rootless">podman service &amp; rootless</h3>
<div class="outline-text-3" id="text-podman-service-rootless">
<p>
podman 对 docker-compose 的支持大概就是模拟了一个 docker.sock，所以也需要启用一个服务来管理，官方当然是用 systemd, 不过好在 gentoo 还是提供了 openrc 的服务文件。但是，需要一些手动的配置，才能让 docker-compose 跑起来。
</p>

<p>
默认的 podman service 会使用 user <code>root:root</code>, sock 文件在 <code>/var/run/podman/podman.sock</code>, 可以通过 <code>/etc/conf.d/podman</code> 来自定义，可以将 sock 文件移动到 docker 的默认位置 <code>/var/run/docker.sock</code>, 也可以让 docker-compose 使用 rootless container.
</p>

<p>
为了避免需要塞 <code>DOCKER_HOST</code> 到 shell init file, 我选择了将 sock 改成 docker 的默认位置。
</p>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 1: </span>in /etc/conf.d/podman</label><pre class="src src-shell"><code><span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">Config file for /etc/init.d/podman
</span>
<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">Sets the API service daemon log level
</span><span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">valid levels: debug, info, warn, error, fatal or panic
</span><span style="color: #595959; font-style: italic;">#</span><span style="color: #595959; font-style: italic;">LOG_LEVEL="info"
</span>
<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">Sets the API service daemon socket
</span><span style="color: #005e8b;">SOCKET</span>=<span style="color: #3548cf;">"unix:/var/run/docker.sock"</span>

<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">Configure the user[:group] the API service daemon will run as
</span><span style="color: #595959; font-style: italic;">#</span><span style="color: #595959; font-style: italic;">RUN_AS_USER="root:root"</span>
</code></pre>
</div>
</div>
</div>
</div>
<div id="outline-container-dnsname-plugin" class="outline-2">
<h2 id="dnsname-plugin">dnsname plugin</h2>
<div class="outline-text-2" id="text-dnsname-plugin">
<p>
在使用 docker 作为 docker-compose 的后端时，默认创建的 network 中，services 之间可以通过名字相互访问。但是在使用 podman 作为后端时，默认无法实现这个功能，而是需要用到 <a href="https://github.com/containers/dnsname">dnsname</a> 这个 cni plugin。
</p>

<p>
<del>由于 gentoo 没有提供 podman 相关插件的 package, 所以需要手动安装一下。</del> Update 2022-04-01: added to <a href="https://github.com/merrickluo/metoo/blob/master/net-misc/cni-plugin-dnsname/cni-plugin-dnsname-1.3.1.ebuild">my overlay</a>.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #005f5f; font-weight: bold;">git</span> clone https://github.com/containers/dnsname
<span style="color: #005f5f; font-weight: bold;">cd</span> dnsname
<span style="color: #005f5f; font-weight: bold;">make</span>
<span style="color: #005f5f; font-weight: bold;">make</span> install <span style="color: #005e8b;">PREFIX</span>=/usr/local
</code></pre>
</div>

<p>
NOTE: 如果安装前尝试过 docker-compose up，需要清理旧的 container 和 network, 否则
</p>
<ol class="org-ol">
<li>container 无法获取 dnsname plugin 给到的 resolv.conf.</li>
<li>创建的 network 没有正确配置 dnsname plugin.</li>
</ol>

<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">after docker-compose down
</span><span style="color: #005f5f; font-weight: bold;">sudo</span> podman network <span style="color: #005f5f; font-weight: bold;">rm</span> xx_default <span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-style: italic;">it should be removed, but just in case
</span><span style="color: #005f5f; font-weight: bold;">sudo</span> podman container prune
</code></pre>
</div>

<p>
NOTE 2: 默认的 dnsname 配置，在同一 network 中访问其他 service 的域名为 <code>[service name].dns.podman</code>, 作为比较，使用 docker 时只需要用 service name 就行。
</p>
</div>
</div>
<div id="outline-container-cloudtube" class="outline-2">
<h2 id="cloudtube">cloudtube</h2>
<div class="outline-text-2" id="text-cloudtube">
<p>
附上使用的 <code>docker-compose.yml</code> 以供参考。
</p>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 2: </span>tube/docker-compose.yml</label><pre class="src src-yaml"><code><span style="color: #005e8b;">version</span>: <span style="color: #3548cf;">"3"</span>
<span style="color: #005e8b;">services</span>:
  <span style="color: #005e8b;">nginx</span>:
    <span style="color: #005e8b;">image</span>: nginx:stable-alpine
    <span style="color: #005e8b;">ports</span>:
      - <span style="color: #3548cf;">"80:80"</span>
    <span style="color: #005e8b;">volumes</span>:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/sites-available:/etc/nginx/sites-available:ro
      - ./nginx/sites-enabled:/etc/nginx/sites-enabled:ro
      - ./nginx/nginxconfig.io:/etc/nginx/nginxconfig.io:ro
    <span style="color: #005e8b;">depends_on</span>:
      - tube
  <span style="color: #005e8b;">tube</span>:
    <span style="color: #005e8b;">build</span>: ./cloudtube
    <span style="color: #005e8b;">ports</span>:
      - <span style="color: #3548cf;">"10412:10412"</span>
    <span style="color: #005e8b;">volumes</span>:
      - ./config.js:/workdir/config/config.js:ro
  <span style="color: #005e8b;">newleaf</span>:
    <span style="color: #005e8b;">build</span>: ./NewLeaf
    <span style="color: #005e8b;">volumes</span>:
      - ./configuration.py:/workdir/configuration.py:ro
</code></pre>
</div>
</div>
</div>
<div id="outline-container-formatdocker" class="outline-2">
<h2 id="formatdocker">&ndash;format=docker</h2>
<div class="outline-text-2" id="text-formatdocker">
<p>
如果有某些 <del>傻逼</del> 奇怪的 Dockerifle 用到一些 docker 特定的语法，需要指定 <code>--format=docker</code>.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code>WARN[0017] SHELL is not supported for OCI image format, [/bin/bash -c] will be ignored. Must use <span style="color: #8f0075; font-weight: bold;">`docker`</span> format
</code></pre>
</div>

<p>
但是这个没有办法在 docker-compose.yml 里面写，因为是 buildlah 的参数，还好也可以通过环境变量覆盖。
</p>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 3: </span>add to .envrc in your project</label><pre class="src src-shell"><code><span style="color: #8f0075; font-weight: bold;">export</span> <span style="color: #005e8b;">BUILDAH_FORMAT</span>=docker
</code></pre>
</div>
</div>
</div>
]]>
</description></item>
<item>
<title>Play with Generic Go</title>
<link>https://merrick.luois.me/posts/play-with-generic-go.html</link>
<pubDate>Wed, 30 Mar 2022 18:15:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/play-with-generic-go.html</guid>
<description>
<![CDATA[<div id="outline-container-play-with-generic-go" class="outline-2">
<h2 id="play-with-generic-go">Play with Generic Go</h2>
<div class="outline-text-2" id="text-play-with-generic-go">
<p>
Go 终于在 <a href="https://tip.golang.org/doc/go1.18">1.18 喜迎泛型</a>，在它正式 release 之前忍不住玩了一下，然后跟 <a href="https://github.com/ahxxm">ahxxm</a> 一起写了一个名字非常普通（当然跟 lodash 没有关系，我学的是 dash.el）的工具库 <a href="https://github.com/merrickluo/go-dash">go-dash</a>。
</p>
</div>
</div>
<div id="outline-container-go-与泛型与我" class="outline-2">
<h2 id="go-与泛型与我">Go 与泛型与我</h2>
<div class="outline-text-2" id="text-go-与泛型与我">
<p>
第一次用 Go 可能要回到 5 年前，刚从一个 Android/iOS Developer 转型，给公司写一个新的后端项目。在用习惯了充满语法糖的 kotlin 和 swift 之后再来使用这样一个“大道至简”的语言确实不太习惯。其中的一点当然就是泛型。关于泛型的讨论在 Go 社区应该从未停止过，这当中还有不少支持者是让我比较难以相信的，这也算是我第一次接触到“语言宗教”这样一个概念吧。不过这就扯远了，我简单说一下我不喜欢的理由吧。
</p>

<p>
没有泛型必然导致很多“泛用”方法需要针对不同类型重复定义，在没有泛型的时候，大概有这样三种 workaround(AFAIK)。而这三种方法和我不喜欢的主要理由如下：
</p>

<ul class="org-ul">
<li>标准库作弊，比如说 <code>append</code>, <code>len</code> 等。相当于是对于特定数据结构进行了“特殊处理”，如果你有类似的自定义数据结构，却没办法保证一致的处理模式。</li>

<li>使用 <code>interface{}</code> 然后通过反射处理。既享受不了动态语言的好处，却要承担动态语言的坏处。</li>

<li>代码生成。虽然重复，但又没那么重复。生成的代码是代码还是数据？应不应该放在仓库里？</li>
</ul>

<p>
他们还有一个共同的问题就是会导致代码的可读性或可浏览性变差，虽然没有盲目使用其他语言的“设计模式”来得伤害那么大，但也算是相当难受了。咳咳，阴阳怪气就到这里吧。毕竟后来官方就宣布“<a href="https://go.dev/blog/generics-next-step">已经在做了</a>”。
</p>

<p>
快进到前段时间突然在 HN 看到了 <a href="https://github.com/mattn/go-generics-example">go-generics-example</a>，发现本来预订要在 Go 2 出现的泛型，竟然在 Go 1.17 已经可以实验性开启，也就是说不需要等到<a href="https://go.dev/blog/go2-here-we-come">很大概率不会保持向后兼容</a>的 Go 2 了。
</p>
</div>
</div>
<div id="outline-container-go-dash-go" class="outline-2">
<h2 id="go-dash-go">Go Dash, Go</h2>
<div class="outline-text-2" id="text-go-dash-go">
<p>
泛型成为 a thing 之后，似乎 Golang 团队对如何修改标准库开始犯难了，作为一个长期向后兼容的语言，如何合理的进化标准库确实是一个很难的话题。详情可见这些讨论：
</p>
<ul class="org-ul">
<li><a href="https://github.com/golang/go/discussions/48287">how to update APIs for generics</a></li>
<li><a href="https://github.com/golang/go/issues/48918">go: don't change the libraries in 1.18</a>.</li>
</ul>

<p>
抱着知道写这些代码多半不会有太大用处的心情，我们还是从 <a href="https://clojuredocs.org/clojure.core">clojure.core</a> 以及 <a href="https://clojuredocs.org/clojure.core.async">clojure.core.async</a> 中精心(<del>随机</del>)挑选了一些 API 之后，就开始模仿(<del>抄袭</del>)了。
</p>

<p>
Go 1.17 中的实验性泛型功能无法定义 public function, 所以需要用到 gotip 来获取 master 分支的 Go. 比较惊喜的是 gopls 也同步更新着，所以工具支持上没有任何问题。
</p>

<div class="org-src-container">
<pre class="src src-shell"><code>go get -v golang.org/dl/gotip
gotip download
gotip get golang.org/x/tools/gopls@master golang.org/x/tools@master
</code></pre>
</div>

<blockquote>
<p>
在 <del>发稿日</del> 之前，2022/3/15 Go 1.18 正式 release 了，所以 gotip 不再必要。
</p>
</blockquote>
</div>
</div>
<div id="outline-container-gerrit-what" class="outline-2">
<h2 id="gerrit-what">Gerrit What</h2>
<div class="outline-text-2" id="text-gerrit-what">
<p>
实现这些方法倒是也不难（比较难的是我不确定只写了针对 int 类型的测试算不算完全覆盖），不过在写了一点注释后尝试通过 go doc 生成文档时倒是发现了一个奇妙的 bug，那就是
<b>所有返回 []T 的方法都会被 go doc 忽略</b> ，对于针对 slice 写的 dash 包几乎可以说是全灭了。
</p>

<p>
勤奋的 ahxxm 同学即日就阅读了 go doc 源码并提交了 <a href="https://github.com/golang/go/issues/48485">issue</a> 和 <a href="https://go-review.googlesource.com/c/go/+/352389/">pr</a>，不过最后因为某团队 Code Review 效率问题，最后还是被<a href="https://go-review.googlesource.com/c/go/+/362758/">内部解决</a>了。
</p>
</div>
</div>
<div id="outline-container-play-and-learn" class="outline-2">
<h2 id="play-and-learn">Play and Learn</h2>
<div class="outline-text-2" id="text-play-and-learn">
<p>
Go 其实不算是一个能让人感觉 exciting 的语言，增加泛型这次算是个例外吧。写这个没用的库倒是也能学到一些东西，比如在 pkg.go.dev 可以<a href="https://pkg.go.dev/github.com/merrickluo/go-dash@v0.0.0-20220313083855-09f60221ba81/dash">随意申请添加 package</a>。看到 go doc 生成的 html 之后我对从注释生成文档也没那么讨厌了（治好了我的 javadoc 后遗症）。
</p>

<p>
不过比起这些我更希望标准库能尽快更新泛型版本，以后堆代码也能开心一点。就目前来看 1.18 里包含的 golang.org/x/exp 只能算聊胜于无吧，并且也不太可能在生产代码中使用。
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>notmuch is easy</title>
<link>https://merrick.luois.me/posts/notmuch-is-easy.html</link>
<pubDate>Sat, 24 Sep 2022 17:36:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/notmuch-is-easy.html</guid>
<description>
<![CDATA[<div id="outline-container-notmuch-is-easy" class="outline-2">
<h2 id="notmuch-is-easy">notmuch is easy</h2>
</div>

<div id="outline-container-email" class="outline-2">
<h2 id="email">Email</h2>
<div class="outline-text-2" id="text-email">
<p>
I don&rsquo;t have an email workflow, I just use it for tracking news or receiving notifications. I&rsquo;ve been using mbsync &amp; mu4e for almost 2 years, never got to learn any of the &ldquo;advanced&rdquo; features, only read &amp; archive.
</p>

<p>
I also subscribed to the emacs-devel mail list, which basically made the Zoho mail web UI (or any other web mail UI) unusable. I don&rsquo;t chase all the threads too often, but I just feel happy to see emacs development is so active, xD.
</p>
</div>
</div>
<div id="outline-container-mu4e" class="outline-2">
<h2 id="mu4e">mu4e</h2>
<div class="outline-text-2" id="text-mu4e">
<p>
After messing around my own emacs config for quite some time, I&rsquo;m now settled with <a href="https://github.com/doomemacs/doomemacs">doom emacs</a>, it provides a nice-looking mu4e integration, that&rsquo;s where I start to use it. I&rsquo;m not entirely happy with it, I had to write long queries to filter out the mailing list emails in the bookmarks setting, but as I said I&rsquo;m not a heavy email user, so I just live with it.
</p>
</div>
</div>
<div id="outline-container-notmuch" class="outline-2">
<h2 id="notmuch">notmuch</h2>
<div class="outline-text-2" id="text-notmuch">
<p>
I know about notmuch a long time ago, even before I tried to use mu4e, I remember this cuz its logo in the <code>notmuch-hello</code> buffer is so memorably, but obviously, I didn&rsquo;t stick to it for long.
I&rsquo;m just walking through some old <a href="https://sachachua.com/blog/category/emacs-news/">emacs news</a> as usual yesterday, and opened this <a href="https://irreal.org/blog/?p=9697">link</a> and then this <a href="https://www.youtube.com/watch?v=g7iF11qamh8">video</a> by Protesilaos Stavrou.
</p>

<p>
After I finished the video (well, while I&rsquo;m finishing it), I started trying it out, the ability to search quickly with tags and add tags on the fly while reading emails attracted me. Luckily I already have all my emails on my maildir with mbsync.
</p>

<p>
So I enabled the <code>:email notmuch</code> and disable <code>:email mu4e</code> in doom. I can feel immediately that this module is not well maintained like the <code>mu4e</code> one, e.g., it opens up a <code>*notmuch*</code> workspace, but the <code>*mu4e-hello*</code> buffer is just a popup to the left, and the workspace remains when I closed the buffer.
</p>

<p>
The dashboard is just as I remembered with the balance logo, so far the experience is just like the last time I tried, until I learned the real magic, <a href="https://notmuchmail.org/initial_tagging/">initial tagging</a>.
</p>

<p>
The one on notmuch&rsquo;s website is helpful but not as clear as in Prot&rsquo;s video, anyway I basically copied his hook script from his video and did some manual tagging like tag all email in the archive folder with <code>archive</code>, and now I&rsquo;m getting a much cleaner email view, and way easier to configure as well.
</p>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 1: </span>notmuch hook: Maildir/.notmuch/hooks/post-new</label><pre class="src src-bash"><code><span style="color: #595959; font-style: italic;">#</span><span style="color: #595959; font-style: italic;">!/usr/bin/</span><span style="color: #531ab6; font-weight: bold;">env</span><span style="color: #595959; font-style: italic;"> bash
</span>notmuch tag -unread -new -- tag:replied
notmuch tag +inbox +unread -new -- tag:new

notmuch tag -new -unread +sent -- <span style="color: #3548cf;">'(from:"*@luois.me* not to:"*@luois.me*)'</span>

notmuch tag -inbox +list +emacs-devel -- from:emacs-devel@gnu.org or to:emacs-devel@gnu.org or subject:[emacs-devel]
</code></pre>
</div>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 2: </span>emacs configuration for notmuch .config/doom/config.el</label><pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">after!</span> notmuch
  (<span style="color: #7b435c;">set-popup-rule!</span> <span style="color: #3548cf;">"^\\*notmuch"</span> <span style="color: #8f0075; font-weight: bold;">:ignore</span> t)

  (<span style="color: #531ab6; font-weight: bold;">setq</span> notmuch-saved-searches
        <span style="color: #531ab6; font-weight: bold;">'</span>((<span style="color: #8f0075; font-weight: bold;">:name</span> <span style="color: #3548cf;">"inbox"</span> <span style="color: #8f0075; font-weight: bold;">:query</span> <span style="color: #3548cf;">"tag:inbox not tag:trash"</span> <span style="color: #8f0075; font-weight: bold;">:key</span> <span style="color: #3548cf;">"i"</span>)
          (<span style="color: #8f0075; font-weight: bold;">:name</span> <span style="color: #3548cf;">"todo"</span> <span style="color: #8f0075; font-weight: bold;">:query</span> <span style="color: #3548cf;">"tag:todo"</span> <span style="color: #8f0075; font-weight: bold;">:key</span> <span style="color: #3548cf;">"t"</span>)
          (<span style="color: #8f0075; font-weight: bold;">:name</span> <span style="color: #3548cf;">"flagged"</span> <span style="color: #8f0075; font-weight: bold;">:query</span> <span style="color: #3548cf;">"tag:flagged"</span> <span style="color: #8f0075; font-weight: bold;">:key</span> <span style="color: #3548cf;">"f"</span>)
          (<span style="color: #8f0075; font-weight: bold;">:name</span> <span style="color: #3548cf;">"sent"</span> <span style="color: #8f0075; font-weight: bold;">:query</span> <span style="color: #3548cf;">"tag:sent"</span> <span style="color: #8f0075; font-weight: bold;">:key</span> <span style="color: #3548cf;">"s"</span>)
          (<span style="color: #8f0075; font-weight: bold;">:name</span> <span style="color: #3548cf;">"drafts"</span> <span style="color: #8f0075; font-weight: bold;">:query</span> <span style="color: #3548cf;">"tag:draft"</span> <span style="color: #8f0075; font-weight: bold;">:key</span> <span style="color: #3548cf;">"d"</span>)))

  (<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">+notmuch-mail-folder</span> <span style="color: #3548cf;">"~/Maildir"</span>
        <span style="color: #005e8b;">+notmuch-sync-backend</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">mbsync</span>))
</code></pre>
</div>
</div>
</div>
<div id="outline-container-doom-email-notmuch" class="outline-2">
<h2 id="doom-email-notmuch">doom :email notmuch</h2>
<div class="outline-text-2" id="text-doom-email-notmuch">
<p>
As I mentioned, the notmuch module in doom emacs is not quite as good as the mu4e one, but I&rsquo;m planning to improve it myself a little bit, port some of the features from the mu4e module, like the dedicated workspace thing:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">defvar</span> <span style="color: #005e8b;">+notmuch--old-wconf</span> nil)

(<span style="color: #7b435c;">add-hook</span> <span style="color: #531ab6; font-weight: bold;">'</span>notmuch-hello-mode-hook <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #7b435c; font-style: italic;">+notmuch-init-h</span>)

(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">+notmuch-init-h</span> ()
  (<span style="color: #7b435c;">add-hook</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #005e8b;">kill-buffer-hook</span> <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #7b435c; font-style: italic;">+notmuch-kill-notmuch-h</span> nil t))

(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">+notmuch-kill-notmuch-h</span> ()
  <span style="color: #595959; font-style: italic;">;; </span><span style="color: #595959; font-style: italic;">(prolusion-mail-hide)
</span>  (<span style="color: #531ab6; font-weight: bold;">cond</span>
   ((<span style="color: #531ab6; font-weight: bold;">and</span> (<span style="color: #531ab6; font-weight: bold;">modulep!</span> <span style="color: #8f0075; font-weight: bold;">:ui</span> workspaces) (<span style="color: #7b435c; font-style: italic;">+workspace-exists-p</span> <span style="color: #005e8b;">+notmuch-workspace-name</span>))
    (<span style="color: #7b435c; font-style: italic;">+workspace/delete</span> <span style="color: #005e8b;">+notmuch-workspace-name</span>))

   (+notmuch--old-wconf
    (<span style="color: #7b435c;">set-window-configuration</span> +notmuch--old-wconf)
    (<span style="color: #531ab6; font-weight: bold;">setq</span> +notmuch--old-wconf nil))))
</code></pre>
</div>

<p>
I&rsquo;m happy I took 30min to watch the video, email never felt so easy to me, maybe I can have an email workflow now, let&rsquo;s see.
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>How I use YubiKey (Updating)</title>
<link>https://merrick.luois.me/posts/how-i-use-yubikey.html</link>
<pubDate>Mon, 13 Feb 2023 20:48:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/how-i-use-yubikey.html</guid>
<description>
<![CDATA[<div id="outline-container-how-i-use-yubikey-updating" class="outline-2">
<h2 id="how-i-use-yubikey-updating">How I use YubiKey (Updating)</h2>
<div class="outline-text-2" id="text-how-i-use-yubikey-updating">
<p>
Thanks to <a href="https://blog.cloudflare.com/making-phishing-defense-seamless-cloudflare-yubico/">Cloudflare</a>, I got my YubiKey for a really good price. Still trying to setup and use it, starting this post to logging my use cases.
</p>
</div>
</div>
<div id="outline-container-use-for-loginsudo" class="outline-2">
<h2 id="use-for-loginsudo">Use for login/sudo</h2>
<div class="outline-text-2" id="text-use-for-loginsudo">
<p>
ref: <a href="https://github.com/Yubico/pam-u2f">https://github.com/Yubico/pam-u2f</a>
</p>

<p>
There are official <a href="https://www.yubico.com/products/computer-login-tools/">guides</a> on yubico website for how to use yubikey to setup login on windows and macOS, but not for linux.
</p>

<p>
Got those steps after some search and reading the project readme.
</p>

<ol class="org-ol">
<li>install <code>pam-u2f</code> with package manager</li>

<li>generate key handles and public keys</li>
</ol>
<div class="org-src-container">
<pre class="src src-shell"><code>pamu2fcfg -uusername -P -N | <span style="color: #005f5f; font-weight: bold;">sudo</span> tee -a /etc/u2f_mappings
</code></pre>
</div>

<ol class="org-ol">
<li>edit pam config to use it, adjust the options for your need, my key plugged in the back of my desktop, so I don&rsquo;t want to touch it every time I tries to <code>sudo</code>.</li>
</ol>

<p>
:/etc/pam.d/system-auth
</p>
<div class="org-src-container">
<pre class="src src-conf"><code><span style="color: #005e8b;">auth    sufficient      pam_u2f.so  authfile</span>=/etc/u2f_mappings pinverification=1 userpresence=0
</code></pre>
</div>

<p>
On my gentoo system, both <code>/etc/pam.d/sudo</code> and <code>/etc/pam.d/login</code> includes <code>/etc/pam.d/system-auth</code>, so I just need to change this.
</p>

<ol class="org-ol">
<li>test with <code>sudo</code> and switch to another tty for login, success! I can finally change my login password to a auto generated string.</li>
</ol>
</div>
</div>
]]>
</description></item>
<item>
<title>Web Clipping with Org Roam</title>
<link>https://merrick.luois.me/posts/web-clipping-with-org-roam.html</link>
<pubDate>Mon, 13 Feb 2023 21:18:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/web-clipping-with-org-roam.html</guid>
<description>
<![CDATA[<div id="outline-container-web-clipping-with-org-roam" class="outline-2">
<h2 id="web-clipping-with-org-roam">Web Clipping with Org Roam</h2>
<div class="outline-text-2" id="text-web-clipping-with-org-roam">
<p>
Back in the day, there was a popular saying &ldquo;the internet never forgets.&rdquo; Unfortunately, this couldn&rsquo;t be further from the truth. Web pages can disappear or change significantly over time, leaving you with broken links and lost information. That&rsquo;s why it&rsquo;s crucial to have a reliable backup plan for the web pages that matter to you.
</p>

<p>
One such solution is Org Roam, an Emacs package that helps you create and organize notes in a hierarchical manner. Additionally, org-web-tools is a package that enables you to save web pages as plain, readable org files. By combining these two packages, you can build a powerful system for organizing and accessing information.
</p>

<p>
In this post, we&rsquo;ll explore how to use <a href="https://github.com/alphapapa/org-web-tools">org-web-tools</a>, to clip web pages to your Org Roam notes. With this technique, you can easily save and organize web pages that are important to you, even if they disappear from the internet.
</p>
</div>
</div>
<div id="outline-container-web-clipping-with-org-capture" class="outline-2">
<h2 id="web-clipping-with-org-capture">Web clipping with org capture</h2>
<div class="outline-text-2" id="text-web-clipping-with-org-capture">
<p>
Org Capture is a powerful tool for quickly creating notes in Emacs. To use it for web clipping, we&rsquo;ll need to install the org-web-tools package. This package allows us to easily insert web pages into our note-taking system.
</p>

<p>
Org Roam has builtin org protocol support, which includes two types of protocols. For web clipping, we&rsquo;ll be using the <code>roam-ref</code> protocol to preserve the link as a &ldquo;ref&rdquo;, you can find more information about this in the <a href="https://www.orgroam.com/manual.html#org_002droam_002dprotocol">org roam manual</a>.
</p>

<p>
Define a capture template for web clips:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">setq</span> org-roam-capture-ref-templates
        <span style="color: #531ab6; font-weight: bold;">'</span>((<span style="color: #3548cf;">"w"</span> <span style="color: #3548cf;">"ref"</span> plain <span style="color: #3548cf;">"%(org-web-tools--url-as-readable-org \"${ref}\")"</span>
           <span style="color: #8f0075; font-weight: bold;">:target</span> (file+head <span style="color: #3548cf;">"clips/${slug}.org"</span> <span style="color: #3548cf;">"#+title: ${title}\n"</span>)
           <span style="color: #8f0075; font-weight: bold;">:unnarrowed</span> t)))
</code></pre>
</div>

<p>
However, since the function <code>org-web-tools--url-as-readable-org</code> is not autoloaded, make sure to load the package before capture:
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">use-package!</span> org-web-tools
  <span style="color: #8f0075; font-weight: bold;">:commands</span> org-web-tools--url-as-readable-org)
</code></pre>
</div>

<p>
As mentioned in my previous <a href="posts/roam-capture-workflow-in-doom-emacs.html">post</a>, I use <a href="https://github.com/tridactyl/tridactyl">tridactyl</a> in Firefox, with the following configuration:
</p>
<div class="org-src-container">
<pre class="src src-vimrc"><code>bind ;r js javascript:location.href = 'org-protocol://roam-ref?template=w&amp;ref=' + encodeURIComponent(location.href) + '&amp;title=' + encodeURIComponent(document.title)
</code></pre>
</div>

<p>
Now I can pressing <code>;r</code> in Firefox would bring up a capture frame. The web page is then converted to a plain readable org format with org-web-tools, although I do need to do some minor cleanup after the capture, such as removing base64 images from the result.
</p>

<p>
Overall, this is a highly efficient and streamlined way of clipping web pages and integrating them into my note-taking workflow.
</p>
</div>
</div>
<div id="outline-container-screenshot" class="outline-2">
<h2 id="screenshot">Screenshot</h2>
<div class="outline-text-2" id="text-screenshot">

<figure id="org07a494f">
<img src="https://merrick.luois.me/../static/images/2023-02-14_22-36_roam-capture.png" alt="2023-02-14_22-36_roam-capture.png">

</figure>
</div>
</div>
<div id="outline-container-disclaimer" class="outline-2">
<h2 id="disclaimer">Disclaimer</h2>
<div class="outline-text-2" id="text-disclaimer">
<p>
This post is written with the <b>help</b> of chatgpt. What can I say, it writes English waaayy better than me :). I do think it makes the article looks too &ldquo;formal&rdquo; to me, but still a quite good experience.
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>Typescript/TSX in (Doom) Emacs 29+</title>
<link>https://merrick.luois.me/posts/typescript-in-emacs-29.html</link>
<pubDate>Sun, 19 Mar 2023 20:20:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/typescript-in-emacs-29.html</guid>
<description>
<![CDATA[<div id="outline-container-typescripttsx-in-doom-emacs-29" class="outline-2">
<h2 id="typescripttsx-in-doom-emacs-29">Typescript/TSX in (Doom) Emacs 29+</h2>
<div class="outline-text-2" id="text-typescripttsx-in-doom-emacs-29">
<p>
I still don&rsquo;t like TypeScript, but with the current trend of front-end development, it&rsquo;s hard to avoid.
</p>

<p>
To work with it in Emacs, I&rsquo;ve been using the &ldquo;hacks&rdquo; I mentioned in my previous post <a href="posts/better-tsx-support-in-doom-emacs.html">Better TSX support w/ Tree-sitter in Doom Emacs</a>. However, with the coming Emacs 29 release, this all changes. It has built-in support for Tree-sitter, including TypeScript/TSX modes, so I no longer need to use those hacks.
</p>
</div>
</div>
<div id="outline-container-tree-sitter-in-emacs-29" class="outline-2">
<h2 id="tree-sitter-in-emacs-29">Tree-sitter in Emacs 29</h2>
<div class="outline-text-2" id="text-tree-sitter-in-emacs-29">
<p>
Tree-sitter is a big deal in text editors lately. And now even Emacs is getting in on the action.
</p>

<p>
In the Emacs 29 release branch, we not only have built-in Tree-sitter support, but also many Tree-sitter powered major modes, including TypeScript/TSX.
</p>

<p>
These new major modes are developed by the maintainers of the <code>typescript-mode</code> package, who have <a href="https://github.com/emacs-typescript/typescript.el#a-short-note-on-development-halt">stopped maintaining</a> the old typescript-mode package. As a result, we can expect the new Tree-sitter based major mode to be more stable and feature-rich. IMO, it&rsquo;s already better than the old typescript-mode package, and it&rsquo;s the best new Tree-sitter based major mode in Emacs 29.
</p>
</div>
</div>
<div id="outline-container-start-using-it-now" class="outline-2">
<h2 id="start-using-it-now">Start using it now</h2>
<div class="outline-text-2" id="text-start-using-it-now">
</div>
<div id="outline-container-install-emacs-29" class="outline-3">
<h3 id="install-emacs-29">Install Emacs 29</h3>
<div class="outline-text-3" id="text-install-emacs-29">
<p>
Firstly, ensure that you are using Emacs 29. If you are on Gentoo, simply sync the emacs-29 version and select it with eselect. Don&rsquo;t forget to enable the tree-sitter USE flag.
</p>

<div class="org-src-container">
<pre class="src src-shell"><code><span style="color: #005f5f; font-weight: bold;">echo</span> <span style="color: #3548cf;">'&gt;=app-editors/emacs-29.0.9999 tree-sitter'</span> | <span style="color: #005f5f; font-weight: bold;">sudo</span> tee -a /etc/portage/package.use/emacs

<span style="color: #005f5f; font-weight: bold;">sudo</span> emerge -av =emacs-29.0.9999-r1
<span style="color: #005f5f; font-weight: bold;">sudo</span> eselect emacs set emacs-29-vcs
</code></pre>
</div>

<p>
I&rsquo;m sure you can find a way to install it on your system too.
</p>
</div>
</div>
<div id="outline-container-prepare-tree-sitter-libraries" class="outline-3">
<h3 id="prepare-tree-sitter-libraries">Prepare tree-sitter libraries</h3>
<div class="outline-text-3" id="text-prepare-tree-sitter-libraries">
<p>
Although the built-in support is available, there are still some hassles to get it working properly. You need to install the grammar files for the major modes you want to use and enable the tree-sitter-based major modes in your configuration.
</p>

<p>
<a href="https://github.com/renzmann/treesit-auto">treesit-auto</a> is a package to minimizes the hassle, but since I only want to use the TypeScript/TSX major modes, I prefer to do it manually.
</p>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 1: </span>in config.el</label><pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">after!</span> treesit
  (<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">treesit-language-source-alist</span>
        <span style="color: #531ab6; font-weight: bold;">'</span>((typescript <span style="color: #3548cf;">"https://github.com/tree-sitter/tree-sitter-typescript"</span> <span style="color: #3548cf;">"master"</span> <span style="color: #3548cf;">"typescript/src"</span> nil nil)
          (tsx <span style="color: #3548cf;">"https://github.com/tree-sitter/tree-sitter-typescript"</span> <span style="color: #3548cf;">"master"</span> <span style="color: #3548cf;">"tsx/src"</span> nil nil))))
</code></pre>
</div>

<p>
After evaluating the code above, run <code>M-x treesit-install-language-grammar</code>, and select <code>typescript</code> and <code>tsx</code>, This convenient function is provided by the built-in <code>treesit</code> package. It will download and build the grammar files for you, and install them in the correct place.
</p>
</div>
</div>
<div id="outline-container-use-the-new-major-modes" class="outline-3">
<h3 id="use-the-new-major-modes">Use the new major modes</h3>
<div class="outline-text-3" id="text-use-the-new-major-modes">
<p>
Now, you can activate the new major modes in your config, and you are good to go, you can skip the lsp part if you don&rsquo;t use lsp of course.
</p>

<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 2: </span>in config.el</label><pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">use-package</span> typescript-ts-mode
  <span style="color: #8f0075; font-weight: bold;">:mode</span> ((<span style="color: #3548cf;">"\\.ts\\'"</span> . typescript-ts-mode)
         (<span style="color: #3548cf;">"\\.tsx\\'"</span> . tsx-ts-mode))
  <span style="color: #8f0075; font-weight: bold;">:config</span>
  (<span style="color: #531ab6; font-weight: bold;">add-hook!</span> <span style="color: #531ab6; font-weight: bold;">'</span>(typescript-ts-mode-hook tsx-ts-mode-hook) <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">lsp!</span>))
</code></pre>
</div>

<p>
optionally, you can disable the <code>typescript-mode</code> package.
</p>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 3: </span>in packages.el</label><pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">package!</span> typescript-mode <span style="color: #8f0075; font-weight: bold;">:disable</span> t)
</code></pre>
</div>
</div>
</div>
</div>
<div id="outline-container-electric-pair" class="outline-2">
<h2 id="electric-pair">&ldquo;Electric Pair&rdquo;</h2>
<div class="outline-text-2" id="text-electric-pair">
<p>
The new major modes works great, but there is this one thing I miss from the <code>rjsx-mode</code>: the &ldquo;electric pair&rdquo; feature, which automatically insert the closing tag when you type the opening tag.
</p>

<p>
I tried to do the same hack as I did in the previous post, but it doesn&rsquo;t work, since <code>rjsx-minor-mode</code> relies on <code>js2-mode</code> to build the syntax tree, and I don&rsquo;t think it works well with the Typescript syntax.
</p>

<p>
I really hope I can get this feature in the new <code>typescript-tsx-mode</code>, maybe even trying to implement it myself, let&rsquo;s see.
</p>
</div>
</div>
<div id="outline-container-non-doom-emacs" class="outline-2">
<h2 id="non-doom-emacs">Non Doom Emacs</h2>
<div class="outline-text-2" id="text-non-doom-emacs">
<p>
This post discusses how to use it in Doom Emacs, but it doesn&rsquo;t use any Doom-specific features or packages other than the configuration macros, so it should be easy to port to vanilla Emacs.
</p>
</div>
</div>
<div id="outline-container-conclusion" class="outline-2">
<h2 id="conclusion">Conclusion</h2>
<div class="outline-text-2" id="text-conclusion">
<p>
As you can see, this is way easier to work with typescript/tsx in emacs 29 now, and all the hack config I mentioned in my previous post is no longer needed, and I&rsquo;m happy to delete them.
</p>
</div>
</div>
]]>
</description></item>
<item>
<title>Blogging with Org Mode and Denote</title>
<link>https://merrick.luois.me/posts/blog-redecoration-2025.html</link>
<pubDate>Sun, 20 Apr 2025 12:28:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/blog-redecoration-2025.html</guid>
<description>
<![CDATA[<div id="outline-container-blogging-with-org-mode-and-denote" class="outline-2">
<h2 id="blogging-with-org-mode-and-denote">Blogging with Org Mode and Denote</h2>
<div class="outline-text-2" id="text-blogging-with-org-mode-and-denote">
<p>
It&rsquo;s that time of a year, you want to &ldquo;reboot&rdquo; your blog site again, instead of actually writing something, you prefer to build the site in a completely new way instead, or it&rsquo;s just me? Never mind then.
</p>
</div>
</div>
<div id="outline-container-to-simplicity" class="outline-2">
<h2 id="to-simplicity">To Simplicity</h2>
<div class="outline-text-2" id="text-to-simplicity">
<p>
My view of what makes a beautiful blog has changed over time, but always circles back to simplicity. I used to build my blog with Next.js with server site rendering — already fairly minimal with limited JavaScript—but now I question whether I even need a framework. While I still enjoy working with React, it seems an overkill for a blog site. And <a href="https://sr.ht">sourcehut</a> and <a href="https://bearblog.dev/">bearblog</a> shows how elegant true minimalism can be.
</p>
</div>
</div>
<div id="outline-container-the-plan" class="outline-2">
<h2 id="the-plan">The Plan</h2>
<div class="outline-text-2" id="text-the-plan">
<p>
I&rsquo;m already using org-publish to generate the posts last time, and I know that org-publish is capable of generating fully featured websites. It&rsquo;s an obvious choice for me.
</p>

<p>
However, since my last blog post, I made a lot of changes with my note workflow, notably, I have switched my note taking system from <a href="https://github.com/org-roam/org-roam">org-roam</a> to <a href="https://protesilaos.com/emacs/denote">denote</a>, and all my blog posts are still in the roam collection, so I need to take care of the migration too.
</p>

<p>
So the overall plan looks like this:
</p>
<ul class="org-ul">
<li>make a org-publish project that can generate
<ul class="org-ul">
<li>pages: index page, about page etc</li>
<li>posts: all past and future blog posts</li>
<li>rss: I hecking love rss</li>
<li>styles: custom css styles</li>
</ul></li>
<li>migrate all past notes from roam to denote</li>
<li>tweak the styles until I feel good about it</li>
</ul>

<p>
Time to dive in!
</p>
</div>
<div id="outline-container-org-publish" class="outline-3">
<h3 id="org-publish">Org Publish</h3>
<div class="outline-text-3" id="text-org-publish">
<p>
It&rsquo;s easier than I thought, there&rsquo;s ton of good <a href="https://www.reddit.com/r/emacs/comments/ng9hyq/good_tutorials_on_orgpublish/">tutorials</a> as well as packages out there for using org-publish for blogging, I cherry picked some of their snippets and come up with my own.
</p>

<p>
First I have some helper functions for creating new blog post as well as publishing it.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">denote-blog-post</span> ()
  <span style="color: #2a5045; font-style: italic;">"Create a blog entry in denote sub directory."</span>
  (<span style="color: #531ab6; font-weight: bold;">declare</span> (<span style="color: #8f0075;">interactive-only</span> t))
  (<span style="color: #531ab6; font-weight: bold;">interactive</span>)
  (<span style="color: #531ab6; font-weight: bold;">let</span> ((<span style="color: #005e8b;">denote-use-directory</span> (<span style="color: #7b435c;">expand-file-name</span> <span style="color: #3548cf;">"blog/posts"</span> <span style="color: #005e8b;">denote-directory</span>)))
    (<span style="color: #7b435c;">call-interactively</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">denote</span>)))
</code></pre>
</div>

<p>
And there is some variables used in the project definitions, here I choose to make the publish directory a git project too, so I still remain some control on the final publish, in case I messed up the publish flow later.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">defvar</span> <span style="color: #005e8b;">m/blog-publishing-directory</span> (<span style="color: #7b435c;">expand-file-name</span> <span style="color: #3548cf;">"~/projs/blog-publish/public"</span>))

(<span style="color: #531ab6; font-weight: bold;">defvar</span> <span style="color: #005e8b;">m/blog-header</span> <span style="color: #3548cf;">"&lt;header&gt;
    &lt;a class=\"title\" href=\"/\"&gt;
        &lt;h2&gt;Uncharted Mind Space&lt;/h2&gt;
    &lt;/a&gt;
    &lt;nav&gt;
        &lt;a href=\"/\"&gt;Home&lt;/a&gt;
        &lt;a href=\"/about\"&gt;About&lt;/a&gt;
    &lt;/nav&gt;
&lt;/header&gt;"</span>)

(<span style="color: #531ab6; font-weight: bold;">defvar</span> <span style="color: #005e8b;">m/blog-footer</span> <span style="color: #3548cf;">"&lt;footer&gt;
&lt;p&gt;Powered by &lt;a href=\"https://orgmode.org/\"&gt;Org Mode&lt;/a&gt;&lt;/p&gt;
&lt;/footer&gt;"</span>)

(<span style="color: #531ab6; font-weight: bold;">defvar</span> <span style="color: #005e8b;">m/blog-meta</span> <span style="color: #3548cf;">"&lt;link rel=\"stylesheet\" type=\"text/css\" href=\"static/style.css\"/&gt;"</span>)
</code></pre>
</div>

<p>
And  finally the org publish projects setup.
</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">org-publish-project-alist</span>
      <span style="color: #531ab6; font-weight: bold;">`</span>((<span style="color: #3548cf;">"blog"</span> <span style="color: #8f0075; font-weight: bold;">:components</span> (<span style="color: #3548cf;">"blog-posts"</span> <span style="color: #3548cf;">"blog-static"</span>))
        (<span style="color: #3548cf;">"blog-posts"</span>
         <span style="color: #8f0075; font-weight: bold;">:base-directory</span> ,(<span style="color: #0000b0;">expand-file-name</span> <span style="color: #3548cf;">"blog"</span> <span style="color: #005e8b;">denote-directory</span>)
         <span style="color: #8f0075; font-weight: bold;">:base-extension</span> <span style="color: #3548cf;">"org"</span>
         <span style="color: #8f0075; font-weight: bold;">:recursive</span> t
         <span style="color: #8f0075; font-weight: bold;">:publishing-function</span> org-html-publish-to-html
         <span style="color: #8f0075; font-weight: bold;">:exclude</span> ,(<span style="color: #0000b0;">regexp-opt</span> <span style="color: #531ab6; font-weight: bold;">'</span>(<span style="color: #3548cf;">"draft"</span> <span style="color: #3548cf;">"template"</span> <span style="color: #3548cf;">"sitemap"</span>))
         <span style="color: #8f0075; font-weight: bold;">:publishing-directory</span> ,(<span style="color: #0000b0;">expand-file-name</span> <span style="color: #3548cf;">""</span> m/blog-publishing-directory)
         <span style="color: #8f0075; font-weight: bold;">:html-head</span> ,m/blog-meta
         <span style="color: #8f0075; font-weight: bold;">:html-preamble</span> ,m/blog-header
         <span style="color: #8f0075; font-weight: bold;">:html-postamble</span> ,m/blog-footer
         <span style="color: #8f0075; font-weight: bold;">:html-link-org-files-as-html</span> t

         <span style="color: #8f0075; font-weight: bold;">:auto-rss</span> t
         <span style="color: #8f0075; font-weight: bold;">:rss-title</span> <span style="color: #3548cf;">"Uncharted Mind Space"</span> <span style="color: #595959; font-style: italic;">;; </span><span style="color: #595959; font-style: italic;">TODO: use a variable
</span>         <span style="color: #8f0075; font-weight: bold;">:rss-description</span> <span style="color: #3548cf;">"Hello"</span>
         <span style="color: #8f0075; font-weight: bold;">:rss-link</span> <span style="color: #3548cf;">"https://merrick.luois.me"</span>
         <span style="color: #8f0075; font-weight: bold;">:rss-filter-function</span> m/blog-filter-rss
         <span style="color: #8f0075; font-weight: bold;">:rss-with-content</span> all
         <span style="color: #8f0075; font-weight: bold;">:completion-function</span> org-publish-rss)
        (<span style="color: #3548cf;">"blog-static"</span>
         <span style="color: #8f0075; font-weight: bold;">:base-directory</span> ,(<span style="color: #0000b0;">expand-file-name</span> <span style="color: #3548cf;">"blog/static"</span> <span style="color: #005e8b;">denote-directory</span>)
         <span style="color: #8f0075; font-weight: bold;">:base-extension</span> ,(<span style="color: #0000b0;">regexp-opt</span> <span style="color: #531ab6; font-weight: bold;">'</span>(<span style="color: #3548cf;">"css"</span> <span style="color: #3548cf;">"png"</span> <span style="color: #3548cf;">"svg"</span>))
         <span style="color: #8f0075; font-weight: bold;">:recursive</span> t
         <span style="color: #8f0075; font-weight: bold;">:publishing-directory</span> ,(<span style="color: #0000b0;">expand-file-name</span> <span style="color: #3548cf;">"static"</span> m/blog-publishing-directory)
         <span style="color: #8f0075; font-weight: bold;">:publishing-function</span> org-publish-attachment)))
</code></pre>
</div>

<p>
You&rsquo;ll notice there is some :rss-* keys in the blog-posts project, which comes with my choice of rss generation package: <a href="https://git.sr.ht/~taingram/org-publish-rss">org-publish-rss</a>. It almost works out of the box, with 1 major problem: it doesn&rsquo;t work with the <code>export_file_name</code> property, so I had to <a href="https://git.sr.ht/~merrick/org-publish-rss/tree/feat/custom-link-method">fork it</a> and make a workaround, until I figure out how to properly fix it and submit a patch.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">use-package!</span> org-publish-rss
  <span style="color: #8f0075; font-weight: bold;">:config</span>
  (<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">m/gen-rss-link-name</span> (file)
    (<span style="color: #0000b0;">concat</span> <span style="color: #3548cf;">"posts/"</span> (org-export-file-name file)))

  (<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">org-publish-rss-publish-immediately</span> t)
  (<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">org-publish-rss-link-method</span> <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">m/gen-rss-link-name</span>))

(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">m/blog-filter-rss</span> (path)
  (<span style="color: #7b435c;">not</span> (<span style="color: #7b435c;">string-match-p</span> (<span style="color: #7b435c;">regexp-opt</span> <span style="color: #531ab6; font-weight: bold;">'</span>(<span style="color: #3548cf;">"index"</span> <span style="color: #3548cf;">"template"</span> <span style="color: #3548cf;">"page"</span>)) <span style="color: #2f3f83;">path</span>)))
</code></pre>
</div>

<p>
The same issue happened when exporting denote links, but it was simple enough to use an advice to fix it, I&rsquo;ve also reported the <a href="https://github.com/protesilaos/denote/issues/584">issue</a> to denote, hopefully it can be fixed soon.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">org-export-file-name</span> (path)
  (<span style="color: #531ab6; font-weight: bold;">with-temp-buffer</span>
    (<span style="color: #7b435c;">insert-file-contents</span> <span style="color: #2f3f83;">path</span>)
    (<span style="color: #7b435c;">org-mode</span>)
    (<span style="color: #7b435c;">org-export-output-file-name</span> <span style="color: #3548cf;">""</span>)))

(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">org-export-file-path</span> (path)
  <span style="color: #2a5045; font-style: italic;">"Return the export file path for PATH."</span>
  (<span style="color: #531ab6; font-weight: bold;">let</span> ((dir (<span style="color: #7b435c;">file-name-directory</span> <span style="color: #2f3f83;">path</span>))
        (name (<span style="color: #7b435c; font-style: italic;">org-export-file-name</span> path)))
    (<span style="color: #7b435c;">expand-file-name</span> <span style="color: #2f3f83;">name</span> <span style="color: #2f3f83;">dir</span>)))

(<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">m/denote-link-ol-export</span> (link description format)
  <span style="color: #2a5045; font-style: italic;">"Export a `</span><span style="color: #0000b0; font-style: italic;">denote:</span><span style="color: #2a5045; font-style: italic;">' link from Org files.
The LINK, DESCRIPTION, and FORMAT are handled by the export
backend."</span>
  (<span style="color: #531ab6; font-weight: bold;">pcase-let*</span> ((<span style="color: #531ab6; font-weight: bold;">`</span>(,path ,query ,file-search) (<span style="color: #721045;">denote-link--ol-resolve-link-to-target</span> link <span style="color: #8f0075; font-weight: bold;">:full-data</span>))
               (anchor (<span style="color: #531ab6; font-weight: bold;">when</span> path (<span style="color: #0000b0;">file-relative-name</span> (org-export-file-path path))))
               <span style="color: #595959; font-style: italic;">;;</span><span style="color: #595959; font-style: italic;">(anchor (when path (file-relative-name (file-name-sans-extension path))))
</span>               (desc (<span style="color: #531ab6; font-weight: bold;">cond</span>
                      (description)
                      (file-search (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"denote:%s::%s"</span> query file-search))
                      (t (<span style="color: #0000b0;">concat</span> <span style="color: #3548cf;">"denote:"</span> query)))))
    (<span style="color: #531ab6; font-weight: bold;">if</span> path
        (<span style="color: #531ab6; font-weight: bold;">pcase</span> format
          (<span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">html</span> (<span style="color: #531ab6; font-weight: bold;">if</span> file-search
                     (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"&lt;a href=\"%s.html%s\"&gt;%s&lt;/a&gt;"</span> anchor file-search desc)
                   (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"&lt;a href=\"%s.html\"&gt;%s&lt;/a&gt;"</span> anchor desc)))
          (<span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">latex</span> (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"\\href{%s}{%s}"</span> (<span style="color: #0000b0;">replace-regexp-in-string</span> <span style="color: #3548cf;">"[\\{}$%&amp;_#~^]"</span> <span style="color: #3548cf;">"\\\\\\&amp;"</span> path) desc))
          (<span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">texinfo</span> (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"@uref{%s,%s}"</span> path desc))
          (<span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">ascii</span> (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"[%s] &lt;denote:%s&gt;"</span> desc path))
          (<span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">md</span> (<span style="color: #0000b0;">format</span> <span style="color: #3548cf;">"[%s](%s)"</span> desc path))
          (_ path))
      (<span style="color: #0000b0;">format-message</span> <span style="color: #3548cf;">"[[Denote query for `</span><span style="color: #0000b0;">%s</span><span style="color: #3548cf;">']]"</span> query))))

(<span style="color: #7b435c;">advice-add</span> <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">denote-link-ol-export</span> <span style="color: #8f0075; font-weight: bold;">:override</span> <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #7b435c; font-style: italic;">m/denote-link-ol-export</span>)
</code></pre>
</div>

<p>
And it&rsquo;s done! I won&rsquo;t say it&rsquo;s effortless, but it feels really good when you see the site working.
</p>
</div>
</div>
<div id="outline-container-styling" class="outline-3">
<h3 id="styling">Styling</h3>
<div class="outline-text-3" id="text-styling">
<p>
The css styles is mostly inspired by <del>shamelessly taken from</del> <a href="https://bearblog.dev/">bearblog</a>, with some minor tweaks. You can easily find it in the site&rsquo;s source.
</p>
</div>
</div>
<div id="outline-container-migrate-posts" class="outline-3">
<h3 id="migrate-posts">Migrate Posts</h3>
<div class="outline-text-3" id="text-migrate-posts">
<p>
With a simple search, I discovered this handy tool: <a href="https://github.com/bitspook/notes-migrator/blob/master/nm-org-roam-to-denote.el">nm-org-roam-to-denote.el</a>. Since it&rsquo;s a one-time use script, I simply copied it to my scratch buffer and evaluated it. To keep things organized, I limited the scope to just my blog posts subdirectory. After the migration, I did some manual adjustments to optimize the front matter for Denote, then used `denote-rename-file-using-front-matter` to properly rename all the files.
</p>

<p>
Now publish the project again and.. Oops, the date is completely wrong compare to the original site, some more manual fix again, luckily I only have 10+ posts anyway.
</p>
</div>
</div>
<div id="outline-container-open-graph-protocol" class="outline-3">
<h3 id="open-graph-protocol">Open Graph Protocol</h3>
<div class="outline-text-3" id="text-open-graph-protocol">
<p>
There is shocking lack of resource online for doing this in org-publish, so I had to make my own, it&rsquo;s set to a global option <code>org-html-meta-tags</code> which is not ideal but I&rsquo;m not using org-publish for other stuff yet, so it&rsquo;s acceptable for now.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code>(<span style="color: #531ab6; font-weight: bold;">after!</span> (ox-publish org-publish-rss)
  (<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">m/org-element-plain-text</span> (<span style="color: #0000b0;">info</span> key)
    (<span style="color: #721045;">org-html-plain-text</span>
     (<span style="color: #721045;">org-element-interpret-data</span> (<span style="color: #0000b0;">plist-get</span> info key)) info))

  (<span style="color: #531ab6; font-weight: bold;">defun</span> <span style="color: #721045;">m/blog-opengraph-meta</span>(<span style="color: #0000b0;">info</span>)
    <span style="color: #2a5045; font-style: italic;">"Build Open Graph meta fields for html."</span>
    (<span style="color: #0000b0;">append</span>
     (<span style="color: #721045;">org-html-meta-tags-default</span> info)

    (<span style="color: #531ab6; font-weight: bold;">let*</span> ((site-name <span style="color: #3548cf;">"Uncharted Mind Space"</span>)
           (parsed-tree (<span style="color: #0000b0;">plist-get</span> info <span style="color: #8f0075; font-weight: bold;">:parse-tree</span>))
         (first-heading (<span style="color: #721045;">org-element-map</span> parsed-tree <span style="color: #531ab6; font-weight: bold;">'</span><span style="color: #0000b0;">headline</span> <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">identity</span> nil t))
         (section-content (<span style="color: #721045;">org-element-property</span> <span style="color: #8f0075; font-weight: bold;">:contents-begin</span> first-heading))
         (raw-content (<span style="color: #0000b0;">plist-get</span> info <span style="color: #8f0075; font-weight: bold;">:input-buffer</span>))
         (description
          (<span style="color: #531ab6; font-weight: bold;">when</span> section-content
            (<span style="color: #531ab6; font-weight: bold;">let</span> ((text (<span style="color: #531ab6; font-weight: bold;">with-current-buffer</span> raw-content
                          (<span style="color: #0000b0;">buffer-substring-no-properties</span>
                           section-content
                           (<span style="color: #0000b0;">min</span> (<span style="color: #0000b0;">+</span> section-content 100)
                                (<span style="color: #0000b0;">buffer-size</span>))))))
              (<span style="color: #531ab6; font-weight: bold;">if</span> (<span style="color: #0000b0;">&gt;</span> (<span style="color: #0000b0;">length</span> text) 97)
                  (<span style="color: #0000b0;">concat</span> (<span style="color: #0000b0;">substring</span> text 0 97) <span style="color: #3548cf;">"..."</span>)
                text)))))
      <span style="color: #531ab6; font-weight: bold;">`</span>((<span style="color: #3548cf;">"name"</span> <span style="color: #3548cf;">"description"</span> ,(<span style="color: #531ab6; font-weight: bold;">or</span> description <span style="color: #3548cf;">""</span>))
        (<span style="color: #3548cf;">"property"</span> <span style="color: #3548cf;">"og:locale"</span> ,(m/org-element-plain-text info <span style="color: #8f0075; font-weight: bold;">:language</span>))
        (<span style="color: #3548cf;">"property"</span> <span style="color: #3548cf;">"og:title"</span> ,(m/org-element-plain-text info <span style="color: #8f0075; font-weight: bold;">:title</span>))
        (<span style="color: #3548cf;">"property"</span> <span style="color: #3548cf;">"og:type"</span> <span style="color: #3548cf;">"article"</span>)
        (<span style="color: #3548cf;">"property"</span> <span style="color: #3548cf;">"og:description"</span> ,(<span style="color: #531ab6; font-weight: bold;">or</span> description <span style="color: #3548cf;">""</span>))
        (<span style="color: #3548cf;">"property"</span> <span style="color: #3548cf;">"og:site_name"</span> ,site-name)))))

  (<span style="color: #531ab6; font-weight: bold;">setq</span> <span style="color: #005e8b;">org-html-meta-tags</span> <span style="color: #531ab6; font-weight: bold;">#'</span><span style="color: #0000b0;">m/blog-opengraph-meta</span>)
</code></pre>
</div>
</div>
</div>
</div>
<div id="outline-container-closing-thoughts" class="outline-2">
<h2 id="closing-thoughts">Closing Thoughts</h2>
<div class="outline-text-2" id="text-closing-thoughts">
<p>
This new blogging setup feels just right for me. Did you notice all the code blocks in this post have syntax highlighting? And the best part - no custom CSS or JavaScript required! It even uses your Emacs theme when exporting.
</p>

<p>
Here it is: a clean, fast blog with minimal CSS, completely generated from Org files. And I&rsquo;m happy with it.
</p>
</div>
</div>
<div id="outline-container-updates" class="outline-2">
<h2 id="updates">Updates</h2>
<div class="outline-text-2" id="text-updates">
<ul class="org-ul">
<li><span class="timestamp-wrapper"><time class="timestamp" datetime="2025-04-27">&lt;2025-04-27 Sun&gt;</time></span> add Denote to title</li>
</ul>
</div>
</div>
]]>
</description></item>
<item>
<title>Guix: Avoid Entering LUKS Passphrase Twice</title>
<link>https://merrick.luois.me/posts/guix-avoid-entering-luks-passphrase-twice.html</link>
<pubDate>Sun, 04 May 2025 12:08:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/guix-avoid-entering-luks-passphrase-twice.html</guid>
<description>
<![CDATA[<div id="outline-container-guix-avoid-entering-luks-passphrase-twice" class="outline-2">
<h2 id="guix-avoid-entering-luks-passphrase-twice">Guix: Avoid Entering LUKS Passphrase Twice</h2>
<div class="outline-text-2" id="text-guix-avoid-entering-luks-passphrase-twice">
<p>
If you follow the manual when installing Guix with full disk encryption, you&rsquo;ll notice there is an annoying behavior: you need to input the LUKS passphrase <i>twice</i> during boot.
</p>

<p>
The reason is straightforward. During partitioning, we&rsquo;re instructed to mount the EFI partition at <code>/boot/efi</code>, meaning the <code>/boot</code> directory (containing Grub&rsquo;s configuration) resides within the encrypted root partition. This requires decrypting <code>/boot</code> first for Grub to read its configuration, followed by another decryption when booting the system.
</p>

<p>
The obvious solution is to use an unencrypted boot partition, but I do see the benefit of having it encrypted, and I want to avoid break everything again :), so I was about to make peace with it.
</p>

<p>
Until I read this comment in a mailing list <a href="https://lists.gnu.org/archive/html/guix-devel/2025-03/msg00332.html">thread</a>. Apparently there is a more elegant solution and has been <a href="https://issues.guix.gnu.org/65002">there</a> for over a year.
</p>
</div>
</div>
<div id="outline-container-unlocking-with-a-key-file" class="outline-2">
<h2 id="unlocking-with-a-key-file">Unlocking with A Key File</h2>
<div class="outline-text-2" id="text-unlocking-with-a-key-file">
<p>
The approach involves using a key file to unlock the disk, while we still need to input the passphrase for Grub, This key file handles the second decryption during boot. While many guides exist for other distros (easily found with a quick search), there&rsquo;s a lack of documentation for Guix—which motivated me to write this post (Even before I complete my &ldquo;migrate to Guix&rdquo; post).
</p>

<p>
Okay, enough rants, here are the steps.
</p>
</div>
<div id="outline-container-prepare-the-files" class="outline-3">
<h3 id="prepare-the-files">Prepare the Files</h3>
<div class="outline-text-3" id="text-prepare-the-files">
<ul class="org-ul">
<li>Arch Wiki&rsquo;s <a href="https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system#Avoiding_having_to_enter_the_passphrase_twice">guide</a> to this contains the first part we need: create a key file and add it as LUKS key.</li>
<li>Guix Manual&rsquo;s <a href="https://guix.gnu.org/manual/devel/en/html_node/Bootloader-Configuration.html">Bootloader Configuration</a> section explains how to create an <code>extra-initrd</code> image.</li>
</ul>

<div class="org-src-container">
<pre class="src src-shell"><code>guix shell cryptsetup cpio

dd <span style="color: #005e8b;">bs</span>=512 <span style="color: #005e8b;">count</span>=4 <span style="color: #005e8b;">if</span>=/dev/random <span style="color: #005e8b;">iflag</span>=fullblock | <span style="color: #005f5f; font-weight: bold;">sudo</span> install -m 0600 /dev/stdin /cryptroot.key

<span style="color: #005f5f; font-weight: bold;">echo</span> /cryptroot.key | <span style="color: #005f5f; font-weight: bold;">sudo</span> cpio -oH newc | <span style="color: #005f5f; font-weight: bold;">sudo</span> tee /boot/cryptroot.cpio &gt; /dev/null
<span style="color: #005f5f; font-weight: bold;">sudo</span> <span style="color: #005f5f; font-weight: bold;">chmod</span> 0000 /boot/cryptroot.cpio

<span style="color: #595959; font-style: italic;"># </span><span style="color: #595959; font-weight: bold; font-style: italic;">sudo</span><span style="color: #595959; font-style: italic;"> </span><span style="color: #595959; font-weight: bold; font-style: italic;">rm</span><span style="color: #595959; font-style: italic;"> /cryptroot.key # can also move to a backup device</span>
</code></pre>
</div>

<p>
The raw key file is not needed afterwards, so it&rsquo;s safe to delete it or backup it somewhere else.
</p>
</div>
</div>
<div id="outline-container-update-system-config" class="outline-3">
<h3 id="update-system-config">Update System Config</h3>
<div class="outline-text-3" id="text-update-system-config">
<p>
This is adapted from the manual with two key modifications:
</p>

<ol class="org-ol">
<li>On L#4, note that the path to <code>extra-initrd</code> may require an additional <code>/root</code> prefix depending on your file system setup.
<ul class="org-ul">
<li>To verify the correct path, attempt booting first.
<ul class="org-ul">
<li>If Grub fails to find the file, boot will fail.</li>
<li>On next boot, press &rsquo;c&rsquo; in the Grub menu to inspect the kernel path.</li>
</ul></li>
<li>In my configuration, all paths required the <code>/root</code> prefix for successful boot.</li>
</ul></li>
<li>On L#11, ensure the key-file path matches exactly what you specified in the <code>cpio</code> image. Using <code>/cryptoroot.key</code> is recommended as alternative paths may cause mounting issues.
<ul class="org-ul">
<li>I initially tried <code>/boot/cryptoroot.key</code> which failed to work.</li>
</ul></li>
</ol>

<div class="org-src-container">
<pre class="src src-scheme"><code>(bootloader (bootloader-configuration
             (bootloader grub-efi-bootloader)
             (targets (list <span style="color: #3548cf;">"/boot/efi"</span>))
             (extra-initrd <span style="color: #3548cf;">"/root/boot/cryptroot.cpio"</span>)
             (keyboard-layout keyboard-layout)))

(mapped-devices (list (mapped-device
                       (source (uuid <span style="color: #3548cf;">"24288d14-bfe1-475e-96af-5a2ad58fd82c"</span>)) <span style="color: #595959; font-style: italic;">;; </span><span style="color: #595959; font-style: italic;">replace this
</span>                       (target <span style="color: #3548cf;">"cryptroot"</span>)
                       (type (luks-device-mapping-with-options
                              <span style="color: #8f0075; font-weight: bold;">#:key-file</span> <span style="color: #3548cf;">"/cryptroot.key"</span>)))))
</code></pre>
</div>
</div>
</div>
</div>
]]>
</description></item>
<item>
<title>Guix Home is not a good place for dotfiles^{*}</title>
<link>https://merrick.luois.me/posts/guix-home-is-not-a-good-place-for-dotfiles.html</link>
<pubDate>Sun, 09 Aug 2026 11:08:00 +0800</pubDate>
<guid>https://merrick.luois.me/posts/guix-home-is-not-a-good-place-for-dotfiles.html</guid>
<description>
<![CDATA[<div id="outline-container-guix-home-is-not-a-good-place-for-dotfiles" class="outline-2">
<h2 id="guix-home-is-not-a-good-place-for-dotfiles">Guix Home is not a good place for dotfiles<sup>*</sup></h2>
<div class="outline-text-2" id="text-guix-home-is-not-a-good-place-for-dotfiles">
<p>
I switched to Guix System ~3 years ago on my desktop. I use it for development/entertainment and even gaming (thanks to Flatpak).
</p>

<p>
Like most Guix/Nix users, I have that urge to manage EVERYTHING in Guix. Nix&rsquo;s <a href="https://github.com/nix-community/home-manager">home-manager</a> was getting popular around that time, and <a href="https://guix.gnu.org/manual/devel/en/html_node/Home-Configuration.html">Guix Home</a> quickly followed. Needless to say, I was on board!
</p>

<p>
Since I only have limited experience with home-manager, this post only focuses on Guix Home.
</p>
</div>
<div id="outline-container-what-counts-as-dotfiles" class="outline-3">
<h3 id="what-counts-as-dotfiles">What counts as dotfiles?</h3>
<div class="outline-text-3" id="text-what-counts-as-dotfiles">
<p>
I have checked out some dotfile repos out there. I think everyone has their own opinions on this, for example, one would consider the whole Guix System config as dotfiles, but here in my title, I&rsquo;d only count the configuration files for my commonly used tools, such as Emacs, fish (Bash), terminal emulators like alacritty/ghostty, tmux, window managers sway/niri, and so on. And nowadays, agent tools (I&rsquo;ve been using <a href="https://pi.dev/">pi-coding-agent</a> recently).
</p>
</div>
</div>
<div id="outline-container-methods-to-manage-dotfiles-with-guix-home" class="outline-3">
<h3 id="methods-to-manage-dotfiles-with-guix-home">Methods to manage dotfiles with Guix Home</h3>
<div class="outline-text-3" id="text-methods-to-manage-dotfiles-with-guix-home">
<p>
Guix Home also provides a wide variety of options for managing dotfiles, for example:
</p>
<ul class="org-ul">
<li><code>home-files-service-type</code></li>
<li><code>home-dotfiles-service-type</code></li>
<li><code>home-xdg-configuration-files-service-type</code></li>
</ul>

<p>
There are also application-specific services, like
</p>
<ul class="org-ul">
<li><code>home-openssh-service-type</code></li>
<li><code>home-bash-service-type</code></li>
<li><code>home-fish-service-type</code></li>
<li><code>home-mpv-service-type</code></li>
</ul>
<p>
&hellip; and a lot more
</p>
</div>
</div>
<div id="outline-container-the-problem" class="outline-3">
<h3 id="the-problem">The Problem</h3>
<div class="outline-text-3" id="text-the-problem">
<p>
They&rsquo;re all great tools, especially <code>home-dotfiles-service-type</code>; I&rsquo;m able to dump my existing dotfiles right into Guix Home, but they all share the same problem that hurts the whole flow: it symlinks the config file to the immutable Guix store.
</p>

<p>
That&rsquo;s not wrong; that&rsquo;s the whole point of Guix/Nix: it manages everything in the store, and you can use it to control the &ldquo;generations&rdquo;, roll-back and switch at any point. That&rsquo;s an absolutely killer feature, and it works so well with
</p>

<ul class="org-ul">
<li>system config - reboot into disaster? Just select a previous working generation!</li>
<li>package management - never forget about which package to install.</li>
<li>background daemons - which systemd unit file did I just change?</li>
</ul>

<p>
But not for the dotfiles that you want to change often, I tweak my Emacs config every now and then, sometimes I want to try different keybindings in niri, and many times I want to write a new extension for pi, and I still want them to be git-tracked. With the Guix Home managed services, I need to
</p>

<ol class="org-ol">
<li>go to my Guix configuration repo</li>
<li>make the change</li>
<li><code>guix home reconfigure</code></li>
<li>try it out
<ol class="org-ol">
<li>it works, good, commit the change.</li>
<li>it doesn&rsquo;t work, well, tweak it again and go back to step 2</li>
</ol></li>
</ol>

<p>
Oh did I mention <code>reconfigure</code> takes forever? Guix often likes to contact substitute servers when I make no change to my packages (this might be a solvable problem but I didn&rsquo;t bother). Imagine wanting to add/change a niri keybinding (which has config hot reload by default): instead of verifying it in 1s, you now need a 1min loop. And good luck if you happen to have just done a <code>guix pull</code> but forgotten to reconfigure, only to find out you have to wait for LibreWolf to compile because it&rsquo;s not available in the substitute server yet&hellip;
</p>
</div>
</div>
<div id="outline-container-stow" class="outline-3">
<h3 id="stow">Stow</h3>
<div class="outline-text-3" id="text-stow">
<p>
And yes, all of that has happened to me, and I fail to think of a good reason to keep doing this. The benefit of being able to roll back can come from a git-tracked .dotfiles repo too, symlinked into place with <code>stow</code>. So the other day I just spun up a coding agent, asked it to migrate those back to a standalone dotfiles repo, and baam, just 5 mins later, I can edit my dotfiles freely again, and every change is still tracked.
</p>
</div>
</div>
<div id="outline-container-closing" class="outline-3">
<h3 id="closing">Closing</h3>
<div class="outline-text-3" id="text-closing">
<p>
Guix (and Nix) are great pieces of software that changed the way I manage my servers and desktop, but the &ldquo;all in one&rdquo; mindset actually constrained me for a long time, just like someone trying to apply a &ldquo;design pattern&rdquo; or &ldquo;tech stack&rdquo; to every project &ndash; a wise man once said: it&rsquo;s always about trade-offs.
</p>

<p>
I still use a lot of Guix Home services, to manage those configurations I rarely change, like gpg-agent, GTK themes etc, but I finally achieved freedom of dotfiles after breaking out of the &ldquo;all in one&rdquo; mindset (pardon the exaggeration).
</p>
</div>
</div>
</div>
]]>
</description></item>
</channel>
</rss>
