diff --git a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php --- a/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php +++ b/src/applications/files/markup/PhabricatorEmbedFileRemarkupRule.php @@ -5,7 +5,7 @@ private $viewer; - const KEY_EMBED_FILE_PHIDS = 'phabricator.embedded-file-phids'; + const KEY_ATTACH_INTENT_FILE_PHIDS = 'files.attach-intent'; protected function getObjectNamePrefix() { return 'F'; @@ -23,13 +23,44 @@ PhabricatorFileThumbnailTransform::TRANSFORM_PREVIEW, )) ->execute(); + $objects = mpull($objects, null, 'getID'); - $phids_key = self::KEY_EMBED_FILE_PHIDS; - $phids = $engine->getTextMetadata($phids_key, array()); - foreach (mpull($objects, 'getPHID') as $phid) { - $phids[] = $phid; + + // Identify files embedded in the block with "attachment intent", i.e. + // those files which the user appears to want to attach to the object. + // Files referenced inside quoted blocks are not considered to have this + // attachment intent. + + $metadata_key = self::KEY_RULE_OBJECT.'.'.$this->getObjectNamePrefix(); + $metadata = $engine->getTextMetadata($metadata_key, array()); + + $attach_key = self::KEY_ATTACH_INTENT_FILE_PHIDS; + $attach_phids = $engine->getTextMetadata($attach_key, array()); + + foreach ($metadata as $item) { + + // If this reference was inside a quoted block, don't count it. Quoting + // someone else doesn't establish an intent to attach a file. + $depth = idx($item, 'quote.depth'); + if ($depth > 0) { + continue; + } + + $id = $item['id']; + $file = idx($objects, $id); + + if (!$file) { + continue; + } + + $attach_phids[] = $file->getPHID(); } - $engine->setTextMetadata($phids_key, $phids); + + $attach_phids = array_fuse($attach_phids); + $attach_phids = array_keys($attach_phids); + + $engine->setTextMetadata($attach_key, $attach_phids); + return $objects; } diff --git a/src/infrastructure/markup/PhabricatorMarkupEngine.php b/src/infrastructure/markup/PhabricatorMarkupEngine.php --- a/src/infrastructure/markup/PhabricatorMarkupEngine.php +++ b/src/infrastructure/markup/PhabricatorMarkupEngine.php @@ -632,7 +632,7 @@ foreach ($content_blocks as $content_block) { $engine->markupText($content_block); $phids = $engine->getTextMetadata( - PhabricatorEmbedFileRemarkupRule::KEY_EMBED_FILE_PHIDS, + PhabricatorEmbedFileRemarkupRule::KEY_ATTACH_INTENT_FILE_PHIDS, array()); foreach ($phids as $phid) { $files[$phid] = $phid; diff --git a/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php b/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php --- a/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php +++ b/src/infrastructure/markup/blockrule/PhutilRemarkupBlockRule.php @@ -43,6 +43,14 @@ return; } + public function willMarkupChildBlocks() { + return; + } + + public function didMarkupChildBlocks() { + return; + } + final public function setEngine(PhutilRemarkupEngine $engine) { $this->engine = $engine; $this->updateRules(); diff --git a/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php b/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php --- a/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php +++ b/src/infrastructure/markup/blockrule/PhutilRemarkupQuotedBlockRule.php @@ -7,6 +7,22 @@ return true; } + public function willMarkupChildBlocks() { + $engine = $this->getEngine(); + + $depth = $engine->getQuoteDepth(); + $depth = $depth + 1; + $engine->setQuoteDepth($depth); + } + + public function didMarkupChildBlocks() { + $engine = $this->getEngine(); + + $depth = $engine->getQuoteDepth(); + $depth = $depth - 1; + $engine->setQuoteDepth($depth); + } + final protected function normalizeQuotedBody($text) { $text = phutil_split_lines($text, true); foreach ($text as $key => $line) { diff --git a/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php b/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php --- a/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php +++ b/src/infrastructure/markup/remarkup/PhutilRemarkupEngine.php @@ -42,6 +42,14 @@ return $this->mode & self::MODE_HTML_MAIL; } + public function getQuoteDepth() { + return $this->getConfig('runtime.quote.depth', 0); + } + + public function setQuoteDepth($depth) { + return $this->setConfig('runtime.quote.depth', $depth); + } + public function setBlockRules(array $rules) { assert_instances_of($rules, 'PhutilRemarkupBlockRule'); @@ -255,18 +263,24 @@ } private function markupBlock(array $block) { + $rule = $block['rule']; + + $rule->willMarkupChildBlocks(); + $children = array(); foreach ($block['children'] as $child) { $children[] = $this->markupBlock($child); } + $rule->didMarkupChildBlocks(); + if ($children) { $children = $this->flattenOutput($children); } else { $children = null; } - return $block['rule']->markupText($block['text'], $children); + return $rule->markupText($block['text'], $children); } private function flattenOutput(array $output) { 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 @@ -318,6 +318,7 @@ 'id' => $matches[1], 'options' => idx($matches, 2), 'original' => $matches[0], + 'quote.depth' => $engine->getQuoteDepth(), )); } @@ -337,6 +338,7 @@ 'id' => $matches[1], 'anchor' => idx($matches, 2), 'original' => $matches[0], + 'quote.depth' => $engine->getQuoteDepth(), )); }