テンプレート挿入・展開に便利なパッケージ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)))