-
-
Notifications
You must be signed in to change notification settings - Fork 84
/
parsedText.ts
135 lines (109 loc) · 3.8 KB
/
parsedText.ts
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
133
134
135
import { MappedText, TextOffset } from '@cspell/cspell-types';
import type { ValidationIssue } from '../Models/ValidationIssue';
import { extractTextMapRangeOrigin } from '../util/TextMap';
import * as TextRange from '../util/TextRange';
export type Offset = number;
export type SimpleRange = readonly [Offset, Offset];
export function mapIssueBackToOriginalPos(mappedText: MappedText, issue: ValidationIssue): ValidationIssue {
if (!mappedText.map || mappedText.map.length === 0) return issue;
const textOff = mapTextOffsetBackToOriginalPos(mappedText, issue);
return {
...issue,
...textOff,
};
}
function mapTextOffsetBackToOriginalPos(mappedText: MappedText, textOff: TextOffset): TextOffset {
if (!mappedText.map || !mappedText.map.length) return textOff;
const off = textOff.offset - mappedText.range[0];
const range = mapRangeBackToOriginalPos([off, off + (textOff.length ?? textOff.text.length)], mappedText.map);
return {
text: textOff.text,
offset: mappedText.range[0] + range[0],
length: range[1] - range[0],
};
}
export function mapRangeBackToOriginalPos(offRange: SimpleRange, map: number[] | undefined): SimpleRange {
if (!map || !map.length) return offRange;
const [start, end] = offRange;
let i = 0,
j = 0,
p = 1;
while (p < map.length && map[p] < start) {
i = map[p - 1];
j = map[p];
p += 2;
}
const iA = start - j + i;
while (p < map.length && map[p] < end) {
i = map[p - 1];
j = map[p];
p += 2;
}
const iB = end - j + i;
return [iA, iB];
}
export function mapRangeToLocal(rangeOrig: SimpleRange, map: number[] | undefined): SimpleRange {
if (!map || !map.length) return rangeOrig;
const [start, end] = rangeOrig;
let i = 0,
j = 0,
p = 0;
while (p < map.length && map[p] < start) {
i = map[p];
j = map[p + 1];
p += 2;
}
const jA = start - i + j;
while (p < map.length && map[p] < end) {
i = map[p];
j = map[p + 1];
p += 2;
}
const jB = end - i + j;
return [jA, jB];
}
/**
* Factory to create a segmentation function that will segment MappedText against a set of includeRanges.
* The function produced is optimized for forward scanning. It will perform poorly for randomly ordered offsets.
* @param includeRanges Allowed ranges for words.
*/
export function createMappedTextSegmenter(
includeRanges: TextRange.MatchRange[]
): (text: MappedText) => Iterable<MappedText> {
let rangePos = 0;
function* segmenter(pText: MappedText): Iterable<MappedText> {
if (!includeRanges.length) {
return;
}
const range = pText.range;
const textEndPos = range[1];
let textStartPos = range[0];
while (rangePos && (rangePos >= includeRanges.length || includeRanges[rangePos].startPos > textStartPos)) {
rangePos -= 1;
}
const cur = includeRanges[rangePos];
if (textEndPos <= cur.endPos && textStartPos >= cur.startPos) {
yield pText;
return;
}
while (textStartPos < textEndPos) {
while (includeRanges[rangePos] && includeRanges[rangePos].endPos <= textStartPos) {
rangePos += 1;
}
if (!includeRanges[rangePos]) {
break;
}
const { startPos, endPos } = includeRanges[rangePos];
if (textEndPos < startPos) {
break;
}
const a = Math.max(textStartPos, startPos);
const b = Math.min(textEndPos, endPos);
if (a !== b) {
yield extractTextMapRangeOrigin(pText, [a, b]);
}
textStartPos = b;
}
}
return segmenter;
}