From 35546e556a63186c686b7d685fa13b2f8c5c292d Mon Sep 17 00:00:00 2001 From: Michael Ochmann Date: Mon, 28 Feb 2022 10:51:04 +0100 Subject: [PATCH] implemented tables --- index.php | 8 +++++ src/Lexer.php | 8 +++++ src/Parser.php | 80 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/Token.php | 2 ++ test/test1.md | 5 +++- 5 files changed, 100 insertions(+), 3 deletions(-) diff --git a/index.php b/index.php index 60f4a72..ad0699d 100644 --- a/index.php +++ b/index.php @@ -5,5 +5,13 @@ require __DIR__."/vendor/autoload.php"; $source = file_get_contents(dirname(__FILE__)."/test/test1.md"); +echo " + +"; + $Instance = new parkdown\Parkdown($source); $Instance->html(); \ No newline at end of file diff --git a/src/Lexer.php b/src/Lexer.php index 1b9857b..af7033f 100644 --- a/src/Lexer.php +++ b/src/Lexer.php @@ -51,6 +51,10 @@ class Lexer { $clearBuffer(); array_push($tokens, new Token(TokenType::DOT, $char)); break; + case '-': + $clearBuffer(); + array_push($tokens, new Token(TokenType::MINUS, $char)); + break; case '`': $clearBuffer(); array_push($tokens, new Token(TokenType::BACKTICK, $char)); @@ -75,6 +79,10 @@ class Lexer { $clearBuffer(); array_push($tokens, new Token(TokenType::BANG, $char)); break; + case '|': + $clearBuffer(); + array_push($tokens, new Token(TokenType::PIPE, $char)); + break; case ':': if (str_ends_with($buffer, "http") || str_ends_with($buffer, "https")) { $buffer .= $char; diff --git a/src/Parser.php b/src/Parser.php index 255fc6b..1af84f7 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -5,7 +5,6 @@ namespace parkdown; use DOMDocument; use DOMElement; use DOMNode; -use DOMText; class Parser { const MAGIC_CHAR = "*"; @@ -214,7 +213,7 @@ class Parser { } private function parseOrderedList() : void { - $list = $this->document->createElement("ol"); + $list = $this->document->createElement("ol"); while (!($this->current()->type === TokenType::EOL && $this->next()->type !== TokenType::NUMBER) && $this->current()->type !== TokenType::EOF) { @@ -316,7 +315,81 @@ class Parser { $this->references[$index] = trim($buffer); } + private function parseTableHead(string $nodeName = "th", ?array $props = null) : DOMNode { + $elm = $this->document->createElement("tr"); + $i = 0; + while ($this->current()->type !== TokenType::EOL && $this->current()->type !== TokenType::EOF) { + $pipe = $this->consume(); + $buffer = ""; + while ($this->current()->type !== TokenType::PIPE && $this->current()->type !== TokenType::EOL) + $buffer .= $this->consume()->data; + + if ($buffer === "") + continue; + $col = $this->document->createElement($nodeName, $buffer); + if ($props) + $col->setAttribute("style", "text-align: ".$props[$i]); + $elm->appendChild($col); + $i++; + } + $this->consume(); // EOL + + return $elm; + } + + private function parseTableRow(array $props) : DOMNode { + return $this->parseTableHead("td", $props); + } + + private function parseTableAlignment() : array { + $props = []; + + while ($this->current()->type !== TokenType::EOL && $this->current()->type !== TokenType::EOF) { + $pipe = $this->consume(); + $buffer = ""; + while ($this->current()->type !== TokenType::PIPE && $this->current()->type !== TokenType::EOL) + $buffer .= $this->consume()->data; + + if ($buffer === "") + continue; + if (substr($buffer, 0, 1) === ':') + array_push($props, "left"); + elseif (substr($buffer, strlen($buffer) - 1, 1) === ':') + array_push($props, "right"); + elseif (str_contains($buffer, ':')) + array_push($props, "center"); + else + array_push($props, "left"); + } + + return $props; + } + + private function parseTable() : void { + $elm = $this->document->createElement("table"); + $head = $this->parseTableHead(); + $props = $this->parseTableAlignment(); + + $i = 0; + foreach($head->childNodes as $col) { + $col->setAttribute("style", "text-align: ".$props[$i]); + $i++; + } + + $elm->appendChild($head); + + while ($this->current()->type === TokenType::EOL && $this->next()->type === TokenType::PIPE) { + $this->consume(); // EOL + $elm->appendChild($this->parseTableRow($props)); + } + + $this->document->appendChild($elm); + } + private function resolveReferences(DOMElement $node) : void { + if (count($this->references) < 1) + return; + if ($node->hasAttribute("href")) { $href = $node->getAttribute("href"); if (substr($href, 0, 1) === self::MAGIC_CHAR) { @@ -360,6 +433,9 @@ class Parser { case TokenType::LBRACKET: $this->parseReference(); break; + case TokenType::PIPE: + $this->parseTable(); + break; default: $this->buildParagraph($this->parseText()); break; diff --git a/src/Token.php b/src/Token.php index 4c3cb48..3d5711c 100644 --- a/src/Token.php +++ b/src/Token.php @@ -7,6 +7,7 @@ enum TokenType { case ASTERISK; case TEXT ; case DOT ; + case MINUS ; case NUMBER ; case EOL ; case EOF ; @@ -17,6 +18,7 @@ enum TokenType { case RPAREN ; case BANG ; case COLON ; + case PIPE ; } class Token { diff --git a/test/test1.md b/test/test1.md index a06653b..cb7ffef 100644 --- a/test/test1.md +++ b/test/test1.md @@ -20,8 +20,11 @@ And we test: all [special chars][1] in random [text][hallo]. this [word][http:// lol 1 bild ![Eine Perle: für **die Ewigkeit* ..](https://mike-ochmann.de/assets/images/perl_jam.jpg) +| Spalte 1 | Spalte 2 | Spalte 3 | +|:---------|-----:----|---------:| +| value a | value b | value c | -At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. {class: rot} ``` //this should be a codeblock