%PDF- %PDF-
| Direktori : /home/q/g/b/qgbqkvz/www/wp-content/plugins/wp-scss/scssphp/src/SourceSpan/ |
| Current File : /home/q/g/b/qgbqkvz/www/wp-content/plugins/wp-scss/scssphp/src/SourceSpan/SourceFile.php |
<?php
/**
* SCSSPHP
*
* @copyright 2012-2020 Leaf Corcoran
*
* @license http://opensource.org/licenses/MIT MIT
*
* @link http://scssphp.github.io/scssphp
*/
namespace ScssPhp\ScssPhp\SourceSpan;
/**
* @internal
*/
final class SourceFile
{
/**
* @var string
* @readonly
*/
private $string;
/**
* @var string|null
* @readonly
*/
private $sourceUrl;
/**
* @var int[]
* @readonly
*/
private $lineStarts;
/**
* The 0-based last line that was returned by {@see getLine}
*
* This optimizes computation for successive accesses to
* the same line or to the next line.
* It is stored as 0-based to correspond to the indices
* in {@see $lineStarts}.
*
* @var int|null
*/
private $cachedLine;
public function __construct(string $content, ?string $sourceUrl)
{
$this->string = $content;
$this->sourceUrl = $sourceUrl;
// Extract line starts
$this->lineStarts = [0];
if ($content === '') {
return;
}
$prev = 0;
while (($pos = strpos($content, "\n", $prev)) !== false) {
$this->lineStarts[] = $pos;
$prev = $pos + 1;
}
$this->lineStarts[] = \strlen($content);
if (substr($content, -1) !== "\n") {
$this->lineStarts[] = \strlen($content) + 1;
}
}
public function span(int $start, ?int $end = null): FileSpan
{
if ($end === null) {
$end = \strlen($this->string);
}
return new FileSpan($this, $start, $end);
}
public function getSourceUrl(): ?string
{
return $this->sourceUrl;
}
/**
* The 0-based line
*
* @param int $position
*
* @return int
*/
public function getLine(int $position): int
{
if ($position < 0) {
throw new \RangeException('Position cannot be negative');
}
if ($position > \strlen($this->string)) {
throw new \RangeException('Position cannot be greater than the number of characters in the string.');
}
if ($this->isNearCacheLine($position)) {
assert($this->cachedLine !== null);
return $this->cachedLine;
}
$low = 0;
$high = \count($this->lineStarts);
while ($low < $high) {
$mid = (int) (($high + $low) / 2);
if ($position < $this->lineStarts[$mid]) {
$high = $mid - 1;
continue;
}
if ($position >= $this->lineStarts[$mid + 1]) {
$low = $mid + 1;
continue;
}
$this->cachedLine = $mid;
return $this->cachedLine;
}
$this->cachedLine = $low;
return $this->cachedLine;
}
/**
* Returns `true` if $position is near {@see $cachedLine}.
*
* Checks on {@see $cachedLine} and the next line. If it's on the next line, it
* updates {@see $cachedLine} to point to that.
*
* @param int $position
*
* @return bool
*/
private function isNearCacheLine(int $position): bool
{
if ($this->cachedLine === null) {
return false;
}
if ($position < $this->lineStarts[$this->cachedLine]) {
return false;
}
if ($this->cachedLine >= \count($this->lineStarts) - 1 ||
$position < $this->lineStarts[$this->cachedLine + 1]
) {
return true;
}
if ($this->cachedLine >= \count($this->lineStarts) - 2 ||
$position < $this->lineStarts[$this->cachedLine + 2]
) {
++$this->cachedLine;
return true;
}
return false;
}
/**
* The 0-based column of that position
*
* @param int $position
*
* @return int
*/
public function getColumn(int $position): int
{
$line = $this->getLine($position);
return $position - $this->lineStarts[$line];
}
/**
* Returns the text of the file from $start to $end (exclusive).
*
* If $end isn't passed, it defaults to the end of the file.
*/
public function getText(int $start, ?int $end = null): string
{
if ($end === null) {
return substr($this->string, $start);
}
if ($end < $start) {
$length = 0;
} else {
$length = $end - $start;
}
return substr($this->string, $start, $length);
}
}