<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Wanten</title>
    <description>Wanten's personal website showcases his work and thoughts.</description>
    <link>https://www.wanten.org</link>
    <atom:link href="https://www.wanten.org/rss.xml" rel="self" type="application/rss+xml" />
    <language>zh-CN</language>
    <lastBuildDate>Tue, 28 Apr 2026 12:20:00 GMT</lastBuildDate>
    <item>
      <title>Emacs Wayland 解决输入法候选框跳动的问题</title>
      <link>https://www.wanten.org/2026/04/28/1220</link>
      <guid>https://www.wanten.org/2026/04/28/1220</guid>
      <pubDate>Tue, 28 Apr 2026 12:20:00 GMT</pubDate>
      <description>&lt;h2 id=&quot;一、问题描述&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;一、问题描述&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#一、问题描述&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;使用 Emacs Wayland v30.2 版本，搭配 fcitx5 输入中文时，会出现一个影响使用体验的问题：输入法候选框会跟随 preedit（汉字未上屏时的拼音显示）不断跳动，输入过程中候选框位置不稳定，影响输入流畅度。&lt;/p&gt;
&lt;h2 id=&quot;二、快速解决方案&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;二、快速解决方案&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#二、快速解决方案&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;无需修改 Emacs 源码、无需重新编译，只需在 Emacs 配置文件中添加以下 Lisp 代码，即可直接解决候选框跳动问题：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;;; Emacs Wayland 避免候选框跟随 preedit 跳动&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(with-eval-after-load &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;pgtk-win&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;  (advice-add&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;   &apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;pgtk-preedit-text &lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;:filter-return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (_)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; pgtk-preedit-overlay&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;       (overlay-put&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;        pgtk-preedit-overlay&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;        &apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;before-string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;        (propertize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;         (overlay-get pgtk-preedit-overlay &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;before-string)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;         &apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;cursor &lt;/span&gt;&lt;span style=&quot;color:#2F798A;--shiki-dark:#4C9A91&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;))))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;三、原理分析&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;三、原理分析&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#三、原理分析&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;要理解问题的根源和解决方案的逻辑，我们先从 Emacs Wayland 下的输入渲染机制说起。&lt;/p&gt;
&lt;h3 id=&quot;31-emacs-wayland-输入渲染基础&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;3.1 Emacs Wayland 输入渲染基础&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#31-emacs-wayland-输入渲染基础&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Emacs 在 Wayland 环境下，通过 PGTK（Pure GTK）后端进行界面渲染和输入处理。当我们使用输入法输入中文时，会经历一个 &lt;code&gt;preedit&lt;/code&gt; 状态——即拼音已输入、但汉字尚未上屏的阶段，此时输入法会向 Emacs 发送 &lt;code&gt;preedit-text&lt;/code&gt; 事件，告知 Emacs 需显示的拼音内容及样式。&lt;/p&gt;
&lt;p&gt;这个事件的处理逻辑，定义在 Emacs 源码的 &lt;code&gt;emacs/lisp/term/pgtk-win.el&lt;/code&gt; 文件中，核心函数是 &lt;code&gt;pgtk-preedit-text&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&quot;32-原始函数工作流程&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;3.2 原始函数工作流程&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#32-原始函数工作流程&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;以下是 &lt;code&gt;pgtk-preedit-text&lt;/code&gt; 函数的完整源码，我们拆解其工作流程，找到问题关键：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;defun&lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt; pgtk-preedit-text&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (event)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;  &quot;&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;An internal function to display preedit text from input method.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;EVENT is a `preedit-text&apos; event.&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;  (interactive &lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; pgtk-preedit-overlay&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    (delete-overlay pgtk-preedit-overlay))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; pgtk-preedit-overlay &lt;/span&gt;&lt;span style=&quot;color:#1E754F;--shiki-dark:#4D9375&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;  (&lt;/span&gt;&lt;span style=&quot;color:#1E754F;--shiki-dark:#4D9375&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; ((ovstr &lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;        (idx &lt;/span&gt;&lt;span style=&quot;color:#2F798A;--shiki-dark:#4C9A91&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;        atts ov str color face-name)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;dolist&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (part (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;nth&lt;/span&gt;&lt;span style=&quot;color:#2F798A;--shiki-dark:#4C9A91&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; event))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; str (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;car&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; part))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; face-name (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;intern&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;pgtk-im-%d&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; idx)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;eval&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;       `&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(defface &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;face-name &lt;/span&gt;&lt;span style=&quot;color:#1E754F;--shiki-dark:#4D9375&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;face of input method preedit&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; atts &lt;/span&gt;&lt;span style=&quot;color:#1E754F;--shiki-dark:#4D9375&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; color (cdr-safe (assq &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;fg (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;cdr&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; part))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; atts (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; atts &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;:foreground&lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt; ,&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;color))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; color (cdr-safe (assq &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;bg (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;cdr&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; part))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; atts (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; atts &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;:background&lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt; ,&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;color))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; color (cdr-safe (assq &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;ul (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;cdr&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; part))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;        (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; atts (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;append&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; atts &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;:underline&lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt; ,&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;color))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (face-spec-set face-name &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#1E754F;--shiki-dark:#4D9375&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt; .&lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt; ,&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;atts)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (add-text-properties &lt;/span&gt;&lt;span style=&quot;color:#2F798A;--shiki-dark:#4C9A91&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;length&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; str) &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(face &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;face-name) str)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; ovstr (concat ovstr str))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;      (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; idx (&lt;/span&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;1+&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; idx)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; ov (make-overlay (point) (point)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    (overlay-put ov &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;before-string ovstr)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;setq&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; pgtk-preedit-overlay ov)))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;其工作步骤可概括为 3 步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;清空旧状态&lt;/strong&gt;：删除上一次生成的 Overlay（覆盖层），避免残留内容干扰。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构造拼音字符串&lt;/strong&gt;：遍历输入法传来的事件数据，将拼音内容（ovstr）根据输入法指定的样式（前景色、背景色、下划线）进行着色处理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创建并渲染 Overlay&lt;/strong&gt;：在当前光标位置（point）创建一个长度为 0 的 Overlay，将着色后的拼音字符串作为 &lt;code&gt;before-string&lt;/code&gt; 渲染——简单说，就是“在光标位置之前显示这段拼音”。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;33-候选框跳动的核心原因&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;3.3 候选框跳动的核心原因&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#33-候选框跳动的核心原因&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;问题就出在 &lt;code&gt;before-string&lt;/code&gt; 的渲染逻辑上：&lt;/p&gt;
&lt;p&gt;当 &lt;code&gt;before-string&lt;/code&gt; 插入拼音文本后，Emacs 的物理光标会被自动推到这段拼音的后面；而 GTK 后端会将光标所在的实时位置告知输入法，输入法则会根据光标位置调整候选框的显示坐标。&lt;/p&gt;
&lt;p&gt;这样一来，每输入一个拼音字符，&lt;code&gt;before-string&lt;/code&gt; 的长度就会增加，光标就会向后移动，候选框也会跟着向后“跳动”，形成我们遇到的问题。&lt;/p&gt;
&lt;h3 id=&quot;34-解决方案的核心逻辑&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;3.4 解决方案的核心逻辑&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#34-解决方案的核心逻辑&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;解决问题的关键，是固定光标的位置——让光标始终停留在 preedit 拼音的起始位置，这样输入法获取到的光标坐标就不会变化，候选框自然也就不会跳动。&lt;/p&gt;
&lt;p&gt;在 Emacs 中，&lt;code&gt;cursor&lt;/code&gt; 文本属性可以控制物理光标在 Overlay 字符串上的停留位置。我们只需给 &lt;code&gt;before-string&lt;/code&gt; 增加 &lt;code&gt;&apos;cursor 1&lt;/code&gt; 属性，就能让光标固定在拼音字符串的第一个字符位置，修改逻辑如下（对比原始代码）：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    (overlay-put ov &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;before-string ovstr)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#998418;--shiki-dark:#B8A965&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    (overlay-put ov &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;before-string (propertize ovstr &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;cursor &lt;/span&gt;&lt;span style=&quot;color:#2F798A;--shiki-dark:#4C9A91&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;四、解决方案补充说明&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;四、解决方案补充说明&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#四、解决方案补充说明&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我们使用 Emacs 强大的 Advice 机制（类似面向切面编程 AOP），在不修改源码的前提下，动态注入上述修改逻辑，这也是我们开头给出的配置代码的核心原理。下面拆解这段配置的关键细节：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;;; 解决 Wayland 环境下 PGTK 版本 Emacs 候选框跳动问题&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;(with-eval-after-load &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;pgtk-win&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;  (advice-add&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;   &apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;pgtk-preedit-text &lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;:filter-return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;   (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;lambda&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; (_)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;     (&lt;/span&gt;&lt;span style=&quot;color:#AB5959;--shiki-dark:#CB7676&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; pgtk-preedit-overlay&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;       (&lt;/span&gt;&lt;span style=&quot;color:#1E754F;--shiki-dark:#4D9375&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; ((ovstr (overlay-get pgtk-preedit-overlay &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;before-string)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;         (overlay-put&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;          pgtk-preedit-overlay&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;          &apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;before-string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;          (propertize ovstr &lt;/span&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;cursor &lt;/span&gt;&lt;span style=&quot;color:#2F798A;--shiki-dark:#4C9A91&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;))))))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;with-eval-after-load &apos;pgtk-win&lt;/code&gt;：延迟加载保护。因为 &lt;code&gt;pgtk-preedit-text&lt;/code&gt; 函数定义在 &lt;code&gt;pgtk-win.el&lt;/code&gt; 模块中，只有在 Wayland 环境下加载该模块后，&lt;code&gt;advice-add&lt;/code&gt; 才能找到目标函数，避免启动报错。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:filter-return&lt;/code&gt;：Advice 的类型，意为“在原始函数执行完毕后，对其返回值进行过滤/修改”。这里我们不需要修改返回值，只是利用其“执行时机”，在原始函数创建完 Overlay 后，追加光标位置的设置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;overlay-put ... &apos;cursor 1&lt;/code&gt;：核心操作。原始函数执行后，&lt;code&gt;pgtk-preedit-overlay&lt;/code&gt; 已创建并渲染，我们获取其 &lt;code&gt;before-string&lt;/code&gt;，添加 &lt;code&gt;&apos;cursor 1&lt;/code&gt; 属性后重新赋值，从而固定光标位置，解决候选框跳动问题。&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    <item>
      <title>最好用的视频倍速脚本</title>
      <link>https://www.wanten.org/2026/03/17/1132</link>
      <guid>https://www.wanten.org/2026/03/17/1132</guid>
      <pubDate>Tue, 17 Mar 2026 11:32:00 GMT</pubDate>
      <description>&lt;p&gt;这个&lt;a href=&quot;https://greasyfork.org/en/scripts/536243-fullscreen-video-speed-controller&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;脚本&lt;/a&gt;是我写的，对我来说，当然是“最好的”。&lt;/p&gt;
