Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2010-12-01

prognを活用しよう(Emacs Advent Calendar jp:2010)

| 11:21 | prognを活用しよう(Emacs Advent Calendar jp:2010) - わだばLisperになる を含むブックマーク はてなブックマーク - prognを活用しよう(Emacs Advent Calendar jp:2010) - わだばLisperになる

こんにちは、今年もEmacs Advent Calendarの季節です!

Emacsのちょっとした便利機能を紹介しようと思って色々考えたのですが、誰でも使えそうなtipsということで、今回は、.emacsを設定したい編集したりする際に便利に使えそうな progn の使い方を紹介したいと思います。

.emacsに色々設定を追加していくと、関連する項目をまとめたくなることがあります。

そういう時は、

;;; モードラインの時刻表示関係 ===================

;;  24時間表示にする
(setq display-time-24hr-format t)
(setq display-time-day-and-date t)
(display-time)

;;; 設定その101 ================================

という風に見出しを付けて編集しやすくしたりすると思うのですが、ここで、progn を使って関連の項目を一つの式にまとめると便利です。

prognでまとめると

(progn
  ;; モードラインの時刻表示関係 ==================

  ;;  24時間表示にする
  (setq display-time-24hr-format t)
  (setq display-time-day-and-date t)
  (display-time))

という風になります。

最大のメリットは、Emacsには、S式の編集支援機能が豊富にあるので、例えばC-M-kでまとめて切り取りが簡単にできるようになったりするところです。

この強力な編集機能が、散らかった.emacs整理に力を発揮するのです!

年末の.emacsの整理に progn いかがでしょうか。

2010-10-17

EmacsのBackward Up Listの動きが気に入らない(2)

| 23:48 | EmacsのBackward Up Listの動きが気に入らない(2) - わだばLisperになる を含むブックマーク はてなブックマーク - EmacsのBackward Up Listの動きが気に入らない(2) - わだばLisperになる

昨日のコードだと

(("foo\"''\"\"\"\"((((((\"\"))))))\"\"\"\"\"\"\"\"\"\"\"BARBAZ"))

のような場合に上手く動かないのでちょっと修正。何も考えず直前のダブルクォートを見ていただけだったので、ダブルクォートがエスケープされている場合に意図しない動きになっていました…。

(defun up-list-or-string (&optional arg)
  (interactive "^p")
  (or arg (setq arg 1))
  (let ((inc (if (> arg 0) 1 -1))
        (in-string-p (in-string-p)))
    (cond (in-string-p
           (let* ((in-string-p (char-to-string in-string-p))
                  (p (search-backward in-string-p)))
             (while (string= "\\" (buffer-substring (1- p) p))
               (setq p (search-backward in-string-p))))
           (setq arg (- arg inc))
           nil)
          ('T (while (/= arg 0)
                (goto-char (or (scan-lists (point) inc 1) (buffer-end arg)))
                (setq arg (- arg inc)))))))

2010-10-16

EmacsのBackward Up Listの動きが気に入らない

| 22:30 | EmacsのBackward Up Listの動きが気に入らない - わだばLisperになる を含むブックマーク はてなブックマーク - EmacsのBackward Up Listの動きが気に入らない - わだばLisperになる

自分は、EmacsではLISPコード編集に限らずS式編集のキーバインドを良く使う程、S式編集のキーバインドが好きなのですが、backward-up-listの動きがどうも気に入りません。

具体的には、文字列の上で実行するとエラーになってしまうのが気に入らないポイントです。

LispマシンのエディタだったZmacs(Zwei)では、文字列の上で実行すると両端のダブルクォートを括弧と見做したような動きになります。

こっちの方が快適なのでこの動きをデフォルトにしてみたいところ。

とりあえず、Zweiはどうやっているのかソースを眺めてみることにしてみました。

(DEFCOM COM-BACKWARD-UP-LIST "Move up one level of list structure, backward.
Also, if called inside of a string, moves back up out of that string." (KM)
  (LET ((BP (IF (LISP-BP-SYNTACTIC-CONTEXT (POINT))
                (FORWARD-UP-STRING (POINT) (NOT (MINUSP *NUMERIC-ARG*)))
                (FORWARD-SEXP (POINT) (- *NUMERIC-ARG*) NIL 1))))
    (OR BP (BARF))
    (MOVE-BP (POINT) BP))
  DIS-BPS)

