diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2e5d1afcc9..aff14d41ac 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -474,6 +474,7 @@ phutil_register_library_map(array( 'DivinerListController' => 'applications/diviner/controller/DivinerListController.php', 'DivinerPublishCache' => 'applications/diviner/cache/DivinerPublishCache.php', 'DivinerPublisher' => 'applications/diviner/publisher/DivinerPublisher.php', + 'DivinerRemarkupRuleSymbol' => 'applications/diviner/markup/DivinerRemarkupRuleSymbol.php', 'DivinerRenderer' => 'applications/diviner/renderer/DivinerRenderer.php', 'DivinerStaticPublisher' => 'applications/diviner/publisher/DivinerStaticPublisher.php', 'DivinerWorkflow' => 'applications/diviner/workflow/DivinerWorkflow.php', @@ -1974,6 +1975,7 @@ phutil_register_library_map(array( 'DivinerGenerateWorkflow' => 'DivinerWorkflow', 'DivinerListController' => 'PhabricatorController', 'DivinerPublishCache' => 'DivinerDiskCache', + 'DivinerRemarkupRuleSymbol' => 'PhutilRemarkupRule', 'DivinerStaticPublisher' => 'DivinerPublisher', 'DivinerWorkflow' => 'PhutilArgumentWorkflow', 'DrydockAllocatorWorker' => 'PhabricatorWorker', diff --git a/src/applications/diviner/atomizer/DivinerArticleAtomizer.php b/src/applications/diviner/atomizer/DivinerArticleAtomizer.php index c18061b301..3a6f0bf826 100644 --- a/src/applications/diviner/atomizer/DivinerArticleAtomizer.php +++ b/src/applications/diviner/atomizer/DivinerArticleAtomizer.php @@ -2,7 +2,7 @@ final class DivinerArticleAtomizer extends DivinerAtomizer { - public function atomize($file_name, $file_data) { + protected function executeAtomize($file_name, $file_data) { $atom = $this->newAtom(DivinerAtom::TYPE_ARTICLE) ->setLine(1) ->setLength(count(explode("\n", $file_data))) diff --git a/src/applications/diviner/atomizer/DivinerAtomizer.php b/src/applications/diviner/atomizer/DivinerAtomizer.php index 7f26a6312b..0661cfe846 100644 --- a/src/applications/diviner/atomizer/DivinerAtomizer.php +++ b/src/applications/diviner/atomizer/DivinerAtomizer.php @@ -6,6 +6,7 @@ abstract class DivinerAtomizer { private $book; + private $fileName; /** * If you make a significant change to an atomizer, you can bump this @@ -15,7 +16,12 @@ abstract class DivinerAtomizer { return 1; } - abstract public function atomize($file_name, $file_data); + final public function atomize($file_name, $file_data) { + $this->fileName = $file_name; + return $this->executeAtomize($file_name, $file_data); + } + + abstract protected function executeAtomize($file_name, $file_data); final public function setBook($book) { $this->book = $book; @@ -29,6 +35,7 @@ abstract class DivinerAtomizer { protected function newAtom($type) { return id(new DivinerAtom()) ->setBook($this->getBook()) + ->setFile($this->fileName) ->setType($type); } diff --git a/src/applications/diviner/atomizer/DivinerFileAtomizer.php b/src/applications/diviner/atomizer/DivinerFileAtomizer.php index 3ea1ded7d6..0287808e38 100644 --- a/src/applications/diviner/atomizer/DivinerFileAtomizer.php +++ b/src/applications/diviner/atomizer/DivinerFileAtomizer.php @@ -2,7 +2,7 @@ final class DivinerFileAtomizer extends DivinerAtomizer { - public function atomize($file_name, $file_data) { + protected function executeAtomize($file_name, $file_data) { $atom = $this->newAtom(DivinerAtom::TYPE_FILE) ->setName($file_name) ->setFile($file_name) diff --git a/src/applications/diviner/markup/DivinerRemarkupRuleSymbol.php b/src/applications/diviner/markup/DivinerRemarkupRuleSymbol.php new file mode 100644 index 0000000000..bf2273b9ea --- /dev/null +++ b/src/applications/diviner/markup/DivinerRemarkupRuleSymbol.php @@ -0,0 +1,36 @@ +replaceHTML( + '/(?:^|\B)@{(?:(?P[^:]+?):)?(?P[^}]+?)}/', + array($this, 'markupSymbol'), + $text); + } + + public function markupSymbol($matches) { + $type = $matches['type']; + $name = $matches['name']; + + // Collapse sequences of whitespace into a single space. + $name = preg_replace('/\s+/', ' ', $name); + + $book = null; + if (strpos($type, '@') !== false) { + list($type, $book) = explode('@', $type, 2); + } + + // TODO: This doesn't actually do anything useful yet. + + $link = phutil_tag( + 'a', + array( + 'href' => '#', + ), + $name); + + return $this->getEngine()->storeText($link); + } + +} diff --git a/src/applications/diviner/renderer/DivinerDefaultRenderer.php b/src/applications/diviner/renderer/DivinerDefaultRenderer.php index cbe7eae3b8..e5ca5958e5 100644 --- a/src/applications/diviner/renderer/DivinerDefaultRenderer.php +++ b/src/applications/diviner/renderer/DivinerDefaultRenderer.php @@ -172,7 +172,10 @@ final class DivinerDefaultRenderer extends DivinerRenderer { } protected function getBlockMarkupEngine() { - return PhabricatorMarkupEngine::newMarkupEngine(array()); + return PhabricatorMarkupEngine::newMarkupEngine( + array( + 'preserve-linebreaks' => false, + )); } protected function getInlineMarkupEngine() { diff --git a/src/applications/diviner/workflow/DivinerAtomizeWorkflow.php b/src/applications/diviner/workflow/DivinerAtomizeWorkflow.php index 18102103ce..ace4b1dd15 100644 --- a/src/applications/diviner/workflow/DivinerAtomizeWorkflow.php +++ b/src/applications/diviner/workflow/DivinerAtomizeWorkflow.php @@ -59,9 +59,14 @@ final class DivinerAtomizeWorkflow extends DivinerWorkflow { $file_atomizer = new DivinerFileAtomizer(); + foreach (array($atomizer, $file_atomizer) as $configure) { + $configure->setBook($this->getConfig('name')); + } + $all_atoms = array(); foreach ($files as $file) { - $data = Filesystem::readFile($file); + $abs_path = Filesystem::resolvePath($file, $this->getConfig('root')); + $data = Filesystem::readFile($abs_path); if (!$this->shouldAtomizeFile($file, $data)) { $console->writeLog("Skipping %s...\n", $file); @@ -89,10 +94,6 @@ final class DivinerAtomizeWorkflow extends DivinerWorkflow { $all_atoms = array_mergev($all_atoms); - foreach ($all_atoms as $atom) { - $atom->setBook($this->getConfig('name')); - } - $all_atoms = mpull($all_atoms, 'toDictionary'); $all_atoms = ipull($all_atoms, null, 'hash'); diff --git a/src/applications/diviner/workflow/DivinerGenerateWorkflow.php b/src/applications/diviner/workflow/DivinerGenerateWorkflow.php index 248bd85f40..53dd0b1a1a 100644 --- a/src/applications/diviner/workflow/DivinerGenerateWorkflow.php +++ b/src/applications/diviner/workflow/DivinerGenerateWorkflow.php @@ -198,7 +198,7 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow { private function findFilesInProject() { - $file_hashes = id(new FileFinder($this->getConfig('root'))) + $raw_hashes = id(new FileFinder($this->getConfig('root'))) ->excludePath('*/.*') ->withType('f') ->setGenerateChecksums(true) @@ -206,11 +206,13 @@ final class DivinerGenerateWorkflow extends DivinerWorkflow { $version = $this->getDivinerAtomWorldVersion(); - foreach ($file_hashes as $file => $md5_hash) { + $file_hashes = array(); + foreach ($raw_hashes as $file => $md5_hash) { + $rel_file = Filesystem::readablePath($file, $this->getConfig('root')); // We want the hash to change if the file moves or Diviner gets updated, // not just if the file content changes. Derive a hash from everything // we care about. - $file_hashes[$file] = md5("{$file}\0{$md5_hash}\0{$version}").'F'; + $file_hashes[$rel_file] = md5("{$rel_file}\0{$md5_hash}\0{$version}").'F'; } return $file_hashes; diff --git a/src/infrastructure/markup/PhabricatorMarkupEngine.php b/src/infrastructure/markup/PhabricatorMarkupEngine.php index d0c8545809..4096493e04 100644 --- a/src/infrastructure/markup/PhabricatorMarkupEngine.php +++ b/src/infrastructure/markup/PhabricatorMarkupEngine.php @@ -355,6 +355,7 @@ final class PhabricatorMarkupEngine { 'uri.allowed-protocols'), 'syntax-highlighter.engine' => PhabricatorEnv::getEnvConfig( 'syntax-highlighter.engine'), + 'preserve-linebreaks' => true, ); } @@ -368,7 +369,7 @@ final class PhabricatorMarkupEngine { $engine = new PhutilRemarkupEngine(); - $engine->setConfig('preserve-linebreaks', true); + $engine->setConfig('preserve-linebreaks', $options['preserve-linebreaks']); $engine->setConfig('pygments.enabled', $options['pygments']); $engine->setConfig( 'uri.allowed-protocols', @@ -422,6 +423,8 @@ final class PhabricatorMarkupEngine { $rules[] = new PhabricatorRemarkupRuleMeme(); } + $rules[] = new DivinerRemarkupRuleSymbol(); + $rules[] = new PhabricatorRemarkupRuleMention(); $rules[] = new PhutilRemarkupRuleBold();