トップ 追記 RSS feed

継続にっき

2004|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|03|05|06|08|09|10|12|
2007|01|02|03|05|07|12|
2008|10|
2009|01|05|

2009-05-17 (Sun)

))) Scalaパターンマッチング一覧

最近周りでScalaが盛り上がっているのでつられて勉強中。

パターンマッチングでどのようなものが使えるのかサンプル込みでまとめられた資料が 見あたらなかったので、仕様書を見つつメモ。 (まだ理解があやふやなので内容は怪しいですが。。)

8.1.1 Variable Patterns

var x = 0
var _ = 0

8.1.2 Typed Patterns

var x: Int = 0

8.2 Type Patternsに

The bottom types scala.Nothing and scala.Null cannot be used as type patterns, because they would match nothing in any case.

とあるように、Nothing、Nullは指定できない。

scala> null match { case x: Null => 0 }
<console>:6: error: this type cannot be used in a type pattern

でも、Nullは定義文としては使える。

scala> var x: Null = null
x: Null = null

他にもこのパターンはいろいろな書き方があるっぽいけど、 今は手に余るのでとりあえずパス。

8.1.3 Literal Patterns

0 match { case 0 => 1 }

定義文とmatch式で使えるパターンはほぼ同じようなので以下のようなことも可能。

var 0 = 0

8.1.4 Stable Identifier Patterns

2つの引数を受け取り値が等しいかどうかを判定する関数fを考える。

def f(x: Int, y: Int): Boolean = x match {
  case y => true
  case _ => false
}

上記のように書くと、「case y」のyがvariable patternと見なされるため 「case _」がerror: unreachable codeとなりコンパイルすら通らない。

これを回避するのがこのパターン。

  • 識別子をバッククォートで囲む
def f(x: Int, y: Int): Boolean = x match {
  case `y` => true
  case _ => false
}
  • 識別子を小文字以外で始める
def f(x: Int, Y: Int): Boolean = x match {
  case Y => true
  case _ => false
}

8.1.5 Constructor Patterns

case classによるマッチングのこと。

8.1.6 Tuple Patterns

scala> var (a, b) = (0, 1)
a: Int = 0
b: Int = 1

8.1.7 Extractor Patterns

unapply、unapplySeqを定義したオブジェクトを利用するマッチングのこと。 文法的にはConstructor Patternsと同じで以下のような感じ。

object A {
  def unapply(x: Int) = Some(x)
}

0 match {
  case A(0) => 0
  case _ =>    1
}
// => 0

1 match {
  case A(0) => 0
  case _ =>    1
}
// => 1

case classは「自動でapply、unapplyが定義されるクラス」と説明されることが多いが、 一応仕様としては別物のよう。

8.1.8 Pattern Sequences

簡単に言えば、Constructor PatternやExtractor Patternで@(Haskellのas-patternと同じ)や_*が使えるということかと。

scala> var List(a, b@_*) = List(1,2)
a: Int = 1
b: Seq[Int] = List(2)

8.1.9 Infix Operation Patterns

上記の中置記法版。

scala>  var a List b = List(1,2)
a: Int = 1
b: Int = 2

scala> var a List (b, c) = List(1,2,3)
a: Int = 1
b: Int = 2
c: Int = 3

この場合、_*は使えない。

scala> var a List (b, _*) = List(1,2,3)
<console>:1: error: illegal start of simple pattern

8.1.10 Pattern Alternatives

1 match { case 1 | 2 => 3 }

ちなみに「1 | _」は出来るけど、 「1 | x」はNG。

8.1.11 XML Patterns

scala> var <t>{a}</t> = <t>0</t>
a: scala.xml.Node = 0

8.1.12 Regular Expression Patterns

Scala 2.0以降は無くなった、とのこと。 ほかにもちょこちょこと書いてあるんだけど、具体的にどういうことなのかよく分からず。

8.1.13 Irrefutable Patterns

これも、いまいちよく分からない。。


2009-01-10 (Sat)

))) Sleipnir 1.66からFirefox 3.0.5へ

積年の課題であったブラウザの乗り換えをやっと行うことが出来たのでそのまとめ。

