meow + puniでevil-surroundっぽいことをする

# 背景
こんにちは。Emacsを触り始めて４～５年くらいのEmacs初心者です。
今回はmeow+puniでevil-surroundのような機能を作成し、キーに割り当ててみるといい感じだったので記事にしました。
また、新しい試みでChatGPTで記事を生成して多少の手直しをして貼り付けてみました。


# meow + puniでevil-surroundっぽいことする

Emacsを使っていて、コード編集の効率を向上させる方法として、Vimの`evil-surround`を使ったことがある方も多いでしょう。本記事では、Emacs用のモーダル編集モードである`meow`と、リスト操作に特化した`puni`を組み合わせて、`evil-surround`に似た機能を実現する方法をご紹介します。

---

## evil、meow、puniの簡単な解説

### evil
`evil`は、EmacsでVimライクな操作を可能にするモードです。`evil-surround`はその拡張機能の一つで、テキストの周囲に括弧やクォートなどを追加・削除する操作を簡単にします。

### meow
`meow`は、Emacs用のモーダル編集モードで、直感的で簡単にカスタマイズ可能な操作体系を提供します。特に、キー設定が簡単で、`evil`よりもシンプルで軽量です。

#### meowの利点
- **シンプルでカスタマイズ性が高い**: キーバインドの設定がわかりやすく、拡張が容易です。
- **軽量**: 必要な機能だけを絞り込んで動作させられるため、パフォーマンスが良好。
- **Emacsらしさを重視**: Emacsの哲学に沿った設計で、Vimに過度に依存しません。

### puni
`puni`は、括弧やリストを扱う際に便利なEmacsパッケージです。セックスピー（S式）を意識した操作を提供し、括弧で囲む、括弧を削除する、括弧を入れ替えるといった操作が容易です。

---

## meow + puniでevil-surroundの機能を実装する

以下では、`meow`と`puni`を組み合わせて、文字列や括弧で囲む操作を`evil-surround`風に実現する設定をご紹介します。

### 設定例

実際の設定は下記の通りです。

```emacs-lisp
(use-package puni
  :config
  (defun puni-wrap-dobule-quote (&optional n)
    (interactive "P")
    (puni-wrap-next-sexps
     (puni--parse-interactive-argument-for-wrap n)
     "\"" "\""))

  (defun puni-wrap-single-quote (&optional n)
    (interactive "P")
    (puni-wrap-next-sexps
     (puni--parse-interactive-argument-for-wrap n)
     "'" "'"))

  (defun puni-wrap-back-quote (&optional n)
    (interactive "P")
    (puni-wrap-next-sexps
     (puni--parse-interactive-argument-for-wrap n)
     "`" "`"))

  (defun puni-wrap-~ (&optional n)
    (interactive "P")
    (puni-wrap-next-sexps
     (puni--parse-interactive-argument-for-wrap n)
     "~" "~"))

  (defun puni-wrap-= (&optional n)
    (interactive "P")
    (puni-wrap-next-sexps
     (puni--parse-interactive-argument-for-wrap n)
     "=" "="))

  (defun puni-wrap-+ (&optional n)
    (interactive "P")
    (puni-wrap-next-sexps
     (puni--parse-interactive-argument-for-wrap n)
     "+" "+"))

  (defun puni-wrap-- (&optional n)
    (interactive "P")
    (puni-wrap-next-sexps
     (puni--parse-interactive-argument-for-wrap n)
     "-" "-"))

  (with-eval-after-load 'meow
    (meow-normal-define-key
     '("S {" . puni-wrap-curly)
     '("S }" . puni-wrap-curly)
     '("S [" . puni-wrap-square)
     '("S ]" . puni-wrap-square)
     '("S (" . puni-wrap-round)
     '("S )" . puni-wrap-round)
     '("S <" . puni-wrap-angle)
     '("S >" . puni-wrap-angle)
     '("S '" . puni-wrap-single-quote)
     '("S \"" . puni-wrap-dobule-quote)
     '("S `" . puni-wrap-back-quote)
     '("S ~" . puni-wrap-~)
     '("S =" . puni-wrap-=)
     '("S +" . puni-wrap-+)
     '("S -" . puni-wrap--)))

  (puni-global-mode +1))
```
### 解説

evilはキーの割当をvimに近づけるよう自動的にキーを割り当ててくれますが、meowは自分で設定する必要があります。
一から設定するとしんどいので、[こちら](https://github.com/meow-edit/meow/blob/master/TUTORIAL.org#keybindings-cheat-sheet)をベースにキーを設定し、自分好みにカスタマイズしていくようになります。
`meow-normal-define-key`はnormalモード中に使用するキーで今回はこの関数でsurround用のキーを割り当てます。

ちなみに私はなるべくVimに近づけるようにしています。[こんな感じ](https://qiita.com/nobuyuki86/items/122e85b470b361ded0b4#meow)。
大文字のSが空いていたので、私はそこに今回のキーを割り当てました。

### 操作例

1. 範囲選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696232/7b5acdeb-76f3-4950-743f-4e98304938ff.png)

2. `S (`を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696232/605fc0db-0d0e-7aee-8625-907954a988fb.png)

3. `, r`で範囲選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696232/3d2b162e-04d4-cd7f-9108-bf9d6bf4dc1e.png)

4. `S "`を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696232/9bc2056c-009d-2e58-f761-81a6b63067a5.png)

5. カーソルを合わせるだけでも利用できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696232/df66fbe2-1ff4-dde0-392b-2536fbe11c3c.png)

6. `S -`を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696232/7476f60d-0a0b-1328-1796-8b2373dac97b.png)

# 終わりに

記事の作成にChatGPTを利用してみましたが、手軽に記事が作成できてよかったです。
もっと良い実装方法などがあればぜひ教えていただきたいです。