From 4487595892a5a4789b540a8656608d98ce878903 Mon Sep 17 00:00:00 2001 From: Energy <71418770+energy-coresky@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:42:01 +0300 Subject: [PATCH] MD tables --- assets/dev.css | 2 +- sky.php | 2 +- w2/_data.yaml | 10 ++-- w2/md.php | 130 +++++++++++++++++++++++++++++++------------------ w2/show.php | 7 +-- w2/xml.php | 65 +++++++++++++------------ 6 files changed, 128 insertions(+), 88 deletions(-) diff --git a/assets/dev.css b/assets/dev.css index 7488b23..d9465a5 100644 --- a/assets/dev.css +++ b/assets/dev.css @@ -49,7 +49,7 @@ hr { border-top: 1px solid #ccc; border-bottom:0; } -pre, fieldset { +fieldset {/* pre, */ width: 95%; margin-bottom:10px; } diff --git a/sky.php b/sky.php index ccdbcd7..9e3a29f 100644 --- a/sky.php +++ b/sky.php @@ -9,7 +9,7 @@ class SKY implements PARADISE const ERR_DETECT = 1; const ERR_SHOW = 3; const ERR_SUPPRESSED = 4; - const CORE = '0.576 2025-01-25T14:48:59+02:00 energy'; + const CORE = '0.577 2025-02-05T19:41:20+02:00 energy'; public $tracing = ''; public $error_prod = ''; diff --git a/w2/_data.yaml b/w2/_data.yaml index 121fa01..4d7be2d 100644 --- a/w2/_data.yaml +++ b/w2/_data.yaml @@ -93,7 +93,7 @@ blk_chr: { '-*_=': leaf_h2r, '#': leaf_h6, '-*+': blk_ul, '0123456789': blk_ol, '>': blk_bq, '-:|': leaf_table, - '[': in_square, + '[': square, '<': leaf_html, '~`': leaf_fenced, '': leaf_p, @@ -103,10 +103,10 @@ blk_re: [ "/^()([\*\-\+])(\s+|\z)/", # for blk_ul [1] "/^()(>)(\s*)/", # for blk_bq [2] ] -in_chr: { - '*_': in_ems, '~': in_del, '^': in_sup, '=': in_mark, ':': in_emoji_dl, '|': in_table, - '[': in_square, '`': in_code, -} +#in_chr: { +# '*_': in_ems, '~': in_del, '^': in_sup, '=': in_mark, ':': in_emoji_dl, '|': in_table, +# '[': square, '`': in_code, +#} email_re: "/^[a-z\d.!#$%&'*+/=?^_`{|}~-]+@[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?(?:\.[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?)*$/i" tagfilter: @csv title textarea style xmp iframe noembed noframes script plaintext tags: @csv { diff --git a/w2/md.php b/w2/md.php index f46db78..1fe8125 100644 --- a/w2/md.php +++ b/w2/md.php @@ -41,8 +41,9 @@ private function leaf_html($x, &$t) { if ($blank && $x->empty || !$blank && false !== strpos($x->line, $x->grab)) $x->grab = false; $x->empty or $this->j += strlen($x->line); - return $this->push('#raw', $x->line, ['c' => 'r']); + return $this->push('y-html', $x->line);//, ['c' => 'r'] } + private function leaf_dl($x, &$t) {# :dl-dt-dd } @@ -61,10 +62,9 @@ private function leaf_h2r($x, $y) { if (!preg_match("/^\\{$y}[\\$y \t]*$/", $x->line)) return false; $z = str_replace(["\t", ' '], '', $x->line); - $p =& $this->up->name; $h12 = '=' == $y ? 'h1' : ('-' == $y ? 'h2' : false); - if ($h12 && 'p' == $p && $z == chop($x->line) && !$x->close) { - $p = $h12; + if ($h12 && 'p' == $this->up->name && $z == chop($x->line) && !$x->close) { + $this->up->name = $h12; $br =& $this->last->left; if ($br && $br->name == 'br') $br->name = '#skip'; @@ -80,38 +80,65 @@ private function leaf_h2r($x, $y) { private function leaf_table($x, &$y) { if ($x->table) { - 'tbody' == $this->up->name or $this->push('tbody'); - $this->push('tr'); - $line = trim($x->line); - if ($line && '|' == $line[0]) - $line = substr($line, 1); - $ary = preg_split("/\s*\|\s*/", $line && '|' == $line[-1] ? substr($line, 0, -1) : $line); - foreach ($x->table as $n => $align) - $this->push('td', $ary[$n] ?? '', $align); - $this->close('tr'); + $tbody = $this->up->name; + if ('tbody' == $tbody) { + $tr =& $this->last->right; + } else { + $tbody = $this->push('tbody'); + $tr =& $tbody->val; + } + $this->line($x); + $tr = $this->tr('td', $x->table, $tr); + return $tr->up = $tbody; } elseif ('p' != $this->up->name || '' !== chop($x->line, "\t -:|")) { - return $this->leaf_p($x, $y); + return $this->leaf_p($x, $y); } else { $x->table = array_map(function ($v) { - $align = ':' == $v[0] ? ['align' => 'left'] : []; - return ':' != $v[-1] ? $align : ['align' => $align ? 'center' : 'right']; + $align = ':' == $v[0] ? ' align="left"' : ''; + return ':' != $v[-1] ? $align : ($align ? ' align="center"' : ' align="right"'); }, preg_split("/\s*\|\s*/", trim($x->line, "|\t "))); - $line = ''; - foreach ($this->gen($this->up->val) as $node) - '#text' != $node->name or $line .= $node->val; - $ary = preg_split("/\s*\|\s*/", trim($line, "|\n\t ")); - if (count($ary) != count($x->table)) + $first = $this->up->val; + $td = 'yd' == $first->name ? 1 : 0; + if (end($x->td)->right->val == "\n") + $td++; + if (count($x->table) != 1 + count($x->td) - $td) return $x->table = false; - $this->up->name = 'table'; - $this->parent($this->up); - $thead = $this->push('thead', null, ['t' => chop($line)]); - $this->push('#text', "\n"); - $this->push('tr', null, ['t' => $x->line]); - foreach ($x->table as $n => $align) - $this->push('th', $ary[$n], $align + ['t' => '']); - $this->last($thead); + $this->parent($this->up, 'table'); + $this->push('thead', $this->tr('th', $x->table, $first)); //, null, ['t' => chop($line)] + return $this->add($x->line, ['c' => 'r']); } - return $this->j += strlen($x->line); + } + + private function tr($tag, $ary, $node) { + $val = "<$tag" . array_shift($ary) . '>'; + $close = false; + if ('yd' == $node->name) { + $node->val = $val; + $node->attr['t'] = '|'; + $tr = XML::node('tr', $node); + } else { + $tr = XML::node('tr', $yd = XML::node('yd', $val, null, $node)); + [$node->left, $node] = [$yd, $yd]; + } + for ($node->up = $tr, $last = $node; $node = $node->right; $last = $node) { + $node->up = $tr; + $yd = 'yd' == $node->name; + if ($ary && $yd) { + $node->val = "<$tag" . array_shift($ary) . '>'; + $node->attr['t'] = '|'; + } elseif ($close) { + $node->name = '#skip'; + } elseif ($yd) { + $node->val = ""; + $node->attr['t'] = '|'; + $close = true; + } + } + if (!$close) { + $yd = XML::node('yd', str_repeat("<$tag>", count($ary)) . ""); + [$last->right, $yd->left, $yd->up] = [$yd, $last, $tr]; + } + return $tr; } private function leaf_p($x, &$y) { @@ -222,7 +249,8 @@ protected function parse(): ?stdClass { $this->old_blk($x, $y, $empty); if ($x->empty && $this->close('p')) { $this->use_close($x); - } elseif ($x->empty && $this->close('tbody')) { + } elseif ($x->empty && $x->table) { + $this->close('tbody'); $this->close('table'); $x->table = false; } else { @@ -236,26 +264,34 @@ protected function parse(): ?stdClass { return $this->root->val; } - private function line($x) { - $in =& $this->in; - $j =& $this->j; + private function line($x, $line = '') { + if ('' === $line) { + $in =& $this->in; + $j =& $this->j; + $x->td = []; + } else { + $in =& $line; + $j = 0; + } while (!in_array($y = $in[$j] ?? '', ['', "\n"], true)) { $next = $in[1 + $j] ?? ''; if ("\\" == $y) { # escape - $esc = '' !== $next && strpbrk($next, MD::$MD->esc); - if ($esc) { #$this->push('#esc', $next, ['t' => "\\$next"]); #$j += 2; + if ('' !== $next && strpbrk($next, MD::$MD->esc)) { $this->add("\\", ['c' => 'r']); $this->add($next); } else { $this->add("\\");// 2do
} + } elseif ('|' == $y) { + $j++; + $x->td[] = $this->push('yd', '|', ['i' => count($x->td)]); } elseif (strpbrk($y, MD::$MD->esc)) { $img = '!' == $y; - if (!$img && '[' != $y || !$this->in_square($x, $y, true, $img)) { - $uu = $this->spn($y); + if (!$img && '[' != $y || !$this->square($x, $y, true, $img)) { + $uu = substr($in, $j, strspn($in, $y, $j)); if (strpbrk($y, "*_")) { $j += $sz = strlen($uu); - $this->inline($uu, $sz, $in[$j - $sz - 1] ?? '', $in[$j] ?? ''); + $this->stk_call($uu, $sz, $in[$j - $sz - 1] ?? '', $in[$j] ?? ''); } else { $this->add($uu); } @@ -267,7 +303,7 @@ private function line($x) { $this->add($t2 = chop($y)); $this->push('br', 0, ['t' => $rest = substr($y, strlen($t2))]); $j += strlen($rest); - } elseif (':' == ($in[$j + $n] ?? '') && $this->auto_link($j, $y)) { + } elseif (':' == ($in[$j + $n] ?? '') && $this->auto_link($j, $y, $in)) { $j += strlen($y); $this->push('a', $y, ['href' => $y, 'c' => 'g']); } else { @@ -337,7 +373,7 @@ private function new_blk($x, &$y) { } } - private function inline($uu, $sz, $left, $right) { + private function stk_call($uu, $sz, $left, $right) { $u2 = $uu[0] . $uu[0]; $y = ($em = 1 == $sz) ? $uu : $u2; $close = $left !== '' && !strpbrk($left, " \t\r\n"); @@ -346,18 +382,18 @@ private function inline($uu, $sz, $left, $right) { if ($close && $node) { $node->val = $em ? '' : ''; $node = false; - $this->push('#raw', $em ? '' : '', ['t' => $uu]); + $this->push('y', $em ? '' : '', ['t' => $uu]); } elseif ($open && !$node) { - $node = $this->push('#raw', $uu, ['t' => $uu]); + $node = $this->push('y', $uu, ['t' => $uu]); } else { $this->push('#text', $uu); } } - private function auto_link($j, &$y) { + private function auto_link($j, &$y, &$in) { if (!preg_match("/\bhttps?$/ui", $y, $m1)) return false; - if (!preg_match("/^:\/\/[^\s<]+\b\/*/ui", substr($this->in, $j + strlen($y)), $m2)) //2do substr + if (!preg_match("/^:\/\/[^\s<]+\b\/*/ui", substr($in, $j + strlen($y)), $m2)) //2do substr return false; if ($m1[0] === $y) return $y .= $m2[0]; @@ -365,7 +401,7 @@ private function auto_link($j, &$y) { return false; } - private function in_square($x, $y, $inline = false, $img = false) { # 2do footnote + private function square($x, $y, $inline = false, $img = false) { # 2do footnote $j = $img ? 1 + $this->j : $this->j; if (!$len = strlen($head = Rare::bracket($this->in, '[', $j, "\n\\"))) return false; @@ -430,7 +466,7 @@ function md_nice($in) { $out .= pre(tag(html($code), true === $type ? '' : "class=\"language-$type\"", 'code'), ''); } $type = ''; - } elseif ('#raw' == $node->name) { + } elseif ('y' == $node->name[0]) { $out .= $node->val; } elseif ('#' == $node->name[0]) { '' === $type ? ($out .= html($node->val)) : ($code .= $node->val); diff --git a/w2/show.php b/w2/show.php index 2bed096..9d7f16e 100644 --- a/w2/show.php +++ b/w2/show.php @@ -5,7 +5,7 @@ class Show # php jet yaml html bash || php_method md || var diff log const lay_l = '
'; const lay_m = ''; const lay_r = '
'; - const style = 'style="tab-size:4; margin:0; color:%s; background-color:%s"';//width:100%%; + const style = 'style="tab-size:4; line-height:14px; margin:0; color:%s; background-color:%s"';//width:100%%; private static $bg; private static $clr; @@ -270,7 +270,7 @@ static function doc($markdown, $render = 'md_nice', $hightlight = true) { static function highlight_md($code, &$bg) { # r g d c m j - gray self::scheme(); $md = new MD($code); - $out = $node = $bg = ''; + $out = $node = $bg = $html = ''; $hl = '='; $attr = function ($n) use (&$node, $md) { return $md->attr($node, $n); @@ -282,7 +282,7 @@ static function highlight_md($code, &$bg) { # r g d c m j - gray $hl = '*'; } elseif (is_string($node->val)) { if ($cnt = substr_count($node->val, "\n")) { - $bg .= str_pad('', $cnt, '#skip' == $node->name ? '=' : $hl); + $bg .= str_pad('', $cnt, $html ? '+' : ('#skip' == $node->name ? '=' : $hl)); if (is_null($node->right) && !$attr('last')) $hl = '='; } @@ -292,6 +292,7 @@ static function highlight_md($code, &$bg) { # r g d c m j - gray $out .= html($node->val); } } + $html = 'y-html' == $node->name && '' !== $node->val; } $bg .= $hl; return $out; diff --git a/w2/xml.php b/w2/xml.php index 31efd70..5cf24e8 100644 --- a/w2/xml.php +++ b/w2/xml.php @@ -66,7 +66,7 @@ function clone(?array $ary = null): ?stdClass { $last = false; foreach ($ary ?? $this->selected as $node) { $last ? $this->last($last) : $this->parent($this->root); - $this->insert($last = clone $node, true); // is_object($node->val) + $this->insert($last = clone $node, true); if (is_object($node->val)) { foreach ($this->gen($node->val) as $node) { $this->insert(clone $node, is_object($node->val)); @@ -177,33 +177,21 @@ function remove($ary = [], $with_childs = true) { is_array($ary) or $ary = [$ary]; foreach ($ary as $dst) { if ($with_childs || !$this->has_childs($dst, $obj)) { - $this->del_relations($dst, $dst->right, $dst->left); + $this->del_topology($dst, $dst->right, $dst->left); } elseif ($obj) { - $this->ins_relations($dst->val, $dst->left, $dst->up, $dst->right, $last); - $this->del_relations($dst, $dst->val, $last); + $this->ins_topology($dst->val, $dst->left, $dst->up, $dst->right, $last); + $this->del_topology($dst, $dst->val, $last); } else { $dst->name = '#text'; } } } - private function ins_relations($ins, $left, $up, $right, &$last = null) { - for ($ins->left = $left; $ins; $ins = $ins->right) - [$ins->up, $last] = [$up, $ins]; - $last->right = $right; - } - - private function del_relations($del, $first, $last) { - $del->left ? ($del->left->right = $first) : ($del->up->val = $first); - if ($del->right) - $del->right->left = $last; - } - function inner($src) { $src instanceof XML or ($src = new XML($src))->parse(); $src->selected or $src->selected = [$src->root->val]; foreach ($this->selected as $dst) { - $this->ins_relations($dst->val = $src->clone(), null, $dst, null); + $this->ins_topology($dst->val = $src->clone(), null, $dst, null); } } @@ -211,8 +199,8 @@ function outer($src) { $src instanceof XML or ($src = new XML($src))->parse(); $src->selected or $src->selected = [$src->root->val]; foreach ($this->selected as $dst) { - $this->ins_relations($first = $src->clone(), $dst->left, $dst->up, $dst->right, $last); - $this->del_relations($dst, $first, $last); + $this->ins_topology($first = $src->clone(), $dst->left, $dst->up, $dst->right, $last); + $this->del_topology($dst, $first, $last); } } @@ -220,7 +208,7 @@ function before($src) { $src instanceof XML or ($src = new XML($src))->parse(); $src->selected or $src->selected = [$src->root->val]; foreach ($this->selected as $dst) { - $this->ins_relations($first = $src->clone(), $dst->left, $dst->up, $dst, $last); + $this->ins_topology($first = $src->clone(), $dst->left, $dst->up, $dst, $last); $dst->left ? ($dst->left->right = $first) : ($dst->up->val = $first); $dst->left = $last; } @@ -230,7 +218,7 @@ function after($src) { $src instanceof XML or ($src = new XML($src))->parse(); $src->selected or $src->selected = [$src->root->val]; foreach ($this->selected as $dst) { - $this->ins_relations($first = $src->clone(), $dst, $dst->up, $dst->right, $last); + $this->ins_topology($first = $src->clone(), $dst, $dst->up, $dst->right, $last); if ($dst->right) $dst->right->left = $last; $dst->right = $first; @@ -241,7 +229,7 @@ function prepend($src) { $src instanceof XML or ($src = new XML($src))->parse(); $src->selected or $src->selected = [$src->root->val]; foreach ($this->selected as $dst) { - $this->ins_relations($first = $src->clone(), null, $dst, $dst->val, $last); + $this->ins_topology($first = $src->clone(), null, $dst, $dst->val, $last); [$dst->val->left, $dst->val] = [$last, $first]; } } @@ -251,7 +239,7 @@ function append($src) { $src->selected or $src->selected = [$src->root->val]; foreach ($this->selected as $dst) { for ($left = $dst->val; $left->right; $left = $left->right); - $this->ins_relations($left->right = $src->clone(), $left, $dst, null); + $this->ins_topology($left->right = $src->clone(), $left, $dst, null); } } @@ -409,22 +397,23 @@ protected function parse(): ?stdClass { # 2do strict mode return $this->root->val; } + protected function close($tag = null) { + return is_null($tag) || $tag === $this->up->name ? $this->last($this->up) : false; + } + protected function last($node) { # setup cursor right $this->up = $node->up; $this->next =& $node->right; return $this->left = $this->last = $node; } - protected function parent($node) { # setup cursor down + protected function parent($node, $name = null) { # setup cursor down + is_null($name) or $node->name = $name; $this->left = null; $this->next =& $node->val; return $this->up = $this->last = $node; } - protected function close($tag = null) { - return is_null($tag) || $tag === $this->up->name ? $this->last($this->up) : false; - } - protected function insert($node, $parent) { $node->left = $this->left; $node->up = $this->up; @@ -439,17 +428,31 @@ protected function push($name, $val = null, $attr = null) { if ($this->up->name == $name && in_array($name, $this->omis[0])) $this->close(); } - return $this->insert(XML::node($name, $val, $attr), null === $val); + $node = XML::node($name, $val, $attr); + is_object($val) && $this->ins_topology($val, null, $node, null); + return $this->insert($node, is_null($val)); + } + + protected function ins_topology($ins, $left, $up, $right, &$last = null) { + for ($ins->left = $left; $ins; $ins = $ins->right) + [$ins->up, $last] = [$up, $ins]; + $last->right = $right; + } + + protected function del_topology($del, $first, $last) { + $del->left ? ($del->left->right = $first) : ($del->up->val = $first); + if ($del->right) + $del->right->left = $last; } - static function node($name, $val = null, $attr = null) { + static function node($name, $val = null, $attr = null, $right = null) { return (object)[ 'name' => $name, 'attr' => $attr, 'up' => null, 'val' => $val, # text | object=first-child | 0=void | null=not-void 'left' => null, - 'right' => null, + 'right' => $right, ]; } }