拡張一覧

  • Adblock Plus 1.0
  • Enter Selects 4
  • Extended Cookie Manager 0.9
  • FireGestures 1.1.6
  • Firebug 1.3.0
  • functions for keyconfig 1.4.0
  • Greasemonkey 0.8.20080609.0
  • keyconfig 20080929
  • Live HTTP headers 0.14
  • Menu Editor 1.2.6
  • MozRepl 0.2.0.2008122712
  • NewsFox 1.0.4.1
  • NoScript 1.8.8.8
  • QuickProxy 2008.08.24
  • SearchBox Companion 1.77
  • SearchBox Companion Utils 1.0.0
  • Second Search 0.5.2008111401
  • Stylish 0.5.8
  • Tab Mix Plus 0.3.7.3
  • Tiny Menu 1.4.9
  • TotalToolbar 1.4
  • XPather 1.4.1
  • XUL/Migemo 0.11.8

タブ、キー定義、マウスジェスチャ

基本的な部分は最近の定番っぽい次の拡張を入れることで問題なく移行できた。

  • Tab Mix Plus 0.3.7.3
  • FireGestures 1.1.6
  • keyconfig 20080929
    • functions for keyconfig 1.4.0

割り当てのためにコードを書かないといけなかったのは次のもの。

Close All Tabs

gBrowser.removeAllTabsBut(gBrowser.addTab("about:blank"));

Close Other Tabs

gBrowser.removeAllTabsBut(gBrowser.mCurrentTab);

Focus Content

gBrowser.focus();
_content.focus();

Open NewsFox

openNewsfox(false);

Find [Edit] Toggle Ver.

if ("isFindBarVisible" in gFindBar)
  gFindBar.isFindBarVisible() ? gFindBar.closeFindBar() : gFindBar.onFindCmd();
else
  gFindBar.hidden ? gFindBar.onFindCommand() : gFindBar.close();

Lock Tab

gBrowser.lockTab(gBrowser.mCurrentTab);

Allow Page To Run Script

noscriptOverlay.allowPage()

Open Or Search Selection

Stylish

userstyles.orgより、 まず全体的に見た目をコンパクトにするものを。

  • Remove Forward Button For Firefox3
  • Remove star button FF3
  • Compress Toolbars for More Browsing Space
  • Remove Extra Padding From the Navigation Bar

これに加え、タブ周りの余白も削るスタイルを追加。

@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
tab {
    margin-top: 0px !important;
    margin-right: 0px !important;
    padding: 0px !important;
    -moz-border-radius: 0px !important;
}
.tab-icon-image {
    -moz-margin-start: 1px !important;
    -moz-margin-end: 1px !important;
    width: 12px !important;
    height: 12px !important;
}
.tab-text-container {
    -moz-margin-end: 0px !important;
}

次にタブのカラーリングを設定。

  • Tab Color Underscoring active/read/unread
    • アクティブなタブ向けに「background-color: rgb(255,245,210) !important;」を追加してより目立つように

検索

ロケーションバーからお気に入り検索

Sleipnir 1.66でいう「アドレスバーでCtrl+Enter」相当の機能は、 スマートロケーションバーが代替。Enter Selectsを入れるとEnterを叩くだけで 最初の候補が開かれるので効率的。

検索機能の使い分け

検索エンジンやらスマートキーワードやら、Firefoxはどうも検索系が節操なく突っ込んである印象がある。 ページ内検索も、検索バーとは別だし。

  • Second Search 0.5.2008111401
    • 検索エンジンとスマートキーワードをまとめて検索バーで扱えるように
  • SearchBox Companion 1.77
    • 上述の「Open Or Seach Selection」や、Googleの「もしかして」にて検索した文字列を検索バーに取り込み
    • 検索バーの文字列でページ内検索(参照: SearchBox Companion Utils 1.0.0 リリース)

))) NewsFox 1.0.4.1 カスタマイズ

ブラウザをFirefoxに移行したのにあわせ、RSSリーダーとしてNewsFoxを利用するようになった。 基本的にはキーボードのみで操作するようにしている。

Alt+q
NewsFox起動。(keyconfigで「openNewsfox(false);」を割り当て)
n、p
前後の未読フィードへ
w
RSSとWeb Filter表示の切り替え
o
新しいタブで開く
r
全フィード更新
v、Alt+v
スクロールダウン、スクロールアップ

後者3つは標準の機能では出来ないのでソース(newsfox.jar)の変更が必要になる。 クイックハックなのでソースを見て何をやっているか理解できないようであれば真似しない方が無難かと。

diff -ur orig/content/newsfox/newsfox.xul mod/content/newsfox/newsfox.xul
--- orig/content/newsfox/newsfox.xul	2008-09-22 13:04:38.000000000 +0900
+++ mod/content/newsfox/newsfox.xul	2009-01-09 23:41:54.000000000 +0900
@@ -99,10 +99,10 @@
 			label="&sCaddSearch;" command="cmd_addSearch"/>
 		<key id="add-group-key" modifiers="" key=""
 			mod0="" key0="" mod1="" key1="g" mod2="alt" key2="x"
