• 追加された行はこの色です。
  • 削除された行はこの色です。
#indent
#contents

* 当初の目標 [#u4d3368c]
- 数式機能 ── 数式を簡単に扱える環境の構築 → Latex との連携
- 字下げ書式 ── ウィキコードの可読性の向上
* 目標 [#u4d3368c]
- 工学数学サイト
-- Wiki システムの導入 ── 楽をするため。
--- 数式機能 ── 数式を扱うため → Latex。
--- コード機能 ── コードを扱うため → codehighlight。
--- 字下げ書式 ── ウィキコードの可読性向上のため。

* やっちゃったこと [#k374ea5f]

** 字下げ書式の導入 [#i1a118a8]
//-- convert_html L977 L981 L986
*** 方針
- Wikiは行指向のため、コードの見通しが悪くなりがち。字下げを導入でコード可読性を改善。得に複数行プラグインとか。
*** 仕様 [#m9bc6a64]
- 字下げ書式モードでは、行頭の空白は無視。
-- ただし、複数行プラグインの引数に対しては、プラグインの先頭行の字下げ分のみを無視。~
   例:
   ^    #plugin(){{
   ^        arg
   ^        arg
   ^    }}
   は、
   ^#plugin(){{
   ^    arg
   ^    arg
   ^}}
   と等価。
- 疑似プラグイン ##&#;indent## で字下げ書式モードに切り替え。
- 疑似プラグイン ##&#;noindent## で天突き書式モードに切り替え。
- デフォルトは天突き書式。
- 字下げ書式では、行頭が空白の整形済みテキストは無効。
- [[字下げ書式の導入>./字下げ書式]]
- [[H整形済みテキスト書式の導入>./H整形書式]]
- [[P表組書式の改造>./P表組書式]]
- [[数式プラグインの導入>./数式プラグイン]]
- [[複数行インラインプラグインの導入>./複数行インラインプラグイン]]
- [[コードプラグインの改造>./コードプラグイン]]
- [[エスケープシーケンスの追加>./エスケープシーケンス]]
- [[リスト系書式のスキーン変更>./リストスキーン]]
- [[ネイティブエイリアスの導入>./ネイティブエイリアス]] ── PukiWiki風のプラグイン書式
- 空行書式の導入
- [[SC改行改段書式の導入>./SC改行改段書式]]
- [[その他>./その他]]
-- パンくずリストの改造
//-- ページの先頭と末尾へのリンクの移動
- [[ググるプラグインの導入>./ググる]]
- [[日本語アンカー名の導入>./日本語アンカー名]]
- [[blockdiagの導入>./blockdiagの導入]]
- [[YouTubeプラグイン>./YouTubeプラグイン]]

*** 改造 [#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') {...}## は天突き書式へ切り替える疑似プラグイン
*** 課題
- 「##&#;indent##」と「##&#;noindent##」による文脈の切り替えは良くない。
-- 互換性を捨て、字下げ書式に限定すべきか?

** H整形の導入
//-- convert_html L800 L1100
*** 方針
- 字下げ書式では、行頭の空白は無視されるため、従来の空白整形済みテキストに代わる書式が必要。
- 先頭が「##&^;##」で始まる「H整形/Hat整形」を導入。
-- 正規表現で行頭を示す「##&^;##」、また、Wikiで引用を表す「##&>;##」や「##&<;##」からの連想。
- 以降では便宜上、空白で始まる整形済みテキストの書式を「S整形/Space整形」で区別。

*** 仕様
- 行頭が「##&^;##」の行は整形済み書式と見なす。基本仕様はS整形に同じ。
- S整形とH整形の混用は無効。段が一旦切られる。
- 天突き書式の場合、「##&^;##」の左に空白があるとSと見なされ、「##&^;##」が残る。

*** 改造
- ##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表の改造
//-- convert_html L498 L507 L530 L636 L668
*** 方針
- 便宜上、行頭が「##|##」の表を「P表/Pipe表」、行頭が「##,##」の表を「C表/Comma表」で区別する。
- P表では、縦方向の関連性が強いので、空白による整列はコードの可読性向上に必要。
- P表では、行方向のセル連結は右方向(##&>;##)でも良いが、左方向の連結も欲しい。
-- コードは左から右、上から下に向かって読むもの、列方向と同様、結合記号より先にセル内容を記述すべき。
- 「##&~;##」は列方向のセル連結と、ヘッダ(##th##)の2つの意味がある上、空白による整列を許すと構文が衝突する。
-- 「##&>;##」からの連想で、左向き連結に「##&<;##」を、上向き連結に「##&^;##」を導入。
-- 「*」などからの連想で、ヘッダに「##&^;##」を導入。
*** 仕様
- セル内の先頭と末尾の空白を無視。
- 「##&>;##」のみのセルは右のセルに連結
- 「##&^;##」のみのセルは上のセルに連結
- 「##&<;##」のみのセルは左のセルに連結(互換仕様)
- 「##&~;##」のみのセルは上のセルに連結(互換仕様)
- 「##&*;##」で始まるセルはヘッダ(##th##)。
- 「##&~;##」で始まる非空白セルはヘッダ(##th##)。(互換仕様)

*** 改造
- ##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);## の符号 ##+## は連結方向の影響。

** リスト系書式のスキーン変更
// / L318x L323x L352x L373
//-- default.ini.php / 特殊シンボル
*** 方針
- リストの左マージンや階層間間隔はSkinとして指定すべき。
- タグ中にstyle属性を直に指定されると、外部CSSが優先順位で負けてしまうので都合が悪い。

*** 改造
- ##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## の追加
*** 方針
- 引数をLaTeXに渡し、dvipngにより画像に変換し、convertで適切に画像処理を施す。
-- なお、convertは画像編集ツール群[[Imagemagic>http://www.imagemagick.org/script/index.php]]の一要素。CUIによる画像処理に長けてる。
- 基本仕様は[[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]]に従う。
- WindwosとUnix/Linuxのコマンドの違いを可能な限りプラグイン側で吸収する。
- 並列処理してもファイル名が衝突がしないようにする。 
- インライン数式の場合、分数線が中心に来るように位置調節する。
-- 例えば、数式の中心揃えは&attachref;ではなく、&eq(\ffd{\ffd{X}{X}}{X});であるべきです。
#eq{{{{
    \ffd{\ffd{X}{X}}{X}
}}}}

*** 仕様
-- 現時点では、まだUnix/Linuxで確認しておらず。
- 
- 

*** 改造
- ##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 '</p><div><pre class=eq_error_title>'.$arg.'</pre><pre class=eq_error_message>'.$err_code.'</pre></div><p>';
            }
            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.'">';
    }
    ?>
    }}}}


- 複数行eq書式
//* 複数行eq書式
// -- pukiwiki.php L135 L140


*
----
- 複数行インラインプラグイン
-- 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]
- 編集画面のスキーン変更
-- 編集関連ボタンの上下配置
-- テキストエリアの寸法の相対指定

* タッチしたファイル [#j8c5f492]

- lib/
-- &attachref(./convert_html.php); for 字下げ、H整形、P表組
- plugin/
-- code/
--- &attachref(./codehighlight.php);
--- &attachref(./line.diff.php);
--- &attachref(./line.pukiwiki.php);
-- &attachref(./code.inc.php);
-- &attachref(./eq.inc.php);
- eq/
-- &attachref(./convert.tex);
-- &attachref(./inline.tex);
-- pukiwiki.sty (アップ予定) 

つづく

fileline.pukiwiki.php 459件 [詳細] fileline.diff.php 448件 [詳細] fileinline.tex 437件 [詳細] fileconvert_html.php 470件 [詳細] fileeq.inc.php 506件 [詳細] fileconvert.tex 422件 [詳細] filecodehighlight.php 438件 [詳細] filecode.inc.php 474件 [詳細]
    初基 一覧 検索 最新 バックアップ リンク元   ヘルプ   最終更新のRSS