• 追加された行はこの色です。
  • 削除された行はこの色です。
/日本語アンカー名
#indent
#contents

////////////////////////////////////////////////////////////////
*方針 [#wbd776ad]
 
ページ名を日本語に設定できることが PukiWiki 派閥の売りの一つ。
しかし、アンカー名は HTML の制約を受けて英字限定である。
日本語のページ名を設定できることが PukiWiki 流派の売りの一つ。
しかし、アンカー名は HTML の制約を受けて英字限定のままである。

Wiki は HTML ではないから、Wiki は HTML のできないことをできても良い。
そして、日本語のページが必要とされるように、日本語のアンカー名も必要とされている。
Wiki は HTML ではない。
Wiki は HTML のできないことをして良い。
日本語のページが必要とされるように、日本語のアンカー名も必要である。

また、日本語のページ名に対応するため、PukiWiki では「ブラケット名」と呼ばれる以下の構文を導入した。
また、日本語のページ名に対応するため、PukiWiki では「ブラケット名」と呼ばれる以下の構文を導入している。
###
   [[ページ名#アンカー名]]
###
これに対し、アンカーを下ろすには aname プラグインを使う必要がある。
###
   &aname(アンカー名);
###
この非対称を無くすため、そして、アンカーを目立たせるため、
aname に対応した Wiki 構文 = [[ネイティブエイリアス>../ネイティブエイリアス]]を設ける。
aname に対応した Wiki 構文 = [[ネイティブエイリアス>../ネイティブエイリアス]]を設けべし。
 
////////////////////////////////////////////////////////////////
* 仕様 [#q38acc3a]
////////////////////////////////////////////////////////////////
** アンカープラグイン aname とブラケット書式 ##[&[;〜&];]##の仕様変更 [#xfd8274a]
アンカーに日本語を許す。
ただし、半角記号「##[>#]##」は書式に使用するため、アンカー文字に使用不可とする。

** アンカーのエンコード方式 [#hc15664a]
アンカーのエンコードは PukiWiki に使われる URL のエンコード方式を流用する。
ただし、HTML の id の仕様を満たすため、以下の変換とする。
#ceq(e)
    変換規則
#ceq(q)
    例:アンカー名
#ceq(a)
    目的
#ceq(e)
    1. rawurlencode で URL 文字列に変換
#ceq(q)
    %A5%A2%A5%F3%A5%AB%A1%BC%CC%BE
#ceq(a)
    PukiWiki の URL エンコード方式
#ceq(e)
    2. 「##%##」を「##_##」に置換
#ceq(q)
    _A5_A2_A5_F3_A5_AB_A1_BC_CC_BE
#ceq(a)
    HTML の id では「%」を使用不能。
#ceq(e)
    3. 「Anchor」を先頭に付加
#ceq(q)
    Anchor_A5_A2_A5_F3_A5_AB_A1_BC_CC_BE
#ceq(a)
    HTML の id は「_」を先頭に配置不能。Anchorであることを明示。
#ceq(end)

** ネイティブエイリアス ##[&[;[〜]&];]## [#db881104]
リンクのネイティブ書式が ##&[;[〜]&];## に因み、アンカーを ##[&[;[〜]&];]## とする。
これは、似た目的のインライン書式に同じ記号を割り当てる Wiki の方針に則っている。
|      |l:lx:            |lx:       |lx:      |l:lx:              |c
|太字  |: ##'&';〜&';'##|## ⇔ ##|斜体     |: ##'&';'〜'&';'##|
|削除  |: ##%&%;〜&%;%##|## ⇔ ##|更新     |: ##%&%;%〜%&%;%##|
|リンク|: ##[&[;〜&];]##|## ⇔ ##|アンカー |: ##[&[;[〜]&];]##|

##[&[;〜&];]## 自体の拡張も検討したが、##[&[;〜&];]## が既に複雑であることを考慮し、別書式とした。
- 例: アンカー ##[&[;#&#;〜&];]## ## ⇔ ## リンク ##[&[;#〜&];]##

ネイティブエイリアス##[&[;[〜]&];]##の書式を以下の3つのモードとする。
:アンカーのみ ##[&[;[&#;## '''Anchor''' ##]&];]##|
-'''Anchor''' をアンカーに設定する。
-アンカー位置には何も表示しない。
:エイリアス指定 ##[&[;[## '''Alias''' ##]&];]##|
-'''Alias'''をアンカーに設定する。
-アンカー位置に'''Alias'''を表示する。
:エイリアスとアンカーの同時指定 ##[&[;[## '''Alias''' ># '''Anchor''' ##]&];]##|
-'''Anchor''' をアンカーに設定する。
-アンカー位置に'''Alias'''を表示する。
 
書式文字を「##@##」、対応するプラグイン名を「##plugin##」とする。
 
:単一行インラインプラグイン|「##@@〜@@##」は「##&plugin(〜);##」または「##&plugin{〜};##」と等価である。
機能的違いは引数の展開/保持。どっちになるかはプラグインの性質次第。
 
:複数行インラインプラグイン|
^@@ …
^〜
^@@

^$plugin(…){{{{{{{{{{{{{{{{
^〜
^}}}}}}}}}}}}}}}};
と等価である。
 
:複数行ブロックプラグイン|
^@@@ …
^〜
^@@@

^#plugin(…){{{{{{{{{{{{{{{{
^〜
^}}}}}}}}}}}}}}}}
と等価である。
 
