@adecore/editor-core 0.39.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/block-folds.js +5 -2
- package/dist/bracket-tracker.js +4 -3
- package/dist/brackets.d.ts +2 -12
- package/dist/brackets.js +3 -15
- package/dist/closer-tracker.js +0 -1
- package/dist/doc-comments.js +0 -1
- package/dist/document.d.ts +2 -0
- package/dist/document.js +33 -35
- package/dist/edit-regions.js +3 -4
- package/dist/enter.d.ts +2 -0
- package/dist/enter.js +11 -9
- package/dist/fold-roles.js +2 -2
- package/dist/lexical-folds.d.ts +0 -1
- package/dist/lexical-folds.js +1 -4
- package/dist/lexical.d.ts +11 -5
- package/dist/lexical.js +13 -17
- package/dist/line-commands.js +7 -15
- package/dist/line-text.d.ts +2 -0
- package/dist/line-text.js +4 -0
- package/dist/markup-regions.js +2 -3
- package/dist/paste.js +2 -7
- package/dist/structure.js +2 -1
- package/dist/typing-context.js +5 -15
- package/package.json +2 -2
- package/src/block-folds.ts +39 -2
- package/src/bracket-tracker.ts +55 -12
- package/src/brackets.ts +35 -42
- package/src/closer-tracker.ts +6 -1
- package/src/comments.ts +103 -0
- package/src/doc-comments.ts +19 -1
- package/src/document.ts +505 -36
- package/src/edit-regions.ts +26 -4
- package/src/enter.ts +104 -9
- package/src/fold-roles.ts +34 -2
- package/src/index.ts +2 -0
- package/src/languages.ts +11 -0
- package/src/lexical-folds.ts +21 -5
- package/src/lexical.ts +31 -23
- package/src/line-commands.ts +81 -17
- package/src/line-text.ts +7 -0
- package/src/markup-regions.ts +101 -3
- package/src/offsets.ts +10 -0
- package/src/paste.ts +20 -7
- package/src/php-markup.ts +23 -0
- package/src/preserve-case.ts +12 -0
- package/src/rope.ts +70 -0
- package/src/script-source.ts +10 -0
- package/src/search.ts +38 -0
- package/src/structure.ts +29 -1
- package/src/text-span.ts +53 -0
- package/src/typing-context.ts +65 -41
- package/src/typing-handlers.ts +28 -0
- package/src/words.ts +10 -0
package/src/brackets.ts
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
hasBlockComments,
|
|
3
|
-
hasDashComments,
|
|
4
|
-
hasHashComments,
|
|
5
|
-
hashNeedsWordStart,
|
|
6
|
-
hasMarkupComments,
|
|
7
|
-
hasSlashComments,
|
|
8
|
-
isPhp,
|
|
9
|
-
isScript,
|
|
10
|
-
isWordCharacter,
|
|
11
|
-
openers,
|
|
12
|
-
startsExpressionAfter,
|
|
13
|
-
startsExpressionAt,
|
|
14
|
-
startsWord
|
|
15
|
-
} from './lexical.ts';
|
|
1
|
+
import { isWordCharacter, lexerRules, type LexerRules, openers, startsExpressionAfter, startsExpressionAt, startsWord } from './lexical.ts';
|
|
16
2
|
|
|
17
3
|
export interface BracketIndex {
|
|
18
4
|
/* Both directions: an opener maps to its closer and the closer back to the opener. */
|
|
@@ -44,17 +30,6 @@ export interface BracketState {
|
|
|
44
30
|
stack: OpenBracket | undefined;
|
|
45
31
|
}
|
|
46
32
|
|
|
47
|
-
export interface BracketRules {
|
|
48
|
-
script: boolean;
|
|
49
|
-
hash: boolean;
|
|
50
|
-
hashAtWordStart: boolean;
|
|
51
|
-
dash: boolean;
|
|
52
|
-
phpAttributes: boolean;
|
|
53
|
-
slash: boolean;
|
|
54
|
-
block: boolean;
|
|
55
|
-
markup: boolean;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
33
|
export interface BracketVisitor {
|
|
59
34
|
open(at: number, depth: number): void;
|
|
60
35
|
/* `depth` counts the opener it closes. */
|
|
@@ -67,37 +42,29 @@ export function initialBracketState(): BracketState {
|
|
|
67
42
|
return { mode: 'code', quote: '', inClass: false, expression: true, stack: undefined };
|
|
68
43
|
}
|
|
69
44
|
|
|
70
|
-
export function bracketRules(language: string): BracketRules {
|
|
71
|
-
return {
|
|
72
|
-
script: isScript(language),
|
|
73
|
-
hash: hasHashComments(language),
|
|
74
|
-
hashAtWordStart: hashNeedsWordStart(language),
|
|
75
|
-
dash: hasDashComments(language),
|
|
76
|
-
phpAttributes: isPhp(language),
|
|
77
|
-
slash: hasSlashComments(language),
|
|
78
|
-
block: hasBlockComments(language),
|
|
79
|
-
markup: hasMarkupComments(language)
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
45
|
export function sameBracketState(left: BracketState, right: BracketState): boolean {
|
|
84
46
|
if (left.mode !== right.mode || left.quote !== right.quote || left.inClass !== right.inClass || left.expression !== right.expression) {
|
|
85
47
|
return false;
|
|
86
48
|
}
|
|
49
|
+
|
|
87
50
|
let one = left.stack;
|
|
88
51
|
let other = right.stack;
|
|
52
|
+
|
|
89
53
|
while (one !== other) {
|
|
90
54
|
if (one === undefined || other === undefined || one.close !== other.close || one.template !== other.template || one.depth !== other.depth) {
|
|
91
55
|
return false;
|
|
92
56
|
}
|
|
57
|
+
|
|
93
58
|
one = one.previous;
|
|
94
59
|
other = other.previous;
|
|
95
60
|
}
|
|
61
|
+
|
|
96
62
|
return true;
|
|
97
63
|
}
|
|
98
64
|
|
|
99
65
|
function isSpace(character: string): boolean {
|
|
100
66
|
const code = character.charCodeAt(0);
|
|
67
|
+
|
|
101
68
|
return code === 32 || (code >= 9 && code <= 13) || (code > 127 && /\s/.test(character));
|
|
102
69
|
}
|
|
103
70
|
|
|
@@ -108,10 +75,13 @@ function isCloser(character: string): boolean {
|
|
|
108
75
|
/* Where a comment that runs to `terminator` ends in `text`, or `to` when it goes on past it. */
|
|
109
76
|
function commentEnd(state: BracketState, text: string, at: number, to: number, terminator: string): number {
|
|
110
77
|
const end = text.indexOf(terminator, at);
|
|
78
|
+
|
|
111
79
|
if (end < 0 || end + terminator.length > to) {
|
|
112
80
|
return to;
|
|
113
81
|
}
|
|
82
|
+
|
|
114
83
|
state.mode = 'code';
|
|
84
|
+
|
|
115
85
|
return end + terminator.length - 1;
|
|
116
86
|
}
|
|
117
87
|
|
|
@@ -119,25 +89,31 @@ function commentEnd(state: BracketState, text: string, at: number, to: number, t
|
|
|
119
89
|
* Lexes `text` from `from` to `to`, continuing `state`, and reports every bracket of the code at its offset plus
|
|
120
90
|
* `offset`. A piece has to end at a line break or the end of the text, as nothing here looks past one.
|
|
121
91
|
*/
|
|
122
|
-
export function lexBrackets(state: BracketState, rules:
|
|
92
|
+
export function lexBrackets(state: BracketState, rules: LexerRules, text: string, from: number, to: number, offset: number, visitor: BracketVisitor): void {
|
|
123
93
|
for (let at = from; at < to; at++) {
|
|
124
94
|
const char = text[at]!;
|
|
95
|
+
|
|
125
96
|
if (state.mode !== 'code') {
|
|
126
97
|
switch (state.mode) {
|
|
127
98
|
case 'line-comment': {
|
|
128
99
|
const end = text.indexOf('\n', at);
|
|
100
|
+
|
|
129
101
|
if (end < 0 || end >= to) {
|
|
130
102
|
return;
|
|
131
103
|
}
|
|
104
|
+
|
|
132
105
|
state.mode = 'code';
|
|
133
106
|
at = end;
|
|
107
|
+
|
|
134
108
|
continue;
|
|
135
109
|
}
|
|
136
110
|
case 'block-comment':
|
|
137
111
|
at = commentEnd(state, text, at, to, '*/');
|
|
112
|
+
|
|
138
113
|
continue;
|
|
139
114
|
case 'markup-comment':
|
|
140
115
|
at = commentEnd(state, text, at, to, '-->');
|
|
116
|
+
|
|
141
117
|
continue;
|
|
142
118
|
case 'string':
|
|
143
119
|
if (char === '\\') {
|
|
@@ -145,6 +121,7 @@ export function lexBrackets(state: BracketState, rules: BracketRules, text: stri
|
|
|
145
121
|
} else if (char === state.quote || (rules.script && (char === '\n' || char === '\r'))) {
|
|
146
122
|
state.mode = 'code';
|
|
147
123
|
}
|
|
124
|
+
|
|
148
125
|
continue;
|
|
149
126
|
case 'template':
|
|
150
127
|
if (char === '\\') {
|
|
@@ -160,6 +137,7 @@ export function lexBrackets(state: BracketState, rules: BracketRules, text: stri
|
|
|
160
137
|
state.expression = true;
|
|
161
138
|
visitor.open(offset + at, depth);
|
|
162
139
|
}
|
|
140
|
+
|
|
163
141
|
continue;
|
|
164
142
|
case 'regex':
|
|
165
143
|
if (char === '\\') {
|
|
@@ -171,22 +149,26 @@ export function lexBrackets(state: BracketState, rules: BracketRules, text: stri
|
|
|
171
149
|
} else if ((char === '/' && !state.inClass) || char === '\n' || char === '\r') {
|
|
172
150
|
state.mode = 'code';
|
|
173
151
|
}
|
|
152
|
+
|
|
174
153
|
continue;
|
|
175
154
|
}
|
|
155
|
+
|
|
176
156
|
continue;
|
|
177
157
|
}
|
|
178
158
|
|
|
179
159
|
if (isSpace(char)) {
|
|
180
160
|
continue;
|
|
181
161
|
}
|
|
162
|
+
|
|
182
163
|
const next = text[at + 1];
|
|
164
|
+
|
|
183
165
|
if (rules.markup && char === '<' && text.startsWith('<!--', at)) {
|
|
184
166
|
state.mode = 'markup-comment';
|
|
185
167
|
at += 3;
|
|
186
168
|
} else if (
|
|
187
169
|
(rules.slash && char === '/' && next === '/') ||
|
|
188
170
|
(rules.dash && char === '-' && next === '-') ||
|
|
189
|
-
(rules.hash && char === '#' && !(rules.
|
|
171
|
+
(rules.hash && char === '#' && !(rules.php && next === '[') && (!rules.hashAtWordStart || startsWord(text, at)))
|
|
190
172
|
) {
|
|
191
173
|
state.mode = 'line-comment';
|
|
192
174
|
} else if (rules.block && char === '/' && next === '*') {
|
|
@@ -209,22 +191,28 @@ export function lexBrackets(state: BracketState, rules: BracketRules, text: stri
|
|
|
209
191
|
visitor.open(offset + at, depth);
|
|
210
192
|
} else if (isCloser(char)) {
|
|
211
193
|
const open = state.stack;
|
|
194
|
+
|
|
212
195
|
if (open?.close === char) {
|
|
213
196
|
state.stack = open.previous;
|
|
197
|
+
|
|
214
198
|
if (open.template) {
|
|
215
199
|
state.mode = 'template';
|
|
216
200
|
}
|
|
201
|
+
|
|
217
202
|
visitor.close(offset + at, open.depth);
|
|
218
203
|
} else {
|
|
219
204
|
state.stack = undefined;
|
|
220
205
|
visitor.mismatch(offset + at);
|
|
221
206
|
}
|
|
207
|
+
|
|
222
208
|
state.expression = false;
|
|
223
209
|
} else if (isWordCharacter(char)) {
|
|
224
210
|
const start = at;
|
|
211
|
+
|
|
225
212
|
while (at + 1 < to && isWordCharacter(text[at + 1]!)) {
|
|
226
213
|
at++;
|
|
227
214
|
}
|
|
215
|
+
|
|
228
216
|
state.expression = startsExpressionAt(text, start, at + 1);
|
|
229
217
|
} else {
|
|
230
218
|
state.expression = startsExpressionAfter(char);
|
|
@@ -237,7 +225,8 @@ export function scanBrackets(text: string, language = 'typescript'): BracketInde
|
|
|
237
225
|
const pairs = new Map<number, number>();
|
|
238
226
|
const unmatched = new Set<number>();
|
|
239
227
|
let open: number[] = [];
|
|
240
|
-
|
|
228
|
+
|
|
229
|
+
lexBrackets(initialBracketState(), lexerRules(language), text, 0, text.length, 0, {
|
|
241
230
|
open(at) {
|
|
242
231
|
open.push(at);
|
|
243
232
|
},
|
|
@@ -248,15 +237,19 @@ export function scanBrackets(text: string, language = 'typescript'): BracketInde
|
|
|
248
237
|
},
|
|
249
238
|
mismatch(at) {
|
|
250
239
|
unmatched.add(at);
|
|
240
|
+
|
|
251
241
|
// A mismatched closer keeps a distant opener from claiming it later.
|
|
252
242
|
for (const abandoned of open) {
|
|
253
243
|
unmatched.add(abandoned);
|
|
254
244
|
}
|
|
245
|
+
|
|
255
246
|
open = [];
|
|
256
247
|
}
|
|
257
248
|
});
|
|
249
|
+
|
|
258
250
|
for (const at of open) {
|
|
259
251
|
unmatched.add(at);
|
|
260
252
|
}
|
|
253
|
+
|
|
261
254
|
return { pairs, unmatched };
|
|
262
255
|
}
|
package/src/closer-tracker.ts
CHANGED
|
@@ -17,12 +17,12 @@ export class CloserTracker {
|
|
|
17
17
|
|
|
18
18
|
add(open: number, close: number): void {
|
|
19
19
|
this.marks.push({ open, close });
|
|
20
|
+
|
|
20
21
|
if (this.marks.length > maxMarks) {
|
|
21
22
|
this.marks.shift();
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
/* The closer that sits at `offset`, which a Tab there steps over. */
|
|
26
26
|
isCloserAt(offset: number): boolean {
|
|
27
27
|
return this.marks.some((mark) => mark.close === offset);
|
|
28
28
|
}
|
|
@@ -31,6 +31,7 @@ export class CloserTracker {
|
|
|
31
31
|
this.marks = this.marks.flatMap((mark) => {
|
|
32
32
|
const open = mapThrough(mark.open, edits);
|
|
33
33
|
const close = mapThrough(mark.close, edits);
|
|
34
|
+
|
|
34
35
|
return open === null || close === null ? [] : [{ open, close }];
|
|
35
36
|
});
|
|
36
37
|
}
|
|
@@ -47,14 +48,18 @@ export class CloserTracker {
|
|
|
47
48
|
/* Null when an edit replaced the character at `offset`. */
|
|
48
49
|
function mapThrough(offset: number, edits: readonly TextEdit[]): number | null {
|
|
49
50
|
let delta = 0;
|
|
51
|
+
|
|
50
52
|
for (const edit of edits) {
|
|
51
53
|
if (offset < edit.from) {
|
|
52
54
|
break;
|
|
53
55
|
}
|
|
56
|
+
|
|
54
57
|
if (offset < edit.to) {
|
|
55
58
|
return null;
|
|
56
59
|
}
|
|
60
|
+
|
|
57
61
|
delta += edit.text.length - (edit.to - edit.from);
|
|
58
62
|
}
|
|
63
|
+
|
|
59
64
|
return offset + delta;
|
|
60
65
|
}
|