-			label="&sCaddGroup;" command="cmd_addGroup"/>
+			label="&sCaddGroup;" oncommand="scrollContent(500);"/>
 		<key id="delete-group-key" modifiers="" key=""
 			mod0="" key0="" mod1="shift" key1="G" mod2="alt shift" key2="X"
-			label="&sCdeleteGroup;" command="cmd_deleteGroup"/>
+			label="&sCdeleteGroup;" oncommand="scrollContent(-500);"/>
 		<key id="add-feed-key" modifiers="" key=""
 			mod0="" key0="" mod1="" key1="f" mod2="alt" key2="c"
 			label="&sCadd;" command="cmd_addFeed"/>
@@ -114,7 +114,7 @@
 			label="&sCdeleteFeedFromGroup;" oncommand="deleteSingleFeedRow()"/>
 		<key id="refresh-key" modifiers="" key=""
 			mod0="" key0="" mod1="" key1="r" mod2="alt" key2="r"
-			label="&sCrefresh;" command="cmd_checkFeedsslct"/>
+			label="&sCrefresh;" command="cmd_checkFeedsauto"/>
 		<key id="do-cancel-check-feeds-key" modifiers="" key=""
 			mod0="" key0="" mod1="" key1="q" mod2="alt" key2="q"
 			label="&sCcancel;" command="cmd_cancelCheckFeeds"/>
diff -ur orig/content/newsfox/ui.js mod/content/newsfox/ui.js
--- orig/content/newsfox/ui.js	2008-10-01 08:54:30.000000000 +0900
+++ mod/content/newsfox/ui.js	2009-01-09 23:36:30.000000000 +0900
@@ -754,6 +754,11 @@
 	feed.changed = false;
 }

+function scrollContent(offset)
+{
+    document.getElementById("buildContent").contentWindow.scrollBy(0, offset);
+}
+
 function openArticle()
 {
     var arttree = document.getElementById("newsfox.articleTree");

これとあわせ、オプションでShortcut Keys: standardとして生成した profiles/newsfox/accel.xmlを以下のように修正。

--- accel.xml.standard	2009-01-09 16:05:14.638875000 +0900
+++ accel.xml	2009-01-09 23:59:46.498250000 +0900
@@ -5,8 +5,8 @@
 	<feedtree disableKeyNavigation="true"/>

 	<key id="add-search-group-key" modifiers="" key="s"/>
-	<key id="add-group-key" modifiers="" key="g"/>
-	<key id="delete-group-key" modifiers="shift" key="G"/>
+	<key id="add-group-key" modifiers="" key="v"/>
+	<key id="delete-group-key" modifiers="alt" key="v"/>
 	<key id="add-feed-key" modifiers="" key="f"/>
 	<key id="delete-feed-key" modifiers="shift" key="F"/>
 	<key id="delete-feed-from-group-key" modifiers="shift" key="D"/>
@@ -16,9 +16,8 @@
 	<key id="next-unread-key" modifiers="" key="n"/>
 	<key id="prev-unread-key" modifiers="" key="p"/>
 	<key id="open-unread-key" modifiers="" key="u"/>
-	<key id="options-key" modifiers="" key="o"/>
 	<key id="home-key" modifiers="" key="h"/>
-	<key id="open-selected-key" modifiers="" key="v"/>
+	<key id="open-selected-key" modifiers="" key="o"/>
 	<key id="delete-selected-key" modifiers="shift" key="V"/>
 	<key id="manage-livemarks-key" modifiers="" key="l"/>
 	<key id="toggle-filter-key" modifiers="" key="w"/>

Tipsとして、web filterとして「linkHTML;」だけを設定しておくとwキーでの 表示切り替え時にコンテンツがHTMLでそのまま表示されるようになる。

))) SearchBox Companion Utils 1.0.0 リリース

概要

FireFoxの検索バーでCtrl+Enterを入力するとページ内検索、Ctrl+Alt+Enterを入力するとハイライトを検索バーの文字列を用いて実行します。 また、SearchBox Companion 1.77のオプション「F3 Shortcut: Let firefox use it」が、 F3を標準バインディング以外に設定していた場合にうまく動かない問題を修正します。

動作確認環境

  • Firefox 3.0.5
  • SearchBox Companion 1.77

