TITLE:複数行インラインプラグイン %indent #contents // convert_html / function & Factory_span L164 L246 L466 L889 L939 L965 L1041 L1096 L1166 // v v v v v v v v //////////////////////////////////////////////////////////////// * 方針 [#d6cbd2b4] - インラインプラグインの引数が長くなると改行が必要になる。 -- 特に TeX を利用している ##eq## とか。 - 複数行ブロックプラグインを真似て同じ構文で複数行インラインプラグインを導入。 - 引数展開もブロックプラグインに準じて非展開。 -- 技術上、従来のインラインプラグインのように引数を展開するのは困難。 -- TeX などの場合、引数非展開の方が好都合。 //////////////////////////////////////////////////////////////// * 仕様 [#e768ed92] >##$##'''plugin''' ##(##'''arg''' ##){{&br; ##'''body'''&br;##}}## <で、 >##&##'''plugin''' ##(##'''arg'''##,##'''body''' ##)## <と同等の振る舞い。 - 引数の処理は複数行ブロックプラグインに準ずる。 -- '''arg''' と'''body''' は引数非展開。 -- '''body''' の前、各行末は ##"\r" ##を挿入。 //////////////////////////////////////////////////////////////// * 実装 [#c9482637] - ##lib/convert_html.php## にて、##function & Factory_Div## をコピーし、##function & Factory_Span## に改造。 -- 「##!##」の行は ##function Factory_Div## からの差分。 --- ##&#;## の正規表現を ##\$## に、##new Div## を ##new Span## に置換。 - #code(diff){{{{ !function & Factory_Span(& $root, $text) { $matches = array(); // Seems block plugin? if (PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK) { // Usual code ! if (preg_match('/^\$([^\(]+)(?:\((.*)\))?/', $text, $matches) && exist_plugin_convert($matches[1])) { ! return new Inline($matches); } } else { // Hack code ! if(preg_match('/^\$([^\(\{]+)(?:\(([^\r]*)\))?(\{*)/', $text, $matches) && exist_plugin_inline($matches[1])) { $len = strlen($matches[3]); $body = array(); if ($len == 0) { return new Span($matches); // Seems legacy block plugin } else if (preg_match('/\{{' . $len . '}\s*\r(.*)\s*\}{' . $len . '}/', $text, $body)) { $matches[2] .= $body[1]; return new Span($matches); // Seems multiline-enabled block plugin } } } return new Inline($text); } }}}} // - - 同ファイルの ##class Div## をコピーし、##class Span## に改造。 -- 「##!##」の行は ##class Div## からの差分。 -- 「##+##」の行は ##class Inline## からのコピー。 --- これらは、インラインプラグインで始まる文を、後に段落に昇格させるための関数。 - #code(diff){{{{ !// $something (started with '$') for Multiline-enabled Argment-keeping Inline-plugin !class Span extends Element { var $name; var $param; ! function Span($out) { parent::Element(); list(, $this->name, $this->param) = array_pad($out, 3, ''); } function canContain(& $obj) { return FALSE; } + function & insert(& $obj) + { + $this->elements[] = $obj->elements[0]; + return $this; + } function toString() { // Call $plugin ! return do_plugin_inline($this->name, $this->param); } + function & toPara($class = '') + { + $obj = & new Paragraph('', $class); + $obj->insert($this); + return $obj; + } } }}}} // - 同ファイル、##class Body##の##var $factories##に対し、 - #code(diff){{{{ var $factories = array( ':' => 'DList', '|' => 'Table', ',' => 'YTable', - '#' => 'Div'); + '#' => 'Div', + '$' => 'Span'); }}}} // - 同クラス ##class Body## の ##function parse##の複数行ブロックプラグインの分岐をコピーして改造。 -- 「##!##」はコピー元に対する変更。 -- 丸引数の有無をチェックし、波引数との間の「##,##」の有無を調節。 - #code(diff){{{{ ! // Multiline-enabled Argment-keeping Inline-plugin if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK && ! preg_match('/^\$[^({]*(\((.*)\))?(\{\{+)\s*$/', $line, $matches)) { $delimiter = "\r"; ! $len = strlen($matches[3]); ! $line .= ($matches[2] == '') ? $delimiter : ','.$delimiter; while (! empty($lines)) { $next_line = rtrim(array_shift($lines), "\r\n"); if ($indent_format) { preg_match('/^(\s{'.$indent.'}?)?(.*)$/', $next_line, $matches); $next_line = $matches[2]; } if (preg_match('/\s*\}{' . $len . '}/', $next_line)) { $line .= ltrim($next_line); break; } else { $line .= $next_line . $delimiter; } } } }}}} // - 複数行インラインプラグインをインライン要素と同じ振る舞いさせるため、~ 同ファイル中の「##is_a($obj, 'Inline')##」を「##is_a($obj, 'Inline') || is_a($obj, 'Span')##」に置換。 -- ただし、##class Inline## の ##function canContain## だけは変えてはダメ。(理由は説明できないが、経験則) -- 同ファイル、##class Paragraph## と ##class Align## のそれぞれの ##function canContain## にて、 -- #code(diff){{{{ function canContain($obj) { - return is_a($obj, 'Inline'); + return is_a($obj, 'Inline') || is_a($obj, 'Span'); } }}}} // -- 同クラス ##class Body## の ##function & insert##にて、 -- #code(diff){{{{ function & insert(& $obj) { - if (is_a($obj, 'Inline')) $obj = & $obj->toPara(); + if (is_a($obj, 'Inline') || is_a($obj, 'Span')) $obj = & $obj->toPara(); return parent::insert($obj); } }}}} // -- 同ファイル、##class BQuote## の ##function & insert## にて、 -- #code(diff){{{{ function & insert(& $obj) { // BugTrack/521, BugTrack/545 - if (is_a($obj, 'inline')) + if (is_a($obj, 'inline') || is_a($obj, 'Span')) return parent::insert($obj->toPara(' class="quotation"')); }}}} //////////////////////////////////////////////////////////////// * 課題 [#jf808bb1] - プラグインの書式 -- 第1案:先頭1字で書式決定 --- 既存の「##&#;##」と「##&&;##」の間を日本語キーボード配列順(=ASCII順)に補間。 -- |* |*引数非展開 |< |*引数展開 |< | |^ |*ブロック |*インライン |*ブロック |*インライン | |*単一行|###〜(〜){〜}; ## |##$〜(〜){〜}; ## |##&%;〜(〜){〜}; ## |##&〜(〜{〜}; ## | |*複数行|###〜(〜){{&br;〜&br;}}##|##$〜(〜){{&br;〜&br;}}##|##&%;〜(〜){{&br;〜&br;}}##|##&〜(〜){{&br;〜&br;}}##| // -- 第2案:先頭1字でブロック/インラインを決定、第2字で引数展開/非展開を決定。 --- 既存の「##&#;##」と「##&&;##」のみで解決。 --- 「##&#;##」と「##&&;##」はそれぞれ「##&#;&#;##」と「##&&;&&;##」の省略的扱い。 -- |* |*ブロック |< |*インライン |< | |^ |*引数非展開 |*引数展開 |*引数非展開 |*引数展開 | |*単一行|##&#;#〜(〜){〜};## |###&〜(〜){〜};## |##&#〜(〜){〜};## |##&&〜(〜{〜};## | |*複数行|##&#;#〜(〜){{&br;〜&br;}}##|###&〜(〜){{&br;〜&br;}}##|##&#〜(〜){{&br;〜&br;}}##|##&&〜(〜){{&br;〜&br;}}##| //////////////////////////////////////////////////////////////// * コメント [#y2e30490] #pcomment //////////////////////////////////////////////////////////////// |