Skip to content

Commit 2ca117b

Browse files
Merge pull request #107 from BenjaminHoegh/codex/improve-smartypants-performance
Optimize smartypants handling
2 parents f9526e9 + 39712b2 commit 2ca117b

File tree

1 file changed

+73
-85
lines changed

1 file changed

+73
-85
lines changed

src/ParsedownExtended.php

Lines changed: 73 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,113 +1000,101 @@ protected function inlineSmartypants($Excerpt)
10001000
'ellipses' => html_entity_decode($config->get('smartypants.substitutions.ellipses')),
10011001
];
10021002

1003-
// Define patterns for various Smartypants substitutions
1004-
$patterns = [
1005-
'smart_backticks' => [
1006-
'pattern' => '/^(?:``)(?!\s)([^"\'`]+)(?:\'\')/i',
1007-
'callback' => function ($matches) use ($substitutions, $Excerpt) {
1008-
if (strlen(trim($Excerpt['before'])) > 0) {
1009-
return null; // Skip if the backticks do not start at the beginning
1010-
}
1003+
$text = $Excerpt['text'];
1004+
$first = $text[0] ?? '';
1005+
1006+
// ``like this''
1007+
if ('`' === $first && $config->get('smartypants.smart_backticks')) {
1008+
if (preg_match('/^(?:``)(?!\s)([^"\'`]+)(?:\'\')/i', $text, $matches)) {
1009+
if (strlen(trim($Excerpt['before'])) > 0) {
1010+
return null;
1011+
}
1012+
1013+
return [
1014+
'extent' => strlen($matches[0]),
1015+
'element' => [
1016+
'text' => $substitutions['left_double_quote'] . $matches[1] . $substitutions['right_double_quote'],
1017+
],
1018+
];
1019+
}
1020+
}
1021+
1022+
// "like this" or 'like this'
1023+
if (('"' === $first || "'" === $first) && $config->get('smartypants.smart_quotes')) {
1024+
if (preg_match('/^(\")(?!\s)([^\"]+)(?:\")|^(?<!\w)(\')(?!\s)([^\']+)(?:\')/i', $text, $matches)) {
1025+
if (strlen(trim($Excerpt['before'])) > 0) {
1026+
return null;
1027+
}
10111028

1012-
// Return transformed text with left and right double quotes
1029+
if (isset($matches[3]) && $matches[3] === "'") {
10131030
return [
10141031
'extent' => strlen($matches[0]),
10151032
'element' => [
1016-
'text' => $substitutions['left_double_quote'] . $matches[2] . $substitutions['right_double_quote'],
1033+
'text' => $substitutions['left_single_quote'] . $matches[4] . $substitutions['right_single_quote'],
10171034
],
10181035
];
1019-
},
1020-
],
1021-
'smart_quotes' => [
1022-
'pattern' => '/^(\")(?!\s)([^\"]+)(?:\")|^(?<!\w)(\')(?!\s)([^\']+)(?:\')/i',
1023-
'callback' => function ($matches) use ($substitutions, $Excerpt) {
1024-
if (strlen(trim($Excerpt['before'])) > 0) {
1025-
return null; // Skip if quotes are in the middle of a word
1026-
}
1036+
}
10271037

1028-
// Check if the match is for single or double quotes and return transformed text
1029-
if ("'" === $matches[1]) {
1030-
return [
1031-
'extent' => strlen($matches[0]),
1032-
'element' => [
1033-
'text' => $substitutions['left_single_quote'] . $matches[2] . $substitutions['right_single_quote'],
1034-
],
1035-
];
1036-
}
1038+
return [
1039+
'extent' => strlen($matches[0]),
1040+
'element' => [
1041+
'text' => $substitutions['left_double_quote'] . $matches[2] . $substitutions['right_double_quote'],
1042+
],
1043+
];
1044+
}
1045+
}
10371046

1038-
if ('"' === $matches[1]) {
1039-
return [
1040-
'extent' => strlen($matches[0]),
1041-
'element' => [
1042-
'text' => $substitutions['left_double_quote'] . $matches[2] . $substitutions['right_double_quote'],
1043-
],
1044-
];
1045-
}
1046-
},
1047-
],
1048-
'smart_angled_quotes' => [
1049-
'pattern' => '/^(?:<{2})(?!\s)([^<>]+)(?:>{2})/i',
1050-
'callback' => function ($matches) use ($substitutions, $Excerpt) {
1051-
if (strlen(trim($Excerpt['before'])) > 0) {
1052-
return null; // Skip if angled quotes do not start at the beginning
1053-
}
1047+
// <<like this>>
1048+
if ('<' === $first && $config->get('smartypants.smart_angled_quotes')) {
1049+
if (preg_match('/^(?:<{2})(?!\s)([^<>]+)(?:>{2})/i', $text, $matches)) {
1050+
if (strlen(trim($Excerpt['before'])) > 0) {
1051+
return null;
1052+
}
1053+
1054+
return [
1055+
'extent' => strlen($matches[0]),
1056+
'element' => [
1057+
'text' => $substitutions['left_angle_quote'] . $matches[1] . $substitutions['right_angle_quote'],
1058+
],
1059+
];
1060+
}
1061+
}
10541062

1055-
// Return transformed text with left and right angle quotes
1063+
// -- or ---
1064+
if ('-' === $first && $config->get('smartypants.smart_dashes')) {
1065+
if (preg_match('/^(-{2,3})(?!-)/', $text, $matches)) {
1066+
if ('---' === $matches[1]) {
10561067
return [
1057-
'extent' => strlen($matches[0]),
1068+
'extent' => strlen($matches[1]),
10581069
'element' => [
1059-
'text' => $substitutions['left_angle_quote'] . $matches[2] . $substitutions['right_angle_quote'],
1070+
'text' => $substitutions['mdash'],
10601071
],
10611072
];
1062-
},
1063-
],
1064-
'smart_dashes' => [
1065-
'pattern' => '/^(?<!\.)\.{3}(?!\.)/i',
1066-
'callback' => function ($matches) use ($substitutions) {
1067-
// Replace double dashes with ndash or triple dashes with mdash
1068-
if ('---' === $matches[1]) {
1069-
return [
1070-
'extent' => strlen($matches[0]),
1071-
'element' => [
1072-
'text' => $substitutions['mdash'],
1073-
],
1074-
];
1075-
}
1073+
}
10761074

1077-
if ('--' === $matches[1]) {
1078-
return [
1079-
'extent' => strlen($matches[0]),
1080-
'element' => [
1081-
'text' => $substitutions['ndash'],
1082-
],
1083-
];
1084-
}
1085-
},
1086-
],
1087-
'smart_ellipses' => [
1088-
'pattern' => '/^(?<!\.)(\.{3})(?!\.)/i',
1089-
'callback' => function ($matches) use ($substitutions) {
1090-
// Replace three dots with an ellipsis
1075+
if ('--' === $matches[1]) {
10911076
return [
1092-
'extent' => strlen($matches[0]),
1077+
'extent' => 2,
10931078
'element' => [
1094-
'text' => $substitutions['ellipses'],
1079+
'text' => $substitutions['ndash'],
10951080
],
10961081
];
1097-
},
1098-
],
1099-
];
1082+
}
1083+
}
1084+
}
11001085

1101-
// Iterate over each pattern and apply the corresponding callback if a match is found
1102-
foreach ($patterns as $key => $value) {
1103-
if ($config->get('smartypants.' . $key) && preg_match($value['pattern'], $Excerpt['text'], $matches)) {
1104-
$matches = array_values(array_filter($matches)); // Filter out empty matches
1105-
return $value['callback']($matches); // Return the transformed text using the callback
1086+
// ...
1087+
if ('.' === $first && $config->get('smartypants.smart_ellipses')) {
1088+
if (preg_match('/^(?<!\.)(\.{3})(?!\.)/i', $text, $matches)) {
1089+
return [
1090+
'extent' => strlen($matches[0]),
1091+
'element' => [
1092+
'text' => $substitutions['ellipses'],
1093+
],
1094+
];
11061095
}
11071096
}
11081097

1109-
// If no substitutions were made, return null
11101098
return null;
11111099
}
11121100

0 commit comments

Comments
 (0)