インストール


2008-10-14 (Tue)

))) MercurialからGitへ

Git(ギット)勉強会メモに触発されてGitの利用を再検討。

  • indexバッファ
  • stash
  • rebase, reset, commit --amend
  • bisect
  • logの-pオプション

あたりの機能が便利そうなので乗り換えることにした。 以前評価したときはCogitoでラップする必要があったりと使いづらいものだったけれど、 最近のバージョンはインターフェースもこなれていて悪くない。 ただ、Mercurialのリビジョンナンバー(ローカルでのみ有効な連番ID)相当の機能がないのが残念といえば残念か。

以下、試していて気になったポイントについて。

リポジトリの変換

Gitのアーカイブに含まれるcontrib/hg-to-git/hg-to-git.pyで変換が可能。

git diのようにサブコマンド名の短縮が出来ない

「.gitconfigでaliasを設定すればよい」という解決策がすぐに見つかるものの、 それだとzsh上で補完が効かなくなるという問題がある。

これはグローバルエイリアスを設定して解決。

$ alias -g ann=annotate
$ alias -g ci=commit
$ alias -g co=checkout
$ alias -g di=diff
$ alias -g st=status

Ubuntu 8.04のzshだと補完関数が古くてstashなどをサポートしてない

CVS HEADでは実装されているので、 そこから_gitを持ってきてfpathに配置すればOK。

revertとreset

CodeRepos::Share ? Trac参照。

revertの機能がMercurialのそれと異なるので注意。

$ hg revert --no-backup

に対応するコマンドは

$ git reset --hard (HEAD)

になる。


2007-12-02 (Sun)

))) JScript(WSH 5.6)小ネタ

車輪の再発明のような気もするけれど。

JavaScriptフレームワーク prototype.jsを使う

次のようなWSFファイルを作成する。

<job id="sample">
  <script language="JScript" src="pre_prototype.js"/>
  <script language="JScript" src="prototype.js"/>
  <script language="JScript" src="post_prototype.js"/>
  <script language="JScript">
    (3).times(function(i) {WScript.Echo(i)});
  </script>
</job>
実装

prototype.jsはブラウザで動かすことを前提とした作りになっているために、そのままではWSHでロードすることができない。 適当にダミーオブジェクトを定義する必要あり(pre_prototype.js)。

// For prototype.js version 1.6.0
var document = {
    createElement:  function() {return {appendChild: function(){}}},
    createTextNode: function() {return {}},
    createEvent:    function() {return {__proto__: {}}},
    write:          function() {return {}},
    getElementById: function() {return {}}
};
var window = {};
var navigator = {appVersion: ""};
var Element = {};

また、オートメーションオブジェクトにtoStringプロパティが定義されておらず Object.inspectの呼び出しに失敗するので、該当関数を再定義してみる(post_prototype.js)。

Object.extend(Object, {
    inspect: function(object) {
        try {
            if (object === undefined) return 'undefined';
            if (object === null) return 'null';
            return object.inspect ? object.inspect() :
                                   (object.toString ? object.toString() : "#<UnknownObject:" + object + ">");
        } catch (e) {
            if (e instanceof RangeError) return '...';
            throw e;
        }
    }
});

Railsのbreakpoint(ruby-breakpoint)もどき

ruby-breakpointはコード中に"breakpoint"と書いておくと実行時にその環境でreplに突入してくれるというもの。 オリジナルは複数行にわたる入力やdRubyを用いたリモートアクセスもサポートするが、そこまで考えなければ簡単に似たようなものが用意できる。

(function(i) {eval(breakpoint)})(0);

実行結果。

> i + 1
1
実装
var breakpoint =
    'for(;;) {' +
    '    WScript.StdOut.Write("> ");' +
    '    if (WScript.StdIn.AtEndOfStream) break;' +
    '    var expr = WScript.StdIn.ReadLine();' +
    '    try {' +
    '        WScript.StdOut.WriteLine(Object.inspect(eval(expr)));' +
    '    }' +
    '    catch (e) {' +
    '        WScript.StdOut.WriteLine("Error Code: " + e.number);' +
    '        WScript.StdOut.WriteLine(e.description);' +
    '    }' +
    '}';

例外発生時にスタックトレース取得

例外をキャッチしてスタックトレースを付与する関数でラップする。

function func1(i, j) {
    (function () { func2("foo") })([]);
}

function func2(i, j) {
    throw new Error("ERROR");
}
func2 = throwsInformationalError(func2);


