cloudflare/pint

Public

mirrored fromhttps://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
cf569e66637dd7c62a7f7b6762b4defada974793

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/diags/position.go

170lines · modecode

1package diags
2
3import (
4 "strconv"
5
6 "go.yaml.in/yaml/v3"
7)
8
9type LineRange struct {
10 First int
11 Last int
12}
13
14func (lr LineRange) String() string {
15 if lr.First == lr.Last {
16 return strconv.Itoa(lr.First)
17 }
18 return strconv.Itoa(lr.First) + "-" + strconv.Itoa(lr.Last)
19}
20
21func (lr LineRange) Expand() []int {
22 lines := make([]int, 0, lr.Last-lr.First+1)
23 for i := lr.First; i <= lr.Last; i++ {
24 lines = append(lines, i)
25 }
26 return lines
27}
28
29type PositionRange struct {
30 Line int // 1-indexed
31 FirstColumn int // 1-indexed
32 LastColumn int // 1-indexed
33}
34
35type PositionRanges []PositionRange
36
37func (prs PositionRanges) Len() (l int) {
38 for _, pr := range prs {
39 l += pr.LastColumn - pr.FirstColumn + 1
40 }
41 return l
42}
43
44func (prs PositionRanges) Lines() (lr LineRange) {
45 for i, pr := range prs {
46 if i == 0 {
47 lr.First = pr.Line
48 lr.Last = pr.Line
49 continue
50 }
51 lr.First = min(lr.First, pr.Line)
52 lr.Last = max(lr.Last, pr.Line)
53 }
54 return lr
55}
56
57func (prs PositionRanges) AddOffset(line, column int) {
58 for i := range prs {
59 prs[i].Line += line
60 prs[i].FirstColumn += column
61 prs[i].LastColumn += column
62 }
63}
64
65func appendPosition(src PositionRanges, line, column int) PositionRanges {
66 size := len(src)
67
68 if size == 0 {
69 return append(src, PositionRange{
70 Line: line,
71 FirstColumn: column,
72 LastColumn: column,
73 })
74 }
75
76 if src[size-1].Line == line && src[size-1].LastColumn+1 == column {
77 src[size-1].LastColumn = column
78 return src
79 }
80
81 return append(src, PositionRange{
82 Line: line,
83 FirstColumn: column,
84 LastColumn: column,
85 })
86}
87
88func NewPositionRange(lines []string, val *yaml.Node, minColumn int) (offsets PositionRanges) {
89 if len(val.Value) == 0 {
90 return PositionRanges{
91 {Line: val.Line, FirstColumn: val.Column, LastColumn: val.Column},
92 }
93 }
94
95 var needIndex, lineSpaces, valSpaces int
96 need := val.Value[needIndex]
97 lineIndex := val.Line
98 columnIndex := val.Column
99
100 for lineIndex <= len(lines) {
101 // Append new line but only if we already have any tokens.
102 if len(offsets) > 0 {
103 offsets = appendPosition(offsets, lineIndex-1, len(lines[lineIndex-2])+1)
104 }
105
106 if len(lines[lineIndex-1]) == 0 {
107 goto NEXT
108 }
109
110 columnIndex = min(len(lines[lineIndex-1]), columnIndex)
111
112 lineSpaces = countLeadingSpace(lines[lineIndex-1][columnIndex-1:])
113 valSpaces = countLeadingSpace(val.Value[needIndex:])
114 if lineSpaces > valSpaces {
115 columnIndex += lineSpaces - valSpaces
116 }
117
118 for gotIndex, got := range []byte(lines[lineIndex-1][columnIndex-1:]) {
119 if need == got {
120 offsets = appendPosition(offsets, lineIndex, columnIndex+gotIndex)
121 needIndex++
122 if needIndex >= len(val.Value) {
123 goto END
124 }
125 need = val.Value[needIndex]
126 }
127 }
128
129 NEXT:
130 lineIndex++
131 columnIndex = minColumn
132
133 if need == ' ' || need == '\n' {
134 needIndex++
135 if needIndex >= len(val.Value) {
136 goto END
137 }
138 need = val.Value[needIndex]
139 }
140 }
141
142END:
143 return offsets
144}
145
146func countLeadingSpace(line string) (i int) {
147 for _, r := range line {
148 if r != ' ' {
149 return i
150 }
151 i++
152 }
153 return i
154}
155
156func readRange(firstColumn, lastColumn int, prs PositionRanges) PositionRanges {
157 out := make(PositionRanges, 0, len(prs))
158
159 var index int
160 for _, pr := range prs {
161 for j := pr.FirstColumn; j <= pr.LastColumn; j++ {
162 index++
163 if index >= firstColumn && index <= lastColumn {
164 out = appendPosition(out, pr.Line, j)
165 }
166 }
167 }
168
169 return out
170}
171