スポンサーリンク

2016年2月16日火曜日

Emacs + howm で ag (The Silver Searcher) を使う

前回に引き続き Emacs + ag (The Silver Searcher) ネタです。howm で ag を使えるようにしてみました。

howm (一人お手軽 Wiki もどき)というメモ書きツール、今どれだけ使っている人がいるでしょう?一時期話題になり、雑誌などでも特集が組まれるほど盛り上がっていましたが、ここ数年サポートすら行なわれているのか分からないような状況です。ブログなどでも取り上げられることはほとんどありません。Emacs のパッケージリポジトリに登録されるでもなく、野良アプリとしてですが、今でもダウンロードはできるようになっていますが。

しかし私にとってメモ書きツールとして今でも無くてはならない存在です。howm のいい所は特定のフォーマットを規定している訳ではなく、単なるテキストファイルを扱う「マイナーモード」なので、他のメジャーモードと組み合わせて使うことができる点です。単なるテキストファイルなので、例え howm の使用を止めても今までのメモが無駄になることもありません。ドキュメントにも書かれているように、いつでも宗旨変えをすることができます。といいつつ、org-mode + howm の組合せで私は約10年もメモを書き溜めています。

howm にはデフォルトで elisp による検索と外部コマンドの grep を使って検索する機能があります。メモが少ないうちは elisp 検索で事足りますが、そのうち grep を使うようになり、更に grep でも遅く感じるようになる、というのが howm ユーザが通る道です。そこで ag の登場です。

ag を使う上で問題になることが ここ で少しだけ述べられています。ag は検索対象ファイルが唯一つだけだった場合、出力結果にファイル名を表示してくれないのです。これさえ何とかなれば使えそうです。

何だそんなことか、という気がしました。実はこれ、昔の grep にも同じ問題がありました。なので当時 Emacs から grep を呼び出す場合何をやっていたかというと、検索対象に常に /dev/null を追加して、強制的に二つ以上のファイル検索になるようにしていたのです。(ちなみに今の grep には -H というオプションがあり、これは必要ありません。) しかしこれがまた Windows では問題になり、使う grep によっては、そんなファイルないよエラーが出たりしたものです。

基本的に同じ方法を使ってみようと思いますが、grep でやっていたように何がなんでも常に /dev/null を追加するというのも芸が無いので、ファイルが一つだけだった場合のみ追加するという風にしてみます。

howm のソースコードを見てみると grep にハードコードされているわけではなく、変数設定で他のコマンドも使えるようになっています。この辺は設計者様に感謝です。

今回も Emacs24.4 から使えるようになった nadvice.el を使いました。旧来の defadvice を使った方法も載せておきますので、古い Emacs を使っている場合はコメントアウトされている方のコードを使ってください。

私の環境は以下の通りです。

  • Windows10 Pro x64
  • NTEmacs 24.5.1
  • ag on Cygwin64 

ag にはパスを通しておいてください。また Windows 環境では Cygwin 意外の ag では使えないと思います( /dev/null を認識しないので)。

以下、設定コードです。先頭の howm-process-coding-system の設定は Windows を前提としたものなので、Mac や Linux では削除してください。たぶんそれ意外はそのまま使えると思います。


