Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2656651
D25299.1732650230.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
6 KB
Referenced Files
None
Subscribers
None
D25299.1732650230.diff
View Options
diff --git a/src/infrastructure/markup/blockrule/PhutilRemarkupCodeBlockRule.php b/src/infrastructure/markup/blockrule/PhutilRemarkupCodeBlockRule.php
--- a/src/infrastructure/markup/blockrule/PhutilRemarkupCodeBlockRule.php
+++ b/src/infrastructure/markup/blockrule/PhutilRemarkupCodeBlockRule.php
@@ -44,7 +44,18 @@
}
public function markupText($text, $children) {
- if (preg_match('/^\s*```/', $text)) {
+ // Header/footer eventually useful to be nice with "flavored markdown".
+ // When it starts with ```stuff the header is 'stuff' (->language)
+ // When it ends with stuff``` the footer is 'stuff' (->garbage)
+ $header_line = null;
+ $footer_line = null;
+
+ $matches = null;
+ if (preg_match('/^\s*```(.*)/', $text, $matches)) {
+ if (isset($matches[1])) {
+ $header_line = $matches[1];
+ }
+
// If this is a ```-style block, trim off the backticks and any leading
// blank line.
$text = preg_replace('/^\s*```(\s*\n)?/', '', $text);
@@ -52,6 +63,13 @@
}
$lines = explode("\n", $text);
+
+ // If we have a flavored header, it has sense to look for the footer.
+ if ($header_line !== null && $lines) {
+ $footer_line = $lines[last_key($lines)];
+ }
+
+ // Strip final empty lines
while ($lines && !strlen(last($lines))) {
unset($lines[last_key($lines)]);
}
@@ -65,20 +83,35 @@
$parser = new PhutilSimpleOptions();
$custom = $parser->parse(head($lines));
+ $valid_options = null;
if ($custom) {
- $valid = true;
+ $valid_options = true;
foreach ($custom as $key => $value) {
if (!array_key_exists($key, $options)) {
- $valid = false;
+ $valid_options = false;
break;
}
}
- if ($valid) {
+ if ($valid_options) {
array_shift($lines);
$options = $custom + $options;
}
}
+ // Check for flavored markdown only if there was no "lang=" or other options.
+ // We are strict to don't conflict with legitimate content in Remarkup.
+ if (
+ $valid_options === false &&
+ $header_line !== null &&
+ $footer_line === '' &&
+ count($lines) > 1
+ ) {
+ if ($this->isKnownLanguageCode($header_line)) {
+ array_shift($lines);
+ $options['lang'] = $header_line;
+ }
+ }
+
// Normalize the text back to a 0-level indent.
$min_indent = 80;
foreach ($lines as $line) {
@@ -249,4 +282,59 @@
$engine->highlightSource($options['lang'], $text)));
}
+ /**
+ * Check if a language code can be used in flavored markdown.
+ * @param string $lang Language code after backticks
+ * @return bool
+ */
+ private function isKnownLanguageCode($lang) {
+ return in_array($lang, $this->getKnownLanguageCodes(), true);
+ }
+
+ /**
+ * Get all the available languages for flavored markdown.
+ * @return array
+ */
+ private function getKnownLanguageCodes() {
+ // This is a friendly subset from https://pygments.org/languages/
+ return [
+ 'arduino',
+ 'assembly',
+ 'awk',
+ 'bash',
+ 'bat',
+ 'c',
+ 'cmake',
+ 'cobol',
+ 'cpp',
+ 'css',
+ 'csharp',
+ 'dart',
+ 'delphi',
+ 'fortran',
+ 'go',
+ 'groovy',
+ 'haskell',
+ 'java',
+ 'javascript',
+ 'kotlin',
+ 'lisp',
+ 'lua',
+ 'matlab',
+ 'make',
+ 'perl',
+ 'php',
+ 'powershell',
+ 'python',
+ 'r',
+ 'ruby',
+ 'rust',
+ 'scala',
+ 'sh',
+ 'sql',
+ 'typescript',
+ 'vba',
+ ];
+ }
+
}
diff --git a/src/infrastructure/markup/remarkup/__tests__/PhutilRemarkupEngineTestCase.php b/src/infrastructure/markup/remarkup/__tests__/PhutilRemarkupEngineTestCase.php
--- a/src/infrastructure/markup/remarkup/__tests__/PhutilRemarkupEngineTestCase.php
+++ b/src/infrastructure/markup/remarkup/__tests__/PhutilRemarkupEngineTestCase.php
@@ -2,6 +2,8 @@
/**
* Test cases for @{class:PhutilRemarkupEngine}.
+ * @TODO: This unit is not always triggered when you need it.
+ * https://we.phorge.it/T15500
*/
final class PhutilRemarkupEngineTestCase extends PhutilTestCase {
diff --git a/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-flavored.txt b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-flavored.txt
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-flavored.txt
@@ -0,0 +1,7 @@
+```cpp
+code
+```
+~~~~~~~~~~
+<div class="remarkup-code-block" data-code-lang="cpp" data-sigil="remarkup-code-block"><pre class="remarkup-code">code</pre></div>
+~~~~~~~~~~
+ code
diff --git a/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored-comment.txt b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored-comment.txt
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored-comment.txt
@@ -0,0 +1,18 @@
+```#comment
+code
+
+#more comment
+more code```
+
+~~~~~~~~~~
+<div class="remarkup-code-block" data-code-lang="text" data-sigil="remarkup-code-block"><pre class="remarkup-code">#comment
+code
+
+#more comment
+more code</pre></div>
+~~~~~~~~~~
+ #comment
+ code
+
+ #more comment
+ more code
diff --git a/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored-empty.txt b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored-empty.txt
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored-empty.txt
@@ -0,0 +1,9 @@
+```
+cpp
+second line```
+~~~~~~~~~~
+<div class="remarkup-code-block" data-code-lang="text" data-sigil="remarkup-code-block"><pre class="remarkup-code">cpp
+second line</pre></div>
+~~~~~~~~~~
+ cpp
+ second line
diff --git a/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored.txt b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored.txt
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/markup/remarkup/__tests__/remarkup/tick-block-multi-flavored.txt
@@ -0,0 +1,20 @@
+```cpp
+code
+
+more code
+
+more code
+```
+
+~~~~~~~~~~
+<div class="remarkup-code-block" data-code-lang="cpp" data-sigil="remarkup-code-block"><pre class="remarkup-code">code
+
+more code
+
+more code</pre></div>
+~~~~~~~~~~
+ code
+
+ more code
+
+ more code
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 26, 19:43 (18 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
997854
Default Alt Text
D25299.1732650230.diff (6 KB)
Attached To
Mode
D25299: Remarkup Code-block: parse language specifier in markdown
Attached
Detach File
Event Timeline
Log In to Comment