【Emacs】dired-modeでGNU sushiを使ったファイルプレビュー機能の実装

こうする. call-process-shell-command の活用がカギだった.

(with-eval-after-load "dired"
  (defvar dired-sushi-search-command
    "xdotool search --desktop 0 org.gnome.NautilusPreviewer windowactivate")
  (defun dired-sushi ()
    (interactive)
    (call-process-shell-command 
     (format "sushi %s; sleep 0.1; %s" (dired-get-file-for-visit)
             dired-sushi-search-command)
     nil 0))
  (define-key dired-mode-map (kbd "SPC") #'dired-sushi)
  )

【Emacs】neotreeで使うiconをall-the-iconsからnerd-iconsに変えた

こんな感じで neo-buffer--insert-fold-symbol を再定義した.nerd-icons-icon-for-dir-with-chevron は新規に作成した.

(defun neo-buffer--insert-fold-symbol (name &optional node-name)
  "Write icon by NAME, the icon style affected by neo-theme.
`open' write opened folder icon.
`close' write closed folder icon.
`leaf' write leaf icon.
Optional NODE-NAME is used for the `icons' theme"
  (let ((n-insert-image (lambda (n)
                          (insert-image (neo-buffer--get-icon n))))
        (n-insert-symbol (lambda (n)
                           (neo-buffer--insert-with-face
                            n 'neo-expand-btn-face))))
    (cond
     ((and (display-graphic-p) (equal neo-theme 'classic))
      (or (and (equal name 'open)  (funcall n-insert-image "open"))
          (and (equal name 'close) (funcall n-insert-image "close"))
          (and (equal name 'leaf)  (funcall n-insert-image "leaf"))))
     ((equal neo-theme 'arrow)
      (or (and (equal name 'open)  (funcall n-insert-symbol "▾"))
          (and (equal name 'close) (funcall n-insert-symbol "▸"))))
     ((equal neo-theme 'nerd)
      (or (and (equal name 'open)  (funcall n-insert-symbol "▾ "))
          (and (equal name 'close) (funcall n-insert-symbol "▸ "))
          (and (equal name 'leaf)  (funcall n-insert-symbol "  "))))
     ((and (display-graphic-p) (equal neo-theme 'icons))
      (unless (require 'all-the-icons nil 'noerror)
        (error "Package `all-the-icons' isn't installed"))
      (setq-local tab-width 1)
      (or (and (equal name 'open)  (insert (all-the-icons-icon-for-dir-with-chevron (directory-file-name node-name) "down")))
          (and (equal name 'close) (insert (all-the-icons-icon-for-dir-with-chevron (directory-file-name node-name) "right")))
          (and (equal name 'leaf)  (insert (format "\t\t\t%s\t" (all-the-icons-icon-for-file node-name))))))
     ((and (display-graphic-p) (equal neo-theme 'nerd-icons))
      (unless (require 'nerd-icons nil 'noerror)
        (error "Package `nerd-icons' isn't installed"))
      (setq-local tab-width 1)
      (or (and (equal name 'open)  (insert (nerd-icons-icon-for-dir-with-chevron (directory-file-name node-name) "down")))
          (and (equal name 'close) (insert (nerd-icons-icon-for-dir-with-chevron (directory-file-name node-name) "right")))
          (and (equal name 'leaf)  (insert (format "\t\t\t\t%s\t" (nerd-icons-icon-for-file node-name))))))
     (t
      (or (and (equal name 'open)  (funcall n-insert-symbol "- "))
          (and (equal name 'close) (funcall n-insert-symbol "+ ")))))))

(defun nerd-icons-icon-for-dir-with-chevron (dir &optional chevron padding)
  "Format an icon for DIR with CHEVRON similar to tree based directories.

If PADDING is provided, it will prepend and separate the chevron
and directory with PADDING.

Produces different symbols by inspecting DIR to distinguish
symlinks and git repositories which do not depend on the
directory contents"
  (let ((icon (nerd-icons-icon-for-dir dir))
        (chevron (if chevron (nerd-icons-octicon (format "nf-oct-chevron_%s" chevron) :height 0.8 :v-adjust -0.1) ""))
        (padding (or padding "\t")))
    (format "%s%s%s%s%s" padding chevron padding icon padding)))

あとは

(setq neo-theme 'nerd-icons)

としておけばOK. 当然,nerd-icons はインストールしておくこと.

余談

nerd fontsの検索に便利なサイト

www.nerdfonts.com

追記

今回の記事の後にほぼ同じ修正を施したプルリクを見つけた

github.com

【Emacs】completion-preview の設定

ちなみに completion-previewEmacs 30 系に搭載予定.

最新のソースコードはこちらから。

github.com

(require 'completion-preview)

;; Enable Completion Preview mode in code buffers
(add-hook 'prog-mode-hook #'completion-preview-mode)
;; also in text buffers
(add-hook 'text-mode-hook #'completion-preview-mode)
;; also in eshell-buffers
(add-hook 'eshell-mode-hook #'completion-preview-mode)

;; and in \\[shell] and friends
(with-eval-after-load 'comint
  (add-hook 'comint-mode-hook #'completion-preview-mode))

(setq completion-preview-minimum-symbol-length 3)

;; Non-standard commands to that should show the preview:

;; Org mode has a custom `self-insert-command'
(push 'org-self-insert-command completion-preview-commands)
;; Paredit has a custom `delete-backward-char' command
(push 'paredit-backward-delete completion-preview-commands)

;; Bindings that take effect when the preview is shown:

;; Cycle the completion candidate that the preview shows
(keymap-set completion-preview-active-mode-map
            "M-n" #'completion-preview-next-candidate)
(keymap-set completion-preview-active-mode-map
            "M-p" #'completion-preview-prev-candidate)

;; Convenient alternative to C-i after typing one of the above
;; (keymap-set completion-preview-active-mode-map
;;             "M-i" #'completion-preview-insert)

(keymap-set completion-preview-active-mode-map
            "M-i" #'completion-preview-complete)

(keymap-set completion-preview-active-mode-map
            "<remap> <forward-word>" #'completion-preview-insert-word)
(keymap-set completion-preview-active-mode-map
            "<remap> <forward-sexp>" #'completion-preview-insert-sexp)

参考

eshelyaron.com

【Emacs】centaur-tabs の設定

こんな感じ.

;; 'tab タブ切り替えの単位をグループ内の「バッファ」に限定
;; 'groups タブ切り替えの単位を「グループ」に限定
(setq centaur-tabs-cycle-scope 'tabs)

;; アイコン表示
(setq centaur-tabs-set-icons t)
(setq centaur-tabs-icon-type 'all-the-icons)

;; バッファ名の代わりにグループ表示する場合
;; (setq centaur-tabs--buffer-show-groups nil)
;; (centaur-tabs-toggle-groups)

;; t: 変更され未保存のバッファにマーカーを表示する
(setq centaur-tabs-set-modified-marker t)
(setq centaur-tabs-modified-marker "●")

;; 'over: 現在選択中のタブに上線を引く
(setq centaur-tabs-set-bar 'over)

;; キーバインド
(global-set-key (kbd "C-<tab>") 'centaur-tabs-forward)
(global-set-key (kbd "C-S-<iso-lefttab>") 'centaur-tabs-backward)
(global-set-key (kbd "C-z C-s") #'centaur-tabs-switch-group)

;; 特有の関数は centaur-tabs-mode を有効にしたあとで定義する
(centaur-tabs-mode t)

;; タブを非表示にしたいバッファ
(defun centaur-tabs-hide-tab (x)
  "Do no to show buffer X in tabs."
  (let ((name (format "%s" x)))
    (or
     ;; Current window is not dedicated window.
     (window-dedicated-p (selected-window))

     ;; Buffer name not match below blacklist.
     (string-prefix-p "*epc" name)
     (string-prefix-p "*lsp" name)
     (string-prefix-p "*Flycheck" name)
     (string-prefix-p "*tramp" name)
     (string-prefix-p " *Mini" name)
     (string-prefix-p "*help" name)
     (string-prefix-p " *temp" name)
     (string-prefix-p "*Help" name)
     (string-prefix-p "*Compile-Log*" name)
     ;; (string-prefix-p "*scratch*" name)
     (string-prefix-p "*Messages*" name)
     (string-prefix-p "*Async-native-compile-log*" name)
     (string-prefix-p "*Native-compile-Log" name))))

(defun which-active-modes ()
  "Return which minor modes are enabled in the current buffer."
  (interactive)
  (let ((active-modes))
    (mapc (lambda (mode) (condition-case nil
                             (if (and (symbolp mode) (symbol-value mode))
                                 (add-to-list 'active-modes mode))
                           (error nil) ))
          minor-mode-list)
    active-modes))

;; バッファのメジャーモードに沿ってグループ化
(defun centaur-tabs-buffer-groups ()
  "`centaur-tabs-buffer-groups' control buffers' group rules."
  (list
   (cond
    ((when-let ((project-name (centaur-tabs-project-name)))
       project-name))
    ((derived-mode-p 'shell-mode) "Shell")
    ((derived-mode-p 'eshell-mode) "EShell")
    ((derived-mode-p 'emacs-lisp-mode) "Elisp")
    ((derived-mode-p 'dired-mode) "Dired")
    ((derived-mode-p 'python-ts-mode) "Python")
    ((derived-mode-p 'c-mode) "C-lang")
    ((derived-mode-p 'LaTeX-mode 'TeX-mode) "LaTeX")
    ((or (derived-mode-p 'howm-menu-mode)
         (memq 'howm-mode (which-active-modes))) "HOMW")
    ((derived-mode-p 'yaml-ts-mode 'conf-toml-mode) "Config")
    ((derived-mode-p 'org-mode 'org-agenda-mode 'diary-mode) "OrgMode")
    ((string-equal "*" (substring (buffer-name) 0 1)) "Emacs")
    (t
     (centaur-tabs-get-group-name (current-buffer))))))

;; タブを閉じるためのユーティリティ
(defun centaur-close-ace-jump (&optional arg)
  (interactive)
  (centaur-tabs-ace-action 'close-tab))

【Emacs】補完機能の運用ポリシー

1. hippie-expand (M-/)
2. completion-preview (C-i, M-i)
3. dabbrev-expand or cape-dabbrev
4. completion-at-point with corfu and hotfuzz (C-M-i)

corfu-modeはONだが corfu-auto は nil にしておく。

入力中、基本はhippie-expandで候補検索・確定する。completion-previewでお目当ての候補が表示されたら C-i で候補確定してOK。completion-previewによる補完中はM-n, M-p で他の候補を選択できる。M-iを使えばcompletion-previewの枠組みで部分補完しつつ、fallbackしてcorfuのUIで補完開始もできる。

最終手段としてC-M-iを残しておく。

【Emacs】neotreeで別タブでファイルを開くときの設定

こうする。挙動がVSCodeに近くなると思われる。キーバインドはお好みで。

(defun neo-open-file-other-tab (full-path &optional arg)
  "Open a file node in another tab.

FULL-PATH is the file path you want to open."
  (neo-global--select-mru-window arg)
  (find-file-other-tab full-path)
  (neotree-toggle))

(with-eval-after-load "neotree"
  (define-key neotree-mode-map (kbd "f")
              (neotree-make-executor :file-fn 'neo-open-file-other-tab))
)