aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/scssphp/source-span/src/SourceSpanMixin.php
blob: b9bbdb01b179d6175875e8d52526436a5700ebc5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php

namespace SourceSpan;

use League\Uri\Contracts\UriInterface;
use SourceSpan\Highlighter\Highlighter;

/**
 * A mixin for easily implementing {@see SourceSpan}.
 *
 * This implements the {@see SourceSpan} methods in terms of {@see getStart}, {@see getEnd}, and
 * {@see getText}. This assumes that {@see getStart} and {@see getEnd} have the same source URL, that
 * {@see getStart} comes before {@see getEnd}, and that {@see getText} has a number of characters equal
 * to the distance between {@see getStart} and {@see getEnd}.
 *
 * @internal
 */
abstract class SourceSpanMixin implements SourceSpan
{
    public function getSourceUrl(): ?UriInterface
    {
        return $this->getStart()->getSourceUrl();
    }

    public function getLength(): int
    {
        return $this->getEnd()->getOffset() - $this->getStart()->getOffset();
    }

    public function union(SourceSpan $other): SourceSpan
    {
        if (!Util::isSameUrl($this->getSourceUrl(), $other->getSourceUrl())) {
            throw new \InvalidArgumentException("Source URLs \"{$this->getSourceUrl()}\" and \"{$other->getSourceUrl()}\" don't match.");
        }

        if ($this->getStart()->compareTo($other->getStart()) > 0) {
            $start = $other->getStart();
            $beginSpan = $other;
        } else {
            $start = $this->getStart();
            $beginSpan = $this;
        }
        if ($this->getEnd()->compareTo($other->getEnd()) > 0) {
            $end = $this->getEnd();
            $endSpan = $this;
        } else {
            $end = $other->getEnd();
            $endSpan = $other;
        }

        if ($beginSpan->getEnd()->compareTo($endSpan->getStart()) < 0) {
            throw new \InvalidArgumentException("Spans are disjoint.");
        }

        $text = $beginSpan->getText() . substr($endSpan->getText(), $beginSpan->getEnd()->distance($endSpan->getStart()));

        return new SimpleSourceSpan($start, $end, $text);
    }

    public function compareTo(SourceSpan $other): int
    {
        $result = $this->getStart()->compareTo($other->getStart());

        if ($result !== 0) {
            return $result;
        }

        return $this->getEnd()->compareTo($other->getEnd());
    }

    public function message(string $message): string
    {
        $startLine = $this->getStart()->getLine() + 1;
        $startColumn = $this->getStart()->getColumn() + 1;
        $sourceUrl = $this->getSourceUrl();

        $buffer = "line $startLine, column $startColumn";

        if ($sourceUrl !== null) {
            $prettyUri = Util::prettyUri($sourceUrl);
            $buffer .= " of $prettyUri";
        }

        $buffer .= ": $message";

        $highlight = $this->highlight();
        if ($highlight !== '') {
            $buffer .= "\n";
            $buffer .= $highlight;
        }

        return $buffer;
    }

    public function messageMultiple(string $message, string $label, array $secondarySpans): string
    {
        $startLine = $this->getStart()->getLine() + 1;
        $startColumn = $this->getStart()->getColumn() + 1;
        $sourceUrl = $this->getSourceUrl();

        $buffer = "line $startLine, column $startColumn";

        if ($sourceUrl !== null) {
            $prettyUri = Util::prettyUri($sourceUrl);
            $buffer .= " of $prettyUri";
        }

        $buffer .= ": $message";

        $highlight = $this->highlightMultiple($label, $secondarySpans);
        if ($highlight !== '') {
            $buffer .= "\n";
            $buffer .= $highlight;
        }

        return $buffer;
    }

    public function highlight(): string
    {
        if (!$this instanceof SourceSpanWithContext && $this->getLength() === 0) {
            return '';
        }

        return Highlighter::create($this)->highlight();
    }

    public function highlightMultiple(string $label, array $secondarySpans): string
    {
        return Highlighter::multiple($this, $label, $secondarySpans)->highlight();
    }
}