1<?php 2 3/* 4 * This file is part of the league/commonmark package. 5 * 6 * (c) Colin O'Dell <colinodell@gmail.com> 7 * 8 * Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js) 9 * - (c) John MacFarlane 10 * 11 * For the full copyright and license information, please view the LICENSE 12 * file that was distributed with this source code. 13 */ 14 15namespace League\CommonMark; 16 17use League\CommonMark\Block\Element\AbstractBlock; 18use League\CommonMark\Block\Element\Document; 19use League\CommonMark\Reference\ReferenceParser; 20 21/** 22 * Maintains the current state of the Markdown parser engine 23 */ 24class Context implements ContextInterface 25{ 26 /** 27 * @var EnvironmentInterface 28 */ 29 protected $environment; 30 31 /** 32 * @var Document 33 */ 34 protected $doc; 35 36 /** 37 * @var AbstractBlock|null 38 */ 39 protected $tip; 40 41 /** 42 * @var AbstractBlock 43 */ 44 protected $container; 45 46 /** 47 * @var int 48 */ 49 protected $lineNumber; 50 51 /** 52 * @var string 53 */ 54 protected $line; 55 56 /** 57 * @var UnmatchedBlockCloser 58 */ 59 protected $blockCloser; 60 61 /** 62 * @var bool 63 */ 64 protected $blocksParsed = false; 65 66 /** 67 * @var ReferenceParser 68 */ 69 protected $referenceParser; 70 71 public function __construct(Document $document, EnvironmentInterface $environment) 72 { 73 $this->doc = $document; 74 $this->tip = $this->doc; 75 $this->container = $this->doc; 76 77 $this->environment = $environment; 78 79 $this->referenceParser = new ReferenceParser($document->getReferenceMap()); 80 81 $this->blockCloser = new UnmatchedBlockCloser($this); 82 } 83 84 /** 85 * @param string $line 86 * 87 * @return void 88 */ 89 public function setNextLine(string $line) 90 { 91 ++$this->lineNumber; 92 $this->line = $line; 93 } 94 95 public function getDocument(): Document 96 { 97 return $this->doc; 98 } 99 100 public function getTip(): ?AbstractBlock 101 { 102 return $this->tip; 103 } 104 105 /** 106 * @param AbstractBlock|null $block 107 * 108 * @return $this 109 */ 110 public function setTip(?AbstractBlock $block) 111 { 112 $this->tip = $block; 113 114 return $this; 115 } 116 117 public function getLineNumber(): int 118 { 119 return $this->lineNumber; 120 } 121 122 public function getLine(): string 123 { 124 return $this->line; 125 } 126 127 public function getBlockCloser(): UnmatchedBlockCloser 128 { 129 return $this->blockCloser; 130 } 131 132 public function getContainer(): AbstractBlock 133 { 134 return $this->container; 135 } 136 137 /** 138 * @param AbstractBlock $container 139 * 140 * @return $this 141 */ 142 public function setContainer(AbstractBlock $container) 143 { 144 $this->container = $container; 145 146 return $this; 147 } 148 149 public function addBlock(AbstractBlock $block) 150 { 151 $this->blockCloser->closeUnmatchedBlocks(); 152 $block->setStartLine($this->lineNumber); 153 154 while ($this->tip !== null && !$this->tip->canContain($block)) { 155 $this->tip->finalize($this, $this->lineNumber); 156 } 157 158 // This should always be true 159 if ($this->tip !== null) { 160 $this->tip->appendChild($block); 161 } 162 163 $this->tip = $block; 164 $this->container = $block; 165 } 166 167 public function replaceContainerBlock(AbstractBlock $replacement) 168 { 169 $this->blockCloser->closeUnmatchedBlocks(); 170 $replacement->setStartLine($this->container->getStartLine()); 171 $this->container->replaceWith($replacement); 172 173 if ($this->tip === $this->container) { 174 $this->tip = $replacement; 175 } 176 177 $this->container = $replacement; 178 } 179 180 public function getBlocksParsed(): bool 181 { 182 return $this->blocksParsed; 183 } 184 185 /** 186 * @param bool $bool 187 * 188 * @return $this 189 */ 190 public function setBlocksParsed(bool $bool) 191 { 192 $this->blocksParsed = $bool; 193 194 return $this; 195 } 196 197 public function getReferenceParser(): ReferenceParser 198 { 199 return $this->referenceParser; 200 } 201} 202