あまり良く分かりませんが、関数の名前からすると、どうやら括弧だけでなく、ポイントが文字列の上にあった場合のことも考えていたようです。

Emacsの実装ですが、

(defun backward-up-list (&optional arg)
  "Move backward out of one level of parentheses.
With ARG, do this that many times.
A negative argument means move forward but still to a less deep spot.
This command assumes point is not in a string or comment."
  (interactive "^p")
  (up-list (- (or arg 1))))

(defun up-list (&optional arg)
  "Move forward out of one level of parentheses.
With ARG, do this that many times.
A negative argument means move backward but still to a less deep spot.
This command assumes point is not in a string or comment."
  (interactive "^p")
  (or arg (setq arg 1))
  (let ((inc (if (> arg 0) 1 -1)))
    (while (/= arg 0)
      (goto-char (or (scan-lists (point) inc 1) (buffer-end arg)))
      (setq arg (- arg inc)))))

のようになっています。

これをちょっと改造して、ポイントが文字列中にあった場合にも対応してみました

(defun zwei-backward-up-list (&optional arg)
  "Move up one level of list structure, backward.
Also, if called inside of a string, moves back up out of that string."
  (interactive "^p")
  (up-list-or-string (- (or arg 1))))

(defun up-list-or-string (&optional arg)
  (interactive "^p")
  (or arg (setq arg 1))
  (let ((inc (if (> arg 0) 1 -1))
        (in-string-p (in-string-p)))
    (cond (in-string-p
           (search-backward (char-to-string in-string-p))
           (setq arg (- arg inc))
           nil)
          ('T (while (/= arg 0)
                (goto-char (or (scan-lists (point) inc 1) (buffer-end arg)))
                (setq arg (- arg inc)))))))