var Test = Class.create({
    func3: throwsInformationalError(function(i, j) {
        this.func4("bar");
    }, "func3"),

    func4: throwsInformationalError(function(i, j) {
        throw new Error("ERROR");
    }, "func4")
});

それぞれ呼び出したときの実行結果。

func1();

 test.wsf(149, 10) Microsoft JScript 実行時エラー: ERROR
 --- Stack Trace ---
 func2('foo')
 [anonymous]([])
 func1()


(new Test()).func3()

 test.wsf(149, 10) Microsoft JScript 実行時エラー: ERROR
 --- Stack Trace ---
 func4('bar')
 func3()
実装
Object.extend(Function.prototype, {
    getName: function () {
        if (this.name) return this.name;
        var regmatch = this.toString().match(/^function\s*(\w+)/);
        return regmatch ? regmatch[1] : '[anonymous]';
    }
});

function throwsInformationalError(fn, fn_name) {
    function _throwsInformationalError() {
        try {
            return fn.apply(this, arguments);
        }
        catch (e) {
            if (! e.informational) {
                var stack = [];
                for (var i = arguments.callee; i; i = i.caller) {
                    var args = [];
                    for (var j = 0; j < i.arguments.length; j++) {
                        args.push(Object.inspect(i.arguments[j]));
                    }
                    var _fn = (i == arguments.callee) ? fn : i;
                    if (_fn.getName() != "_throwsInformationalError") {
                        stack.push(_fn.getName() +"(" +  args.join(", ") + ")");
                    }
                }
                e.description += "\n--- Stack Trace ---\n" + stack.join("\n");
                e.informational = true;
            }
            throw e;
        }
    };
    if (fn_name) {
        fn.name = fn_name;
    }
    return _throwsInformationalError;
}
  • util.js(breakpointとセット。ロードにはprototype.jsが必要)

foreach

JScriptのfor...in文とVBScriptのFor Each...Next文は言語仕様的には似たようなものだけど、 その実装には決定的な違いがある。その差を埋めるためにEnumeratorが用意されてはいるけれど、 それでもなおカバーしきれないオブジェクトが存在する。ADSIによる属性アクセスなどがそれ。

> var o = GetObject("LDAP://DC=example,DC=com")
#<UnknownObject:>
> o.objectClass
[object Object]
> for (var i in o.objectClass) {WScript.Echo(i)}
undefined
> new Enumerator(o.objectClass)
オブジェクトがコレクションではありません。

ここで各要素にアクセスする方法を調べてみるも、MicrosoftのサンプルはVBScriptでFor Each...Nextしているものばかり。 しょうがないのでVBScript側でFor Each...Next文相当のプロシージャを用意しておいてWSFファイルで読み込んで利用する。 *1

Sub foreach(obj, fn)
  Dim i
  For Each i In obj
    Call fn(i)
  Next
End Sub

JScript側からはこのように。

> foreach(o.objectClass, function(i) {WScript.Echo(i)})
top
domain
domainDNS
undefined

*1 ただ、この例ならばo.objectClass.toArray()とやればアクセス可能。


2007-07-06 (Fri)

))) Mercurialが0.9.4でシンボリックリンクをサポート

Mercurial 0.9.4 released!より。 あまり取り上げられていないようだけど、地味に使いづらいところだったのでありがたい。


2007-05-19 (Sat)

))) mobileimapをアクセスキーに対応させる

クイックハックだけどなかなか便利に。

--- mobileimap.in.orig  2005-05-22 16:04:40.000000000 +0900
+++ mobileimap.in       2007-05-19 21:55:10.000000000 +0900
@@ -862,7 +862,7 @@
                           :seq => seq)
       begin
         generate_from_line(g, seq, nmessages) +
-          g.a(:href => url) {
+          g.a(:href => url, :accesskey =>  nmessages - nth(seq) + 1) {
           emphasize(g, compact_subject(get_subject(seq)).escapeHTML)
         } + g.hr
       rescue Exception => e
@@ -1436,6 +1436,7 @@
             " " + g.a(:href => "#bottom") { "↓" } +
             g.br + generate_seen_mode(g) + g.hr +
             generate_search_form(g) +
+            g.a(:name => 0, :href => "#0", :accesskey => 0) { "→" } + g.br +
             generate_list(g, nmessages, messages) +
             navi + " " +
             g.a(:href => generate_url(:command => "folders",
@@ -1725,6 +1726,7 @@
               g.a(:href => "#bottom") { "↓" } + " " +
               generate_seen_mode(g) + " " + g.hr +
               generate_fsearch_form(g) +
+              g.a(:name => 0, :href => "#0", :accesskey => 0) { "→" } + g.br +
               folders.map {|folder|
               line = g.font(:color => @seq_color) { sprintf("%03d", i) } +
                 if get_unseen_nmessages(folder) > 0 then
@@ -1733,7 +1735,8 @@
                   " "
                 end +
                 g.a(:href => generate_url(:folder => folder,
-                                          :unseen_only => @query.unseen_only)){
+                                          :unseen_only => @query.unseen_only),
+                    :accesskey => i){
                 simplify_folder_name(folder)
               } + g.br
               i += 1

2007-03-29 (Thu)

))) お知らせ

