symbolword-mode-presentation



symbolword-mode-presentation

0 0


symbolword-mode-presentation


On Github ncaq / symbolword-mode-presentation

symbolword-mode

まず言っておくことがあります

これはゲームじゃないです,

ゲームは完成しませんでした.

ごめんなさい

では,これが何なのか?

と言うと,

Emacs用の,いわゆる拡張機能です.

Emacsとは?

テキストエディタの1種です.

テキストエディタの例

  • メモ帳
  • nodepad++
  • Terapad
  • サクラエディタ
  • Kate
  • Vim

私はEmacsを便利に常用していたのですが,少し気に入らないことがありました. それは,「単語」の句切りです.

実例

+=の手前にカーソルがあることに注目してください,

ここでM-dに割り当てられた,「単語削除」コマンドを押すと,

このように,+=だけを消したくても,

;のところまで削られてしまいます.

英文の,「単語」の区切りはそれで良いのかもしれませんが,

プログラムを書いている時に,

こんな単語の区切りで嬉しいことなど何もありません.

そこで,改善をすることにしました.

プログラマの3大美徳は,'(怠惰 短気 傲慢)

Emacsには大きな特徴があります.

それは,Emacs自身が,Emacsで動くEmacs Lispで実装されているという事です.

最低限の所をC言語で実装し,他を動的実行言語で実装することで,大きな柔軟性を手に入れています.

さらに,全てのキーバインドには関数を割り当てられます.

つまり,単語関連の機能を自作してしまえば,自分の思い通りの単語移動が出来るという事です.

さて,この機能を実現するのには,一体何が必要なのか. まずこれを考えてみる.

単語の区切りを判別する 区切りまで{移動,削除}する.

判別する関数がこれです.

(defun div-symbolword-forward (currstr nextstr)
  "単語を分けるか?"
  (let ((currtype (unicode-block-type currstr))
	(nexttype (unicode-block-type nextstr)))
    (cond ((eq nexttype 'space) nil);次が空白の時は単語を分けない
     ((not (equal-syntax currstr nextstr)) t);違う意味の文字なら分ける
     ((and
       (not (or
	     (cl-find currtype *latin*)
	     (cl-find nexttype *latin*)));ラテン文字以外で,
       (not (eq currtype nexttype)))
      t);Unicode的に違う文字であるなら分ける
     ((and;自分が小文字で,次が大文字である時分ける
       (eq currtype 'downcase)
       (eq nexttype 'upcase))
      t))))
	  
lispの高い表現力が, 極めて短いコードで定義を示すことに役だっています. ここで紹介しておくと,lispにはcond式というものがあり,
(cond ((exp1) t)
      ((exp2) nil)
      ((exp3) t))
	  
(or (exp1)
    (and (not (exp2))
	 (exp3)))
	  
上と下の式は等価なものとなっています.
条件関数をcondを使わずに書いてみました.
(defun div-symbolword-forward-and (currstr nextstr)
  "単語を分けるか?"
  (let ((currtype (unicode-block-type currstr))
	(nexttype (unicode-block-type nextstr)))
    (and (not (eq nexttype 'space));次が空白の時は単語を分けない
	 (or (not (equal-syntax currstr nextstr));違う意味の文字なら分ける
	     (and (not (or
			(cl-find currtype *latin*)
			(cl-find nexttype *latin*)));ラテン文字以外で,
		  (not (eq currtype nexttype)));Unicode的に違う文字であるなら分ける
	     (and;自分が小文字で,次が大文字である時分ける
	      (eq currtype 'downcase)
	      (eq nexttype 'upcase))))))
	  
cond式を使ったものに比べると, だいぶ分かり辛くなっていますね… (lisperによってはこっちのほうが良いと言うかもしれません,実際,私はこっちを使っています.) condは,式が上から評価されてるのを分かり易くする働きがあります.
単語条件を定義したらあとは簡単. 再帰によって削除するのみです.
(defun kill-symbolword ()
  (interactive)
  (c-hungry-delete-forward)
  (kill-forward-chars (kill-symbolword-size (get-str-from-buffer) 1)))

(defun kill-symbolword-size (curr num)
  (let ((next (get-str-from-buffer-dif num)))
    (if (not (div-symbolword-forward curr next))
      (kill-symbolword-size next (incf num))
    num)))
	  
この拡張と, このプレゼンはgithubにて公開しています.
本プレゼン,「関数型言語Lispの紹介」 をご覧頂きありがとうございました.