(define-key global-map [(control meta ?u)] 'zwei-backward-up-list)

モードによって依然としてエラーになりますが、プログラミングモード以外は文字列というものがないようなので、これはこれで良いかなということで放置。

割と快適になりました。

各Emacs系エディタでのBackward Up Listの動作

他のエディタはどういう風になっているのかなということで無駄に調べてみました

エディタ文字列中で実行された場合の動作
GNU Emacs括弧の対応でエラー
Xyzzy括弧の対応でエラー
オリジナル Emacs(tecoの実装)じっとして動かない
LispWorksのエディタじっとして動かない
Zwei/Zmacsダブルクォートの先頭に移動する
Allegro CLのIDEのエディタダブルクォートは無視して外の括弧へ飛ぶ
Hemlock/CMUCLダブルクォートは無視して外の括弧へ飛ぶ

どうも3種類位のバリエーションがあるようですね。

個人的にはやはりZweiの動きが一番好きです。

2009-09-21

electric-shift-lock-mode

| 23:52 | electric-shift-lock-mode - わだばLisperになる を含むブックマーク はてなブックマーク - electric-shift-lock-mode - わだばLisperになる

70年代後半位までLISPのソースは大文字で書かれているものが多いのですが、70年代後半に登場したLispマシンのエディタ(ZWEI/Zmacs)にも、そんな時代を反映した、Electric Shift Lockという機能があります。

これは、CAPSキーをオンにしてくれるようなモードで、Shiftを押さない状態が大文字、逆にShiftを押すと小文字というモードです。

気が効いているのは、文字列やコメント等、大文字と小文字を区別する必要がある場所では、通常通りShift押下で大文字になるというところ。

;; foo
(DEFUN FOO (N)
  "foo"
  (LIST N))

こんな感じのがすらすら簡単に書けます。

以前からEmacs上で自作してみたかったのですが、連休中にちょっと挑戦してみようと思いたちました。

しかし、既に前に同じものがあったら嫌だなあと思い、念の為ググってみたら、ずばりを見付けてしまいました(笑)

John Paul Wallingtonさんが、去年の5月に作られていたようです。こんなニッチすぎるところに目をつけるとは…。世界は狭い。

しかし、どうもWallingtonさん作の挙動は、Shiftを押しても小文字は出ず、全部大文字になるようです。

連休中は、ぼーっとこの辺りをLispマシン風の挙動に変えてみたいです。

いまどき大文字でコードを書くということも少ないですが、気分を変えて大文字ベースで書いてみるのも一興かもしれません。

SQLでなんとなくこのモードが使えるかと思ったりもしますが、微妙な気もします。

2009-09-11

続・lisp-modeと表示の畳み込み

| 00:09 | 続・lisp-modeと表示の畳み込み - わだばLisperになる を含むブックマーク はてなブックマーク - 続・lisp-modeと表示の畳み込み - わだばLisperになる

前回、outline-modeについてつらつらと書いたところ、

Chaton CL部屋でd:id:lequeさんに

S 式の折り畳みなんですが hs-minor-mode はどうでしょう

とhs-minor-modeを教えてもらいました。

hs-minor-modeは畳み込み専用のモードらしく、色々カスタマイズもできるようです。

これは良さそうな予感!

早速、minor-modeなので、slimeと共存させてみます。

(defun foo ()
 :foo)

というところで、

M-x hs-toggle-hiding

すると、

...

となります。

…あれ、

(defun foo ...

みたいになるということでしたが…。

ちょっとググってみたところでは、この現象は、自分が利用しているEmacs 23.50.1のバグらしいことが判明しました。

ということで、最新のCVS版をインストールして試してみたところ

(defun foo ()...)

という風に良い感じに表示されるようになりました。

これより以前のhs-minor-modeでは、

(defun foo ...

と表示されていたということなので、今回のバグフィックスのついでに改善されたのかもしれません。

また、

というものも見つけたので、これも併用。

左端に折り畳める印が出て、これをマウスでクリックすると折り畳みを開閉できます。

  • 開いた状態

http://gyazo.com/16cafe3296882bc0f82656cbf043f797.png

  • ポチッと閉じる

http://gyazo.com/2db10ec9d97703711d04c226109b37c6.png

2009-09-07

lisp-modeとoutline-modeの併用

| 04:55 | lisp-modeとoutline-modeの併用 - わだばLisperになる を含むブックマーク はてなブックマーク - lisp-modeとoutline-modeの併用 - わだばLisperになる

今日ぼんやりとGoogle Code Archive - Long-term storage for Google Code Project Hosting.を眺めていたのですが、この最後のバッファローカルの変数を設定しているところで

;; Local Variables: **
;; mode:lisp **
;; outline-regexp: ";;; " **
;; End: **

となっているのに気付きました。

なるほど、outline-modeで、;;;を目印に設定すれば上手く畳めるのかもしれません。

ということでページが見つかりませんでした – bookshelf.jp等を参考にしつつちょっと試してみました。

;; slime-modeへフック
(add-hook 'slime-mode-hook
          (lambda () 
            (setq outline-regexp ";;; ")
            (outline-minor-mode t)))

;; superキーに割付け
(define-key slime-mode-map [(super ?a)]
  'show-all)

(define-key slime-mode-map [(super ?d)]
  'hide-subtree)

(define-key slime-mode-map [(super ?t)]
  'hide-other)

と設定してみる。

コードを書いて試してみる

;;; foo
(defun foo ()
  :foo)

;;; bar■
(defun bar ()
  :bar)

;;; baz
(defun baz ()
  :baz)

と書く。

hide-otherで畳んでみる

;;; foo
;;; bar■
(defun bar ()
  :bar)
;;; baz

なるほど、なるほど。

畳み込み表示のための専用のelispがあったような気もしますが、outline-minor-modeの利用も手軽かもしれません。

他にもっとLISPを書く際に便利で簡単な畳み込みの方法をご存知でしたら是非教えてください!

2009-01-12

対になるものは先に入力する派

| 19:43 | 対になるものは先に入力する派 - わだばLisperになる を含むブックマーク はてなブックマーク - 対になるものは先に入力する派 - わだばLisperになる

自分は、()や、[]、""等は先に入力する派で、M-(やM-[、M-"等に割り当てて入力しています。(※まだpareditは使うには至っていません)

M-)も愛用しているのですが、文字列の中でM-)すると上手く動いてくれません。

これが結構不満でLispマシンだと上手く動くだけにEmacsでもZmacs風に文字列の中でもM-)が効くようにしたいところです。

ということで原因を探ることにしてみました。

M-)はmove-past-close-and-reindentという関数なのですが、

;;!はポイント
(let ((foo "bar!")))

のようなポイント位置で実行すると上手く動きません。

原因はmove-past-close-and-reindentというよりも、その中で使われているup-listが上の"bar!"のような文字列中では上手く機能しないことが原因でした。

恐らく、""を先行入力する人はそれ程多くないのであまり問題にならないのでしょう。

ということで、up-listにadviceをかけようと思いましたが、様子見ということで、とりあえずmove-past-close-and-reindentにadviceを掛けてみることにしました。

;; EMACS
(progn
  (defadvice move-past-close-and-reindent (before mpcar-before ())
    (cond (;; "foo"のうち foo"の上にいる場合
           (not (thing-at-point 'list))
           (cond ( ;; "foo"のうち 後の"の上にいる場合
                  (= ?\" (following-char))
                  (forward-char 1))
                 (t ;; "foo"のうち fooの上にいる場合
                  (forward-sexp)
                  (forward-char 1))))
          (;; "foo"のうち 前の"の上にいる場合
           (= ?\" (following-char))
           (forward-sexp))
          (t nil)))

  (ad-activate 'move-past-close-and-reindent)
  ;; 解除
  ;(ad-deactivate 'move-past-close-and-reindent)
  )

という風にしたのですが、とりあえずは目的の動作になっています。

もっと良い方法がありましたら是非とも教えて下さい!

2008-10-31

SLIMEとElispを連携させたい その2

| 16:35 | SLIMEとElispを連携させたい その2 - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEとElispを連携させたい その2 - わだばLisperになる

コメント覧にて、佐野さんから値を取得する場合には、slime-evalを使う、と教えてもらったので早速試してみました。

slime-evalの仕様がいまいち分かっておらず、シンボルのパッケージの指定は強制的に文字列で置換した後にSLIMEに送ることにしてみました。

;; Emacs Lisp
(require 'cl)

(defun has-package-name-p (symbol)
  (and (position ?: (symbol-name symbol)) 'T))

(defun put-package-name (tree &optional pkg)
  (let ((pkg (symbol-name (or pkg 'cl-user))))
    (*put-package-name tree pkg)))

(defun *put-package-name (tree pkg)
  (cond ((null tree) () )
        ((consp (car tree))
         (cons (*put-package-name (car tree) pkg)
               (*put-package-name (cdr tree) pkg)))
        ((and (symbolp (car tree))
              (not (has-package-name-p (car tree))))
         (cons (intern (concat pkg "::" (symbol-name (car tree))))
               (*put-package-name (cdr tree) pkg)))
        ('T (cons (car tree)
                  (*put-package-name (cdr tree) pkg)))))

(defmacro cl-funcall (fn &rest expr)
  `(slime-eval 
    ',(put-package-name `(funcall ,fn ,@expr))))

;; 動作
(+ (cl-funcall #'+ 30 40) 30)
100

(cl-funcall #'ppcre:scan "良し" "これで良し")
3

効率は悪そうですが、まずこれで良しとします。cl-evalとかも欲しいかも。

SLIMEとElispを連携させたい

| 13:41 | SLIMEとElispを連携させたい - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEとElispを連携させたい - わだばLisperになる

先日はSLIME経由で、CLの関数を呼んでみたりしました(→LINK)

しかし、これだけだとつまらないので、もう一歩進んで、CLの関数をELispと混ぜて使えたら便利だなということで、適当に試してみました。

希望としては、Elisp上で

(+ 33 (cl-funcall #'fib 10))
;=> 88

みたいな事ができれば最高です。

とりあえずElisp上でCLの関数が定義できるようにしてみました。

先日定義した、slime-eval-mesgを使用します。

(defmacro define-cl-function (name arg &rest body)
  (slime-eval-mesg
   (format "(defun %s %s %s)"
           name arg (mapconcat (lambda (x) (format "%s" x)) body " "))))

(defun eval-cl (expr)
  (slime-eval-mesg (format "%s" expr)))

;; 関数を定義してみる
(define-cl-function fib (n)
  (if (< n 2)
      n
      (+ (fib (1- n))
         (fib (- n 2)))))

(eval-cl '(fib 20))
;>>> 6765

とりあえずですが、関数は定義できました。ちなみにパッケージの連携については謎です。

それで、その値を取得したい訳なのですが、

(defun cl-funcall (fn &rest args)
  (slime-eval-async
   `(swank:eval-and-grab-output 
     ,(format "(funcall #'%s %s)" 
              fn (mapconcat (lambda (x) (format "%S" x)) args " ")))
   (lambda (result)
     (setq *ans* (cadr result))))
  *ans*) ;; 大域変数に逃すという苦肉の策。しかし*ans*の値がリアルタイムに取得できない。

みたいなものを定義しても、どうやら駄目なようです。

SLIMEの値の受渡しについてもう少し探ってみる必要があるようですが、自分は、根性無しなので知っている方がいらっしゃったら是非教えて欲しいです(笑)

2008-02-22

kill-backward-up-list

| 23:33 | kill-backward-up-list - わだばLisperになる を含むブックマーク はてなブックマーク - kill-backward-up-list - わだばLisperになる

最近S式を書いていて、

(print (+ 3 3))

というのを、「やっぱりprintはいらないや」と、

(+ 3 3)

のように、外側の式を削除して、内側のものを外に括り出す操作をパっとできるようにしたいと思うようになりました。

それで自作しようかなとも思いましたが、確か以前にどこかでこういう拡張を目にした記憶があったので、改めて探してみたところ、そのものズバリなものをみつけました。

;; the Zmacs function `kill-backward-up-list':
(defun kill-backward-up-list (&optional arg)
  "Kill the form containing the current sexp, leaving the sexp itself.
A prefix argument ARG causes the relevant number of surrounding
forms to be removed."
  (interactive "*p")
  (let ((current-sexp (thing-at-point 'sexp)))
    (if current-sexp
	(save-excursion
	  (backward-up-list arg)
	  (kill-sexp)
	  (insert current-sexp))
	(error "Not at a sexp"))))

Zmacs(LispマシンのEmacs)にはこの機能があったそうで、それの再現だそうです。

ちょっと調べたところでは、LispWorksのエディタ(Zmacs系)にもこの関数はあるみたいですね。

それで、キーバインドですが、とりあえず、C-M-sh-Hに割り当てて暫く様子をみることに。

Zmacsには他にもお宝が眠ってる気がする!

2006-08-23

Emacsから携帯にメールする

| 00:46 | Emacsから携帯にメールする - わだばLisperになる を含むブックマーク はてなブックマーク - Emacsから携帯にメールする - わだばLisperになる

最近は、ずーっと家にいるということもあり、ずっとPC

の前から世界を睨み続けているので、携帯に来たメール

も「なりすましメール」で応酬しています。なりすましっ

ていっても単純で、FromとReply-Toを携帯に向けてるだ

けなんですが、結構頻繁に使うので支援の小汚いelisp

とかも書いてみてました。

(setq mb-email-address "foo@jp.earth")

(defun narisumashi (email-address)
  "携帯からのメールをなりすましでPCから送る際のメール作成支援コマンド"
  (interactive "p")
  (save-excursion
    ;; auto-fillを無効にする
    (auto-fill-mode -1)
    ;; Reply-toを携帯へ
    (goto-char (point-min))
    (cond ((re-search-forward "^Reply-To:\\(.*\\)" nil t)
	   (replace-match (format "Reply-To: %s" mb-email-address)))
	  (t (insert (format "Reply-To: %s\n" mb-email-address))))

    (goto-char (point-min))
    (re-search-forward "^From: \\(.*\\)" nil t)
    (replace-match mb-email-address t t nil nil)

    (goto-char (point-min))))

でも、こういうことしなくても、というか寧ろこういう

ことはしないで、メーラーのフックをちゃんと利用すれ

ば、かなり快適な「なりすまし携帯メール」環境を実現

できるんじゃないかと思うわけです。

どういうことをしたいのかといえば、今のところ

  • 絵文字の使用
  • 携帯なので基本的にauto-fillしない。

という位しか思い付きませんが、絵文字については、送

り主のドメインをみて判断し、文章中のキーワードをキャ

リア依存の絵文字を適用して送信する、位のことはフッ

クを使うと実現できそうです。

とりあえず、実験としてAUの絵文字に変換するテストと

してフィルターを書く

(defun ezemoticonize-region (begin end)
  "リージョン中の`うんこ'をez-webの絵文字に変換"
  (interactive "r")
  (save-excursion
    (goto-char (min begin end))
    (while (re-search-forward "うんこ" nil t)
      (replace-match (format "%c" 64336)))))

という感じ。

そしてそれを、

(add-hook 'wl-draft-send-hook
           #'(lambda ()
               (ezemoticonize-region (point-min) (point-max))))

のように送信時のフィルターとして噛ませば、「うんこ」

がすべてうんこの絵文字となります。しかし、全キャリ

アの絵文字に対応するのはなかなか面倒そう。

しかし「うんこ」だけでも是非全キャリ対応させたいと

ころ。