(setq howm-process-coding-system '(utf-8-dos . cp932-unix))

(setq howm-view-use-grep t)
(setq howm-view-grep-command "ag")
(setq howm-view-grep-option "--nocolor --nogroup")
(setq howm-view-grep-extended-option nil)
(setq howm-view-grep-fixed-option "-F")
(setq howm-view-grep-expr-option nil)
(setq howm-view-grep-file-stdin-option nil)

;; 検索対象が単一ファイルだった場合、/dev/null を追加する
;; nadvice を使った実装 (Emacs 24.4 からの機能)
(defun add-devnull (args)
  (let ((str   (car args))      ;; 検索文字列
        (files (nth 1 args)))   ;; ファイルリスト
    (when (= 1 (length files))           ;; 単一ファイル?
      (if (file-regular-p (car files))   ;; 通常ファイル?
          ;; 単一の通常ファイルが指定された場合に /dev/null を追加
          (setq files (append files '("/dev/null"))))
      )
    (list str files)))
(advice-add 'howm-real-grep-single :filter-args #'add-devnull)

;; 検索対象が単一ファイルだった場合、/dev/null を追加する
;; (defadvice howm-real-grep-single (before single-file-modifier activate)
;;   "If argument parameter specifies single file, then add /dev/null."
;;   (let ((arg-files (ad-get-arg 1)))          ;; 第二引数
;;     (when (= 1 (length arg-files))           ;; 単一ファイル?
;;       (if (file-regular-p (car arg-files))   ;; 通常ファイル?(ディレクトリでなく)
;;           (progn
;;             (setq arg-files (append arg-files '("/dev/null")))   ;; /dev/null を追加
;;             (ad-set-arg 1 arg-files)         ;; 元の関数に引数をセット
;;             ))))
;;   )

2016年1月30日土曜日

Windows NTEmacs で ag (The Silver Searcher) を使う

IDE全盛の昨今、Emacs で(elisp 以外の)プログラミングコードを書くことはめっきりなくなりました。しかし文章を書く作業は今でもEmacsが中心です。

Windows 上で Emacs を使っていると鬼門なのが外部コマンドとの連携です。例えば grep を呼び出して文章を検索するなどということはよくやりますが、英語は検索できても日本語が通らないといったケースがよくあります。

また ag (The Silver Searcher) の検索の早さには目を見張るものがあります。一度使ってみるとどうしても Emacs からも使えるようにしておきたくなります。

単に使うだけであればインストールさえすれば、最低限英語の検索はできます。自分も長い間その状態で放って置いたのですが、ちゃんと日本語も検索できるようにしておこうと思い調べてみました。

調べてみると結構根深い問題があったりして、自分でも勉強になったので、ここにメモを残しておこうと思います。

まず簡単に自分の環境を説明しておきます。

  • Windows10 Pro x64
  • NTEmacs 24.5.1 (IMEパッチなし)
  • Cygwin64 + ag

ag をインストール

ag は Cygwin64 上で自分でビルドしたものを使います。既にお持ちの方はここはスキップしてください。

ag は Cygwin のパッケージになっていないので、自力でビルドする必要があります。ソースコードはここからダウンロードしてください。


ビルドに必要なパッケージはだいたい以下の通りです。

 gcc
 make
 autoconf
 automake
 pkg-config
 zlib-devel
 libpcre1
 libpcre-devel
 liblzma-devel
 liblzma5
 pcre

これらがインストールされていれば、後は展開したソースの ./build.sh を Cygwin のコマンドラインから実行するだけです。いくつか警告が出ますが無視して構いません。実行したディレクトリに ag.exe が生成されている筈です。

あとは make install すれば Cygwin の /usr/local/bin にコピーされます。このディレクトリをWindowsの PATH に追加しておいて下さい。

ag.el を動かす

まずは ag.el パッケージを動くようにしてみます。経験から言うと、外部コマンド絡みの問題はほんとんどが文字コードに起因するものです。逆に言うと文字コードさえ適切に設定してやれば、ほんとんどはちゃんと動くとも言えます。

Mac や Linux であれば何も考えずとにかく utf-8 にしておけばまず問題は起きません。しかしWindows の場合、SJIS(cp932)が嫌がらせのようにあちこちに顔を出します。

更にやっかいなのが、Emacs には文字コードを設定するにも似たようなコマンドや変数がいくつもあり、いったい何をどう使えばいいのかよく分からないというEmacsの闇です。

では Cygwin のコマンドを呼び出すには文字コードとして何を使えばいいのでしょうか?意外なことに、こうすべきという情報が見つかりませんでした。

そこで試行錯誤的に試してみました。結論から言うと、コマンドへの入力は cp932、コマンドからの出力は utf-8-dosにすればとりあえず動くということが分かりました。つまり入力と出力が非対称なのです。

外部プロセスに対する文字コード指定はいくつか方法がありますが、今回は変数 default-process-coding-system を使いました。この変数は Emacs のすべての外部プロセス呼び出しに影響します。というか特に指定が無かった場合のフォールバック先として機能します。

以下を初期化ファイルに追加してください。

  (setq default-process-coding-system '(utf-8-dos . cp932))


これだけで日本語が検索できるようになりました。M-x ag で検索文字列とディレクトリを入力すれば物凄い勢いで検索してくれます。

ただし、(prefer-coding-system ...) や (set-default-coding-systems ...) があると上書きされてしまうので、これらを使っている人はそれ以降に記述してください。Emacs の闇です。

helm-ag を動かす

helm-ag も普通に実行してみると日本語が検索できません。こちらは結構やっかいでした。

まずは以下のコードを見てください。helm-ag が ag コマンドを呼び出している部分です。


(defun helm-ag--init ()
  (let ((buf-coding buffer-file-coding-system))      ; (1)
    (helm-attrset 'recenter t)
    (with-current-buffer (helm-candidate-buffer 'global)
      (let* ((default-directory (or helm-ag--default-directory
                                    default-directory))
             (cmds (helm-ag--construct-command (helm-attr 'search-this-file)))
             (coding-system-for-read buf-coding)     ; (2)
             (coding-system-for-write buf-coding))   ; (3)
        (setq helm-ag--ignore-case (helm-ag--ignore-case-p cmds helm-ag--last-query))
        (let ((ret (apply 'process-file (car cmds) nil t nil (cdr cmds))))   ; (4)
          (if (zerop (length (buffer-string)))
              (error "No output: '%s'" helm-ag--last-query)
            (unless (zerop ret)
              (unless (executable-find (car cmds))
                (error "'ag' is not installed."))
              (error "Failed: '%s'" helm-ag--last-query))))
        (helm-ag--save-current-context)))))


(1)でバッファのファイル・コーディングシステムを取り出し、それを (2)(3) で coding-system-for-read, coding-system-for-write に設定しています。これが外部プロセスに対して read/write する文字コード(コーディングシステム)になります。そして(4)で外部コマンド ag を呼び出しています。

つまりバッファのファイル・コーディングシステムを強制的に ag コマンドの入・出力に使っているのです。これじゃWindowsでまともに動くわけありません。この部分意図がさっぱり理解できませんが、とにかく原因は分かりました。

原因が分かれば後は対策です。変数の設定でどうにかできるレベルではないので、今回は外部プロセスを呼び出している関数(process-file)を advice という仕組みで書き換え、コーディングシステムを強制的に設定することにしました。advice にもいくつか方法がありますが、Emacs24.4 から導入された nadvice.el を使いました。古い Emacs を使っている方は注意してください。一応古い advice を使った方法もコメントとして残しておきましたので、必要であればそちらを使って下さい。

以下が最終的なコードです。これで helm-ag で日本語の検索、絞り込みができるようになりました。


(when (executable-find "ag")
  (require 'helm-ag)

  (defvar helm-ag-base-command)
  (defvar helm-ag-insert-at-point)
  (defvar helm-ag-ignore-patterns)

  ;; ag のデフォルトのコマンドオプションを指定
  ;; -n を消すとサブディレクトリも再帰的に検索
  ;; (setq helm-ag-base-command "ag --nocolor --nogroup -n")
  (setq helm-ag-base-command "ag --nocolor --nogroup")

  ;;; ポイント位置のシンボルをデフォルトのクエリにする
  (setq helm-ag-insert-at-point 'symbol)

  ;; 検索で無視するファイルパターン (ag --ignore xxxx に渡す文字列を設定)
  ;; (setq helm-ag-ignore-patterns '("*~" "#.*#" "TAGS"))
  ;; 無視パターンに grep.el の変数を使う
  (setq helm-ag-use-grep-ignore-list t)

  ;; process-file を呼び出す前に R/W の coding system を強制的に設定
  ;; (defadvice process-file (before configure-process-coding activate)
  ;;   "Configure process coding for Cyrgin application."
  ;;   (setq coding-system-for-read  'utf-8-dos)     ;; 行末の ^M を避けるため -dos が必要
  ;;   (setq coding-system-for-write 'cp932-dos)
  ;;   )

  ;; :around による advice
  (defun set-rw-coding-system:around (orig-func &rest args)
    (let ((coding-system-for-read  'utf-8-dos) ; 行末の ^M を避けるため -dos が必要
          (coding-system-for-write 'cp932-dos))
      (apply orig-func args)          ; オリジナル関数を呼び出し
      ))
  (advice-add 'process-file :around #'set-rw-coding-system:around)


  ;; === キーバインド ===
  (global-set-key (kbd "C-M-g") 'helm-ag)
  (global-set-key (kbd "C-M-k") 'backward-kill-sexp) ;推奨
  )



2016年1月28日木曜日

ブラックホールの特異点は存在するか?



昔ある本の中で、ブラックホールは無限の質量を持っているという記述を見たことがあります。しかしこれは間違いであることに直ぐに気付きました。だって、無限の質量を持っていたらそれだけで全宇宙の質量を越えてしまいます。ブラックホールにだって有限の質量があります。

では何が無限なのでしょうか?一般相対性理論では、ブラックホール内部に空間の曲率と密度が無限大になる点が存在するとされています。空間の曲率というと何だかよく分りませんが、これは重力が無限大になるということです。この点を「ブラックホールの特異点」と呼びます。

ここで「点」と書きましたが、これは静止しているブラックホールの場合で、回転しているブラックホールでは特異点はリング状に存在します。重要なのはどちらの場合も、特異点は体積を持たないということです。何しろ密度が無限大なので、少しでも体積を持った瞬間これまた宇宙の質量を越えてしまいます。それにしても体積が無いのに密度が無限大?訳分らないでしょう?

更にやっかいなのは特異点がブラックホールの外に出てしまうことがあるということです。特異点は通常、光でさえ脱出することができなくなる境界領域「事象の地平線」の内側に在ります。その場合外側の世界に対して何等影響を与えることができないので、外側の世界は何とか秩序を保っていられます。

しかし一般相対性理論的は、特異点が必ずしも事象の地平線の内側に在ることを要求していません。外側に出てしまっても理論的に何ら矛盾は発生しないのです。このブラックホールの外側に出てしまった特異点の事を「裸の特異点」と呼びます。

ブラックホールの内側に特異点がある場合は特異点以前にブラックホールがとてつもなく危険なので、絶対に近づいてはいけません。

しかし裸の特異点がポンと目の前に表われたらどうなるでしょう?全てを破壊しつくすものすごく恐ろしい存在かもしれませんし、ひょっとしたら誰も気づかない全く無害な存在かもしれません。何しろ計算できないのですから何が起こるかまったく分かりません。

裸の特異点が存在するかどうかはブラックホールを語る上で最大の謎ですが、それ以前に特異点そのものが本当に存在するのでしょうか?これは専門家でも意見が分かれています。

そもそも特異点というのは、一般相対性理論では計算できない領域の事であり、これはつまり一般相対性理論が適用できない領域であるということと等価です。それを無理矢理一般相対性理論で語ろうとするからこういう訳の分からない事になってしまうのです。実存する物理的な存在である以上、無限大や無限小になる手前で、未知の物理法則が働いて、有限の体積、有限の密度に落ち着くのではないでしょうか(と考えている研究者も多くいます)。

このようにブラックホールは謎だらけなのです。考えれば考える程パラドックスが出てきます。だから面白いのですが。

2016年1月27日水曜日

Android6.0(マシュマロ)でSDカードが使えなくなった


Google Play で公開しているアプリをどきどきメンテナンス・リリースを行なっています。基本的にはSDKやライブラリをアップデートし、targetSdkVersion も最新バージョンを指すようにしたりしています。リリース前には当然テストを行ないますが.....あれっ?Android6.0 でアプリが動きません。

にぎやかな宇宙・音源とエネルギーについて


音のエネルギーは音源からの距離に二乗に反比例して減衰します。つまり距離が遠くなるほど加速度的に音が小さくなります。これは音が一点から発生している、つまり点音源の場合です。

では音が線状に発生している線音源の場合はどうでしょう?話を単純化するために長さ無限大の線音源を考えます。この場合音のエネルギーは距離に反比例して小さくなります。つまり点音源より音の減衰が小さいのです。波の音が意外に近くから聴こえてきたことはありませんか?点音源的な距離感に慣れている人間の耳に、波の音はちょっとした錯覚を引き起こします。

では面音源ではどうでしょうか?これも単純化のため無限大の面音源を考えます。驚くべきことにこの場合、音源からいくら離れてもエネルギーが減衰しないのです。つまり音から逃れることができません。しかし安心してください。自然界にこのような音源が存在するか、考えてみても思いつきません。

ここまでの話はずいぶん昔、大学時代に電磁気学の講義で習った内容です。気怠い午後の授業の中で、海辺の風景を思い浮かべながら、なるほどなあと感心しながら聞いていた記憶があります。

点、線、面とくれば次はやはり3次元立体音源でしょう。しかし残念ならが無限立体音源の場合、音源からの距離というものが定義できません。何しろ全ての点が音源なのですから。

「音源」ではありませんが、3次元空間全体に広がるエネルギー源としては、ビッグバンの名残りと言われている宇宙背景放射(宇宙マイクロ波背景放射)がこれに該当するでしょう。しかし人間はマイクロ波を知覚できなくてよかったなあとつくづく思います。何しろ相当うるさいこと間違いありませんから。

2014年8月29日金曜日

Androidエミュレータの "failed to sync vcpu reg" 問題

久し振りに Android エミュレータを立ち上げようと思ったら、あれっ?画面が真っ暗で一向に起動しません。何度やっても同じ結果で、よく見るとメッセージウィンドウに
failed to sync vcpu reg
と出ています。 Windows7 64-bit Professional での話です。メッセージの内容からして仮想化機能絡みで問題が起きていることが想像できます。仮想化機能といえば Intel HAXM。試しにこれを無効にしてみると確かに起動します。
Intel HAXM とは、CPU の仮想化機能を利用した Android エミュレータのアクセラレータ機能で、これがサポートされたお陰でエミュレータは格段に早くなり、以前に比べて快適性がグンと増しました。今ではこれ無しではエミュレータを使う気になれません。
それにしてもちょっと前までは何の問題もなく使えていたので、何かの変更が影響していることは間違いありません。
まずは Google 検索です。分ったのはこの "failed to sync vcpu reg" 問題は実に様々なところで発生していて、原因はよく分らないものの、ああやったら直ったとかこうやったら直ったという報告はいろいろあります。しかしどうも自分にあてはまるものは見つかりませんでした。
自分は結構頻繁にシステムの設定を変えたりする方で、何が影響したのか容易に分りませんでした。少なくとも仮想化に関連するようなものは全く変更していない筈です。インストールしたものをアンインストールしてみたり、バックアップイメージをリストアしてみたり、かなり時間をかけて切り分けを行い、ようやく原因、というか影響している大元がみつかりました。想像もしなかったものです。
それはなんと、SKKFEP(SKK日本語入力FEP) という日本語入力アプリでした。MS IME や Google日本語入力に代る日本語入力システムです。仮想化技術と日本語入力アプリ、一見対局にあるようなアプリが影響しているとは。正直びっくりです。最初は信じられなくて何度も確認してみました。SKKFEP が有効になっていると 100% 問題が発生するし、MS IME や Google日本語入力では絶対に発生しません。
ちょっとした酔狂で SKK を使ってみようと思いたち、入れてみたものです。SKK と呼ばれるちょっとキワモノ的な日本語入力方式は、実は Windows 環境での実装はこの SKKFEP に加え、もう一つ選択肢として CorvusSKK というものがあります。面白いことにこの CorvusSKK でもまったく同じ現象が発生します。どちらも個人開発らしいので、ソースコードを共有している訳でもないと思うので、想像するに、Windows の IME 開発のフレームワークに起因しているような気がします。そういえば、Google 検索したときも、どこの国の人か分かりませんが、Google Input Method をアンインストールしたら問題が直ったといった報告がありました。(但し、自分の環境では Google日本語入力では問題は発生していません。)
ここまで分ったらあとはどうするかです。最初はエミュレータを起動するときにいちいちホットキーで IME を切り替えていましたが、だんだん面倒くさくなってきました。アプリに応じて自動的に IME を切り替えてくれる「あいち」というフリー神ソフトを見つけ、現在はこれを使っています。快適です。作者に感謝。







2013年2月17日日曜日

VoiceRecc


初めてGooglePlayにリリースしてみたボイスレコーダアプリVoiceReccのインストールカウントが徐々に増えてきました。やはりアンドロイダーの公認アプリとして取り上げられたのが大きかった様です。
また全然知らなかったのですが、海外のFileDir.comというサイトがあって、ここでも取り上げたよという連絡がきました。いろいろなところで使ってもらえるのは嬉しいものです。苦労した甲斐があります。

最初は参考書に載っていたほんの1ページ足らずのプログラムだったのが、あれもやろうこれもやろうとしている間にクラスの数は数百にも膨れあがました。

0から全て一人でアプリを作ってみると、プログラミング意外にも、デザイン技術やバージョン管理等様々な技術が必要なのが分かります。実に楽しい一時でした。

初期バージョンではなかったMP3録音機能や、録音レベル補正機能等も追加しました。これからもまだまだバージョンアップする予定ですので、ご期待ください。