[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/diviner/markup/ -> DivinerSymbolRemarkupRule.php (source)

   1  <?php
   2  
   3  final class DivinerSymbolRemarkupRule extends PhutilRemarkupRule {
   4  
   5    const KEY_RULE_ATOM_REF = 'rule.diviner.atomref';
   6  
   7    public function getPriority() {
   8      return 200.0;
   9    }
  10  
  11    public function apply($text) {
  12      // Grammar here is:
  13      //
  14      //         rule = '@{' maybe_type name maybe_title '}'
  15      //   maybe_type = null | type ':' | type '@' book ':'
  16      //         name = name | name '@' context
  17      //  maybe_title = null | '|' title
  18      //
  19      // So these are all valid:
  20      //
  21      //   @{name}
  22      //   @{type : name}
  23      //   @{name | title}
  24      //   @{type @ book : name @ context | title}
  25  
  26      return preg_replace_callback(
  27        '/(?:^|\B)@{'.
  28          '(?:(?P<type>[^:]+?):)?'.
  29          '(?P<name>[^}|]+?)'.
  30          '(?:[|](?P<title>[^}]+))?'.
  31        '}/',
  32        array($this, 'markupSymbol'),
  33        $text);
  34    }
  35  
  36    public function markupSymbol($matches) {
  37      if (!$this->isFlatText($matches[0])) {
  38        return $matches[0];
  39      }
  40  
  41      $type = (string)idx($matches, 'type');
  42      $name = (string)$matches['name'];
  43      $title = (string)idx($matches, 'title');
  44  
  45      // Collapse sequences of whitespace into a single space.
  46      $type = preg_replace('/\s+/', ' ', trim($type));
  47      $name = preg_replace('/\s+/', ' ', trim($name));
  48      $title = preg_replace('/\s+/', ' ', trim($title));
  49  
  50      $ref = array();
  51  
  52      if (strpos($type, '@') !== false) {
  53        list($type, $book) = explode('@', $type, 2);
  54        $ref['type'] = trim($type);
  55        $ref['book'] = trim($book);
  56      } else {
  57        $ref['type'] = $type;
  58      }
  59  
  60      if (strpos($name, '@') !== false) {
  61        list($name, $context) = explode('@', $name, 2);
  62        $ref['name'] = trim($name);
  63        $ref['context'] = trim($context);
  64      } else {
  65        $ref['name'] = $name;
  66      }
  67  
  68      $ref['title'] = nonempty($title, $name);
  69  
  70      foreach ($ref as $key => $value) {
  71        if ($value === '') {
  72          unset($ref[$key]);
  73        }
  74      }
  75  
  76      $engine = $this->getEngine();
  77      $token = $engine->storeText('');
  78  
  79      $key = self::KEY_RULE_ATOM_REF;
  80      $data = $engine->getTextMetadata($key, array());
  81      $data[$token] = $ref;
  82      $engine->setTextMetadata($key, $data);
  83  
  84      return $token;
  85    }
  86  
  87    public function didMarkupText() {
  88      $engine = $this->getEngine();
  89  
  90      $key = self::KEY_RULE_ATOM_REF;
  91      $data = $engine->getTextMetadata($key, array());
  92  
  93      $renderer = $engine->getConfig('diviner.renderer');
  94  
  95      foreach ($data as $token => $ref_dict) {
  96        $ref = DivinerAtomRef::newFromDictionary($ref_dict);
  97        $title = $ref->getTitle();
  98  
  99        $href = null;
 100        if ($renderer) {
 101          // Here, we're generating documentation. If possible, we want to find
 102          // the real atom ref so we can render the correct default title and
 103          // render invalid links in an alternate style.
 104  
 105          $ref = $renderer->normalizeAtomRef($ref);
 106          if ($ref) {
 107            $title = nonempty($ref->getTitle(), $ref->getName());
 108            $href = $renderer->getHrefForAtomRef($ref);
 109          }
 110        } else {
 111          // Here, we're generating comment text or something like that. Just
 112          // link to Diviner and let it sort things out.
 113  
 114          $href = id(new PhutilURI('/diviner/find/'))
 115            ->setQueryParams(
 116              array(
 117                'book' => $ref->getBook(),
 118                'name' => $ref->getName(),
 119                'type' => $ref->getType(),
 120                'context' => $ref->getContext(),
 121                'jump' => true,
 122              ));
 123        }
 124  
 125        // TODO: This probably is not the best place to do this. Move it somewhere
 126        // better when it becomes more clear where it should actually go.
 127        if ($ref) {
 128          switch ($ref->getType()) {
 129            case 'function':
 130            case 'method':
 131              $title = $title.'()';
 132              break;
 133          }
 134        }
 135  
 136        if ($this->getEngine()->isTextMode()) {
 137          if ($href) {
 138            $link = $title.' <'.PhabricatorEnv::getProductionURI($href).'>';
 139          } else {
 140            $link = $title;
 141          }
 142        } else if ($href) {
 143          if ($this->getEngine()->isHTMLMailMode()) {
 144            $href = PhabricatorEnv::getProductionURI($href);
 145          }
 146  
 147          $link = $this->newTag(
 148            'a',
 149            array(
 150              'class' => 'atom-ref',
 151              'href' => $href,
 152            ),
 153            $title);
 154        } else {
 155          $link = $this->newTag(
 156            'span',
 157            array(
 158              'class' => 'atom-ref-invalid',
 159            ),
 160            $title);
 161        }
 162  
 163        $engine->overwriteStoredText($token, $link);
 164      }
 165    }
 166  
 167  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1