2010年5月26日

Cocoa Emacs のフレームをSpaces のワークスペースの上下左右に飛ばす。

個人的な使い方の問題だろうが、emacs に凝っていた頃は仮想ディスクトップ毎にフレームを置いた使い方をしていた。

この使い方の要は、elisp からフレームを任意の位置、任意のワークスペースに移動できる事であった。

既に MacOSX では仮想ディスクトップが Spaces としてサポートされている。 位置移動はできるようだが、ワークスペースの移動はどうもわからない。。。

マウスでチマチマ動かすのは、ちょっといただけない。。。

どうしたもんだろう?

Quartz のなんか

MacOSX の仮想ディスクトップは Leopard で初めてお目見えしたが、 結構前から Window Server (Quartz Compositor/Core Graphics Services/Quartz Window Services...一体いくつの名称があるんだか。。。)には実装されていたそうである。 Tiger の時代から仮想ディスクトップがサードパーティのものがあったのはそういう訳らしい。

で、コイツのAPIのほとんどが今でも非公開になっている。。。断片的には、スクリーンキャプチャ用途レベルのものが公開されている。。。なんとも厄介。

先人が調べ尽くした結果として、最後のリンクの先の内容が、 特定のウィンドウを任意のワークスペースに移動する方法らしい。

模式コードは次のようになる。(CGSPrivate.hは一番目のリンク先にあるもの)

#import <CGSPrivate.h>
...
NSWindow *win = ...;
CGSConnection cid = _CGSDefaultConnection();
CGSWindow wid = [win windowNumber]; // ?
CGSMoveWorkspaceWindowList(cid, &wid, 1, workspace);

CGSを解析した作られた CGSPrivate.h でのCGSWindow と Appleから出ているドキュメントに出てくる CGWindowID とは window server 内で割り振られた番号で同じ実体と思われるが、 NSWindow の windowNumber のドキュメントには、それとは違うと書かれている。 混ぜても動いたから多分良いかと思われるが、、、ここいらはぼかしたい内容なのかなぁ。。。分からんなぁ林檎は。

まぁ、ここまで分かれば、出来たも同然〜。

で、適当にコマンドを作ってみた。

cgsutil.m

Emacs.appの改造

(frame-parameters)には window-id があるから、Cocoa Emacs では多分コイツがフレームウィンドウの CGWindowID のはずで、コイツと飛ばしたい workspace 番号を適当に作ったコマンドに渡して、お仕舞いかなぁ。

わぁーい。らくちん。

はぅ。。。

Cocoa Emacs では window-id の値は、1から単調増になるように割り振った全く意味の無い番号でした。

仕様が無いので、次の追加機能を付けるパッチ(emacs-23-cgs-workspace.diff) を作ってみた。

  • フレームパラメータns-window-idに、CGWindowIDと思われる値
  • フレームパラメータns-workspace-idに、フレームのworkspace番号
  • フレームを指定のworkspaceに移動する関数 (set-frame-ns-workspace FRAME WORKSPACE)

まぁ、最初の一つだけで十分だが、後二つは組込まなくてもいいかも。

まとめ

上のパッチを適用した Emacs.app に適当な elispを書くと、1コマンドで複数のフレームを特定のワークスペース/特定の位置に開く事が出来るようになった。

screenshot-2010-05-26 17.54.51

うん〜〜。快適じゃ。

はぅ。。。

Cocoa Emacs で8フレームも開くと、キー入力が引っ掛かるようになり、Emacsプロセス自体のCPU利用率もイマイチ高い。イベント処理方法にまだ難があるのかなぁ。

4フレームくらいで抑えないとスムーズに使えないかなぁ。。。

追記 (2010/06/16)

複数のフレームを開いたときCPU利用率が高くなるのは、本パッチ内のframe-paramaters にワークスペース番号を追加するのが原因だった。。。frame-parameters の取得は不随に起きるらしくのでどうも軽くなくては行けない。

なので、workspace番号は取得関数から得るように変更し、workspace 絡みの部分を分けたパッチにしてみた。

  1. emacs-23-cg-window-id.diff
    • フレームパラメータns-window-idに、CGWindowIDと思われる値
  2. emacs-23-cgs-workspace.diff
    • 指定フレームのworkspaceを取得する関数 (frame-ns-workspace FRAME)
    • フレームを指定のworkspaceに移動する関数 (set-frame-ns-workspace FRAME WORKSPACE)

ふむ。
8フレームを開いても、キー入力が引っ掛かる症状は無くなった!!
すごく快適〜ん。

