STDIN Pipe判定

https://github.com/monochromegane/the_platinum_searcher/pull/85


Windowsでは, STDINが pipeでないと, os.Stdin.Stat()がエラーを返すという
ことを知らずに, Emacsで the platinum searcherを動かすための PRをしたところ,
Windowsで動かなくなってしまい, その原因を調べました.


具体的には os.Stdin.Stat()の挙動は以下のようになります

 % some_command arg1        # os.Stdin.Stat() エラー
 % some_command arg1 < Nul  # os.Stdin.Stat() エラー
 % some_command < file      # os.Stdin.Stat() エラーなし
 % other_command | some_command # os.Stdin.Stat() エラーなし


Windowsを考慮すると Stdin PIPE判定は以下のように書く必要があります.

package main

import (
	"fmt"
	"os"
	"runtime"
)

func main() {
	fi, err := os.Stdin.Stat()
	if runtime.GOOS == "windows" {
		// error occurs if STDIN is not pipe
		// Ex: $ some_command arg1
		//     $ some_command < Nul
		if err == nil {
			fmt.Println("Stdin is pipe")
		} else {
			fmt.Println("Stdin is not pipe")
		}
	} else {
		if err != nil {
			fmt.Println(err)
			return
		}

		mode := fi.Mode()
		if mode&os.ModeNamedPipe != 0 || mode.IsRegular() {
			fmt.Println("Stdin is pipe")
		} else {
			fmt.Println("Stdin is not pipe")
		}
	}
}


これで期待通り動作しましたが, もっと良い書き方などありましたら教えていただければと思います.

xdg-openで使われるデフォルトブラウザの変更

Google Chromeをインストールしたところ, xdg-openで使われるブラウザが
Chromeになってしまった.

デフォルトブラウザの変更

 % sudo update-alternatives --config x-www-browser

update-alternativesコマンドで確認したところ, x-www-browserに Chrome
設定されていたので Firefoxに変更.

おわりに

xfce4の "Preferred Application"の "Web Browser"は Firefoxのままだったんですが,
これは単に "Web Browser"アイコンをクリックしたときに起動するアプリケーションの指定っぽいです.

git-gutter.el supports live update experimentally

保存時等しか差分更新できないのはいけていないという意見をいただいたので,
保存しなくても差分情報を更新する機能を試験的に実装しました.
(本家 Sublime Text版や Vim版ではだいぶ前に実装されている機能です)

イメージ

設定例

git-gutter:update-interval(単位: 秒)が 0より大きいとその周期で更新します.
(ただし現状は idle timerで更新しているので, ガンガン書いているとき等だと
何の更新も行われません)

(custom-set-variables
 '(git-gutter:update-interval 2))

実装

gitコマンドだけでなんとかできるかと思って調べてみたんですが,
調べた限りうまくいきませんでしたね.


実装方法は以下のとおりです
1. git-gutterが有効かつ, バッファが未保存状態かを確認. そうでないなら何もしない
2. 現在の編集中のバッファの内容のハッシュ値を取得. 前回取ったハッシュ値と比較し, 同じであれば何もしない.
3. `git show :ファイル名`で該当ファイルの最新版のソースを取得. テンポラリファイルに書き出し
4. 現在のバッファの内容をテンポラリファイルに書き出し
5. 3., 4.で取得したファイルの差分を取る(非同期実行)
6. 差分情報を更新.


gitコマンドだけでうまくいく方法があれば教えていただければと思います.

おわりに

要望等ありましたら, twitterまたは github issuesまでお願いします.

(kantou-emacs #x02)に参加します

(kantou-emacs #x02) #関東Emacs : ATND


発表予定は今のところありませんが, それまでにいろいろ作ったり,
既存のものを改良して紹介できればと考えています.


現在職探しも行っているので, 関東方面の情報を収集できればと思います.
よろしくお願いします.

jsonの validation

flycheck

保存時ではありませんが, 常時チェックしたい場合は flycheckがよいでしょう.
jsonlintを事前にインストールしておく必要があります.

 % npm install jsonlint -g
 M-x package-install <ret> flycheck


問題のある行にカーソルを動かすと minibufferにエラーが表示されます.


M-x flycheck-list-errorsとするとエラー一覧が見えます.


next-error, previous-errorでエラーが発生している場所を移動する
ことができます.

json-pretty-print-buffer

Emacs 24.4より, 追加された整形コマンド json-pretty-print-bufferを利用する.
整形コマンドですが, JSONが invalidだとエラーが minibufferに表示されます.

(add-hook 'after-save-hook 'json-pretty-print-buffer)


before-save-hookでなく, after-save-hookなのは, 'Save...'みたいな
メッセージで肝心のエラーが見えなくなってしまう問題を防ぐためです.
(view-echo-area-messages等で見ることはできますが)


Emacs 24.4以上であれば, Emacsのみで使えるのでお手軽です.
整形される分余計といえば余計ですが...

jsonlintのみを使う

無理やりですが, 保存時にエラーがある場合, その内容を popupする
ようにしてみます.

(defun my/json-validate ()
  (let ((file (buffer-file-name)))
    (with-current-buffer (get-buffer-create "*my/jsonlint*")
      (setq buffer-read-only nil)
      (erase-buffer)
      (unless (zerop (process-file "jsonlint" nil t nil file))
        (pop-to-buffer (current-buffer))))))

(defun my/javascript-mode-hook ()
  (when (string-suffix-p ".json" (buffer-file-name))
    (add-hook 'before-save-hook 'my/json-validate)))
(add-hook 'js-mode-hook 'my/javascript-mode-hook)


おわりに

本題とはずれてしまうかもしれないですが, パッケージを入れることに抵抗がなければ,
flycheckがよいのではないかと思います. flycheckを保存時だけ適用してみようかと
思いましたが, ベースが非同期なため, 応用するのが難しそうです.

PATHから特定のパスを抜く

echo "orig="$PATH
IFS=':' read -a pathes <<< "$PATH"
declare -a tmp_pathes
for path in "${pathes[@]}"
do
  if [ "$path" != "$HOME/.plenv/bin" ]; then
    tmp_pathes=("${tmp_pathes[@]}" "$path")
  fi
done
TMP_PATH=$(printf ":%s" "${tmp_pathes[@]}")
PATH=${TMP_PATH:1:${#TMP_PATH}}

echo "after="$PATH
split
IFS=':' read -a pathes <<< "$PATH"

IFS変数と 'read -a'を使って, 文字列を IFSに指定した文字で分割した
配列変数に格納することができる.

join
TMP_PATH=$(printf ":%s" "${tmp_pathes[@]}")
PATH=${TMP_PATH:1:${#TMP_PATH}}

配列変数の前に joinしたい文字を置き %sとすると(ここでは :%s)とすると
配列の要素がその文字で区切られたものが表示される. ただし一番先頭にも
その区切り文字が現れてしまうので, それは次の行の部分文字列記法により
削除する.

結果

% bash test.sh
orig=/home/syohei/.plenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
after=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

おわりに

文字列置換だけでうまくいけばよかったのだが, 少し試したところ
うまくいかなかったのでこのような方法を取ってしまった.
bashの文字列置換をもっと知る必要がある.