数式プラグインの場合、書式文字は「##$##」、プラグイン名は「##eq##」。
書式文字は TeX のインライン数式モード「##$〜$##」に由来。
用例は[[書式/数式]]を参照。
 
コードプラグインの場合、書式文字は「##&#;##」、プラグイン名は「##code##」。
書式文字は、「#####」の形が等幅表示のための桝目からの連想。
また、C言語で、別言語であるプリプロセッサのコードを埋め込むときに用いられることからの連想。
用例は[[書式/コード]]を参照。
 
////////////////////////////////////////////////////////////////
* 実装 [#g668057c]
** 単一行インラインプラグイン [#y4dab69e]
 
- ##lib/make_link.php## の ##class InlineConverter## の ##function InlineConverter## にて、
////////////////////////////////////////////////////////////////
** プラグイン aname [#y4dab69e]
- ##plugin/aname.inc.php## の先頭、グローバル領域にて、
    #code(diff){{{{
         function InlineConverter($converters = NULL, $excludes = NULL)
         {
             if ($converters === NULL) {
                 $converters = array(
                     'plugin',        // Inline plugins
        +            'eq',            // eq plugin
        +            'code',          // code plugin
                     'escape',        // Escapes
                     'note',          // Footnotes
                     ……
        // Max length of ID
    -   define('PLUGIN_ANAME_ID_MAX',   40);
    +   define('PLUGIN_ANAME_ID_MAX',   1024);
    }}}}
 
- ##lib/make_link.php## の ##class Link_plugin## の後に以下を追加。
    #code(php){{{{
        // Native-alias Plugin
        class Link_plugin_alias extends Link_plugin
    日本語アンカーのエンコード結果が、半角40文字を容易に超えるために拡張した。
    HTML としては id の最大長を指定してないようだが、実用的文字数とブラウザの実装限界を考慮して 1024 と決め付けた。
- ##plugin/aname.inc.php## の ##function lugin_aname_tag## の中、##id## を取得直後に以下を追加。
    #code(diff){{{{
        function plugin_aname_tag($args = array(), $convert = TRUE)
        {
            var $name    = 'echo';  // プラグイン名
            var $pattern = '';      // 正規表現 Link_plugin に対応させるため、
                                    // $matches[1] = plain 
                                    // $matches[2] = plugin name
                                    // $matches[3] = parameter
                                    // $matches[4] = body // 独自拡張 // 引数展開
            ...
            
            function Link_eq($start)
            {
                parent::Link_plugin($start);
            }
            
            $id = array_shift($args);
    +       if (! preg_match(PLUGIN_ANAME_ID_REGEX, $id))
    +       {
    +           $id = rawurlencode($id);
    +           $id = 'Anchor' . str_replace('%', '_', $id);
    +       }
    }}}}

