1<?php 2/** 3 * SCSSPHP 4 * 5 * @copyright 2012-2015 Leaf Corcoran 6 * 7 * @license http://opensource.org/licenses/MIT MIT 8 * 9 * @link http://leafo.github.io/scssphp 10 */ 11namespace Leafo\ScssPhp; 12 13use Leafo\ScssPhp\Formatter\OutputBlock; 14/** 15 * Base formatter 16 * 17 * @author Leaf Corcoran <leafot@gmail.com> 18 */ 19abstract class Formatter 20{ 21 /** 22 * @var integer 23 */ 24 public $indentLevel; 25 /** 26 * @var string 27 */ 28 public $indentChar; 29 /** 30 * @var string 31 */ 32 public $break; 33 /** 34 * @var string 35 */ 36 public $open; 37 /** 38 * @var string 39 */ 40 public $close; 41 /** 42 * @var string 43 */ 44 public $tagSeparator; 45 /** 46 * @var string 47 */ 48 public $assignSeparator; 49 /** 50 * @var boolea 51 */ 52 public $keepSemicolons; 53 /** 54 * Initialize formatter 55 * 56 * @api 57 */ 58 public abstract function __construct(); 59 /** 60 * Return indentation (whitespace) 61 * 62 * @return string 63 */ 64 protected function indentStr() 65 { 66 return ''; 67 } 68 /** 69 * Return property assignment 70 * 71 * @api 72 * 73 * @param string $name 74 * @param mixed $value 75 * 76 * @return string 77 */ 78 public function property($name, $value) 79 { 80 return rtrim($name) . $this->assignSeparator . $value . ';'; 81 } 82 /** 83 * Strip semi-colon appended by property(); it's a separator, not a terminator 84 * 85 * @api 86 * 87 * @param array $lines 88 */ 89 public function stripSemicolon(&$lines) 90 { 91 if ($this->keepSemicolons) { 92 return; 93 } 94 if (($count = count($lines)) && substr($lines[$count - 1], -1) === ';') { 95 $lines[$count - 1] = substr($lines[$count - 1], 0, -1); 96 } 97 } 98 /** 99 * Output lines inside a block 100 * 101 * @param \Leafo\ScssPhp\Formatter\OutputBlock $block 102 */ 103 protected function blockLines(OutputBlock $block) 104 { 105 $inner = $this->indentStr(); 106 $glue = $this->break . $inner; 107 echo $inner . implode($glue, $block->lines); 108 if (!empty($block->children)) { 109 echo $this->break; 110 } 111 } 112 /** 113 * Output block selectors 114 * 115 * @param \Leafo\ScssPhp\Formatter\OutputBlock $block 116 */ 117 protected function blockSelectors(OutputBlock $block) 118 { 119 $inner = $this->indentStr(); 120 echo $inner . implode($this->tagSeparator, $block->selectors) . $this->open . $this->break; 121 } 122 /** 123 * Output block children 124 * 125 * @param \Leafo\ScssPhp\Formatter\OutputBlock $block 126 */ 127 protected function blockChildren(OutputBlock $block) 128 { 129 foreach ($block->children as $child) { 130 $this->block($child); 131 } 132 } 133 /** 134 * Output non-empty block 135 * 136 * @param \Leafo\ScssPhp\Formatter\OutputBlock $block 137 */ 138 protected function block(OutputBlock $block) 139 { 140 if (empty($block->lines) && empty($block->children)) { 141 return; 142 } 143 $pre = $this->indentStr(); 144 if (!empty($block->selectors)) { 145 $this->blockSelectors($block); 146 $this->indentLevel++; 147 } 148 if (!empty($block->lines)) { 149 $this->blockLines($block); 150 } 151 if (!empty($block->children)) { 152 $this->blockChildren($block); 153 } 154 if (!empty($block->selectors)) { 155 $this->indentLevel--; 156 if (empty($block->children)) { 157 echo $this->break; 158 } 159 echo $pre . $this->close . $this->break; 160 } 161 } 162 /** 163 * Entry point to formatting a block 164 * 165 * @api 166 * 167 * @param \Leafo\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree 168 * 169 * @return string 170 */ 171 public function format(OutputBlock $block) 172 { 173 ob_start(); 174 $this->block($block); 175 $out = ob_get_clean(); 176 return $out; 177 } 178} 179