2021-07-23

neotreeで(setq neo-smart-open t)すると固まる(Windows)

neotreeを試してみたのですが、neo-smart-openをtにするとf8に割り当てたneotree-toggleを押したときに固まることがありました。普通のファイルを開いているときは固まらず、scratchやdiredでディレクトリを開いているときに固まるようです。

コードを追ってみたところ neo-buffer--select-file-node 関数の中で無限ループに陥ってしまう場所を見つけました。

https://github.com/jaypei/emacs-neotree/blob/98fe21334affaffe2334bf7c987edaf1980d2d0b/neotree.el#L1632

親ディレクトリへ移動するループで、ルートに到達したかの判定を"/"と比較することで行っています。Windowsでは"c:/"等がルートで何度neo-path--updirを適用しても決して"/"になりませんからいつまで経っても終わりません。

とりあえず"/"を"c:/"にしたら直ったのですが、それではあんまりなのでupdirしたときにパスが変化しなかったら終わらせるようにしてみました。

うまくadviceもかけられないしneotree.el読み込み後に関数まるごと再定義。neotreeはそんなに頻繁に更新されていないみたいなのでまあいいか。

(with-eval-after-load "neotree"
  (defun neo-buffer--select-file-node (file &optional recursive-p)
    "Select the node that corresponds to the FILE.
If RECURSIVE-P is non nil, find files will recursively."
    (let ((efile file)
          (iter-prev-dir nil) ;;ADD
          (iter-curr-dir nil)
          (file-node-find-p nil)
          (file-node-list nil))
      (unless (file-name-absolute-p efile)
        (setq efile (expand-file-name efile)))
      (setq iter-curr-dir efile)
      (catch 'return
        (while t
          (setq iter-prev-dir iter-curr-dir) ;;ADD
          (setq iter-curr-dir (neo-path--updir iter-curr-dir))
          (push iter-curr-dir file-node-list)
          (when (neo-path--file-equal-p iter-curr-dir neo-buffer--start-node)
            (setq file-node-find-p t)
            (throw 'return nil))
          (let ((niter-curr-dir (file-remote-p iter-curr-dir 'localname)))
            (unless niter-curr-dir
              (setq niter-curr-dir iter-curr-dir))
            (when (or (string= iter-curr-dir iter-prev-dir) ;;ADD
                      (neo-path--file-equal-p niter-curr-dir "/"))
              (setq file-node-find-p nil)
              (throw 'return nil)))))
      (when file-node-find-p
        (dolist (p file-node-list)
          (neo-buffer--set-expand p t))
        (neo-buffer--save-cursor-pos file)
        (neo-buffer--refresh nil)))))