- 追加された行はこの色です。
- 削除された行はこの色です。
#indent
#contents
* 当初の目標 [#u4d3368c]
- 数式機能 ── 数式を簡単に扱える環境の構築 → Latex との連携
- 字下げ書式 ── ウィキコードの可読性の向上
* 目標 [#u4d3368c]
- 工学数学サイト
-- Wiki システムの導入 ── 楽をするため。
--- 数式機能 ── 数式を扱うため → Latex との連携。
--- コード機能 ── コードを扱うため → code プラグイン。
--- 字下げ書式 ── ウィキコードの可読性向上のため → 地道に努力。
* 自分への警告
- Wiki は道具。目的に非ず。
* やっちゃったこと [#k374ea5f]
- [[字下げ書式の導入>字下げ書式]]
//-- convert_html L977 L981 L986
*** 方針 [#fbf6bd7e]
- Wikiは行指向のため、コードの見通しが悪くなりがち。字下げを導入でコード可読性を改善。得に複数行プラグインとか。
*** 仕様 [#m9bc6a64]
- 字下げ書式モードでは、行頭の空白は無視。
-- ただし、複数行プラグインの引数に対しては、プラグインの先頭行の字下げ分のみを無視。~
例:
^ #plugin(){{
^ arg
^ arg
^ }}
は、
^#plugin(){{
^ arg
^ arg
^}}
と等価。
- 疑似プラグイン ##&#;indent## で字下げ書式モードに切り替え。
- 疑似プラグイン ##&#;noindent## で天突き書式モードに切り替え。
- デフォルトは天突き書式。
- 字下げ書式では、行頭が空白の整形済みテキストは無効。
- [[字下げ書式の導入>./字下げ書式]]
- [[H整形済みテキスト書式の導入>./H整形書式]]
- [[P表組書式の改造>./P表組書式]]
*** 改造 [#cfaf32ae]
- ##pukiwiki.ini.php## の適当な場所にて、
#code(diff){{
+ $indent_format = 0;
}}
-- ##$indent_format## は天突きと字下げを表すフラグ。
--- ##$indent_format = 0# ⇔ 天突き書式。(デフォルト)
--- ##$indent_format = 1# ⇔ 字下げ書式。
//
- ##convert_html.php## の ##function parse## 入り口直後にて、
#code(diff){{
function parse(& $lines)
{
+ global $indent_format;
$this->last = & $this;
$matches = array();
+ $indent = "";
}}
-- ##$indent = "";## は字下げした深さを格納する変数。複数行プラグインで利用。
//
- ##convert_html.php## の ##function parse## の ##while (!empty($lines))##直後にて、
#code(diff){{{{
while (! empty($lines)) {
$line = array_shift($lines);
+ // Indent extension
+ if ($indent_format)
+ {
+ preg_match('/^(\s*)(.*)$/', $line, $matches);
+ $indent = strlen($matches[1]);
+ $line = $matches[2] ;
+ }
+
+ if (rtrim($line) == '#indent') {
+ $indent_format = 1;
+ continue;
+ }
+ if (rtrim($line) == '#noindent') {
+ $indent_format = 0;
+ continue;
+ }
// Escape comments
if (substr($line, 0, 2) == '//') continue;
}}}}
-- ##$line = array_shift($lines);## でラインを切り出すため、この後に記述。
-- ##Escape comments##など全てが字下げの影響を受けるため、これらの前に記述。
-- ##if (rtrim($line) == '#indent') {...}## は字下げ書式へ切り替える疑似プラグイン
-- ##if (rtrim($line) == '#noindent') {...}## は天突き書式へ切り替える疑似プラグイン
*** 課題 [#o0fd377a]
- 「##&#;indent##」と「##&#;noindent##」による文脈の切り替えは良くない。
-- 互換性を捨て、字下げ書式に限定すべきか?
- [[数式プラグインの導入>./数式プラグイン]]
- [[複数行インラインプラグインの導入>./複数行インラインプラグイン]]
- [[コードプラグインの改造>./コードプラグイン]]
** H整形の導入 [#leec5559]
//-- convert_html L800 L1100
*** 方針 [#h5024014]
- 字下げ書式では、行頭の空白は無視されるため、従来の空白整形済みテキストに代わる書式が必要。
- 先頭が「##&^;##」で始まる「H整形/Hat整形」を導入。
-- 正規表現で行頭を示す「##&^;##」、また、Wikiで引用を表す「##&>;##」や「##&<;##」からの連想。
- 以降では便宜上、空白で始まる整形済みテキストの書式を「S整形/Space整形」で区別。
- [[エスケープシーケンスの追加>./エスケープシーケンス]]
- [[リスト系書式のスキーン変更>./リストスキーン]]
- [[その他>./その他]]
-- パンくずリストの改造
-- ページの先頭と末尾へのリンクの移動
*** 仕様 [#z8a6319e]
- 行頭が「##&^;##」の行は整形済み書式と見なす。基本仕様はS整形に同じ。
- S整形とH整形の混用は無効。段が一旦切られる。
- 天突き書式の場合、「##&^;##」の左に空白があるとSと見なされ、「##&^;##」が残る。
*** 改造 [#uc70684d]
- ##convert_html.php## で、S整形のクラス ##class Pre## を''コピー''。場所は任意だが、流れ的にS整形の直後で、
#code(diff){{{{
! // '^ 'Hat-beginning sentence
! // '^ 'Hat-beginning sentence
! // '^ 'Hat-beginning sentence
! class HPre extends Element // for Indent extension
{
! function HPre(& $root, $text)
{
parent::Element();
$this->elements[] = htmlspecialchars(substr($text, 1));
}
function canContain(& $obj)
{
! return is_a($obj, 'HPre');
}
function & insert(& $obj)
{
$this->elements[] = $obj->elements[0];
return $this;
}
function toString()
{
return $this->wrap(join("\n", $this->elements), 'pre');
}
}
}}}}
-- ##'HPre'## はH整形の識別キーであり、クラス名と一致する必要がある。
//
- 同ファイルの ##class Body## の ##function parse## の ##while (! empty($lines))## 中にて、##Pre##に関する分岐を''コピー''し、
#code(diff){{{{
// Pre
- if ($head == ' ' || $head == "\t") {
+ if (!$indent_format && ($head == ' ' || $head == "\t")) {
$this->last = & $this->last->add(new Pre($this, $line));
continue;
}
+ // HPre
+ if ($head == '^') {
+ $this->last = & $this->last->add(new HPre($this, $line));
+ continue;
+ }
}}}}
-- ##!$indent_format && ## は字下げ書式でS整形を無効化する条件。
-- ##if ($head == '^')##はH整形への分岐。
** P表の改造 [#o71c4a74]
//-- convert_html L498 L507 L530 L636 L668
*** 方針 [#c85e18a7]
- 便宜上、行頭が「##|##」の表を「P表/Pipe表」、行頭が「##,##」の表を「C表/Comma表」で区別する。
- P表では、縦方向の関連性が強いので、空白による整列はコードの可読性向上に必要。
- P表では、行方向のセル連結は右方向(##&>;##)でも良いが、左方向の連結も欲しい。
-- コードは左から右、上から下に向かって読むもの、列方向と同様、結合記号より先にセル内容を記述すべき。
- 「##&~;##」は列方向のセル連結と、ヘッダ(##th##)の2つの意味がある上、空白による整列を許すと構文が衝突する。
-- 「##&>;##」からの連想で、左向き連結に「##&<;##」を、上向き連結に「##&^;##」を導入。
-- 「*」などからの連想で、ヘッダに「##&^;##」を導入。
*** 仕様 [#o85fbc27]
- セル内の先頭と末尾の空白を無視。
- 「##&>;##」のみのセルは右のセルに連結
- 「##&^;##」のみのセルは上のセルに連結
- 「##&<;##」のみのセルは左のセルに連結(互換仕様)
- 「##&~;##」のみのセルは上のセルに連結(互換仕様)
- 「##&*;##」で始まるセルはヘッダ(##th##)。
- 「##&~;##」で始まる非空白セルはヘッダ(##th##)。(互換仕様)
*** 改造 [#l46a1161]
- ##convert_html.php## の ##class TableCell## にて、
#code(diff){{{{
class TableCell extends Element
{
var $tag = 'td'; // {td|th}
+ var $colleft = 0; // ==0: colspan to right by '>'; ==1: colspan to left by '<';
var $colspan = 1;
var $rowspan = 1;
var $style; // is array('width'=>, 'align'=>...);
}}}}
-- ##$colleft##は行結合方向を表す変数。
--- ##$colleft = 0# ⇔ 左に連結。
--- ##$colleft = 1# ⇔ 右に連結。
- 同クラスの##function TableCell## にて、
#code(diff){{{{
function TableCell($text, $is_template = FALSE)
{
parent::Element();
$this->style = $matches = array();
+ $text = trim($text);
}}}}
-- ##trim## でセル先頭と末尾の空白を除去。
- 同関数 セル結合の分岐にて、
#code(diff){{{{
if ($text == '>') {
+ $this->colleft = 0;
$this->colspan = 0;
+ } else if ($text == '<') {
+ $this->colleft = 1;
+ $this->colspan = 0;
- } else if ($text == '~') {
+ } else if ($text == '^' || $text == '~') {
$this->rowspan = 0;
- } else if (substr($text, 0, 1) == '~') {
+ } else if (substr($text, 0, 1) == '*' || substr($text, 0, 1) == '~') {
$this->tag = 'th';
$text = substr($text, 1);
}
}}}}
-- ##$this->colleft## の追加は連結向きの指定
-- ##if ($text == '<')## は左向き連結。
-- ##$text == '^' || ## は上向き連結。
-- ##substr($text, 0, 1) == '*' || ## はヘッダ。
- 同関数 セル結合ループにて、右向き連結のオリジナルに対して変更し、さらに左向き連結用に''コピー''、
#code(diff){{{{
! // Set colspan and style, from right to left.
+ $stylerow = NULL;
+ foreach (array_keys($this->elements) as $nrow) {
+ $row = & $this->elements[$nrow];
+ if ($this->types[$nrow] == 'c')
+ $stylerow = & $row;
+ $colspan = 1;
! foreach (array_reverse(array_keys($row)) as $ncol) {
! if ($row[$ncol]->colspan == 0 && $row[$ncol]->colleft == 1) {
+ ++$colspan;
+ continue;
+ }
+ if ($row[$ncol]->colspan > 0 && $row[$ncol]->$colspan < $colspan) {
+ $row[$ncol]->colspan = $colspan;
+ }
+ if ($stylerow !== NULL) {
+ $row[$ncol]->setStyle($stylerow[$ncol]->style);
+ // Inherits column style
+ while (--$colspan)
! $row[$ncol + $colspan]->setStyle($stylerow[$ncol]->style);
+ }
+ $colspan = 1;
+ }
+ }
- // Set colspan and style
+ // Set colspan and style, from left to right.
$stylerow = NULL;
foreach (array_keys($this->elements) as $nrow) {
$row = & $this->elements[$nrow];
if ($this->types[$nrow] == 'c')
$stylerow = & $row;
$colspan = 1;
foreach (array_keys($row) as $ncol) {
- if ($row[$ncol]->colspan == 0) {
+ if ($row[$ncol]->colspan == 0 && $row[$ncol]->colleft == 0) {
++$colspan;
continue;
}
+ if ($row[$ncol]->colspan > 0 && $row[$ncol]->colspan < $colspan) {
$row[$ncol]->colspan = $colspan;
+ }
if ($stylerow !== NULL) {
$row[$ncol]->setStyle($stylerow[$ncol]->style);
// Inherits column style
while (--$colspan)
$row[$ncol - $colspan]->setStyle($stylerow[$ncol]->style);
}
$colspan = 1;
}
}
}}}}
-- 見やすくするため、コピーの差分を「##!##」で示した。
-- 内側ループ ##foreach (array_reverse(array_keys($row)) as $ncol)## の ##array_reverse## でスキャン向きを反転する仕組み。
-- ##$row[$ncol + $colspan]->setStyle($stylerow[$ncol]->style);## の符号 ##+## は連結方向の影響。
** リスト系書式のスキーン変更 [#zc75542f]
// / L318x L323x L352x L373
//-- default.ini.php / 特殊シンボル
*** 方針 [#m982063f]
- リストの左マージンや階層間間隔はSkinとして指定すべき。
- タグ中にstyle属性を直に指定されると、外部CSSが優先順位で負けてしまうので都合が悪い。
*** 改造 [#ude0b949]
- ##convert_html.php## の ##class ListContainer## にて、
#code(diff){{{{
class ListContainer extends Element
{
var $tag;
var $tag2;
var $level;
- var $style;
- var $margin;
- var $left_margin;
}}}}
- 同クラスの ##function ListContainer## にて、
#code(diff){{{{
function ListContainer($tag, $tag2, $head, $text)
{
parent::Element();
- $var_margin = '_' . $tag . '_margin';
- $var_left_margin = '_' . $tag . '_left_margin';
- global $$var_margin, $$var_left_margin;
-
- $this->margin = $$var_margin;
- $this->left_margin = $$var_left_margin;
}}}}
- 同クラスの ##function setParent## にて、
#code(diff){{{{
function setParent(& $parent)
{
global $_list_pad_str;
parent::setParent($parent);
$step = $this->level;
if (isset($parent->parent) && is_a($parent->parent, 'ListContainer'))
$step -= $parent->parent->level;
$margin = $this->margin * $step;
if ($step == $this->level)
$margin += $this->left_margin;
-
- $this->style = sprintf($_list_pad_str, $this->level, $margin, $margin);
}
}}}}
- 同クラスの ##function toString## にて、
#code(diff){{{{
function toString()
{
- return $this->wrap(parent::toString(), $this->tag, $this->style);
+ return $this->wrap(parent::toString(), $this->tag, ' class="list'.$this->level.'"');
}
}}}}
-- 階層毎に異なるスタイルを指定する場合は、従来のまま ##.list1##、##.list2##と##.list3## を利用。
-- 全階層に共通のスタイルを指定する場合は、タグ名を利用すれば良い。そのスタイルを上書きするスタイルは削除済み。
- ##default.ini.php## にて、
#code(diff){{{{
-/////////////////////////////////////////////////
-// リスト構造の左マージン
-$_ul_left_margin = 0; // リストと画面左端との間隔(px)
-$_ul_margin = 16; // リストの階層間の間隔(px)
-$_ol_left_margin = 0; // リストと画面左端との間隔(px)
-$_ol_margin = 16; // リストの階層間の間隔(px)
-$_dl_left_margin = 0; // リストと画面左端との間隔(px)
-$_dl_margin = 16; // リストの階層間の間隔(px)
-$_list_pad_str = ' class="list%d" style="padding-left:%dpx;margin-left:%dpx"';
}}}}
** 数式プラグイン ##eq## の追加 [#i7d58008]
*** 方針 [#m1f9dc5e]
- 基本仕様は[[wikihouse.com>http://www.wikihouse.com/fem/index.php?PukiWiki]]の[[math2.inc.php>http://www.wikihouse.com/fem/index.php?%BC%AB%BA%EE%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3%2Fmath2.inc.php]]に従う。
-- ただし、ハッシュの衝突が心配のため、数式の同定は生のTeXコードで比較。
-- プラグインの同時呼出しで作業ファイルが衝突するため、全てハッシュ名を用いる。
-- LaTeX、dvipngにより数式画像生成後に、[[Imagemagic>http://www.imagemagick.org/script/index.php]]のconvertで画像処理を施す。
- 数式の質は、それなりに拘る。少なくとも処理速度などよりは優先。
*** 仕様 [#g2292a0a]
- パスを通した platex、dvipngとconvertが必要。
- 引数をそのままLaTeXに渡し、最終的にpng画像に変換して出力。
-- ブロックプラグインの場合は、##align##環境(##\begin(align) 〜 \end(align)##)に渡される。
-- インラインプラグインの場合は、ディスプレイ数式モードに変更されるテキスト数式モード($ \displaystyle 〜 $)に渡される。
- 全ファイルはファイル名は数式に基づくハッシュキーを使用。
- ##pukiwiki://eq/{ハッシュキー}.eq## に生のTeX式を保存し、数式の同定に使用。ハッシュキーを同定には使わない。
- ##pukiwiki://eq/{ハッシュキー}.png## に数式画像を出力。
-- ブラウザのズーム対策として、画像を高解像度で出力し、##IMG##タグの##width##と##height##で縮小表示。
- インライン数式の垂直揃えは中心揃え(##vertical-align: middle;##)。分数線が画像中心に来るようにTeX側で調節する。
-- dviには位置決めのために数式に枠を付けて出力。convertにより枠を除去。
- 数式がコンパイルでき無い場合、TeXのエラーを出力。
*** 改造 [#b3d347a1]
- ##pukiwiki://plugin/eq.inc.php## を作成して、
#code(php){{{{
<?php
function plugin_eq_convert()
{
$arg = rtrim(join(func_get_args(), ','), ','); // 末尾の「,」は波引数が空の場合に現れ、不要物。
return '<div class="eq">'.plugin_eq_core($arg, 'convert').'</div>';
}
function plugin_eq_inline()
{
$arg = rtrim(join(func_get_args(), ','), ','); // 末尾の「,」は波引数が空の場合に現れ、不要物。
return '<span class="eq">'.plugin_eq_core($arg, 'inline').'</span>';
}
function plugin_eq_core($arg, $mode)
{
$eq_dir = './eq/'; // 数式と数式画像のパス
$err_msg_end_phrase = 'No pages of output.'.PHP_EOL; // エラー終了を示す文字列(platexの出力依存)
$prefix_convert = 'eq-nc-'; // ブロック用ファイル衝突を避けるための接頭語
$prefix_inline = 'eq-ni-'; // インライン用ファイル衝突を避けるための接頭語
$tex_frame_convert = 'convert.tex'; // ブロック用フレームファイル名
$tex_frame_inline = 'inline.tex' ; // インライン用フレームファイル名
$eq_replace_phrase = '\input{eq}' ; // フレームファイルで数式を埋め込む部を示す文字列
$key = ($mode=='inline') ? $prefix_inline.md5($arg) : $prefix_convert.md5($arg);
$eq = $key.'.eq'; // 照合用引数出力(保存ファイル)
$img = $key.'.png'; // 数式の画像出力(保存ファイル)
$old_dir = getcwd();
chdir($eq_dir);
if (!file_exists($img) || $arg != file_get_contents($eq))
{
// 一時ファイル
$tex = $key.'.tex';
$std = $key.'.std.log'; // Tex の標準出力、エラー出力用
$dvi = $key.'.dvi';
$aux = $key.'.aux';
$log = $key.'.log';
$box = $key.'.box.png';
$face = $key.'.face.png';
$edge = $key.'.edge.png';
$bold = $key.'.bold.png';
flush(); // Timeout 対策
$tex_code = file_get_contents(($mode=='inline') ? $tex_frame_inline : $tex_frame_convert);
$tex_code = str_replace($eq_replace_phrase, $arg, $tex_code);
file_put_contents($eq ,$arg );
file_put_contents($tex ,$tex_code);
exec('platex -halt-on-error '.$tex.' > '.$std);
flush(); // Timeout 対策
if (!file_exists($dvi)) // Tex Error
{
$err_flag = false;
$err_code = "Tex Error:\n\n";
if ($log_code = fopen($std, 'r'))
{
while (!feof($log_code))
{
$tex_msg = fgets($log_code);
if ($tex_msg[0] == '!' ) {$err_flag = true ;}
else if ($tex_msg == $err_msg_end_phrase) {$err_flag = false;}
if ($err_flag) {$err_code .= $tex_msg;}
}
fclose($log_code);
}
chdir($old_dir);
return '<pre class=eq_error_title>'.$arg.'</pre><pre class=eq_error_message>'.$err_code.'</pre>';
}
exec('dvipng -D 720 -T tight --gamma 2.5 -o '.$box.' '.$dvi);
if ($mode=='inline') {
list($width, $height) = getimagesize($box);
exec('convert '.$box.' -crop '.($width-16).'x'.($height-16).'+8+8 -bordercolor #FFFFFF -threshold 50% '.$face);
} else {
exec('convert '.$box.' -bordercolor #FFFFFF -border 16x16 -threshold 50% '.$face);
}
exec('convert '.$face.' -edge 1 -negate '.$edge);
exec('composite -compose multiply '.$face.' '.$edge.' '.$bold);
exec('convert '.$bold.' -black-threshold 90% -antialias -blur 1 - | convert - -transparent #FFFFFF -antialias '.$img);
flush(); // Timeout 対策
unlink($tex );
unlink($std );
unlink($dvi );
unlink($aux );
unlink($log );
unlink($box );
unlink($face);
unlink($edge);
unlink($bold);
}
list($width, $height) = getimagesize($img);
chdir($old_dir);
return '<img widht='.round($width/7).' height='.round($height/7).' src="'.$eq_dir.$img.'" alt="eq: '.$arg.'" title="'.$arg.'">';
}
?>
}}}}
-- 17行目は数式のパスを指定。数式のキャッシュとみなせるため、##cache/##と同じレベルに##eq/##を作った。
-- 26行目は数式のハッシュキー。プラグインの種別と数式のmd5ハッシュに依存。
-- 34〜98行目は変換処理。数式が変換済みの場合は分岐が成立せず、処理が省かれる。
-- 47行目、55行目と88行目の ##flash();## はタイムアウト対策。これらが無いと、大量の数式を変換するとPHPが落ちる。
-- 48、49行目はTeXコードの雛形の読み込みと数式の組み込み(=置換)。52行目で数式のTeXファイルを出力。
-- 56〜76行目はTeXがエラーのときの処理。エラーの場合、ログを解析し、エラーの部分をだけ出力。
--- 67行目と68行目はそれぞれエラー部の開始と終了の検出。これが環境依存のため、変更が必要かもしれない。
-- 77〜86行目は画像処理。インラインプラグインでは位置決め枠の除去のため、ブロックプラグインより処理が多い。
-- 99行目、102行目は数式画像のサイズを取得し、表示すべきサイズを算出し、出力している。
--- 数式画像の表示サイズは、77行目のdvipngの解像度 ##-D 720## と102行目の ##$width/7## と ##$height/7## の分母で調節可能。
- ##pukiwiki://eq/convert.tex## を作成して、
#code(tex){{{{
\documentclass[12pt]{jarticle}
\usepackage{amsmath,amssymb,bm}
\usepackage{pukiwiki}
\pagestyle{empty}
\begin{document}
\thispagestyle{empty}
\begin{align*}
\input{eq}
\end{align*}
\end{document}
}}}}
----
* ----
- 複数行eq書式
//* 複数行eq書式
// -- pukiwiki.php L135 L140
* [#f27cfd07]
----
- 複数行インラインプラグイン
-- convert_html / function & Factory_span L164 L246 L466 L889 L939 L965 L1041 L1096 L1166
- エスケープシーケンス
-- make_link L59 L285
- Code 行番号ズレ
-- codehighlight L83
- インラインcode
-- code.inc.php L71 L101
- Code pukiwiki indent 対応
-- codehighlight L169 L208
-- code/line.pukiwiki.php
- C 拡張
-- code/keyword.c.php
- diff拡張
-- code/line.diff.php
- パンミミ
-- topicpath.inc.php L32
- ページの先頭と末尾へのリンクの移動
-- default.ini.php / 特殊シンボル
-- edit.inc.php L98 L121
- フッとノートスキーン変更
-- html.php L128
* これからやること [#l51150c7]
- 編集画面のスキーン変更
-- 編集関連ボタンの上下配置
-- テキストエリアの寸法の相対指定
* 参考:タッチしてしまったファイル
- アップ予定
* コメント
#pcomment