////////////////////////////////////////////////////////////////
** ブラケット書式 ##[&[;〜&];]## [#xbc98cc4]
- ##lib/make_link.inc.php## の先頭、グローバル領域にて、##plugin/aname.inc.php## で設定されているアンカー名の正規表現を設定する。
    #code(diff){{{{
    +   // Pattern of ID
    +   define('PLUGIN_ANAME_ID_REGEX', '/^[A-Za-z][\w\-]*$/');
    }}}}
- ##lib/make_link.inc.php## の中ほど、##class Link_bracketname extends Link## の ##function get_pattern## にて、##return## 対象の正規表現を変更。
    #code(diff){{{{
            function get_pattern()
            {
                return $this->pattern;
            }
                global $WikiName, $BracketName;
            
            function get_count()
            {
                return 4;
                $s2 = $this->start + 2;
                return <<<EOD
        \[\[                     # Open bracket
        (?:((?:(?!\]\]).)+)>)?   # (1) Alias
        (\[\[)?                  # (2) Open bracket
        (                        # (3) PageName
         (?:$WikiName)
         |
         (?:$BracketName)
        )?
    -   (\#(?:[a-zA-Z][\w-]*)?)? # (4) Anchor
    +   (?:\#([^\[\>\#\]]+)?)?   # (4) Anchor
        (?($s2)\]\])             # Close bracket if (2)
        \]\]                     # Close bracket
        EOD;
            }
    }}}}
- ##lib/make_link.inc.php## の中ほど、##class Link_bracketname extends Link## の ##function toString## にて、
    #code(diff){{{{
    +           if (! preg_match(PLUGIN_ANAME_ID_REGEX,$this->anchor))
    +           {
    +               $this->anchor = rawurlencode($this->anchor);
    +               $this->anchor = 'Anchor' . str_replace('%', '_', $this->anchor);
    +           }
    +           $this->anchor = '#'.$this->anchor;
    +           
                return make_pagelink(
                    $this->name,
                    $this->alias,
                    $this->anchor,
                    $this->page
    }}}}
////////////////////////////////////////////////////////////////
** ネイティブエイリアス ##[&[;[〜]&];]## [#z82f4475]

- ##lib/make_link.inc.php## の先頭、##class InlineConverter## の ##function InlineConverter## にて、##'bracketname'## を登録直前、
    #code(diff){{{{
            function InlineConverter($converters = NULL, $excludes = NULL)
            {
                if ($converters === NULL) {
                    $converters = array(
                        ...
    +                   'bracketanchor', // BracketAnchor
                        'bracketname',   // BracketName
                        ...
                    );
                }
    }}}}
    正規表現として ##[&[;[〜]&];]## は ##[&[;〜&];]## に包含されるため、'bracketanchor' は必ず 'bracketname' の前に登録する必要がある。
- ##lib/make_link.inc.php## の中ほど、##class Link_bracketname## の前にて、以下を挿入
  ((継承している##Link_plugin_alias## は [[ネイティブエイリアス>../ネイティブエイリアス]] で実装したクラスである。))。
    #code(php){{{{
        // BracketAnchor
        // Native-alias for &aname plugin
        class Link_bracketanchor extends Link_plugin_alias
        {
            var $name    = 'aname';
            var $pattern = '\[\[\[(()(?:([^\[\>\#\]]+)>?)?(?:\#?([^\[\]\>\#]+?))?)\]\]\]';
            
            function set($arr, $page)
            {
                list(, $this->plain, , $this->param, $body) = $this->splice($arr);
                list(, $this->plain, , $body, $this->param) = $this->splice($arr);
                if ($this->param == '') {$this->param = $body;}                         // アンカー省略=エイリアスをアンカーに使用
                return parent::setParam($page, $this->name, $body, 'plugin');
            }
        }
        // Native-alias for &eq plugin
        class Link_eq extends Link_plugin_alias
        {
            var $name    = 'eq';
            var $pattern = '\$\$(()(.+?)())\$\$';   // no name, no body
        }
        // Native-alias for &code plugin
        class Link_code extends Link_plugin_alias
        {
            var $name    = 'code';
            var $pattern = '\#\#(()()(.+?))\#\#';   // no name, no parameter
        }
    }}}}
