implemented tables

feature/tests
Michael Ochmann 3 years ago
parent 65744f1363
commit 35546e556a
  1. 8
      index.php
  2. 8
      src/Lexer.php
  3. 80
      src/Parser.php
  4. 2
      src/Token.php
  5. 5
      test/test1.md

@ -5,5 +5,13 @@ require __DIR__."/vendor/autoload.php";
$source = file_get_contents(dirname(__FILE__)."/test/test1.md"); $source = file_get_contents(dirname(__FILE__)."/test/test1.md");
echo "
<style>
table {
width: 100%;
}
</style>
";
$Instance = new parkdown\Parkdown($source); $Instance = new parkdown\Parkdown($source);
$Instance->html(); $Instance->html();

@ -51,6 +51,10 @@ class Lexer {
$clearBuffer(); $clearBuffer();
array_push($tokens, new Token(TokenType::DOT, $char)); array_push($tokens, new Token(TokenType::DOT, $char));
break; break;
case '-':
$clearBuffer();
array_push($tokens, new Token(TokenType::MINUS, $char));
break;
case '`': case '`':
$clearBuffer(); $clearBuffer();
array_push($tokens, new Token(TokenType::BACKTICK, $char)); array_push($tokens, new Token(TokenType::BACKTICK, $char));
@ -75,6 +79,10 @@ class Lexer {
$clearBuffer(); $clearBuffer();
array_push($tokens, new Token(TokenType::BANG, $char)); array_push($tokens, new Token(TokenType::BANG, $char));
break; break;
case '|':
$clearBuffer();
array_push($tokens, new Token(TokenType::PIPE, $char));
break;
case ':': case ':':
if (str_ends_with($buffer, "http") || str_ends_with($buffer, "https")) { if (str_ends_with($buffer, "http") || str_ends_with($buffer, "https")) {
$buffer .= $char; $buffer .= $char;

@ -5,7 +5,6 @@ namespace parkdown;
use DOMDocument; use DOMDocument;
use DOMElement; use DOMElement;
use DOMNode; use DOMNode;
use DOMText;
class Parser { class Parser {
const MAGIC_CHAR = "*"; const MAGIC_CHAR = "*";
@ -214,7 +213,7 @@ class Parser {
} }
private function parseOrderedList() : void { 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) && while (!($this->current()->type === TokenType::EOL && $this->next()->type !== TokenType::NUMBER) &&
$this->current()->type !== TokenType::EOF) { $this->current()->type !== TokenType::EOF) {
@ -316,7 +315,81 @@ class Parser {
$this->references[$index] = trim($buffer); $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 { private function resolveReferences(DOMElement $node) : void {
if (count($this->references) < 1)
return;
if ($node->hasAttribute("href")) { if ($node->hasAttribute("href")) {
$href = $node->getAttribute("href"); $href = $node->getAttribute("href");
if (substr($href, 0, 1) === self::MAGIC_CHAR) { if (substr($href, 0, 1) === self::MAGIC_CHAR) {
@ -360,6 +433,9 @@ class Parser {
case TokenType::LBRACKET: case TokenType::LBRACKET:
$this->parseReference(); $this->parseReference();
break; break;
case TokenType::PIPE:
$this->parseTable();
break;
default: default:
$this->buildParagraph($this->parseText()); $this->buildParagraph($this->parseText());
break; break;

@ -7,6 +7,7 @@ enum TokenType {
case ASTERISK; case ASTERISK;
case TEXT ; case TEXT ;
case DOT ; case DOT ;
case MINUS ;
case NUMBER ; case NUMBER ;
case EOL ; case EOL ;
case EOF ; case EOF ;
@ -17,6 +18,7 @@ enum TokenType {
case RPAREN ; case RPAREN ;
case BANG ; case BANG ;
case COLON ; case COLON ;
case PIPE ;
} }
class Token { class Token {

@ -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) 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 //this should be a codeblock

Loading…
Cancel
Save