Page MenuHomePhabricator

D10753.diff
No OneTemporary

D10753.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2823,6 +2823,7 @@
'ProjectCreateProjectsCapability' => 'applications/project/capability/ProjectCreateProjectsCapability.php',
'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php',
'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php',
+ 'ProjectRemarkupRuleTestCase' => 'applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php',
'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php',
'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php',
'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php',
@@ -6015,6 +6016,7 @@
'ProjectCreateProjectsCapability' => 'PhabricatorPolicyCapability',
'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod',
'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule',
+ 'ProjectRemarkupRuleTestCase' => 'PhabricatorTestCase',
'QueryFormattingTestCase' => 'PhabricatorTestCase',
'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification',
'ReleephBranch' => array(
diff --git a/src/applications/project/remarkup/ProjectRemarkupRule.php b/src/applications/project/remarkup/ProjectRemarkupRule.php
--- a/src/applications/project/remarkup/ProjectRemarkupRule.php
+++ b/src/applications/project/remarkup/ProjectRemarkupRule.php
@@ -30,7 +30,7 @@
// In other contexts, the PhabricatorProjectProjectPHIDType pattern is
// controlling and these names should parse correctly.
- return '[^\s.!,:;{}#]*[^\s\d!,:;{}#]+(?:[^\s.!,:;{}#][^\s!,:;{}#]*)*';
+ return '[^\s.\d!,:;{}#]+(?:[^\s!,:;{}#][^\s.!,:;{}#]+)*';
}
protected function loadObjects(array $ids) {
diff --git a/src/applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php b/src/applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/remarkup/__tests__/ProjectRemarkupRuleTestCase.php
@@ -0,0 +1,57 @@
+<?php
+
+final class ProjectRemarkupRuleTestCase extends PhabricatorTestCase {
+
+ public function testProjectObjectRemarkup() {
+ $cases = array(
+ 'I like #ducks.' => array(
+ 'embed' => array(),
+ 'ref' => array(
+ array(
+ 'offset' => 8,
+ 'id' => 'ducks',
+ ),
+ ),
+ ),
+ 'We should make a post on #blog.example.com tomorrow.' => array(
+ 'embed' => array(),
+ 'ref' => array(
+ array(
+ 'offset' => 26,
+ 'id' => 'blog.example.com',
+ ),
+ ),
+ ),
+ 'We should make a post on #blog.example.com.' => array(
+ 'embed' => array(),
+ 'ref' => array(
+ array(
+ 'offset' => 26,
+ 'id' => 'blog.example.com',
+ ),
+ ),
+ ),
+ '#123' => array(
+ 'embed' => array(),
+ 'ref' => array(),
+ ),
+ '#security#123' => array(
+ 'embed' => array(),
+ 'ref' => array(
+ array(
+ 'offset' => 1,
+ 'id' => 'security',
+ 'tail' => '123',
+ ),
+ ),
+ ),
+ );
+
+ foreach ($cases as $input => $expect) {
+ $rule = new ProjectRemarkupRule();
+ $matches = $rule->extractReferences($input);
+ $this->assertEqual($expect, $matches, $input);
+ }
+ }
+
+}
diff --git a/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php b/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php
--- a/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php
+++ b/src/infrastructure/markup/rule/PhabricatorObjectRemarkupRule.php
@@ -95,15 +95,33 @@
}
public function apply($text) {
- $prefix = $this->getObjectNamePrefix();
- $prefix = preg_quote($prefix, '@');
- $id = $this->getObjectIDPattern();
-
$text = preg_replace_callback(
- '@\B{'.$prefix.'('.$id.')((?:[^}\\\\]|\\\\.)*)}\B@u',
+ $this->getObjectEmbedPattern(),
array($this, 'markupObjectEmbed'),
$text);
+ $text = preg_replace_callback(
+ $this->getObjectReferencePattern(),
+ array($this, 'markupObjectReference'),
+ $text);
+
+ return $text;
+ }
+
+ private function getObjectEmbedPattern() {
+ $prefix = $this->getObjectNamePrefix();
+ $prefix = preg_quote($prefix);
+ $id = $this->getObjectIDPattern();
+
+ return '(\B{'.$prefix.'('.$id.')((?:[^}\\\\]|\\\\.)*)}\B)u';
+ }
+
+ private function getObjectReferencePattern() {
+ $prefix = $this->getObjectNamePrefix();
+ $prefix = preg_quote($prefix);
+
+ $id = $this->getObjectIDPattern();
+
// If the prefix starts with a word character (like "D"), we want to
// require a word boundary so that we don't match "XD1" as "D1". If the
// prefix does not start with a word character, we want to require no word
@@ -121,12 +139,55 @@
// The "\b" allows us to link "(abcdef)" or similar without linking things
// in the middle of words.
- $text = preg_replace_callback(
- '((?<![#-])'.$boundary.$prefix.'('.$id.')(?:#([-\w\d]+))?(?!\w))u',
- array($this, 'markupObjectReference'),
- $text);
+ return '((?<![#-])'.$boundary.$prefix.'('.$id.')(?:#([-\w\d]+))?(?!\w))u';
+ }
- return $text;
+
+ /**
+ * Extract matched object references from a block of text.
+ *
+ * This is intended to make it easy to write unit tests for object remarkup
+ * rules. Production code is not normally expected to call this method.
+ *
+ * @param string Text to match rules against.
+ * @return wild Matches, suitable for writing unit tests against.
+ */
+ public function extractReferences($text) {
+ $embed_matches = null;
+ preg_match_all(
+ $this->getObjectEmbedPattern(),
+ $text,
+ $embed_matches,
+ PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
+
+ $ref_matches = null;
+ preg_match_all(
+ $this->getObjectReferencePattern(),
+ $text,
+ $ref_matches,
+ PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
+
+ $results = array();
+ $sets = array(
+ 'embed' => $embed_matches,
+ 'ref' => $ref_matches,
+ );
+ foreach ($sets as $type => $matches) {
+ $formatted = array();
+ foreach ($matches as $match) {
+ $format = array(
+ 'offset' => $match[1][1],
+ 'id' => $match[1][0],
+ );
+ if (isset($match[2][0])) {
+ $format['tail'] = $match[2][0];
+ }
+ $formatted[] = $format;
+ }
+ $results[$type] = $formatted;
+ }
+
+ return $results;
}
public function markupObjectEmbed($matches) {

File Metadata

Mime Type
text/plain
Expires
Sat, May 18, 10:01 AM (2 w, 7 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6300507
Default Alt Text
D10753.diff (6 KB)

Event Timeline