&lt;p&gt;在播放器里手动调节视频速度我觉得相当麻烦，倍速之后想回到原速还得再调一遍，繁琐且不便，于是我写了一个可以便捷控制视频倍速的浏览器脚本。&lt;/p&gt;
&lt;p&gt;这个脚本只需要使用到右手，在视频&lt;strong&gt;全屏&lt;/strong&gt;状态下生效，按键绑定为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;J&lt;/code&gt; – 原速&lt;/li&gt;
&lt;li&gt;&lt;code&gt;K&lt;/code&gt; – 2 倍速&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L&lt;/code&gt; – 3 倍速&lt;/li&gt;
&lt;li&gt;&lt;code&gt;H&lt;/code&gt; – 后退 5 秒&lt;/li&gt;
&lt;li&gt;&lt;code&gt;;&lt;/code&gt; – 前进 5 秒&lt;/li&gt;
&lt;li&gt;&lt;code&gt;O&lt;/code&gt; – 后退 90 秒&lt;/li&gt;
&lt;li&gt;&lt;code&gt;P&lt;/code&gt; – 前进 90 秒&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;键盘 J 键有一个凸起，可以快速定位，右手默认摆放的位置就和平常打字时一样，食指 J 原速，中指 K 二倍速，无名指 L 三倍速。&lt;/p&gt;
&lt;p&gt;当因为倍速播放错过了精彩的片段，则可以按 H 后退 5 秒，如果退太多，则可以按;（分号）前进 5 秒。&lt;/p&gt;
&lt;p&gt;拇指放在空格键，随时暂停视频。O 和 P 分别是 90 秒，即 1 分 30 秒，主要用于跳过动画的 OP，绝大多数的动画 OP 时常都是 90 秒。&lt;/p&gt;
&lt;p&gt;用一只手就能控制视频的倍速，还能前进后退跳转，这太棒了！我觉得这个按键设计是最好的，没有之一。&lt;/p&gt;</description>
    </item>
    <item>
      <title>我喜欢文字</title>
      <link>https://www.wanten.org/2026/03/17/1045</link>
      <guid>https://www.wanten.org/2026/03/17/1045</guid>
      <pubDate>Tue, 17 Mar 2026 10:45:00 GMT</pubDate>
      <description>&lt;p&gt;文字能保存我的想法，在我需要时，重新阅读文字，就能让我再次想起当时的想法。&lt;/p&gt;