-- Link_plugin_alias は基底クラス。直接生成されることはない。
-- ##eq## は引数保持、##code## は引数展開。
 
** 複数行インラインプラグイン [#ueecdb8a]
 
- ##lib/convert_html.php## の ##class Body## の ##function parse## にて、 複数行プラグインの後あたり。
    #code(php){{{{{{{{{{{{{{{{{{{{
            // Native-alias for $eq-Plugin
            $pattern = '/^\s*\$\$\s*$/';
            if (preg_match($pattern, $line)) {
                $delimiter = "\r";
                $line = '&eq{{{{{{{{{{{{{{{{'.$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($pattern, $next_line)) {
                        $line .= ltrim('}}}}}}}}}}}}}}}};');
                        break;
                    } else {
                        $line .= $next_line . $delimiter;
                    }
                }
            }
    }}}}}}}}}}}}}}}}}}}}
    #code(diff){{{{{{{{{{{{{{{{{{{{
    !        // Native-alias for $code-Plugin
    !        $pattern = '/^\s*##\s*$/';
             if (preg_match($pattern, $line)) {
                 $delimiter = "\r";
    !            $line = '$code{{{{{{{{{{{{{{{{'.$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($pattern, $next_line)) {
                         $line .= ltrim('}}}}}}}}}}}}}}}};');
                         break;
                     } else {
                         $line .= $next_line . $delimiter;
                     }
                 }
             }
    }}}}}}}}}}}}}}}}}}}}
-- 「##!##」に行は、##eq##プラグイン に対する ##code## プラグインの差分。
 
** 複数行ブロックプラグイン [#v78fcaaf]
 
- ##lib/convert_html.php## の ##class Body## の ##function parse## にて、 複数行プラグインの後あたり。
    #code(diff){{{{{{{{{{{{{{{{{{{{
    !            // Native-alias for #eq-Plugin
    !            $pattern = '/^\s*\$\$\$\s*$/';
                 if (preg_match($pattern, $line)) {
                     $delimiter = "\r";
    !                $line = '#eq{{{{{{{{{{{{{{{{'.$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($pattern, $next_line)) {
                             $line .= ltrim('}}}}}}}}}}}}}}}}');
                             break;
                         } else {
                             $line .= $next_line . $delimiter;
                         }
                     }
                 }
    }}}}}}}}}}}}}}}}}}}}
    #code(diff){{{{{{{{{{{{{{{{{{{{
    !            // Native-alias for #code-Plugin
    !            $pattern = '/^\s*###\s*(\w*)\s*$/';
    !            if (preg_match($pattern, $line, $matches)) {
                     $delimiter = "\r";
    !                $line = '#code('.$matches[1].'){{{{{{{{{{{{{{{{'.$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($pattern, $next_line)) {
                             $line .= ltrim('}}}}}}}}}}}}}}}}');
                             break;
                         } else {
                             $line .= $next_line . $delimiter;
                         }
                     }
                 }
    }}}}}}}}}}}}}}}}}}}}
-- 「##!##」に行は、それぞれの複数行インラインプラグインに対する差分。
 
%bodynote

////////////////////////////////////////////////////////////////
* 課題 [#l64ec37e]

- 見出しのアンカー ##[#〜]## をアンカーのネイティブエイリアス ##[&[;[〜]&];]## に統合すべし。
-- 見出しのハッシュではなく、文字列自体をアンカーにすべし。
--- 今でも ##**[&[;[見出し1]&];]## のようにコーディングすれば一応できるけど。
--- アンカーの禁止文字「##[>#]##」を何とかすべし。
-- 見出しの階層構造に応じたアンカーの階層化を検討すべし。
--- 例: ##ページ階層1/ページ階層2/ページ名#見出し1/見出し1-1/見出し1-1-1 ##
--- 例: ##ページ階層1/ページ階層2/ページ名#見出し1-1-1 ## ← も衝突しない限り可能にしたい。


////////////////////////////////////////////////////////////////

    初基 一覧 検索 最新 バックアップ リンク元   ヘルプ   最終更新のRSS