seqdiagの自分向けドキュメント

初めに
======

seqdiagは簡単なシーケンス図を描画するツールです。UMLで定義されたシーケンス図すべてを表現できるわけではありません。
PlantUMLやmscgenのようにテキストベースでシーケンスを作成することができます。

導入にはpythonの実行環境が必要となります。この辺は公式ドキュメントに記載されていることなので詳しくは書きません。

公式ドキュメントはここにあります。
http://blockdiag.com/ja/seqdiag/index.html

背景など
========

sphinx + seqdiagを触る必要があったのですが、「インストールしました」「サンプルと同じ図を描きました」「おわり」。の情報ばかりヒットして細かい情報が見つかりません。

本来なら公式ドキュメントを見るだけで細かい操作方法を把握できるとよいのですが、
実際スカスカなのでpipでインストールしたパッケージのソースを読みながら触ってみた結果わかった知見を共有したいと思います。

非公式なので、正確な情報を知りたい場合は **blockdiagの** 公式ドキュメントやソースをあたってください。


オンラインプレビュー
===================

seqdiagを始めとするblockdiagシリーズのオンラインプレビューを提供してくださっています。
公式ドキュメントの末尾に掲載されているプレビューとの違いはモードを切り替えることでblockdiagなどもプレビューできること、
SVGでダウンロードできることです。

http://interactive.blockdiag.com/

基本的な書き方
==============

書式
----

以下のような書式で書きます。ライフラインの定義の部分は省略可能です。

~~~
seqdiag {
// ライフラインの定義、宣言
A; B; C;

// メッセージ
A => B => C;
}
~~~

詳細
=====

コメント
--------

コメントはC系言語と同様の記法,`//`、`/* ～ */` が使えます。

ライフライン
-------------

（専門用語はわからないのでブロックといったほうがしっくりきます）

1つのオブジェクトに対するフォーマットは以下の通りです。
IDを利用してメッセージのシーケンスを書きます。
定義しない場合はメッセージで出てきた順に自動的に作成されます。
属性を全く定義しない場合は []部分は省略可能です。

~~~
ID [属性1=値1, 属性2=値2, ...];
~~~

使用可能な属性は、seqdiagの公式ドキュメント + blockdiagの公式ドキュメントから以下の通り

* label: オブジェクト名を記載します。デフォルトはIDとなります。\nを書くことで改行可能です。改行した場合、中央揃えとなります。
* icon: 左側にアイコンを表示します。labelと組み合わせることができます。
* background: 背景画像を設定します。中央に表示されるためlabelと被ります（※）。
* numbered: 左上に番号を割り振ります。
* description: sphinx拡張向けの機能です。desctable オプションと併用して説明のテーブルを図の下に表示できます。
* shape: オブジェクト名部分の形を変えます。デフォルト値boxのほか、actor, mail, cloudくらいが有用でしょうか。
* width, height: ボックス部分の幅、高さを指定します。
* textcolor: テキストの色です。
* fontsize: フォントサイズです。width, heightをはみ出すサイズには大きくなりません。逆に言うとwidth, heightを大きくすればfontsize=500でも有効です。

※ backgroundに機種依存文字を含む文字列を画像として張り付けてlabelを空文字にすればSVG出力した場合も機種依存文字を環境によらず表示できるはずです。

以下シーケンス図としての視点でいうとネタ要素です。

* stacked: オブジェクト名の四角が重なります。
* color: オブジェクト名部分の背景色。色名(red, green, blue, white, black, gray,...)または"#RRGGBB"が指定できます。
* style: オブジェクト名の囲み線。未指定(実線), dotted(点線)、dashed(破線), "len1,len2,len3,len4"(実線の長さ,空白の長さ,実線,破線,..) から選択可能です。
* rotate: 文字の向きを指定します。0,90,180,270から選択します。

shapeのひとつ、 beginpoint は表示位置さえまともならもう少し使えそうですが残念ながらオブジェクト名の部分に表示されてしまうため使えません。

メッセージ
-----------

（専門用語に明るくないのでエッジとか矢印とか言ったほうがしっくりきます）

メッセージのフォーマットは以下の通りです。
ID1とID2は同じものを指定しても構いませんが、活性区間が表示されません。
属性を全く定義しない場合は []部分は省略可能です。

~~~
ID1 関係 ID2 [属性1=値1, 属性2=値2, ...];
~~~

関係一覧

| 表記  | 用途 | 出力 |
|------|------|------|
->  | 同期メッセージ（活性区間開始） | 実線 + ▶ |
<- | 同期メッセージ（活性区間終了） | 実線 + ▶ |
--> | 用途不明（活性区間開始） | 破線 + ▶ |
<-- | 用途不明（活性区間終了） | 破線 + ▶ |
->> | 非同期メッセージ（活性区間開始） | 実線 + > |
<<- | 非同期メッセージ（活性区間終了） | 実線 + > |
-->> | 応答メッセージ（活性区間開始） | 破線 + > |
<<-- | 応答メッセージ（活性区間終了） | 破線 + > |
=> | 往復メッセージ（下記参照）| 「実線 + ▶」 ＋ 「破線 + ▶」 |

`=>` は「同期メッセージの開始」と「破線に黒三角」をセットにしたものが出てきます。
同じライフライン上でのメッセージで活性区間を出すためにはこの表記を使うしかないのですが
応答メッセージ（破線＋＞）でないので期待通りではなかったです。
（ネットワークのメッセージ授受では使えるのかな？）

属性はseqdiagに書かれているもののみ。

* label: メッセージ名。
* return: `=>` のみ有効。戻り値のラベル。
* color: 矢印とラベルの色。
* diagonal: 斜めに矢印を出します。属性値はありません。属性が未指定の場合は水平に出します。
* failed: 矢印が活性区間まで到達せずに途中で×を出す。位置がおかしいのでstop、destroyメッセージとしては使えない。
* note, rightnote, leftnote: ノート。それぞれ矢印の左右どちらかにノートを表示します。\nで改行可能です。改行した場合左揃えになります。
noteとrightnoteは同じ挙動をします。


ソースについて（メモ）
=====================

ここはソースを軽く読んだ結果のメモです。読み飛ばしてください。

* seqdiagはblockdiagからブロックやエッジの定義を流用している箇所がある。
* パーサーのバグはseqdiagのparser.pyを変更することでおおむね解決できそう。

できないこと
------------

* オブジェクト生成 (create)
* オブジェクト破棄 (destroy, stop)
* 表記されていないオブジェクトから/へのメッセージ (found, lost) 
* opt, ref, par, break, ... (ref, par以外はparser.pyのkeywordに追加すれば対応できるはず）
* sd (シーケンス名)

このような書き方をすると活性区間が消えてくれない。
 → 活性区間の描画はスタックベースでされているためAのスタックがなくなるまで残る。

~~~
seqdiag {
  A; B; C;

  A ->> B [label="イベント"];
  B -> C [label="データチェック"];
  B <-- C [label="OK"];
  
}
~~~

複合シーケンスの中にaltを書くとパースエラー。
altはトップレベルにないとエラーになります。parser.pyのgroup_stmtにfragment_stmtが含まれていないため。

~~~
seqdiag {
  A; B; C;

  A => B {
    alt {
      B => C;
    }
  }
}
~~~


（注）そもそも alt, loop ブロックはexperimentalな機能。ガード節やif-elseに相当する破線も実装されていない。