&lt;p&gt;文字让我轻松改进自己的想法，因为对文字的优化，就是对想法的优化。&lt;/p&gt;
&lt;p&gt;文字减少了我的思考负担，一边思考，一边记录，审视自己的思路，避免忽略重要细节。&lt;/p&gt;
&lt;p&gt;文字输入很方便，无论在手机还是电脑上，都能轻松输入；编辑器数量繁多，输入方式多样——触屏、键盘、语音识别都可以使用。&lt;/p&gt;
&lt;p&gt;文字能长时间保存，只要载体存在，文字便不会轻易消失。&lt;/p&gt;
&lt;p&gt;文字空间占用小，便于传输和存储。&lt;/p&gt;</description>
    </item>
    <item>
      <title>在 Archlinux 上运行网易云音乐</title>
      <link>https://www.wanten.org/2026/01/26/1919</link>
      <guid>https://www.wanten.org/2026/01/26/1919</guid>
      <pubDate>Mon, 26 Jan 2026 19:19:00 GMT</pubDate>
      <description>&lt;p&gt;安装必要的软件：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; pacman&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -S&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; wine&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; wine-mono&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; winetricks&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;在官网下载网易云音乐的安装包：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://music.163.com/#/download&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://music.163.com/#/download&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 winetricks 安装必要的字体和依赖：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span style=&quot;color:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;~/wine/netease-music&lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt; winetricks&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; arial&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; courier&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; cjkfonts&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; allcodecs&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; d3dx9&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; dxvk&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; winhttp&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; wininet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;安装网易云：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span style=&quot;color:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;~/wine/netease-music&lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt; wine&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; ~/Downloads/NeteaseCloudMusic_Music_official_3.1.26.204919_32.exe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;之后的启动方式：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B07D48;--shiki-dark:#BD976A&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span style=&quot;color:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;~/wine/netease-music&lt;/span&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt; wine&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;/home/wanten/wine/netease-music/drive_c/Program Files (x86)/NetEase/CloudMusic/cloudmusic.exe&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Git Bash 的 ln -s 无法创建软链接</title>
      <link>https://www.wanten.org/2026/01/16/1243</link>
      <guid>https://www.wanten.org/2026/01/16/1243</guid>
      <pubDate>Fri, 16 Jan 2026 12:43:00 GMT</pubDate>
      <description>&lt;p&gt;在 Windows 中创建软链接，我一般都是在 PowerShell 中执行这个命令：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;New-Item&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -ItemType&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; SymbolicLink&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -Path&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;Path to target&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -Target&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt;Path to source&lt;/span&gt;&lt;span style=&quot;color:#B5695977;--shiki-dark:#C98A7D77&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -Force&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;但这个命令太长了，而且先写目标，再写源的这个命令顺序非常不自然。&lt;/p&gt;
