League\CommonMark\Delimiter\DelimiterStack::iterateByCharacters PHP Method

iterateByCharacters() public method

public iterateByCharacters ( string | string[] $characters, callable $callback, Delimiter $stackBottom = null )
$characters string | string[]
$callback callable
$stackBottom Delimiter
    public function iterateByCharacters($characters, $callback, Delimiter $stackBottom = null)
    {
        if (!is_array($characters)) {
            $characters = [$characters];
        }
        $openersBottom = array_fill_keys($characters, $stackBottom);
        // Find first closer above stackBottom
        $closer = $this->findEarliest($stackBottom);
        while ($closer !== null) {
            $closerChar = $closer->getChar();
            if (!$closer->canClose() || !in_array($closerChar, $characters)) {
                $closer = $closer->getNext();
                continue;
            }
            $oddMatch = false;
            $opener = $this->findMatchingOpener($closer, $openersBottom, $stackBottom, $oddMatch);
            if ($opener) {
                $closer = $callback($opener, $closer, $this);
            } elseif ($oddMatch) {
                $closer = $closer->getNext();
            } else {
                $oldCloser = $closer;
                $closer = $closer->getNext();
                // Set lower bound for future searches for openers:
                $openersBottom[$closerChar] = $oldCloser->getPrevious();
                if (!$oldCloser->canOpen()) {
                    // We can remove a closer that can't be an opener,
                    // once we've seen there's no matching opener:
                    $this->removeDelimiter($oldCloser);
                }
                continue;
            }
        }
    }

Usage Example

 public function processInlines(ArrayCollection $inlines, DelimiterStack $delimiterStack, Delimiter $stackBottom = null)
 {
     $callback = function (Delimiter $opener, Delimiter $closer, DelimiterStack $stack) use($inlines) {
         // Calculate actual number of delimiters used from this closer
         if ($closer->getNumDelims() < 3 || $opener->getNumDelims() < 3) {
             $useDelims = $closer->getNumDelims() <= $opener->getNumDelims() ? $closer->getNumDelims() : $opener->getNumDelims();
         } else {
             $useDelims = $closer->getNumDelims() % 2 === 0 ? 2 : 1;
         }
         /** @var Text $openerInline */
         $openerInline = $inlines->get($opener->getPos());
         /** @var Text $closerInline */
         $closerInline = $inlines->get($closer->getPos());
         // Remove used delimiters from stack elts and inlines
         $opener->setNumDelims($opener->getNumDelims() - $useDelims);
         $closer->setNumDelims($closer->getNumDelims() - $useDelims);
         $openerInline->setContent(substr($openerInline->getContent(), 0, -$useDelims));
         $closerInline->setContent(substr($closerInline->getContent(), 0, -$useDelims));
         // Build contents for new emph element
         $start = $opener->getPos() + 1;
         $contents = $inlines->slice($start, $closer->getPos() - $start);
         $contents = array_filter($contents);
         if ($useDelims === 1) {
             $emph = new Emphasis($contents);
         } else {
             $emph = new Strong($contents);
         }
         // Insert into list of inlines
         $inlines->set($opener->getPos() + 1, $emph);
         for ($i = $opener->getPos() + 2; $i < $closer->getPos(); $i++) {
             $inlines->set($i, null);
         }
         // Remove elts btw opener and closer in delimiters stack
         $tempStack = $closer->getPrevious();
         while ($tempStack !== null && $tempStack !== $opener) {
             $nextStack = $tempStack->getPrevious();
             $stack->removeDelimiter($tempStack);
             $tempStack = $nextStack;
         }
         // If opener has 0 delims, remove it and the inline
         if ($opener->getNumDelims() === 0) {
             $inlines->set($opener->getPos(), null);
             $stack->removeDelimiter($opener);
         }
         if ($closer->getNumDelims() === 0) {
             $inlines->set($closer->getPos(), null);
             $tempStack = $closer->getNext();
             $stack->removeDelimiter($closer);
             return $tempStack;
         }
         return $closer;
     };
     // Process the emphasis characters
     $delimiterStack->iterateByCharacters(['_', '*'], $callback, $stackBottom);
     // Remove gaps
     $inlines->removeGaps();
     // Remove all delimiters
     $delimiterStack->removeAll($stackBottom);
 }
All Usage Examples Of League\CommonMark\Delimiter\DelimiterStack::iterateByCharacters