Cunning-mode.el - insert fixed sentence with indent

From Usipedia
Jump to: navigation, search

定型文を適切にインデントしながら挿入するメジャーモードです.

※現在ではsnippet.elやyasnippet.elなどを使った方が幸せになれます.

Author Naoki Ishikawa (tetuet_at_gmail.com)
Keywords programming, c++
Created 2008-11-9
Compatibility Emacs 21.4, Meadow 2.11

Contents

スクリーンショット

詳しい説明

cunning-mode.el はチーター(笑)向けのプログラミングを補助するためのメジャーモードで, 事前に登録した文をインデント(indent-for-tab-command)しながら挿入します.

登録文の中に @ があれば,挿入時にどんな文字で置換したいのか質問します. $ があれば,挿入後に $ のあった位置にカーソルを移動します.

 ;; キー定義テーブルのサンプル
 ;; @ と $ に注目して下さい
 (setq cunning-table-fre '(("m" "int main(void){\n$\n\nreturn 0\;\n}")
                           ("f" "freopen(\"@\", \"r\", stdin);\n$")
                           ("p" "@.push_back(@);$")))

挿入時の質問・選択をミニバッファで行うか,別のバッファで行うか,定義時に選択する事ができます.

 ;; ミニバッファで質問・選択
 (define-key map "\M-1" '(lambda () (interactive) (cunning-mode-ask-minibuffer table nil)))
 ;; 別バッファで質問・選択
 (define-key map "\M-2" '(lambda () (interactive) (cunning-mode-ask-buffer table nil)))

cunning-mode.el は高校の授業の一環として製作されました. その授業において用いたプレゼンテーションをここで公開しておきます.

※右キーを押して何も反応がなかったら多分そのブラウザには対応していません. ブラウザを変更して下さい.

ソースコード

cunning-mode.el

;;; cunning-mode.el --- insert fixed sentence with indent
;;-------------------------------------------------------------------
;;
;; This file is NOT part of Emacs.
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2 of
;; the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be
;; useful, but WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE.  See the GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public
;; License along with this program; if not, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA
;;
;;-------------------------------------------------------------------
 
;; Author: Naoki Ishikawa <tetuet_at_gmail.com>
;; Keywords: programming, c++
;; Created: (2008-9-24 to) 2008-11-9
;; Compatibility: Emacs 21.4, Meadow 2.11
;; URL(jp): http://d.hatena.ne.jp/teturouet/
;;          http://tetuet.is-mine.net/cunning-mode.html
 
;; (require 'cunning-mode)
;; (global-set-key "\C-c\C-f" 'cunning-mode)
;; (global-set-key "\C-c\C-n" 'normal-mode)
 
;;; Code:
 
(require 'cl)
 
(defgroup cunning-mode nil
  "insert fixed sentence with indent"
  :prefix "cunning-mode-"
  :group 'programming)
 
(defvar cunning-mode-map nil)
(defvar cunning-mode-load-paths '("~/.cunning-mode" "./.cunning-mode"))
 
;;;###autoload
(defun cunning-mode ()
  "メジャーモードとして定義する"
  (interactive)
  (use-local-map cunning-mode-map)
  (setq major-mode 'cunning-mode
        mode-name "cunning-mode")
  (run-hooks 'cunning-mode-hook)
  (cunning-mode-load)
  (message "cunning-mode.el on"))
 
(defun cunning-mode-load ()
  "可能性のある設定ファイルを全て読み込む"
  (interactive)
  (dolist (path cunning-mode-load-paths)
    (when (file-exists-p path)
      (load-file path))))
 
(defun cunning-mode-insert (str &optional point-func)
  "-point-func が設定されているなら
そこに移動してから挿入,元のところに戻る
-設定されてないなら
挿入して$の位置に移動して,1行の中に$しかなかったりしたら back-to-indentation"
  (interactive)
  (if point-func
      (save-excursion (goto-char (funcall point-func))
                      (cunning-mode-insert-subs str))
    (progn (goto-char (cunning-mode-insert-subs str))
           (when (bolp)
             (back-to-indentation)))))
 
(defun cunning-mode-insert-subs (str)
  "str を解釈しながら挿入して、$のあるポイントを返す。
-解釈とは
@ が含まれているなら,read-from-minibuffer に置換
$ が含まれているなら,そこを mark-point として記録し$削除
-挿入とは
insert の後に indent-for-tab-command
最後の行以外なら改行
-愚痴
確定した文字はリアルタイムに挿入したいけど、そうするとプログラムがすごく読みにくくなる。
結局 minibuffer に表示して妥協した"
  (interactive)
  (let ((line 1)
        (mark-point 0)
        (split (split-string str "\n")))
    (dolist (s split)
      (while (numberp (string-match "@" s))
        (setq s (replace-match (read-from-minibuffer (substring s 0 (string-match "@" s))) nil nil s nil)))
      (while (numberp (string-match "\\$" s))
        (setq mark-point (+ (point) (string-match "\\$" s))
              s (replace-match "" nil nil s nil)))
      (progn (insert (format "%s" s))
             (indent-for-tab-command)
             (if (< line (length split)) (insert "\n")))
      (incf line))
    mark-point))
 
(defun cunning-mode-ask-buffer (table &optional point-func)
  "table を別バッファに表示し,そこから要素を選択・挿入する
ここでは buffer と window の処理を担当し,キー選択,挿入処理は key-to-insert へ渡している
-memo
truncate-lines: 画面端での自動改行を無効にする"
  (interactive)
  (let ((buffer (get-buffer-create "*list-sentence*"))
        (truncate-lines t))
    (progn (split-window-horizontally (- (cdr (assoc 'width (frame-parameters))) 50))
           (set-buffer buffer)
           (erase-buffer)
           (cunning-table-to-buffer table)
           (display-buffer buffer)
           (other-window 1)
           (goto-char (point-min)))
    (cunning-mode-key-to-insert table point-func '(other-window 1))
    (progn (delete-window)
           (kill-buffer buffer))))
 
(defun cunning-mode-ask-minibuffer (table &optional point-func)
  "table を minibuffer に表示し,そこから要素を選択,挿入する。
既存の関数と無理に合わせたので汚い。実質複雑なキーバインド定義。"
  (interactive)
  (cunning-mode-key-to-insert table point-func nil (cunning-table-to-minibuffer table)))
 
(defun cunning-table-to-buffer (table)
  "table を current-buffer に整形して挿入する
一覧して見れるように改行は半角スペースに置換
mapcarは直感的に分かるから良い"
  ;; (setq table cunning-table-fre)
  (mapcar '(lambda (a)
             (while (numberp (string-match "\n" a))
               (setq a (replace-match " " nil nil a nil)))
             (insert a "\n"))
          (mapcar '(lambda (a)
                     (concat (car a) " : " (cadr a)))
                  table))
  (insert "q : quit"))
 
(defun cunning-table-to-minibuffer (table)
  "table を minibuffer に整形して表示する。
minibuffer が横に伸びると嫌なので,最初の改行より後は切り捨てる。
たくさんの要素が登録されたキー定義テーブルは渡さない方がいい。
見ずらいから concat と format のどっちかに統一しろよ > 俺"
  ;; (setq table cunning-table-fre)
  (let ((out ""))
    (mapcar '(lambda (a)
               (setq out (concat out
                                 (if (< (length a) 20)
                                     (substring a 0 (string-match "\n" a))
                                   (substring a 0 20))
                                 "    ")))
            (mapcar '(lambda (a)
                       (format "%s:%s" (car a) (cadr a)))
                    table))
    (setq out (concat out "q:quit"))
    (message out)))
 
(defun cunning-mode-key-to-insert (table point-func &optional insert-zengo-func &optional mes)
  "read-char を元に table の該当要素を cunning-mode-insert する。
insert-zengo-func があるなら cunning-mode-insert の前後でそれを実行する。
一度起動したら q で終了しない限り動きけ,table に無いキーが押されたらエラーを出す。"
  (loop (let ((in (read-char)))
          (when mes (message mes))
          (setq out (cadr (assoc (string in) table)))
          (cond ((= in ?q) (message "quit") (return))
                ((eq out 'nil) (message (format "%s is not defined." (string in))))
                (t (when insert-zengo-func (eval insert-zengo-func))
                   (cunning-mode-insert out point-func)
                   (when insert-zengo-func (eval insert-zengo-func)))))))
 
(defun cunning-mode-point-end-of-tk ()
  "{ の終了しているポイントへ移動する
forward-list, end-of-defun で代用出来そうだけど無理だった
{□←ここにカーソルがある状態で実行して下さい"
  (let ((hit-count 1))
    (while (> hit-count 0)
      (re-search-forward "[{|}]" nil t)
      (let ((hit (char-after (- (point) 1))))
        (when (= hit ?{) (incf hit-count))
        (when (= hit ?}) (decf hit-count))))
    (point)))
 
(defun cunning-mode-point-include ()
  "#include の挿入位置を調べる"
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "#include.*<.*>\n" nil t))
    (point)))
 
(defun cunning-mode-point-define ()
  "#define の挿入位置を調べる"
  (save-excursion
    (goto-char (cunning-mode-point-include))
    (while (re-search-forward "#define.*\n" nil t))
    (point)))
 
(defun cunning-mode-point-using ()
  "using namespace の挿入位置を調べる"
  (save-excursion
    (goto-char (cunning-mode-point-define))
    (while (re-search-forward "using namespace.*\n" nil t))
    (point)))
 
(defun cunning-mode-point-class ()
  "class の挿入位置を調べる"
  (save-excursion
    (goto-char (cunning-mode-point-using))
    (while (re-search-forward "class.*\n" nil t))
    (re-search-forward "};\n" nil t)
    (point)))
 
(defun cunning-mode-point-beginning-of-main ()
  "main が開始しているポイント"
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "^[void|int].*main(.*).*{" nil t))
    (- (point) (current-column))))
 
(defun cunning-mode-point-end-of-main ()
  "main が終了しているポイント"
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "^[void|int].*main(.*).*{" nil t))
    (re-search-forward "^}\n" nil t) ; ←[これはひどい]ソースが適切にインデントされていなければ誤った結果を返す
    (+ (point) 1)))
 
(provide 'cunning-mode)
 
;;; cunning-mode.el ends here

dot.cunning-mode

;;; dot.cunning-mode --- cunning-mode.el init file sample    -*- emacs-lisp -*-
;;-------------------------------------------------------------------
 
;;; Commentary:
;; ぼくのかんがえたさいきょうせっていファイル
;; 注:) コードの無断引用を避けるため,作者が書いたしょぼいC++プログラムしか登録されていません。
;; どんどん追加していって下さい
 
;;; Code:
 
;; key-chord.el - キーの同時押し入力をサポート
;; 「for 文が欲しいから f と o を同時押し」なんて事が可能です
(require 'key-chord)
(setq key-chord-two-keys-delay 0.05)
(key-chord-mode 1)
 
;; キー定義テーブル
;; ミニバッファとか別バッファに一覧で表示出来ます
(setq cunning-table-fre '(
                          ("m" "int main(void){\n$\n\nreturn 0\;\n}")
                          ("f" "freopen(\"@\", \"r\", stdin);\n$")
                          ("p" "@.push_back(@);$")
                          ))
 
(setq cunning-table-include '(
                              ("i" "#include <iostream>\n$")
                              ("a" "#include <algorithm>\n$")
                              ("f" "#include <functional>\n$")
                              ("t" "#include <iterator>\n$")
                              ("n" "#include <numeric>\n$")
                              ("s" "#include <string>\n$")
                              ("b" "#include <bitset>\n$")
                              ("v" "#include <vector>\n$")
                              ("m" "#include <map>\n$")
                              ("e" "#include <set>\n$")
                              ("l" "#include <list>\n$")
                              ("r" "#include <fstream>\n$")
                              ("c" "#include <complex>\n$")
                              ("Q" "#include <queue>\n$")
                              ("d" "#include <deque>\n$")
                              ("u" "using namespace std;\n$")
                              ))
 
(setq cunning-table-define '(
                             ("a" "#define ALL(c) (c).begin(), (c).end()\n$")
                             ("d" "#define DEBUG(c) cerr<<\"> \"<<#c<<\" = \"<<c<<endl;\n$")
                             ("p" "#define PI (acos(0.0) * 2.0)\n$")
                             ("e" "#define E (2.7182818284)\n$")
                             ("r" "#define REP(i,n) for(int i=0;i<(int)n;++i)\n$")
                             ("f" "#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)\n$")
                             ))
 
(setq cunning-table-class '(
                            ("p" 
                             "class pos {
public:
int x, y;
pos(){ x = 0; y = 0; }
pos(int a, int b){ x = a; y = b; }
void put(void){ cout << x << \" \" << y << endl; }
void operator=(const pos& p){ x = p.x; y = p.y; }
int operator==(const pos& p){ return (x == p.x && y == p.y); }
int operator!=(const pos& p){ return !(x == p.x && y == p.y); }
pos operator-(const pos& p){ return pos(x - p.x, y - p.y); }
pos operator+(const pos& p){ return pos(x + p.x, y + p.y); }
};\n$")
                            ("g" 
                             "class pos{
public:
double x, y, z;
double t, p, d;
pos(double i, double k, double m){
t = (i/180)*PI;
p = (k/180)*PI;
d = m;
x = d * sin(t) * cos(p);
y = d * sin(t) * sin(p);
z = d * cos(t);
}
void put(void){
cout << \"(x, y, z) = (\" << x << \", \" << y << \", \" << z << \")\" << endl;
cout << \"(θ, φ)[rad] = (\" << t << \", \" << p << \")\" << endl;
}
double sc(void){
return sqrt(pow(x, 2.0) + pow(y, 2.0) + pow(z, 2.0));
}
double operator*(const pos& p){
return x*p.x + y*p.y + z*p.z;
}
};\n$")
                            ))
 
(setq cunning-table-function '(
                               ("g"
                                "// 最大公約数
int gcd(int m, int n){
	if((0 == m) || (0 == n)) return 0;
	while(m != n){
		if(m > n) m = m - n;
        else n = n - m;
	}
	return m;
}\n\n$")
                               ("l"
                                "// 最小公倍数
int lcm(int m, int n){
	if((0 == m) || (0 == n)) return 0;
	return ((m / gcd(m, n)) * n);
}\n\n$")
                               ("i"
                                "// 閏年かどうか判定
int is_leap_year(int year){
	return (0 == (year % 400)) || ((0 != (year % 100)) && (0 == (year % 4)));
}\n\n$")
                               ))
 
 
;; キーバインド定義
(unless cunning-mode-map
  (let ((map (make-keymap)))
    ;; 対応した括弧等を既存のキーバインドを上書きする(慣れないとうざったいのでデフォルト無効)
    (define-key map "{" '(lambda () (interactive) (cunning-mode-insert "{\n$\n}")))
;;     (define-key map "(" '(lambda () (interactive) (cunning-mode-insert "($)")))
;;     (define-key map "\[" '(lambda () (interactive) (cunning-mode-insert "\[$\]")))
;;     (define-key map "\"" '(lambda () (interactive) (cunning-mode-insert "\"$\"")))
;;     (define-key map "'" '(lambda () (interactive) (cunning-mode-insert "'$'")))
    ;; キー定義テーブル → ミニバッファ
    (define-key map "\M-s" '(lambda () (interactive) (cunning-mode-ask-minibuffer cunning-table-fre nil)))
    ;; キー定義テーブル → 別バッファ
    ; INclude
    (key-chord-define map "in" '(lambda () (interactive)
                                  (cunning-mode-ask-buffer cunning-table-include 'cunning-mode-point-include)))
    ; DeFine
    (key-chord-define map "df" '(lambda () (interactive)
                                  (cunning-mode-ask-buffer cunning-table-define 'cunning-mode-point-define)))
    ; CLass
    (key-chord-define map "cl" '(lambda ()
                                  (interactive) (cunning-mode-ask-buffer cunning-table-class 'cunning-mode-point-class)))
    ; FUnction
    (key-chord-define map "fu" '(lambda ()
                                  (interactive) (cunning-mode-ask-buffer cunning-table-function 'cunning-mode-point-before-main)))
 
    ;; 同時押し
    ; JK (とりあえず押しやすい位置,と,覚えやすさ)
    (key-chord-define map "jk"
                      '(lambda () (interactive) 
                         (cunning-mode-insert "#include <iostream>\n$")
                         (cunning-mode-insert "using namespace std\;\n$")
                         (cunning-mode-insert "int main(void){\n$\n\nreturn 0\;\n}")))
    ; Common Input/Output
    (key-chord-define map "ci" '(lambda () (interactive) (cunning-mode-insert "cin >> $\;")))
    (key-chord-define map "co" '(lambda () (interactive) (cunning-mode-insert "cout << $ << endl\;")))
    ; FOr Normal/J/K/L/M
    (key-chord-define map "fn" '(lambda () (interactive) (cunning-mode-insert "for(@\; @\; @){\n$\n}")))
    (key-chord-define map "fo" '(lambda () (interactive) (cunning-mode-insert "for(int i = 0\; i < @\; i++){\n$\n}")))
    (key-chord-define map "fj" '(lambda () (interactive) (cunning-mode-insert "for(int j = 0\; j < @\; j++){\n$\n}")))
    (key-chord-define map "fk" '(lambda () (interactive) (cunning-mode-insert "for(int k = 0\; k < @\; k++){\n$\n}")))
    (key-chord-define map "fl" '(lambda () (interactive) (cunning-mode-insert "for(int l = 0\; l < @\; l++){\n$\n}")))
    (key-chord-define map "fm" '(lambda () (interactive) (cunning-mode-insert "for(int m = 0\; m < @\; m++){\n$\n}")))
    ; IF
    (key-chord-define map "if" '(lambda () (interactive) (cunning-mode-insert "if(@){\n$\n}")))
    ; WHile
    (key-chord-define map "wh" '(lambda () (interactive) (cunning-mode-insert "while(@){\n$\n}")))
    ; FrEopen
    (key-chord-define map "fe" '(lambda () (interactive) (cunning-mode-insert "freopen(\"@\", \"r\", stdin);\n$")))
    ; PUsh_back
    (key-chord-define map "pu" '(lambda () (interactive) (cunning-mode-insert "@.push_back(@);$")))
    (setq cunning-mode-map map)))
 
;;; dot.cunning-mode ends here

更新状況

  • [2008/9/9] cunning-mode.el 0.1 公開
  • [2010/3/17] usi3.com に移転
  • [2011/2/24] PukiwikiからMediaWikiに移転
Namespaces
Variants
Views
Actions
Categories