明日からしばらくIP unreachableな状態が続きそうです。


2007-02-22 (Thu)

))) VistaでSleipnir 1.66をHTTPに関連づけるには

メモ。

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice]
"Progid"="Sleipnir.API"

2007-01-18 (Thu)

))) インクリメンタルサーチ対応 Gauche ユーザリファレンス

ちょくちょく利用されているようなので、Gauche 0.8.9リリースにあわせて更新。

ついでに任意のバージョンのドキュメントを用意したい人向けにこの生成方法について簡単に書いておきます。 キモはisearch.html中の<table id="all">の中身なんですが、この部分はHTML化されたGaucheユーザリファレンスを適当なディレクトリに展開したあとその中で

grep 'class="summary-letter"' gauche-refj*|\
  grep --only-matching 'gauche-refj_[0-9]*\.html'|sort|uniq|\
  xargs grep --no-filename '^<tr><td></td><td valign="top"><a href="gauche-refj'|\
  sed 's/a href/a target="ref" href/g'

としたものを埋め込んでいます。あとは必要なファイルを落として同じディレクトリに置けば完成。


2007-01-06 (Sat)

))) /etcのバージョン管理 with Mercurial

CVSによるオープンソース開発にも話題が出てるけど、 実際にやってるって話をとんと聞かない/etcのバージョン管理。これをMercurialを使って試してみた。

この用途にCVSやSubversionではなくMercurialを使うメリットは少なくとも2つ考えられる。

  • cd /etc;hg init で用意が完了する。最初のimportとcheckoutがいらないので導入コストが低い。
  • 管理ディレクトリがトップディレクトリ中の.hgのみしかないのでアクセスコントロールが楽。CVSなどはサブディレクトリごとに管理ディレクトリを作成する。

試してないけど、サーバ間で変更の同期を取るのにも使えるかも。

))) hg logでsummaryではなくdescriptionを出力する

で、初めて本格的にMercurialを使い始めたのだけど、いろいろカスタマイズしたいところが出てきた。

標準のhg logの出力は次のような形で、コミットメッセージはそのsummary(=1行目)が出力される。 つまり、コミットメッセージが複数行に渡る時はそのすべてを確認することが出来ない。

changeset:   3:b9d48fc01c60
user:        User <user@example.com>
date:        Thu Jan 05 21:00:27 2007 +0900
summary:     commit message line1.

-vオプションを使うというのも一つの手だけど、もう少し柔軟に何とかならないものかと調べてみると--styleオプションが使えそうだということが分かった。

hg log [OPTION]... [FILE]
options:
     --style           display using template map file

オリジナルのテンプレートはDebianの場合/usr/share/mercurial/templates/map-cmdline.defaultにあるのでそいつをカスタマイズして使えばいいみたい。

# mkdir ~/.hg
# cp /usr/share/mercurial/templates/map-cmdline.default ~/.hg/map-cmdline.custom
# vi ~/.hg/map-cmdline.custom

-changeset = 'changeset:   {rev}:{node|short}\n ... summary:     {desc|firstline}\n\n'
+changeset = 'changeset:   {rev}:{node|short}\n ... description:\n{desc|strip}\n\n'

# cd /etc
# hg log --style ~/.hg/map-cmdline.custom

 changeset:   3:b9d48fc01c60
 user:        User <user@example.com>
 date:        Thu Jan 05 21:00:27 2007 +0900
 description:
 commit message line1.
 commit message line2.

うん、出来た。標準でこのフォーマットを使いたいなら次のようにする。

# vi ~/.hgrc

 [defaults]
 log = --style /root/.hg/map-cmdline.custom

2004|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|03|05|06|08|09|10|12|
2007|01|02|03|05|07|12|
2008|10|
2009|01|05|
トップ 追記 RSS feed