&lt;p&gt;于是我尝试在 Git Bash 中用 &lt;code&gt;ln -s&lt;/code&gt;命令，这个命令很简短，先源再到目标的这个顺序也让我感到舒服：&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; /path/to/source&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; /path/to/target&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;我运行这个命令，成功了。但没过多久，我感到不对劲，因为我偶然发现对源文件的修改，没有同步到目标文件中，两者就好像毫无关联一般。&lt;/p&gt;
&lt;p&gt;针对这个问题，我认真测试了&lt;code&gt;ln -s&lt;/code&gt;命令，运行之后，分别对源文件和目标文件进行修改，对照着观察变化。结果就是，它没有创建软链接，而是直接复制了一份源文件。&lt;/p&gt;
&lt;p&gt;这个结果让我感到意外，我猜测可能是兼容性问题。&lt;/p&gt;
&lt;p&gt;在网上调研后发现，这是一个常见的坑。Git Bash 中创建软链接要用 &lt;code&gt;mklink&lt;/code&gt; 替代，或配置 &lt;code&gt;core.symlinks&lt;/code&gt;或开启&lt;code&gt;Developer Mode&lt;/code&gt;……我觉得这个也好麻烦啊，干脆继续使用 PowerShell 命令。&lt;/p&gt;</description>
    </item>
    <item>
      <title>在 Obsidian 中专注于子文件夹</title>
      <link>https://www.wanten.org/2026/01/15/1213</link>
      <guid>https://www.wanten.org/2026/01/15/1213</guid>
      <pubDate>Thu, 15 Jan 2026 12:13:00 GMT</pubDate>
      <description>&lt;p&gt;我的 Vault 中很多文件夹，其中有一些文件夹有很深的子文件夹，例如 &lt;code&gt;vault/a/b/c/d/e&lt;/code&gt;。某些时候我想专注于文件夹&lt;code&gt;e&lt;/code&gt;进行编辑，而不想在&lt;code&gt;Files&lt;/code&gt;中看到这个文件夹之外的内容。&lt;/p&gt;