パッチを切ったり張ったり入れ替えたりする(1)のに、git rebase -i は極めて便利。git 優秀だなぁ

2010年5月18日

Emacs で文法チェック

Emacs でプログラムを書く人々は、リアルタイムに文法チェックをするために flymake を使うらしい。

以前聞き覚えがあるが、何をする物か分からないのでスルーした奴だが、結構使えるものだったのかぁ。

なので flymake の設定をしてみた。

Quick Start

詳細は info マニュアルに書かれているが、 使い始めの設定は次の通りになる。この状態で、何もせずに Perl/PHP の文法チェックは行なえる(perl/php コマンドがあればの話だが)。

(require 'flymake)

;; GUIの警告は表示しない
(setq flymake-gui-warnings-enabled nil)

;; 全てのファイルで flymakeを有効化
(add-hook 'find-file-hook 'flymake-find-file-hook)

;; M-p/M-n で警告/エラー行の移動
(global-set-key "\M-p" 'flymake-goto-prev-error)
(global-set-key "\M-n" 'flymake-goto-next-error)

;; 警告エラー行の表示
(global-set-key "\C-cd" 'flymake-display-err-menu-for-current-line)

次に C/C++ で文法チェックを可能にするには、 Makefile を使い、次の様な check-syntax ルールを追加すればよい。

PHONY: check-syntax
check-syntax:
    $(CC) -Wall -Wextra -pedantic -fsyntax-only $(CHK_SOURCES)

ここまですると、編集途中にリアルタイムに文法エラー/警告の部分に色が付き、分かり易い。

なるほど、、、これは素晴らしい。

以下の設定は、好きずきだと思う

警告エラー行の表示のカスタマイズ

警告エラー行の表示は、 プラットホーム毎のポップアップメニュー実装が使われるが、 色々検索すれば出てくるが、2通りのカスタマイズが良く知られている。

  1. Minibufに表示する。
  2. popup.el(auto-complete に含まれている)のpopup-tipsで表示する。

;; Minibuf に出力
(defun my-flymake-display-err-minibuf-for-current-line ()
  "Displays the error/warning for the current line in the minibuffer"
  (interactive)
  (let* ((line-no            (flymake-current-line-no))
         (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no)))
         (count              (length line-err-info-list)))
    (while (> count 0)
      (when line-err-info-list
        (let* ((text       (flymake-ler-text (nth (1- count) line-err-info-list)))
               (line       (flymake-ler-line (nth (1- count) line-err-info-list))))
          (message "[%s] %s" line text)))
      (setq count (1- count)))))

;; popup.el を使って tip として表示
(defun my-flymake-display-err-popup.el-for-current-line ()
  "Display a menu with errors/warnings for current line if it has errors and/or warnings."
  (interactive)
  (let* ((line-no            (flymake-current-line-no))
         (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no)))
         (menu-data          (flymake-make-err-menu-data line-no line-err-info-list)))
    (if menu-data
      (popup-tip (mapconcat '(lambda (e) (nth 0 e))
                            (nth 1 menu-data)
                            "\n")))
    ))

僕としては popup.el を使うのが結構好み

check-syntaxターゲットルール

先に述べて Makefile の check-syntaxターゲットルールでは一種類の文法チェックプログラムしか使えない。。。 gcc でチェックできるものは全てチェック出来るから、気を回す必要は無いかもしれない。

GNU make を使えば、拡張子毎に文法チェックプログラムを選べるルールの書き方がある。

CHECKSYNTAX.c = $(CC) $(CFLAGS) $(CPPFLAGS) -Wall -Wextra -pedantic -fsyntax-only
CHECKSYNTAX.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -Wall -Wextra -pedantic -fsyntax-only

check-syntax: $(addsuffix -check-syntax,$(CHK_SOURCES))

%.c-check-syntax:
	$(CHECKSYNTAX.c) $*.c

%.cc-check-syntax:
	$(CHECKSYNTAX.cc) $*.cc

まぁ、ここまで書く奴はいないかぁ。。。

Makefileが無くてもC/C++の文法チェック

Makefileが無ければ、直接 gcc で文法チェックをし、 Makefileがあればcheck-syntaxターゲットルールを使いたい場合は、 次の設定をすれば良い。

