GNU Emacs、Emacs Lisp 版 Minesweeper、Cocoa Emacs 日本語表示

最初に Emacs に触れたのは学生時代購入した X68000 上の Micro Emacs です。もしかしたら Sun のワークステーションの方が早かったかもしれません。インターネットもない時代だったので、本屋で立ち読みしたり、少ない小遣いで購入した書籍で、一生懸命操作を学びました。それ以来、あまり上達していません。X68000 の Micro Emacs では、便利な機能があらかじめ設定されていたので、ファンクションキーを多用していたのを覚えています。

今回、Learning GNU Emacs, Third Edition を読み終えたので、久しぶりに Parallels DesktopWindows XPX68000 エミュレータ XM6 を起動して Micro Emacs (em.x) を実行してみました。

もちろん廉価版なので、本家と違うところがいろいろあるのですが、今思うとすごく良くできていますね。ソースは覗いていませんが、OS に依存しているところは分離されているのかな?

Learning GNU Emacs, Third Edition を読んでる途中で

縦分割や

Window と Frame の違いも理解しました。恥ずかしながら、初めて知りましたが Meta Key として Alt (Option) キーも使えるんですね。Micro Emacs から使い始めたので、てっきり ESC キーだけかと思ってました。

Learning GNU Emacs, Third Edition を読みながら、ATOK Pad にメモした箇所がたくさんあります。ちょっとだけ、紹介しておきます。

GNU Emacs には、強力なヘルプがあります。

Help
C-h ?                   ヘルプ一覧
C-h a PATTERN    正規表現 PATTERN に一致する名前を持つコマンド一覧表示
C-h d PATTERN    PATTERN にマッチする関数、変数などを表示
C-h k

Window 操作も C-x と数字を入力するだけで、いろいろな動作をします。

Window
C-x 0       ウィンドウの削除
C-x 1       選択されているウィンドウ以外のウィンドウをすべて閉じる
C-x 2       ウィンドウを上下2つに分割する
C-x 3       ウィンドウを左右2つに分割する
C-x 4 f     他のウィンドウでファイルを開く
C-x 5 2    フレームの作成
C-x 5 o    他のフレームに移動

ディレクトリエディタ dired で、g キーを押せば、ディレクトリの内容を最新の状態に更新します。

dired
C-x d      dired 起動
u             フラグを外す (Remove mark)
d             削除フラグを付ける (Flag of delection)
x             削除フラグがついたファイルを削除 (Delete)       
g             ディレクトリ再読み込み (Immediate Refresh)
=            比較
C            指定したファイルをコピー (copy)
R            ファイル名変更 (Rename file)
v             View モードで表示 (View file, read-only)
s             ファイル名または日付でソート。トグル。
Enter      スクロール (Scroll down)
#            auto-save files にフラグを付ける
~            Backup files にフラグを付ける
* *          excitable files にフラグを付ける
L            ファイルを読み込む (Load file)
%m         正規表現に当てはまるファイル名にフラグを付ける

決まったファイルを編集するには Bookmark に登録しておくと便利です。

C-x r m  bookmark-set
C-x r l   List bookmarks

GNU Emacs の Window 上に shell も起動することができます。

M-x shell
M-p            最後のコマンドを表示
M−n           次のコマンドを表示

検索と置換には、正規表現も使えます。

検索
C-s
置換
M-%
SPACE    置換して次に移動
DEL        置換しないで次に移動
,             置換して結果を表示。移動はしない
正規表現検索
C-M-s
C-M-r
C-M-%

キーは割り当てられていませんが、指定した領域をコメントアウトするには

M-x comment-region
M-x uncomment-region

が便利です。C や Ruby など、ほとんどの言語が対応しています。

C-@ でマークし、カーソルキーで選択します。

M-x comment-region を実行すると、上図のように各行を /* */ でコメントアウトしてくれます。

コメントアウトを取り除くには、上図のように同じく領域を選択し、

M-x uncomment-region を実行します。

