[Emacs]linum-modeを軽くする

最近妙に Cocoa Emacs が重いなあと思っていたのだけれど、 linum-mode が原因のようで、こいつを切ると見違えたように軽くなった。
でもさすがに行番号がないのは寂しい。同じようなインターフェイスの wb-line-number はちょっと使ってみたけどいろいろダメだし。
どうするか・・
しょうがないのでソースを見ることに。

(define-minor-mode linum-mode
  "Toggle display of line numbers in the left marginal area."
  :lighter ""                           ; for desktop.el
  (if linum-mode
      (progn
        (if linum-eager
            (add-hook 'post-command-hook (if linum-delay
                                             'linum-schedule
                                           'linum-update-current) nil t)
          (add-hook 'after-change-functions 'linum-after-change nil t))
        (add-hook 'window-scroll-functions 'linum-after-scroll nil t)
        ;; mistake in Emacs: window-size-change-functions cannot be local
        (add-hook 'window-size-change-functions 'linum-after-size)
        (add-hook 'change-major-mode-hook 'linum-delete-overlays nil t)
        (add-hook 'window-configuration-change-hook
                  'linum-after-config nil t)
        (linum-update-current))
    (remove-hook 'post-command-hook 'linum-update-current t)
    (remove-hook 'post-command-hook 'linum-schedule t)
    (remove-hook 'window-size-change-functions 'linum-after-size)
    (remove-hook 'window-scroll-functions 'linum-after-scroll t)
    (remove-hook 'after-change-functions 'linum-after-change t)
    (remove-hook 'window-configuration-change-hook 'linum-after-config t)
    (remove-hook 'change-major-mode-hook 'linum-delete-overlays t)
    (linum-delete-overlays)))

すると、 add-hook の嵐。これじゃ重くて当然。
うーん。どれか削れるものはないか。

post-command-hook

前のコマンドを逐一見ているこいつが明らかに一番重い。作者もそれをわかっているのか

(if linum-delay
    'linum-schedule
  'linum-update-current)

のようにして、遅延を入れられるようにしているっぽい。で、 linum-delay という変数を見てみたがこれは単なる真理値。
問題は linum-schedule のほうで、こいつを見てみると

(defun linum-schedule ()
  ;; schedule an update; the delay gives Emacs a chance for display changes
  (run-with-idle-timer 0 nil #'linum-update-current))

このようになっているが、これって意味あるのか? 0 秒アイドル後に実行って、タイマー設定しないのと同じでは。
なのでここを適当な 0 でない値に変更することで遅延を入れられるはず。
ただ私の主義としてこういう場合は advice を定義したいので、結局

(setq linum-delay t)
(defadvice linum-schedule (around my-linum-schedule () activate)
  (run-with-idle-timer 0.2 nil #'linum-update-current))

この3行を .emacs に追記することで linum-mode が軽くなった。
ファイル編集中最後の行に追記したりすると表示がちょっと遅れるけど、これは大した問題ではないはず。

関数ポインタの配列

たまにやろうと思っては忘れるので、書き残しておく。

#include <iostream>

bool a(int n, int m) { return n > m; }
bool b(int n, int m) { return n == m; }
bool c(int n, int m) { return n < m; }
bool d(int n, int m) { return n == m; }

int main () {
  bool (*x[])(int, int) = {a, b, c, d};
  for (int i = 0; i < 4; i++) {
    std::cout << x[i](0,1) << std::endl;
  }
}

bool (*x[])(int, int) = {a, b, c, d};
なかなか覚えられない・・

*1328054831*

いろんな技術をかじってはすぐやめ、というのを繰り返してきたけど、このままではいかんと思った。なんとかせんと。
とりあえず今触っているのは iPhone アプリだけど、 Objective-CC++ を一緒に書ける Objective-C++ というやつを使っていて、でもほとんどの部分 C++ で書けるので C++ で書いている。 C++ スラスラ書ける人うらやましい。
これまでアウトプットの手間がめんどくさいと思っていたけど、ちゃんとアウトプットしていきたいですね・・

[Emacs] リモートサーバで開発するときの Emacs 設定まとめ

世間はメリークリスマス。昨日の夜は愉快な人たちが愉快な格好をして街を練り歩く様子が見られましたね。


さて、この記事は Emacs Advent Calendar jp: 2011 : ATND の25日目です。
昨日は [twitter:@sky_y] さんの http://d.hatena.ne.jp/sky-y/20111224/1324714853 でした。
明日は [twitter:@kozo2] さんです。


最近では Web 系や大規模処理など、ローカルに環境を整えられないためサーバ内で開発せざるを得ないという状況があると思います。というか最近の自分の仕事(バイト)がそんな感じです。
そこで、リモートサーバ内で開発を行うときの Emacs やその他ツールをまとめてみました。

大きく分けて4パターンほどあると思っています。

  1. tramp を使う
  2. ローカルで編集して rsync などのツールを使ってアップロードする
  3. sshfs を使ってリモートのディレクトリをマウント
  4. リモートサーバにログインして emacs -nw する

以下で詳しく説明します。

1. tramp を使う

Emacs には tramp という機能があります。これは Emacs 内からリモートに SSH アクセスしてそこのファイルを編集できるというものです。
Emacs 22 以上を使っているならば、特に何も考えず

C-x C-f /ssh:user@hostname:path/to/file

とすればいけるはずです。 ~/.ssh/config も読んでくれます。
この方法によって、普通にローカルでファイルを編集しているのと同じようにリモートのファイルを編集できます。
欠点は2つ:

  • 新しいファイルを開くときとファイルを保存するときに時間がかかること
    これはまあリモートアクセスしているので当然でしょう。
  • 他のプログラムとの連携が悪い
    emacsclient とか使えないし、 flymake もなんか使いづらいです。*1

2. ローカルで編集して rsync などのツールを使ってアップロードする

(rsync の他、 scp や sftp などを使うのも同様です。)
rsync は便利なファイル同期ツールです。

$ rsync -acuvz dir1/ dir2/

とかやれば、リモート間での dir1 と dir2 の同期を取ってくれます。オプションなど詳しいことはググってください。
これらを使えば基本的にローカルで編集することができるので、ファイルの編集においては普通に Emacs を使う場合と完全に同じです。
欠点は:

  • ローカルで編集したあとコマンドを打ってアップロードするのが面倒
    これはまあそうですよね。after-save-hook に start-process でアップロードコマンドを突っこむみたいなこともしてみましたが微妙でした。
  • リモートとの同期をとるタイミングによってはとっても面倒なことになる
    これは、例えばローカルでファイルを編集している状態で、リモートの共有リポジトリ中の同じファイルの他人の編集をローカルに持ってこようとしたときに起こります。
    もちろんそのままダウンロードするとローカルの編集が消えます。目 grep ならぬ目 merge が必要になりそうです。*2

3. sshfs を使ってリモートディレクトリをマウント

1. と 2. の良いとこ取りな感じですが、やはりファイルを開くときと保存するときは遅いです。
あと僕の環境ではなぜか flymake がきちんと動いてくれませんでした。
油断して find とか打つと遅すぎて泣けます。

4. リモートサーバにログインして emacs -nw する

そのままです。
最大の利点はどんなマシンからでも同じように開発できるということでしょうか。
何台ものマシンを使っているとその環境を統一するのに少なからぬコストがかかります*3が、サーバに環境を構築しておけばあとはどこから編集しても同じになるというのが利点です。
例えある日突然 Windows マシンを渡されてこれで開発しろと言われても PuTTY さえあれば大丈夫です。
また GNU screen や tmux のデタッチ・アタッチの機能で、前回の作業環境を一瞬で復元できます。
欠点は:

  • -nw であることによる問題
    これは少しグラフィカルなことをしようとすると途端に太刀打ちできなくなることと、一部のキーバインド(僕は C-tab など使っているのですが)が使えなくなることです。
  • 通信によって動作にラグができる
    これも仕方ないことですが、ローカルで Emacs を立ち上げるのに比べてどうしても動きが鈍くなります。
  • (スペースキーの両隣を Meta として使うのに少し苦労するかも)


以上をまとめると、大体以下のような感じ:

方法利点欠点
tramp手軽
ローカルとほぼ同様
ファイル転送が遅い
他プログラムとの連携が悪い
rsync完全にローカルでの作業アップロードの手間
複数人での開発時のコンフリクト
sshfsローカルでの作業ファイルアクセスは遅い
リモートで emacs -nwどのマシンからでも環境は同じ
screenなどとの親和性
-nwでの作業
通信ラグ
どれも一長一短に感じます。
僕はここ3ヶ月くらいで tramp → rsync → sshfs → tramp → リモート emacs -nw という感じに進んできて、今は リモート emacs -nw が一番使いやすいかなと感じています。

*1:http://d.hatena.ne.jp/higepon/20091211/1260509989

*2:ごめん適当なこと言った。あとでググってわかったんですが目 grep ってバイナリファイルを見る技なんですね

*3:自分の .emacs が大体他の環境でも動くように書いている方ってどのくらいいるんでしょうか・・?

[ArchLinux] ロケールの設定ではまった

Arch Linux では Xfce4 を使っているんだけど、今日

$ sudo pacman -Syu
$ sudo reboot

してみると、なぜか日本語が表示できなくなっていた。
あれーと思って locale まわりを見回してみるも特におかしいところはない。
結構悩んだんだけど、

調べてみると /etc/locale.gen に ja_JP.utf8 UTF-8 と書いて

/etc/locale.gen
  ja_JP.utf8  UTF-8

おまじないすればいいようです。

# locale-gen

早速やってみると日本語の表示ができるようになりました。

http://junk.s21.xrea.com/2011/08.html#05

というのを見つけて、この通りやったらうまくいった。
謎のおまじない。