&lt;p&gt;我想到的解决方案是将文件夹&lt;code&gt;e&lt;/code&gt;作为一个 vault 打开，用另一个 obsidian 窗口去编辑它，但这样做的问题是，它会在文件夹&lt;code&gt;e&lt;/code&gt;之下创建新的配置文件夹&lt;code&gt;.obsidian&lt;/code&gt;，这有些烦人。&lt;/p&gt;
&lt;p&gt;我要么重新配置，要么把原 vault 中的配置复制过来。这导致的情况是我要用额外的空间去存储多出一份的配置文件。&lt;/p&gt;
&lt;p&gt;我想到了另一个解决方案，用软连接将原 vault 中的配置文件链接到子目录&lt;code&gt;e&lt;/code&gt;中，这样几乎不占多余的空间，并且完全继承了原 vault 的各种配置。&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; /path/to/vault/.obsidian&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; /path/to/vault/a/b/c/d/e/.obsidian&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;现在的坏消息是，模板功能没法正常使用了，因为它们的配置是基于目录的，除非我把目录文件夹也软链接到子目录中。&lt;/p&gt;
&lt;p&gt;这样做确实有效。&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;&lt;button type=&quot;button&quot; class=&quot;copy-code-button&quot; data-state=&quot;idle&quot; aria-label=&quot;Copy code&quot; title=&quot;Copy code&quot;&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-copy&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;rect x=&quot;9&quot; y=&quot;9&quot; width=&quot;13&quot; height=&quot;13&quot; rx=&quot;2&quot; ry=&quot;2&quot;&gt;&lt;/rect&gt;&lt;path d=&quot;M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;svg class=&quot;copy-code-icon copy-code-icon-check&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; stroke=&quot;currentColor&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M20 6 9 17l-5-5&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;&lt;pre class=&quot;shiki shiki-themes vitesse-light vitesse-dark&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#121212;color:#393a34;--shiki-dark:#dbd7caee&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#59873A;--shiki-dark:#80A665&quot;&gt;ln&lt;/span&gt;&lt;span style=&quot;color:#A65E2B;--shiki-dark:#C99076&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; /path/to/vault/templates&lt;/span&gt;&lt;span style=&quot;color:#B56959;--shiki-dark:#C98A7D&quot;&gt; /path/to/vault/a/b/c/d/e/templates&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;我写了一个脚本，只需输入目标路径，就能自动将原 vault 的配置和模板自动链接过去。&lt;/p&gt;
&lt;p&gt;最终我达成了我的目的：&lt;strong&gt;在 Obsidian 中专注于子目录&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我认为这是一个实用的功能，希望官方能够实现它，比如点击某个按钮后，&lt;code&gt;Files&lt;/code&gt;只显示我想要专注的目录。&lt;/p&gt;</description>
    </item>
    <item>
      <title>我为什么不再使用纯纯写作</title>
      <link>https://www.wanten.org/2023/10/26/1513</link>
      <guid>https://www.wanten.org/2023/10/26/1513</guid>
      <pubDate>Thu, 26 Oct 2023 15:13:00 GMT</pubDate>
      <description>&lt;h2 id=&quot;多窗口支持&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;多窗口支持&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#多窗口支持&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;纯纯写作在手机上的功能比较健全，电脑版的纯纯写作只有一个编辑器，这个编辑器通过热点连接可以编辑手机上纯纯写作正在编辑的内容。&lt;/p&gt;
