在 wsl2 中用 emacs 的困扰: x-get-selection-internal 卡住, 有什么办法避免?

我在 win11 上使用 emacs 的方法: wsl2 安装 emacs (28.2, snap 安装的), 由 emacs 访问的文件直接保存在 ubuntu 中. 现在 windows 直接支持打开 emacs GUI(wslg), 窗口清晰度感觉与一般应用无异, 窗口管理与 windows 普通应用不同. 但基本上很好用, 至少速度比 mac 快很多, 暂时也没有什么是 mac 可以用而 win11+wsl2 用不了的. 但糟心的有 2 件事:

最可怕的是这件事, 经常不知道为什么 evil-yank, evil-paste-after 都会卡住, 而且主机狂转:

x-get-selection-internal(CLIPBOARD UTF8_STRING nil nil)

我不知道为什么, 也没法 debug, 因为 x-get-selection-internal 是 c 函数. 遇到这件事我发现唯一有用的做法就只有重启 wsl2, 这真的很可怕. 而且这个问题出现的频率非常高, 几小时一次. 所以我频繁重启 wsl2.

第二个问题, 出现频率没有那么高, 但是出现了就很可怕, 那就是 fcitx 有时不灵, 打开 fcitx-config-gtk3 发现输入法一片空白, 添加又找不到任何可以添加的, 对这个问题, 我发现连重启 wsl2 都不管用, 我是重启了 windows 才解决的.

目前就是这糟心的 2 个问题. 想问问大家有什么建议么? 比如对于第一个问题, 用其它的 x server 会解决么? 我试过 x410, 但发现它的分辨率完全不如 windows 自带效果, 哪怕 high quality 都如此.

2 个赞

wsl2 arch emacs28.2 vcxsrv 重度用户,输入法我倒是用emacs-rime,没有遇到你说的问题,你是用wslg?

是的,我用的 wslg

用了一段时间, 前面说的问题基本上解决了, 第一个问题的解决方式是把 select-enable-clipboard 设置为 nil, 这样 emacs 可以正常 kill, yank, 同时 emacs 的剪切板会同步到 windows, 但反之不行, 第二个问题是我的 shell profile 对 fcitx 启动方式有点问题, 没再出现.

我现在还存在且没有很好解决方法的问题是: windows 的剪切板有时候不能同步到 emacs, 这个 “有时候” 是这样的, 在某一刻之前都可以, 在某一刻之后都不行, 我也不知道这个触发条件是什么. 我写了:

(defun sync-clipboard-from-windows-to-wsl2()
  (interactive)
  (kill-new (replace-regexp-in-string "
" "" (shell-command-to-string "powershell.exe -command Get-Clipboard") t t)))

但这个函数不仅延迟大, 更重要的是时不时会让 emacs 进程异常退出, 所以我不太敢用. 因此对于 windows 的剪切板传递到 emacs, 我还是没有什么好的办法.

emacs 29.1 这个问题仍然存在, 不过关于 windows 剪切板传到 emacs 现在有了一个 workaround.

这个方法的想法就是先创建一个 vterm buffer, 打开 powershell, 每次需要获取 clipboard 就执行 get-clipboard 命令, 获取命令结果.

代码如下, 如果不 work, 我猜测最有可能是命令时间不够长, 调一下 sleep 的参数.

(defun my/vterm-yank-pwsh-clipboard()
  "Send 'get-clipboard' to pwsh vterm buffer and kill the output."
  (interactive)
  (let* ((vterm-buffer-name "pwsh") (pwsh-buffer (get-buffer vterm-buffer-name))
        clipboard-content-start-line-number
        clipboard-content-end-line-number)
    (unless pwsh-buffer
      (setq pwsh-buffer (generate-new-buffer vterm-buffer-name))
      (with-current-buffer pwsh-buffer (vterm-mode)
      (vterm-send-string "pwsh.exe" t)
      (vterm-send-return)
                           )
      (sleep-for 1.8)
      )
    (when pwsh-buffer
      ;; Switch to pwsh buffer and send command
      (with-current-buffer pwsh-buffer
        (vterm-send-string "get-clipboard" t)
        (vterm-send-return)

        ;; Wait a bit for the command to execute and output to appear
        (sleep-for 0.3)

        ;; Go to max point and search backward for "get-clipboard"
        (goto-char (point-max))
        (when (search-backward "get-clipboard" nil t)
          (setq clipboard-content-start-line-number (line-number-at-pos))

          ;; Go to max point and search backward for "^PS"
          (goto-char (point-max))
          (when (re-search-backward "^PS" nil t)
            (setq clipboard-content-end-line-number (1- (line-number-at-pos)))
            ;; Get content between start and end line numbers and kill
            (let ((start-pos (progn (goto-line (1+ clipboard-content-start-line-number)) (point)))
                  (end-pos (progn (goto-line clipboard-content-end-line-number) (line-end-position))))
              (kill-new
               (vterm--filter-buffer-substring (buffer-substring start-pos end-pos))
               )))))
      (yank)
      )))
(evil-define-key 'normal global-map (kbd "gp") #'my/vterm-yank-pwsh-clipboard)

你试着看看你用的emacs是不是pgtk的?如果是pgtk的,无法从windows复制到emacs已经是一个known issue了,参见https://emacsredux.com/blog/2022/01/04/dealing-with-clipboard-issues-on-windows-11-wslg/

我试了一下 (featurep 'gtk) 输出 t, 不知道是不是这表示它是 pgtk. 我跟你的这个链接问题刚好相反, 它好像是 emacs->windows 不可以, windows->emacs 可以. 我正好相反, 是 windows->emacs 不行(也不是一直不行, 刚开始的时候可以, 用上个几个小时或者一天多以后就不行了), emacs->windows 没咋遇到过问题.

我win11, pgtk版本的29.1复制到win没问题,win复制进去的话,中文变成问号。有借助wl-clipboard的几个workaround,但是不完美(有的evil粘贴位置不对,有的emacs里复制再在emacs里粘贴会卡住(其实是wl-paste卡住))

最终我还是继续用vcxsrv。

我的选择是退回到gtk,这些问题得等上游修复了。

自从我不用 fcitx 改用 pyim 后, 我目前还没遇到剪切板的问题.