vc-mode-line
最近知ったのですが, vc-modeが mode-lineに表示している情報(VCS+branch名: gitリポジトリであれば Gitとmasterを表示)はファイルが前のコミットから変更されている場合と されていない場合で異なります. わかりづらいですが, 変更がない場合 VCSとブランチ名のサパレータが -, 変更があった場合は :になります.
変更なし
変更あり
見づらい・わかりづらい
上記で示した通り, 見づらいし, わかりづらいんですが, 有用な情報だなと思ったので, 別情報を表示することにしてみました.
現在のバッファの変更 hunk数の表示
現在お試し中. git-gutterユーザ限定ではあるが, (git-gutter:buffer-hunks)
という APIで現在の hunk数を取得している. 変更内容にもよるが, 多すぎるとそろそろコミットしておかないとなぁという気分になれるのでなかなかよい.
(defvar my/vc-mode-line '(:propertize (:eval (let* ((backend (symbol-name (vc-backend (buffer-file-name)))) (branch (substring-no-properties vc-mode (+ (length backend) 2))) (state (if (bound-and-true-p git-gutter-mode) (cl-case (vc-state (buffer-file-name)) (edited (format ":%d" (git-gutter:buffer-hunks))) (otherwise "")) ""))) (concat "(" branch state ")")))) "Mode line format for VC Mode.") (put 'my/vc-mode-line 'risky-local-variable t) (setq-default mode-line-format '("%e" mode-line-front-space mode-line-mule-info mode-line-client mode-line-modified mode-line-remote mode-line-frame-identification mode-line-buffer-identification " " mode-line-position (vc-mode my/vc-mode-line) " " mode-line-modes mode-line-misc-info mode-line-end-spaces))
現在のバッファの変更状態を表示
(git-gutter:statistic)
APIを使ってみた場合(上記の設定にはめ込んでみてください). 戻り地は dot-listで carが追加行数, cdrが削除行数となっている. 具体的すぎるように思えるので保留.
Emacs Lispで socketプログラミング
http://mattn.kaoriya.net/software/vim/20160129114716.htm
Emacsが socket使えることは知っていたが, 使ったことがなかったので書いてみました.
コード
(require 'json) (let ((proc (open-network-stream "test" (get-buffer-create "*test*") "localhost" 8888))) (set-process-filter proc (lambda (proc output) (let ((resp (json-read-from-string output))) (message "ただ今: %s" (aref resp 1))))) (process-send-string proc (json-encode [1 "GET"])) (process-send-eof proc))
open-network-streamは processオブジェクトを返します. 後は start-processみたく扱ってやればよいようです. 非同期です. set-process-filterで callback関数を指定します. process-send-stringでサーバに sendします.
サーバプログラムは上記の記事に載っているものを使っています. 無駄な処理がいくらか含まれてしまっていますが...
結果
サーバを動かし, 上記の式を評価すると以下のようになります.
Emacsで手動スクレイピング
元ネタ
http://qiita.com/muran001/items/7a76a1c70aa12ed68cb6
はてぶのページからリンクを取得する
Vimほど楽ではない気がするが一応
M-x browse-url-emacs [RET] http://b.hatena.ne.jp/ctop/it ;; windowを切り替え, read-only-modeを解除 M-x replace-regexp [RET] >< [RET] >改行< ; 改行は C-r C-jで入力 M-x replace-regexp [RET] ^\s-+ [RET] ; 行頭の空白削除 M-x delete-non-matching-lines [RET] <a [RET] M-x replace-regexp [RET] ^.*href="\([^"]+\)".*$ [RET] \1
Gifは割愛.
解説
データ取得
M-x browse-url-emacs
で直に HTMLファイルを開けます
HTML整形
replace-regexp
コマンドで頑張る
M-x replace-regexp [RET] >< [RET] >改行< ; 改行は C-r C-jで入力 M-x replace-regexp [RET] ^\s-+ [RET] ; 行頭の空白削除
フィルタリング
delete-non-matching-linesで指定した正規表現にマッチしない行を削除できる. その逆は delete-matching-linesでマッチした行を残す.
M-x delete-non-matching-lines [RET] <a [RET]
データの整形
やはり replace-regexpで頑張る
M-x replace-regexp [RET] ^.*href="\([^"]+\)".*$ [RET] \1 ; リンクの中身のみ取得
おまけ
正規表現をイメージするときは re-builderも良いかもしれない. 以下は reb-re-syntax
が 'string
のときのスクリーンショットです.
2015年を振り返る
ある日, 古い Emacsパッケージを使おうとしたとき全然動かなくて, 動くための PRを送ったんですが, そのとき他のも動くのかなと古いやつを片っ端からダウンロードし, 試してみたらいろいろ問題が見つかり PRしまくっていました. それで妙に草が生えてしまっています. それに伴い githubのリポジトリ数も 1000を超えてしまうということになってしまいました.
あとはひたすらメンテナンスですかね. 今年は新しい物を作らなすぎたと思います. 最後の方は Emacs dynamic moduleのテストのためにあれこれ書いてみましたが, どれも中途半端な感じになってしまいました. 来年は新しいものを作れるようにしたいですね.
自分のやる気のなさが原因としか言えませんが, 早い内になんとかしたいです.
参考
ejectで学ぶ Dynamic module機能
Dynamic module機能は 2015年 12月 12日現在開発中の機能です(だいぶ落ち着いてはきていますが). なので以下の内容は最新版では正しくない可能性があります. 動かない場合等はソースコード及び modules以下に含まれるテストコードを確認してみてください.
リポジトリ
https://github.com/syohex/emacs-eject
リビジョンは 20151212 とします.
ヘッダファイル
関連するヘッダファイルは emacs-module.hだけです. Cファイルではこのヘッダのインクルードが必須です. その他は実装するものに応じて適宜 includeしてください.
型
emacs-module.hに定義される型で重要になるのが, emacs_envと emacs_valueです.
emacs_env
Version 25ではその実体は struct emacs_env_25
です. フィールドはほとんど関数ポインタで, Emacs Lisp側から渡された値を Cの型に変換したり, その逆を行うときに必要となります. データのやりとり, 返還等でわからなくなったらとにかくこの構造体のフィールドにそれらしいものがないか確認すると良いでしょう.
C言語側で Emacs Lispから渡された整数値を受け取るときは以下のようになります.
// envは emacs_env*型, eint_valは emacs_value型 intmax_t cval = env->extract_integer(env, eint_val);
逆に C言語側から Emacs Lisp側に整数値を返したい場合は以下のようになります.
// envは emacs_env*型, cint_valは int型. emacs_value eval = env->make_integer(env, (intmax_t)cint_val);
このように C <=> Emacs Lisp間での値の変換はすべて emacs_env型を使って変換します.
emacs_value
Emacs Lispでの値を表現する型です. Emacs Lisp側から渡ってきた値はすべて emacs_value
型です. また C言語から Emacs Lisp側に値を返すときは emacs_value
型に変換する必要があります.
コードを見ていく
ライセンスの宣言
https://github.com/syohex/emacs-eject/blob/20151212/eject.c#L28
コードが GPL互換のライセンスでライセンスされていないとリンクできません. なのでそのことを示すためのシンボル plugin_is_GPL_compatible
を宣言します.
追記
GPLでなく, GPL互換のライセンスでした. 失礼しました.
エントリポイント
https://github.com/syohex/emacs-eject/blob/20151212/eject.c#L55-L56
各モジュールでエントリポイントなる関数は emacs_module_init
です. ここで C言語の関数の登録, パッケージの登録を行います.
関数の登録
関数の登録の流れは以下のとおりです.
- C言語の関数を関数オブジェクト(
emacs_value
型)に変換 fset
関数を呼び出し, Emacs Lisp側で利用する関数名と1.
で作成した関数オブジェクトを関連付ける
それでは順を追って見ていきましょう.
https://github.com/syohex/emacs-eject/blob/20151212/eject.c#L60
emacs_value ejectfn = env->make_function(env, 0, 1, Feject, "Control CD tray", NULL);
make_function
の引数は以下の通りです.
make_functionに渡せる C言語関数のシグネチャは以下のとおりです.
emacs_value func(emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data);
引数はそれぞれ以下のとおりです.
emacs_env*
型変数- 引数の個数
- 引数
- 関数登録時に設定した引数
https://github.com/syohex/emacs-eject/blob/20151212/eject.c#L62-L65
次に作成した関数を登録します. 登録には fset
関数を使います. ここで C言語から Emacs Lisp側の関数を呼び出す必要があります. C言語側から Emacs Lisp側の関数を呼び出す方法はひとつだけで, シンボルを internし, 引数を設定, それらを使い funcall
を呼び出します.
// (fset 'eject ejectfn)と等価 emacs_value Qfset = env->intern(env, "fset"); emacs_value Qeject = env->intern(env, "eject"); emacs_value fset_args[] = { Qeject, ejectfn }; env->funcall(env, Qfset, 2, fset_args);
これで関数の登録ができました. (eject)
と呼び出せば, C言語の関数を呼び出すことができます.
ロードできるようにする
これで関数は呼び出せる準備は整いましたが, ロードできないので provide
を呼び出し, require
でロードできるようにします. これも fset
と同じ流れで provide
呼び出します.
https://github.com/syohex/emacs-eject/blob/20151212/eject.c#L67-L69
// (provide 'eject) と等価 emacs_value Qprovide = env->intern(env, "provide"); emacs_value provide_args[] = { Qeject }; // 先ほど作成した 'eject env->funcall(env, Qprovide, 1, provide_args);
これで require
を使ってライブラリをロードできるようになりました.
関数の登録, provideは定形なので, Emacs本体の modules/以下にあるサンプルコードではDEFUN
マクロや provide
関数が定義されています. (それも面倒なので本体側に何か用意して欲しいところだが...)
eject本体
本体は以下の通りで, 戻り値の部分を除き普通の Cです. 戻り値は emacs_value
である必要があるので, emacs_env
の適切な関数フィールドを使い変換します. ここでは成功か失敗かだけわかればいいので, シンボルを返しています.
static emacs_value Feject(emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data) { int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); if (fd < 0) { perror("open /dev/cdrom"); return env->intern(env, "nil"); } int cmd = CDROMEJECT; if (!env->is_not_nil(env, args[0])) { if (ioctl(fd, CDROM_DRIVE_STATUS, 0) == CDS_TRAY_OPEN) cmd = CDROMCLOSETRAY; else cmd = CDROMEJECT; } if (ioctl(fd, cmd, 0) < 0) { perror("ioctl"); return env->intern(env, "nil"); } return env->intern(env, "t"); }
おわりに
理解を深めるためにもっとコードを書いていこうと思います.
Suppress warning of exec-path-from-shell
Sorry I removed old entry about this thing by mistake. This entry is updated version of it.
Add following configuration in your init.el. Then exec-path-from-shell does not warn about environment variables.
(custom-set-variables '(exec-path-from-shell-check-startup-files nil))
Recently exec-path-from-shell warn if environment variable in interactive mode is different from them in non-interactive mode. I suppose this is right. We should set environment variables in .bash_profile
or .zshenv
, not .bashrc
, .zshrc
. However this is not easy for some configurations such as rbenv. rbenv initialization eval 'rbenv init -'
generates some environment variables setting and function definitions. We should not define functions in .bash_profile
, .zsh_profile
so I think such setting should not be moved. And I want to keep shell configuration in only one file :-)
color-theme-modern
I ported all color-theme themes(over 100 themes) to Emacs theme framework 2 years ago. Now those themes are available on MELPA. You can download themes with package.el. Package name is color-theme-modern.
Repository
All sreenshots are here
https://github.com/emacs-jp/replace-colorthemes
Installation
All themes are available on MELPA and MELPA stable
You can install color-theme-modern with the following command.
M-x package-install color-theme-modern
Enjoy Emacs themes.