テンプレート挿入・展開に便利なパッケージTempel がある.
公式を参考に,設定はこんな感じ.テンプレート展開の部分キーワードを入力して M-+
でテンプレートが展開するので便利である.
また「ここにテンプレートを展開したい」と思ったところで M-*
でテンプレートを選択して展開することもできる.
;; テンプレート展開をトリガーするためのプレフィックス ;; テンプレート挿入モードに入るためのキー,という認識 ;; デフォルトはnil,つまり地のソースコードとテンプレート挿入の境界がない ;; (setq tempel-trigger-prefix "<") (global-set-key (kbd "M-+") 'tempel-complete) ;; テンプレートキーワード途中までの入力内容で補完し,挿入 (global-set-key (kbd "M-*") 'tempel-insert) ;; 何も書かれていないところにテンプレート挿入 ;; completion-at-point にテンプレート展開を追加 (defun tempel-setup-capf () (setq-local completion-at-point-functions (cons #'tempel-expand ;; exact match; キーワードに厳密にマッチしたときに発動 completion-at-point-functions))) ;; テンプレート展開を適用するメジャーモードを指定 (add-hook 'prog-mode-hook 'tempel-setup-capf) ;; プログラミング系全般 (add-hook 'text-mode-hook 'tempel-setup-capf) ;; eglotやcapeと連携させる例 ;; tempel-complete にすると入力途中でもテンプレート候補が出てくるようになる ;; (defun tempel-setup-capf () ;; (setq-local completion-at-point-functions ;; (list (cape-capf-super ;; #'tempel-complete ;; #'eglot-completion-at-point) ;; #'cape-keyword ;; #'cape-dabbrev ;; #'cape-file))) ;; (add-hook 'eglot-managed-mode-hook #'tempel-setup-capf) ;; このとき,(add-hook 'prog-mode-hook 'tempel-setup-capf) は余分なのでコメントアウトしておくこと ;; フィールド移動のキーバインドを追加 (with-eval-after-load "tempel" (define-key tempel-map (kbd "<tab>") #'tempel-next) (define-key tempel-map (kbd "C-i") #'tempel-next) (define-key tempel-map (kbd "<backtab>") #'tempel-previous) (define-key tempel-map (kbd "C-S-i") #'tempel-previous) (define-key tempel-map (kbd "C-<tab>") #'tempel-previous))
tempel自体はテンプレート展開の枠組みを提供しているだけなので,テンプレートは自分で用意しなければならない.
足りないものは自分でテンプレートを書いて追加していけばよい.例えばC言語の場合は以下のようなテンプレートを書いておくのも良いだろう.記述のルールはTempelの公式リポジトリに書いてあり,簡単である.
オリジナルのテンプレートファイルの置き場所は ~/.emacs.d/templates
となっている. (2024/06/29)
c-mode (io "#include <stdio.h>" n) (lib "#include <stdlib.h>" n) (str "#include <string.h>" n) (math "#include <math.h>" n) (main "int main(int argc, const char *argv[]) {"n> q n> "return 0;" n "}") (for "for (" (p "i") "; " p "; " p ") {"n> q n "}" >) (switch "switch (" p ") {"n> "case " (p "1") ":" n> q n> "break;\n" "\t\tdefault:"n >n "break;"> n "}" >) (while "while (" p ") {"n> q n "}" >) (struct "struct " p " {" n> q n "};") (printf "printf(\"" p "\\n\"" p ");" q) (scanf "scanf(\"" p "\", " p ");" q)
pythonだとこんな感じだろうか.
python-ts-mode (for "for " p " in " p ":" n> q) (from "from " p " import " q) (if "if " p ":" n> q) (ife "if " p ":" n> p n> "else:" n> q) (ifmain "if __name__ == '__main__':" n> q) (import "import " p q) (init "def __init__(self" p "):" n> q) (init_docstring "def __init__(self" p "):" n> "\"\"\"" p "\"\"\"" n> q) (np "import numpy as np" n> q) (main "def main():" n> q) (method "def " p "(self" p "):" n> q) (while "while " p ":" n> q) (class "class " p "(" p "):" n> q)
eglot-completion-at-point
を completion-at-point-functions
に含めるとヒットする補完候補が多すぎるケースがしばしばあるので,tempel-setup-capf
を少し修正して思い切って制限するのもアリ.
(defun tempel-setup-capf () (setq-local completion-at-point-functions (list #'tempel-complete #'cape-keyword #'cape-dabbrev #'cape-file)))