(defun flymake-simple-generic-init (cmd &optional opts)
  (let* ((temp-file  (flymake-init-create-temp-buffer-copy
                      'flymake-create-temp-inplace))
         (local-file (file-relative-name
                      temp-file
                      (file-name-directory buffer-file-name))))
    (list cmd (append opts (list local-file)))))

;; Makefile が無くてもC/C++のチェック
(defun flymake-simple-make-or-generic-init (cmd &optional opts)
  (if (file-exists-p "Makefile")
      (flymake-simple-make-init)
    (flymake-simple-generic-init cmd opts)))

(defun flymake-c-init ()
  (flymake-simple-make-or-generic-init
   "gcc" '("-Wall" "-Wextra" "-pedantic" "-fsyntax-only")))

(defun flymake-cc-init ()
  (flymake-simple-make-or-generic-init
   "g++" '("-Wall" "-Wextra" "-pedantic" "-fsyntax-only")))

(push '("\\.[cC]\\'" flymake-c-init) flymake-allowed-file-name-masks)
(push '("\\.\\(?:cc\|cpp\|CC\|CPP\\)\\'" flymake-cc-init) flymake-allowed-file-name-masks)

まとめ

取り敢えず、次いでに ruby/bash の文法チェックを追加したのが、 今現在の設定になっている。

45flymake.el

あとは Python/Java/HTML/CSS をチェックするのがあれば良いが、、、 これくらい素のflymakeに含まれていればいいのになぁ。。。

あとSemanticかぁ。。。

追記 (2010/05/24)

暫く使ってみたが、基本動作で2点だけイマイチな挙動を修正しないと、ストレスが溜まりまくる。

  1. ファイルもしくは上位ディレクトリに書き込み権限が無い場合、messageを吐いて開くのを諦めてしまう。。。
  2. 文法チェックプログラムが無い場合 flymake がオフになるが、それでも何かのプロセス?が残って、後々無意味な y の連打をしないといけない。。。
これも、素のflymakeで用意してくれれば良いのに、、、で場当たり的に次の設定を追加した。。。

;; flymake を使えない場合をチェック
(defadvice flymake-can-syntax-check-file
  (after my-flymake-can-syntax-check-file activate)
  (cond
   ((not ad-return-value))
   ;; tramp 経由であれば、無効
   ((and (fboundp 'tramp-list-remote-buffers)
         (memq (current-buffer) (tramp-list-remote-buffers)))
    (setq ad-return-value nil))
   ;; 書き込み不可ならば、flymakeは無効
   ((not (file-writable-p buffer-file-name))
    (setq ad-return-value nil))
   ;; flymake で使われるコマンドが無ければ無効
   ((let ((cmd (nth 0 (prog1
                          (funcall (flymake-get-init-function buffer-file-name))
                        (funcall (flymake-get-cleanup-function buffer-file-name))))))
      (and cmd (not (executable-find cmd))))
    (setq ad-return-value nil))
   ))

追記 (2010/05/25)

上の修正は、ちょっと上手く行かない場合があったので修正っと。

追記 (2010/05/27)

tramp経由の場合も、イマイチ上手く動かないので、除外に加えてみた。

2010年5月13日

Emacs Refcard 日本語版

Emacs のチートシートは、Emacs と一緒に配布されている。 refcard.tex から pdfを作って印刷すれば良い。 少し古いバージョンだが、日本語に翻訳されたものは「Emacs-20/21 Reference Card 」にある。

キー操作として、手に染み付いているものは半分くらいしか無い。。。 大抵 M-x コマンドで済まして場合が多いなぁ。

いかんなぁ。。。

再度覚え直す為に、先の日本語RefcardとEmacs23に入ってるrefcardと若干漏れている部分を補い、 一部語句を修正し、フォント関係を微調節してものを作ってみた。

refcardja.tex

次いでに ptex/dvipdfmx を使って PDF を作って、Google Docs に上げてみた。

refcardja.pdf

まとめ

うん、久しぶりに素のTeXを弄ったが本当にややこしい奴だな。

2010年5月12日

Cocoa Emacs が落ちる

Cocoa Emacs は安定していると思ったが、 どうもポップアップダイアログが出ると暫くして落ちてしまう。

flymake をチマチマ使えるように設定を弄ったら、時々でるポップアップに刺さる。。。

しようがないので、gdbで追っかけてみた。

調べてみたら、次のような簡単な処理でも、 ポップアップが出て暫くしてEmacsが落ちるようである。

どうも inline patch 側での処理抜けらしい。。。 こんな感じに修正すると落ちなくなった

うん、すこぶる快適

2010年5月7日

Emacs23 の フォント設定

新し目の Emacs ではフォントエンジンの改良が進んでおり、 antialiasing が効いた奇麗な表示が出来る。また、沢山の種類のフォントを扱えるようになっている。

プログラムの編集等をしてると等幅フォントが必要である。 特に、日本人としてはASCII文字と日本語文字の幅が 1:2 である事が強く望ましい

まぁ、いくつか設定方法が流れてるので、コピペして使えば良いのだが。。。 みんなどうやって見やすい設定を探してるのだろうか?

疑問に思ったので、次のような機能のelispを書いてみた

my-sample-ascii.el
my-sample-ascii
既定のフェース default/bold/italic/bold-italic それぞれで同じメッセージを 同一のバッファに出力する
my-sample-face-size
defaultのフェースを継承し(書体を引き継ぎ)、高さが 6〜20ptのフェースを作成し、同じメッセージを 同一のバッファに出力する

適当にdefaultフェースを設定した後だが、CocoaEmacs/NTEmacs/Emacs(onUbuntu)での、 my-sample-face-sizeの結果は次のようになる

ss-20100507-cocoaemacsss-20100507-ntemacs23 ss-20100507-ubuntu10.04

いくつか設定してみたが、全ての pt で、1:2 に揃うフォントの組み合わせはほんとに稀で、日常的に使うサイズに合わせて、サイズの微調節が必要のようである。 やはり、IPAフォントの恩恵は結構でかいなぁ。

今現在、いい感じに設定できたのは次の通り。

まとめ

なんか Emacs をガンガン使い倒したくなってきた!!

追加 (2010/11/03)

VMware 上の X で画面サイズの変化で dpi が変化し pt 単位でフォント指定すると、実際のフォントの大きさがまちまちになるので、 明示的にpixel単位?で指定する方法に切り替えてみた。

2010年5月6日

NTEmacs 23.1.Xを使ってみる

Windowsの定番は Meadowであり、今でも十分安定している。 ただ、ベースにしてるのが Emacs 22系なので、ちょっと新しくないかなぁ。。。

今日では本家EmacsでもWindows版バイナリを配布している。Windows特有のInstallerが使いたければ、EmacsW32から入手できる。

結構、安定して使える。かつ、アイコンが奇麗だ。。。

本家バイナリはネイティブのIMEのサポートが弱い気がする。。。と思ったら、有志によってIMEのinlineパッチも作成されいる。また、 VCSの新し目のタグに有用なパッチを当てたバイナリも「NTEmacs Build History 」から入手できる。

なので有り難く使わせてもらいます。
らくちんだ。

設定

NTEmacs内部ではWin32のA系の呼び出し(ファイルI/Oやプロセス生成など)が使われるっぽいので、 現在の言語環境でのコードページに合わせなければ、奇妙な文字化けが発生する。 つまり、ファイル名とコマンド引数(processのdecoding)のcodingは shift_jis/cp932 じゃないとまずい。

と思うのだが、誰か大層語ってくれる人が見当たらないので、本当のところはさっぱり分かりません。。。

なので、「Cygwin 1.7でUTF-8サポートされたぜ!いぇーい!今時は UTF-8 ですが何か?」とは、口が裂けても言えない。。。僕は恨めしくshift_jis/cp932で使いますよ。。。へたれですから。。。

上のサイトや他多数をちょっと参考にして、今現在の次のようにしている。今でもチマチマ書き換えているのでそのうちgithubで晒しとくかなぁ。。。

Homeディレクトリの指定

ホームディレクトリ指定を環境変数HOMEで与える必要があり、Cygwinでのホームディレクトリと同じにすると混乱せずに済む。

Cygwin 1.7と組み合わせる設定

03cygwin.el

IMEの設定 (04ime.el)
言語設定 (05lang.el)
VCS系の設定

cygwinのsubversionやgitを使う場合、ログメッセージが文字化けするので、ちょっと設定が必要。。。

、、、VC-xx.elの実装では、ログメッセージはコマンド引数で受け渡されるようになっている。 一時ファイル経由で無いとWindowsではバケバケになるのだが。。。そのうち直るのかなぁ

まとめ

あと大事な Font 設定ですね。。。次回で。

2010年5月1日

Cocoa Emacs 64bit版を作ってみる

最近、また Emacs にはまっている。

ここ数年は vi やら eclipse やら JeditX やら xcode やらを広く浅く使っていて、 いまいちスッキリしない感じで、まぁ年なのか諦めていた。 Snow Leopardにアップグレードを期に、 ちょっと設定等を手入れしてMacOSX/Windowsで使い出したらすこぶる手になじむ。。。

はて、なんでEmacsを使うのを忘れていたのかんなぁ。。。

そう、当時 Emacs 20か 21 (mule-2.3だったかもしれん、、、)だったかなぁ。 UTF8/Unicodeを使う為にはMule-UCSとかいうパッケージが必要で、 そいつを組み合わせると普通に使えるのだが、起動も動作ももっさりしていまいちだった。。。

今日のEmacsはサクッとUnicode系の一群のcoding-systemが使えて、それなりに軽快に動作する。

良い時代になったなぁ。。。

MacOSX 上の定番は CarbonEmacsで、 かなりしっかりメンテナンスされており、実に安定している。ただ、ベースにしてるのがEmacs22だったり、Carbonベースだったり、32bitバージョンだったり、本当に細かく気になる人が気になる程度。

ふと気づくと 本家 Emacs では既に 64bit Cocoa版が構築でき、かつ日常作業で問題ならないくらいは安定してるらしい(1,2)。また、フォントの等幅調節設定や日本語入力等のinline patchなどが入手が可能で、 ほぼ CarbonEmacs を置き換えて使えるレベルになっている(と思う)。

なので、Cocoa Emacs 64bit を構築してみる。

ソースを取ってくる

うん、一番の難関は Bazaar という分散VCSを使う事かもしれない。。。準オフィシャルなGitレポジトリがあるので、Gitに慣れてる場合はこっちを使うのが吉。僕は、へたれなので git の方を使った。

取り敢えず、 ローカルネットに emacs.git のミラーレポジトリを立てて、そのマシン上でフォークして個人用の共用レポジトリを作る。 その個人用レポジトリから作業マシンに複製を展開する。 また、継続的にupstreamを追っかけるため、ミラーレポジトリもリモートとして登録する。

% ssh server               # ローカルネットの server にログイン
% cd /git
% git clone --mirror git://repo.or.cz/emacs.git
% git clone --bare --reference emacs.git emacs.git emacs-my.git
...
% ssh client               # 作業マシンにログイン
% cd ~/work
% git clone git+ssh://server/git/emacs-my.git emacs
% cd emacs
% git remote add upstream git+ssh://server/git/emacs.git
% git fetch upstream

個人用レポジトリを挟んだのは、バックアップを意図してなんだが、、、git使いはそんな事はしないのかなぁ。。。分からんなぁ。。。

パッチをあてる

続いてMacEmacs JP から inline_patch を取って当てる。

% ssh client               # 作業マシンにログイン
% cd ~/work/emacs
% git checkout -b topic EMACS_PRETEST_23_1_96  # 次いでに topic ブランチも作っとく
% pathc -p0 < emacs-inline.patch 

構築する

あとは、configure/make で問題が無ければ nextstep/Emacs.app の場所で 64bit Cocoa Emacs が構築される。

% ssh client               # 作業マシンにログイン
% cd ~/work/emacs
% eval "$(PATH= /usr/libexec/path_helper -s)"  # PATHをクリーンにする
% ./configure --with-ns
% make install
% open nextstep/Emacs.app                      # Emacsの実行確認

なんともあっけなく構築できた。 ただ、僕は masterブランチの方にパッチを丁寧に当てた物(24.0.50とか)を使っている。すこぶる快適。

定期的追っかける

まぁ、忘れそうなので次いでに書いとく。

ミラーレポジトリは次のコマンドで更新する。

% ssh server               # server にログイン
% cd /git/emacs.git
% git fetch

そして、作業レポジトリで upstream を追っかけるには

% ssh client           # 作業マシンにログイン
% cd ~/work/emacs
% git fetch upstream
% git rebase upstream/master topic    # upstream 先端に rebase
% git push origin :topic              # topicブランチを削除し、
% git push origin topic:topic         # 新しくtopicブランチをプッシュ

いまいち Git の使い方に慣れない/分からないので、間違ってるかもしれん。。。

そういえば、github にも Emacsのミラーレポジトリが上がってるので、そのうち生えてくるかもしれん。。。

それにしても覚える事が次から次と現れて、知恵熱が出っぱなしだなぁ。。。

初期設定のemacs.elはまた次回。

追記 (2010/05/06)

フォント以外の設定は、殆ど定型文っぽいので以下の用に設定した。

フォントの設定は「Emacs23 の フォント設定」を参照

追記 (2010/05/12)

どうもポップアップダイアログが出たとき落ちる問題にはパッチが必要。

Cocoa Emacs 24.3 構築 (2013/03版)

暫く使っている Cocoa Emacs を更新していなかったので、24.3 に上げてみた。 当てるパッチは inline patch と ポップアップフリーズ対応パッチ くらい。 24.3 には既にフルスクリーン実装が入っているので、よく使われているフルスクリーンパッチは外し...