diff --git a/.php_cs.dist b/.php_cs.dist index 179aead2..52404089 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -17,6 +17,9 @@ return PhpCsFixer\Config::create() 'array_indentation' => true, 'array_syntax' => ['syntax' => 'long'], 'concat_space' => ['spacing' => 'one'], + 'echo_tag_syntax' => ['format' => 'short'], + 'no_alias_language_construct_call' => false, + 'no_alternative_syntax' => false, 'no_useless_else' => true, 'no_useless_return' => true, 'phpdoc_align' => true, diff --git a/README.md b/README.md index 8160231c..3878b7fb 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Available functions: - [`getLanguagesFolder(): string`](src/HighlightUtilities/Functions.php#L136-L144) - [`getLanguageDefinitionPath(string $name): string`](src/HighlightUtilities/Functions.php#L150-L160) - [`getThemeBackgroundColor(string $name): float[]`](src/HighlightUtilities/Functions.php#L80-L93) -- [`splitCodeIntoArray(string $html): false|string[]`](src/HighlightUtilities/Functions.php#L197-L210) +- [`splitCodeIntoArray(string $html): false|string[]`](src/HighlightUtilities/Functions.php#L199-L210) ## Versioning diff --git a/composer.json b/composer.json index bee9ba24..d2b4ae69 100644 --- a/composer.json +++ b/composer.json @@ -53,9 +53,6 @@ "symfony/finder": "^2.8|^3.4", "symfony/var-dumper": "^2.8|^3.4" }, - "suggest": { - "ext-dom": "Needed to make use of the features in the utilities namespace" - }, "extra": { "branch-alias": { "dev-master": "10.0-dev" diff --git a/demo/example.php b/demo/example.php index ec278ffc..580dd466 100644 --- a/demo/example.php +++ b/demo/example.php @@ -41,6 +41,6 @@ -
value; ?>
+
value; ?>
diff --git a/src/HighlightUtilities/Functions.php b/src/HighlightUtilities/Functions.php index 85e269ab..9cdfbdb2 100644 --- a/src/HighlightUtilities/Functions.php +++ b/src/HighlightUtilities/Functions.php @@ -201,58 +201,61 @@ public static function getStyleSheetPath($name) * * @api * + * @since 9.18.1.6 `RuntimeException` and `UnexpectedValueException` can no longer be thrown. * @since 9.15.6.1 * * @param string $html An HTML string generated by `Highlighter::highlight()` * - * @throws \RuntimeException when the DOM extension is not available - * @throws \UnexpectedValueException when the given HTML could not be parsed - * * @return string[]|false An array of lines of code as strings. False if an error occurred in splitting up by lines */ public static function splitCodeIntoArray($html) { - if (!extension_loaded("dom")) { - throw new \RuntimeException("The DOM extension is not loaded but is required."); - } - if (trim($html) === "") { return array(); } - $dom = new \DOMDocument(); + $queuedPrefix = ''; + $regexWorkspace = array(); + $rawLines = preg_split('/\R/u', $html); - // https://stackoverflow.com/a/8218649 - if (!$dom->loadHTML(mb_convert_encoding($html, "HTML-ENTITIES", "UTF-8"))) { - throw new \UnexpectedValueException("The given HTML could not be parsed correctly."); + if ($rawLines === false) { + return false; } - $xpath = new \DOMXPath($dom); - $spans = $xpath->query("//span[contains(text(), '\n') or contains(text(), '\r\n')]"); + foreach ($rawLines as &$rawLine) { + // If the previous line has been marked as "open", then we'll have something + // in our queue + if ($queuedPrefix !== '') { + $rawLine = $queuedPrefix . $rawLine; + $queuedPrefix = ''; + } - /** @var \DOMElement $span */ - foreach ($spans as $span) { - $closingTags = ''; - $openingTags = ''; - $curr = $span; + // Find how many opening `` tags exist on this line + preg_match_all('/]*+>/u', $rawLine, $regexWorkspace); + $openingTags = count($regexWorkspace[0]); - while ($curr->tagName === 'span') { - $closingTags .= ''; - $openingTags = sprintf('%s', $curr->getAttribute("class"), $openingTags); + // Find all of the closing `` tags that exist on this line + preg_match_all('/<\/span>/u', $rawLine, $regexWorkspace); + $closingTags = count($regexWorkspace[0]); - $curr = $curr->parentNode; + // If the number of opening tags matches the number of closing tags, then + // we don't have any new tags that span multiple lines + if ($openingTags === $closingTags) { + continue; } - $renderedSpan = $dom->saveHTML($span); - $finished = preg_replace( - '/\R/u', - $closingTags . PHP_EOL . $openingTags, - $renderedSpan - ); - $html = str_replace($renderedSpan, $finished, $html); + // Find all of the complete `` tags and remove them from a working + // copy of the line. Then we'll be left with just opening tags. + $workingLine = preg_replace('/]*+>[^<]*+<\/span>/u', '', $rawLine); + preg_match_all('/]*+>/u', $workingLine, $regexWorkspace); + $queuedPrefix = implode('', $regexWorkspace[0]); + + // Close all of the remaining open tags on this line + $diff = str_repeat('', $openingTags - $closingTags); + $rawLine .= $diff; } - return preg_split('/\R/u', $html); + return $rawLines; } /** diff --git a/test/HighlightUtilitiesTest.php b/test/HighlightUtilitiesTest.php index 7482a5ce..522ef3d7 100644 --- a/test/HighlightUtilitiesTest.php +++ b/test/HighlightUtilitiesTest.php @@ -37,7 +37,7 @@ protected function setUp() $this->hl = new \Highlight\Highlighter(); } - public function testGetAvailableStyleSheets_NamesOnly() + public function testGetAvailableStyleSheetsNamesOnly() { $results = \HighlightUtilities\Functions::getAvailableStyleSheets(); @@ -49,7 +49,7 @@ public function testGetAvailableStyleSheets_NamesOnly() } } - public function testGetAvailableStyleSheets_FilePaths() + public function testGetAvailableStyleSheetsFilePaths() { $results = \HighlightUtilities\Functions::getAvailableStyleSheets(true); @@ -63,7 +63,7 @@ public function testGetAvailableStyleSheets_FilePaths() } } - public function testGetAvailableStyleSheets_SameCount() + public function testGetAvailableStyleSheetsSameCount() { $namesOnly = \HighlightUtilities\Functions::getAvailableStyleSheets(); $filePaths = \HighlightUtilities\Functions::getAvailableStyleSheets(true); @@ -71,7 +71,7 @@ public function testGetAvailableStyleSheets_SameCount() $this->assertCount(count($namesOnly), $filePaths); } - public function testGetStyleSheet_Exists() + public function testGetStyleSheetExists() { $yesExt = \HighlightUtilities\Functions::getStyleSheet("a11y-dark.css"); $noExt = \HighlightUtilities\Functions::getStyleSheet("a11y-dark"); @@ -80,14 +80,14 @@ public function testGetStyleSheet_Exists() $this->assertEquals($yesExt, $noExt); } - public function testGetStyleSheet_NotExists() + public function testGetStyleSheetNotExists() { $this->setExpectedException('\DomainException'); \HighlightUtilities\Functions::getStyleSheet("strawberry.png"); } - public function testSplitCodeIntoArray_MultilineComment() + public function testSplitCodeIntoArrayMultilineComment() { $raw = <<value); $this->assertEquals( - $split, array( '// ✅ ...', '$user = new \stdClass();', '$isUserPending = $user->isStatus(\'pending\');', - ) + ), + $split ); } - public function testSplitCodeIntoArray_DeeplyNestedSpans() + public function testSplitCodeIntoArrayDeeplyNestedSpans() { $raw = <<<'JAVA' public QuoteEntity( @@ -146,15 +146,63 @@ public function testSplitCodeIntoArray_DeeplyNestedSpans() $split = \HighlightUtilities\Functions::splitCodeIntoArray($highlighted->value); $this->assertEquals( - $split, array( 'public QuoteEntity(', ')', - ) + ), + $split ); } - public function testSplitCodeIntoArray_DeeplyNestedSpansCRLF() + public function testSplitCodeIntoArrayXmlWithAttributesOnNewLines() + { + $raw = <<<'XML' + + + +XML; + $highlighted = $this->hl->highlight('xml', $raw); + $split = \HighlightUtilities\Functions::splitCodeIntoArray($highlighted->value); + + $this->assertEquals( + array( + '<?xml version="1.0" encoding="utf-8" ?>', + ' <tag a="t"', + ' b="t">', + ' </tag>', + ), + $split + ); + } + + public function testSplitCodeIntoArrayXmlWithAttributesSpanningMultipleLines() + { + $raw = <<<'XML' + + + +XML; + $highlighted = $this->hl->highlight('xml', $raw); + $split = \HighlightUtilities\Functions::splitCodeIntoArray($highlighted->value); + + $this->assertEquals( + array( + '<?xml version="1.0" encoding="utf-8" ?>', + '<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"', + ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"', + ' xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"', + ' autoReload="true">', + '</nlog>', + ), + $split + ); + } + + public function testSplitCodeIntoArrayDeeplyNestedSpansCRLF() { $raw = "public QuoteEntity(\r\n)"; @@ -162,11 +210,11 @@ public function testSplitCodeIntoArray_DeeplyNestedSpansCRLF() $split = \HighlightUtilities\Functions::splitCodeIntoArray($highlighted->value); $this->assertEquals( - $split, array( 'public QuoteEntity(', ')', - ) + ), + $split ); } @@ -182,7 +230,7 @@ public static function dataProvider_emptyStrings() /** * @dataProvider dataProvider_emptyStrings */ - public function testSplitCodeIntoArray_EmptyString($string) + public function testSplitCodeIntoArrayEmptyString($string) { $this->assertEquals(array(), \HighlightUtilities\Functions::splitCodeIntoArray($string)); }