&lt;p&gt;手机上的纯纯写作一次只能打开一个文章，这导致电脑上的编辑器一次也只能编辑一个文章，想同时打开两篇及以上的文章？抱歉，目前还做不到。&lt;/p&gt;
&lt;p&gt;文字工作者写作时经常要参考之前写过的文章或笔记，因为纯纯写作无法同时打开多篇文章，于是作者不可避免地要在当前文章和其他参考文章之间频繁性切换，这样的写作体验是非常糟糕的。&lt;/p&gt;
&lt;p&gt;纯纯写作作者 Drakeet 在开发全新的电脑版纯纯写作，到时应该能够在电脑上同时编辑查看不同的文章。&lt;/p&gt;
&lt;h2 id=&quot;章卷管理&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;章卷管理&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#章卷管理&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;纯纯写作中可以创建【书籍】，在【书籍】下可以创建【卷】，在【卷】之下能创建文章，这就是它所有的文章组织方式了。&lt;/p&gt;
&lt;p&gt;卷与卷之间无法嵌套，这样限制了文章的多层级分类管理。文章写得多了，会出现一个卷里有非常多的文章，或一个书籍下有非常多的卷，有些卷是包含关系，但因为不能嵌套，所以只能放到平级。&lt;/p&gt;
&lt;p&gt;我认为理想的组织方式是像传统的文件/文件夹结构一样，文件夹里可以有文件夹，可以一直嵌套。&lt;/p&gt;
&lt;p&gt;除了章卷组织，在纯纯写作中，文章的转移也非常难用。&lt;/p&gt;
&lt;p&gt;一个文章想从 A 卷转移到 X 卷，只能手动拖拽，无法指定转移。&lt;/p&gt;
&lt;p&gt;两个及以上的文章想同时从 A 卷转移到 X 卷？抱歉，做不到，只能一个个拖。&lt;/p&gt;
&lt;p&gt;A 书籍 A1 卷中的文章想转移到 B 书籍 B1 卷中？没有直接的方法，只能先转移到 B 书籍最后一个卷 B99 中，再从 B99 卷拖拽到 B1 卷中。&lt;/p&gt;
&lt;p&gt;A 书籍 A1 卷想要整体转移到 B 书籍中？没有快捷方法，要先在 B 书籍最后面创建一个名叫 A1 的卷，再从 A 书籍中全选 A1 卷中的文章，批量转入到 B 书籍最后一个卷 A1 中。&lt;/p&gt;
&lt;p&gt;A 书籍想要和 B 书籍合并？麻烦，要按前一个方法所说一个一个卷地转移。&lt;/p&gt;
&lt;p&gt;章卷管理，纯纯写作为数不多的优势就是可以手动调整章节的顺序。&lt;/p&gt;
&lt;h2 id=&quot;文章导出&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;文章导出&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#文章导出&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;单篇文章要导出？简单，复制、导出图片、PDF、txt 文件。&lt;/p&gt;
&lt;p&gt;整个卷要导出？麻烦，先把这个卷复制到……噢，好像不能复制，先整卷转移到一本新书籍中，然后整本书导出，接着再转移回去。&lt;/p&gt;
&lt;p&gt;A 书籍整本书导出？就给你生成一个 A.txt，里面混杂所有的章节，所有内容堆在一起。为什么不能生成一个 A 文件夹呢？A 文件夹下面再是卷文件夹 A1、A2、A3，这些卷文件夹下面再是一个个独立的章节文件，a.txt, b.txt……这样不是很好？&lt;/p&gt;
&lt;h2 id=&quot;总结&quot; class=&quot;heading-with-anchor&quot;&gt;&lt;span class=&quot;heading-content&quot;&gt;总结&lt;/span&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;#总结&quot; aria-label=&quot;Jump to section&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我不需要太多东西，只需要【文章的多层级分类管理】、【快捷的文章转移及组织】以及能够【开启多个窗口同时编辑多个文章】。纯纯写作无法满足我这些需求，因此我决定将文章从纯纯写作中迁移出去，迁移到一个能满足我需求的工具上。&lt;/p&gt;
&lt;p&gt;迁移可把我折腾坏了，导出的东西居然是全部混杂在一起的。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