Learning GNU Emacs, Third Edition で、簡単な Emacs Lisp Programming も学んだので、どんな環境でも最初に挑戦するマインスイーパを作成してみたくなりました。Google で検索してみると

EmacsWiki: Mine Sweeper
http://www.emacswiki.org/emacs/MineSweeper

すでに存在するようです。私の理解の仕方が足りないのか、うまく動作させることができません。それで少し mine-sweeper.el を変更してみることにしました。まず、.emacs ファイルに

;; .========== .emacs ==========
;; load-path
(add-to-list 'load-path "~/lisp/")
;; minesweeper
(autoload 'mine-sweeper "mine-sweeper" nil t)
(autoload 'mine-auto "mine-sweeper-auto" nil t)
(add-hook 'mine-sweeper-mode-hook
(lambda ()
(define-key mine-sweeper-mode-map "a" 'mine-auto)))

を追加しました。ホームフォルダlisp フォルダを作成し、その中に mine-sweeper.el、mine-sweeper-auto.el ファイルをそれぞれ置きました。

mine-sweeper.el ファイルの mine-sweeper 関数から

(get-buffer-create "Mine")
(set-window-buffer (selected-window) "Mine")

をコメントアウトし

 (pop-to-buffer "*Mine*" nil)

を追加しました。mine-sweeper 関数は、下記のようになります。

;;; main
(defun mine-sweeper ()
"mine-sweeper
SPC  open
b    mark
m    mark
q    quit"
(interactive)
(setq max-lisp-eval-depth 3000)  ;for recursive call of open.           
(setq max-specpdl-size 3000)     ;for recursive call of open.
;;  (get-buffer-create "Mine")
;; (set-window-buffer (selected-window) "Mine")
(pop-to-buffer "*Mine*" nil)
(setq overwrite-mode t)
(setq major-mode 'mine-sweeper-mode
mode-name  "Mines")
(use-local-map mine-sweeper-mode-map)
(run-hooks 'mine-sweeper-mode-hook)
(mine-start)
(setq buffer-read-only t))

次に mine-clean-and-quit 関数を

(defun mine-clean-and-quit ()
(interactive)
;;  (switch-to-buffer-other-window "*Mine*")
(delete-window)
(kill-buffer "*Mine*"))

に変更しました。これで M-x mine-sweeper を実行すると、マインスイーパで遊ぶことができます。

最初にミニバッファ上で縦横のサイズ、地雷の数を入力します。( デフォルトの値を使用する場合は、Return キーを押すだけです。)
画面が表示されると

カーソルキー     セルを移動
スペースキー     セルをオープン
m キー              マーク
a キー               自動で解く

上記キー操作で遊ぶことができます。a キーを押すと mine-sweeper-auto.el の mine-auto 関数が呼ばれ、マインスイーパを自動で解いてくれます。人間が解くようにコンピュータが解くので、ある程度セルが開いている必要があるようです。条件によっては解けない場合があります。a キーを使って自動で解いた後にプログラムを終了させるとミニバッファに無意味な文字列が表示されます。私が、mine-sweeper.el を変更したのが原因のようです。

自作の Emacs Lispマインスイーパを作ってみたいですね。

GNU Emacs 上の日本語が綺麗に表示できるように、Google で検索していろいろ試しましたが、中々上手くいきません。結局、

IPAフォントのダウンロード || OSS iPedia
http://ossipedia.ipa.go.jp/ipafont/index.html

IPAフォントを使いました。表示結果は

のようになりました。.emacs ファイルは、下記リンクでダウンロードできるようにしておきました。よかったら使ってください。

GNU Emacs 設定ファイル (.emacs) サンプル:  emacs.zip (4K)
http://kyoshiaki.sakura.ne.jp/osx/Download/emacs.zip

Homebrew をちょこっと解析、Cocoa Emacs インストール。

前回書いたように、パッケージシステムとして MacPorts から Homebrew に変更してみました。

Installation - GitHub
https://github.com/mxcl/homebrew/wiki/installation

Homebrew をインストールするには、上記ページの Installation で表示されているスクリプト

/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"

をコピーし、ターミナル上でペーストして実行するだけです。ただし、上記に記載されている通り、事前に Xcode をインストールしておく必要があります。

Safari で直接、https://raw.github.com/gist/323731にアクセスすれば、Homebrew をインストールする Ruby スクリプトを見ることができます。 (curl コマンドでもダウンロードできます。)

curl は、サーバから、あるいはサーバへ、データ伝送を行うツールです。プロトコル HTTP、HTTPSFTP などに対応してます。上のスクリプトの場合、指定した URL [ https://raw.github.com/gist/323731 ] が返す Ruby スクリプトをダウンロードします。各引数は、ターミナルで man curl を使って確認してください。(man curl | col -bfx > curl.txt でファイルに変換して、open curl.txt で中身を確認すると便利です。)

その後、/usr/bin/ruby -e コマンドで Ruby スクリプトを実行します。

スクリプトの内容は、簡単に説明すると

/usr/local/.git ディレクトリの中身が空じゃない時、スクリプトを終了。

/usr/local/
bin/
Cellar/
etc/
include/
lib/
Library/
sbin/
share/
var/
.git/

のそれぞれのディレクトリが存在しない時、/bin/mkdir で新規作成、存在する時は属性を変更。

ディレクトリ /usr/local に移動し、https://github.com/mxcl/homebrew/tarball/master から mxcl-homebrew-xxxxxxxx.tar.gz ファイルをダウンロードして展開する。

これで終了です。

Homebrew のディレクトリのおおざっぱな中身は

/usr/local/
bin/
brew
Cellar/
Library/
Aliases
Contributions
brew_bash_completion.sh
brew_fish_completion.fish
brew_zsh_completion.zsh
examples/
brew-bottle.rb
brew-depstree.rb
brew-dirty.rb
brew-graph
brew-grep
brew-leaves.rb
brew-linkapps.rb
brew-man
brew-missing.rb
brew-pull.rb
brew-readall.rb
brew-server
brew-switch.rb
brew-unpack.rb
brew-upgrade.rb
brew-which.rb
manpages/
Formula/
emacs.rb
wget.rb
.
.
Homebrew/
blacklist.rb
cleaner.rb
compatibility.rb
download_strategy.rb
exceptions.rb
formula.rb
formula_installer.rb
global.rb
hardware.rb
install.rb
keg.rb
keg_fix_install_names.rb
utils.rb
cmd/
---cache.rb
--cellar.rb
--config.rb
--env.rb
--prefix.rb
--repository.rb
audit.rb
cat.rb
cleanup.rb
create.rb
deps.rb
diy.rb
doctor.rb
edit.rb
fetch.rb
help.rb
home.rb
info.rb
install.rb
link.rb
list.rb
log.rb
options.rb
outdated.rb
prune.rb
search.rb
test.rb
uninstall.rb
unlink.rb
update.rb
uses.rb
extend/
ARGV.rb
ENV.rb
pathname.rb
string.rb
test/
share/

です。

また、キャッシュとして

~/Library/Caches/Homebrew 

フォルダが利用されます。Library フォルダは不可視になっていますが、ターミナル上で

~ $ open Library

で開くことができます。

brew コマンドのヘルプは、

man brew
brew help

で確認できます。

ここでは、wget のパッケージをインストールするコマンド

brew install wget

の動作を簡単に説明したいと思います。間違っている個所もあるかもしれません。

実行ファイル /usr/bin/brew は、rubyスクリプトです。

#--- /usr/local/ibin/brew ---
cmd = ARGV.shift # => 'install'
cmd = aliases[cmd] if aliases[cmd] # cmd = :install

cmd に :install が代入され

#--- /usr/local/ibin/brew ---
elsif require? HOMEBREW_REPOSITORY/"Library/Homebrew/cmd"/cmd
Homebrew.send cmd.to_s.gsub('-', '_')

/usr/local/Library/Homebrew/cmd/install.rb が読み込まれ、module Homebrew は /usr/local/Library/Homebrew/cmd/install.rb に宣言されています。

send (Object) - Rubyリファレンス
http://ref.xaio.jp/ruby/classes/object/send

Homebrew.send は Homebrew モジュールの install メソッドを呼ぶことになります。

#--- /usr/local/Library/Homebrew/cmd/install.rb ---
module Homebrew extend self
def install
ARGV.named.each do |name|
msg = blacklisted? name
raise "No available formula for #{name}\n#{msg}" if msg
end unless ARGV.force?
install_formulae ARGV.formulae
end

ARGV は

#--- /usr/local/bin/brew ---
require 'global'

#--- /usr/local/Library/Homebrew/global.rb ---
require 'extend/pathname'
require 'extend/ARGV'
require 'extend/string'
require 'utils'
require 'exceptions'
ARGV.extend(HomebrewArgvExtension)

から /usr/local/Library/Homebrew/extend/ARGV.rb で拡張されています。

#--- /usr/local/iLibrary/Homebrew/cmd/install.rb ---
module Homebrew extend self
def install
ARGV.named.each do |name|
msg = blacklisted? name
raise "No available formula for #{name}\n#{msg}" if msg
end unless ARGV.force?
install_formulae ARGV.formulae
end

/usr/local/Library/Homebrew/blacklist.rb の blacklisted? でインストールできないパッケージを判断。

#--- /usr/local/iLibrary/Homebrew/cmd/install.rb ---
install_formulae ARGV.formulae

ARGV.formulae は Arrray 型で、インストールする Foumla が入っています。今回は Class Wget が1つ入っています。Class Wget は、/usr/local/Library/Formula/wget.rb で宣言されています。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
def install_formulae formulae
formulae = [formulae].flatten.compact
return if formulae.empty?
check_ppc
check_writable_install_location
check_cc
check_macports
formulae.each do |f|
begin
installer = FormulaInstaller.new f
installer.ignore_deps = ARGV.include? '--ignore-dependencies'
installer.go
rescue FormulaAlreadyInstalledError => e
opoo e.message
end
end
end

f は、Formula クラスを継承した Wget クラスが入っています。FormulaInstaller の @f にも格納されています。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
def go
if @f.installed? and not ARGV.force?
raise FormulaAlreadyInstalledError, @f
end
unless ignore_deps
needed_deps = @f.recursive_deps.reject {|d| d.installed?}
unless needed_deps.empty?
puts "Also installing dependencies: "+needed_deps*", "
needed_deps.each do |dep|
FormulaInstaller.install_formula dep
end
end
begin
FormulaInstaller.check_external_deps @f
rescue UnsatisfiedExternalDependencyError => e
onoe e.message
exit! 1
end
end
FormulaInstaller.install_formula @f
end

FormulaInstaller.install_formula @f を呼び出すことになります。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
def self.install_formula f
@attempted ||= Set.new
raise FormulaInstallationAlreadyAttemptedError, f if @attempted.include? f
@attempted << f
ENV['HOMEBREW_ERROR_PIPE'] = write.to_i.to_s
fork do
begin
read.close
exec '/usr/bin/nice',
'/usr/bin/ruby',
'-I', Pathname.new(__FILE__).dirname,
'-rinstall',
'--',
f.path,
*ARGV.options_only
rescue Exception => e
Marshal.dump(e, write)
write.close
exit! 1
end
end

fork、nice を使用していますが、簡単に説明すると

/usr/bin/ruby -I /usr/local/Library/Homebrew -rinstall -- /usr/local/Library/Formula/wget.rb

上記コマンド実行します。

上のスクリプトを実行する時に読み込んでいるライブラリ /usr/local/Library/Homebrew/install.rb の下のソースからプログラムが開始されます。

#--- /usr/local/iLibrary/Homebrew/installer.rb ---
at_exit do
begin
raise $! if $! # an exception was already thrown when parsing the formula
require 'extend/ENV'
require 'fileutils'
require 'hardware'
require 'keg'
require 'compatibility'
ENV.extend(HomebrewEnvExtension)
ENV.setup_build_environment
puts "-----"
puts $0
install(Formula.factory($0))
rescue Exception => e
if ENV['HOMEBREW_ERROR_PIPE']
pipe = IO.new(ENV['HOMEBREW_ERROR_PIPE'].to_i, 'w')
Marshal.dump(e, pipe)
pipe.close
exit! 1
else
onoe e
puts e.backtrace
exit! 2
end
end
end

install(Formula.factory($0)) が実行している箇所です。$0 は、/usr/local/Library/Formula/wget.rb です。

#--- /usr/local/iLibrary/Homebrew/installer.rb ---
def install f
# ・
# ・
# ・
# ・
else
f.prefix.mkpath
beginning=Time.now
f.install if not f.pourable?
FORMULA_META_FILES.each do |filename|
# ・
# ・
# ・
end

f.install の部分が wget.rb の Class Wget で install メソッドを呼び出して実際にインストールしている箇所です。

#--- /usr/local/iLibrary/Formula/wget.rb ---
def install
args = ["--disable-debug",
"--disable-dependency-tracking",
"--with-ssl=openssl",
"--prefix=#{prefix}"]
args << "--disable-iri" unless ARGV.include? "--enable-iri"
system "./configure", *args
system "make install"
end

これが、brew を使って wget をインストールするおおまかな流れです。

Cocoa Emacs も Homebrew を使ってインストールしてみました。Cocoa Emacs の Formula は、あらかじめインストールされているものより

Homebrew Emacs for OSX Lion with native full-screen ― Gist
https://gist.github.com/1109223

で公開されているものから、Forks されている最新版 Formula (emacs.rb : 入手先、インストール方法などが記載されています。)

Homebrew Emacs for OSX Lion with native full-screen ― Gist
https://gist.github.com/1128997

を利用しました。

Formula の URL は、ソースの右上 ‘raw’ 文字をクリックして確認できます。また、Option で –use-git-head を使わない場合、あらかじめ bazaar をインストールしておく必要があります。(残念ながら、git を使って最新版をダウンロードすると patch をあてることができませんでした。)

~ $ brew install bazaar
~ $ brew install https://raw.github.com/gist/1128997/347bb0d97155a294d9c50b6418c9130fadec8a5b/emacs.rb --cocoa --lion
~ $ cp -pR /usr/local/Cellar/emacs/23.3a/Emacs.app /Applications

日本語入力にも対応しています。command + space で日本語入に力切り替えることができます。.emacs ファイルに

;;------- .emacs -------
;; shell
(global-set-key [f5] 'shell)
;; IM
(setq default-input-method "MacOSX")

IM を追加してください。ついでに F5 キーでシェルを起動するようにしてみました。

Emacs を学び直してみようと思い、iTunes App Store

Learning GNU Emacs, Third Edition
カテゴリ/ブック
\600
http://itunes.apple.com/jp/app/learning-gnu-emacs-third-edition/id333188827?mt=8

を購入しました。

404 Blog Not Found:perl - O'ReillyのiPhoneアプリ本からepubをぶっこぬく
http://blog.livedoor.jp/dankogai/archives/51484907.html

上記スクリプトを使って epub に変換し、iPad で読んでいます。たった 600 円でオライリー本を入手できるので、iPad を所有している人には、ぜひお勧めです。

iYKRSSHD、OS X Lion 10.7、PCG-LinkMac とシリアルポート

本題に入る前に宣伝です。

拙作 iPadRSS リーダー iYKRSSHD を通常価格 85 円のところ、8月一杯まで無料で公開します。


iYKRSSHD
カテゴリ/ニュース
8月一杯まで無料
iPad 用のシンプルな RSS リーダー。RSS フィードの更新をマルチタスキング機能に対応しました。また、バックグラウンドで RSS フィードの更新が終了すると画面に通知します。
http://itunes.com/apps/iYKRSSHD

よかったらダウンロードしてください。

とうとう OS X Lion 10.7 が Mac App Store で 2600 円で発売されましたね。

早速、OS X Lion を Mac App Store からダウンロードしました。Snow Leopard から OS X Lion にアップグレードするとインストーラが削除されてしまいます。そのため、インストール DVD が作成できません。それで、インストーラを一旦終了して

OS X LionのインストールDVDを作成する方法 | トブ iPhone
http://applembp.blogspot.com/2011/07/os-x-liondvd.html
【コラム】新・OS X ハッキング! (6) Lionへアップグレードするその前に〜インストールDVDをつくろう〜 | パソコン | マイコミジャーナル
http://journal.mycom.co.jp/column/osxhack/006/index.html

を参考にインストール DVD を作成しました。(Snow Leopard から OS X Lion にアップグレードするとリカバリー HD が作成されます。インストール DVD は、必要なかったかもしれません。リカバリーHD は Mac を Option キーを押したまま起動すると現れます。)

また、作成しインストール DVD で OS X Lion をインストールするとリカバリーHDが作成されないようです。インストール DVD を作成した後、普通にインストーラを使って OS X Lion を一度インストールしました。

ハードディスクのパーテーションの区切り方によっては OS X Lion がインストールができない人もいたようです。私は BOOTCAMP、Macintosh HD の2つのパーテーションでしたが問題はありませんでした。

OS X Lion にアップグレードした後、クリーンインストールするために、先程作成したインストール DVD をドライブに挿入し、C キーを押したまま Mac を起動しました。ディスクユーティリティを使って OS X Lion のパーテーションを Mac OS 拡張 (ジャーナリング)で消去し、OS X Lion を再インストールしました。

Mac を起動すると Time Machine からデータを復元することができます。余計なものを復元して欲しくなかったので、ユーザ、設定だけ復元しました。iPhoneiPad 開発に必要な鍵もしっかり復元されていました。

後は、XcodeParallels DesktopVMware Fusion など最新版をインストールしました。特に問題はありませんでした。

また、私が日頃利用している自作ソフトも問題なく動作しました。ただし、PCG-LinkMac は、シリアルポートを見つけることができませんでした。

以下のサイトから

Welcome to Prolific
http://www.prolific.com.tw/eng/downloads.asp?id=31
md_PL2303_MacOSX10.6_dmg_v1.4.0.zip

ドライバをダウンロードしてインストールしました。

インストールするドライバのファイル名を表示するには、インストーラを起動して、メニュー ‘ファイル/ファイルを表示’ を選べば、表示できます。

’/アプリケーション/ユーティリティ/コンソール’ を起動して、下図のように、ファイル kernel.log を選択します。その後、RS232C シリアル変換ケーブルを接続すると

Jul 26 xxx:xx:xx xxxxxxxx-no-iMac kernel[0]: PL-2303/X V1.3.0 start, Prolific

と表示され、ドライバが読み込まれていることが確認できます。

ただし、PCG-LinkMac のパリティが ‘Odd: 奇数’ だとエラーが生じます。パリティを ‘なし: none’ にするとうまく動作しました。

また、Japanino で利用する Ardunio も USB シリアルポートを見つけることができませんでした。Japanino を USB に差すと

Jul 26 xxxx:xx xxxxxxxx-no-iMac kernel[0]: 0        0 AppleUSBCDC: start - initDevice failed

というエラーが出てドライバが読み込まれません。原因を追及することができませんでした。ただ、

AppleUSBCDC: start initDevice failed - InsanelyMac Forum
http://www.insanelymac.com/forum/index.php?showtopic=262659

のサイトから判断すると Apple 側に問題があるのかもしれません。

MacPorts をやめて Homebrew や RVM – Ruby Version Manager もインストールしてみました。次回にでも詳細について書きたいと思います。