@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.
Files changed (53) hide show
  1. package/dist/block-folds.js +5 -2
  2. package/dist/bracket-tracker.js +4 -3
  3. package/dist/brackets.d.ts +2 -12
  4. package/dist/brackets.js +3 -15
  5. package/dist/closer-tracker.js +0 -1
  6. package/dist/doc-comments.js +0 -1
  7. package/dist/document.d.ts +2 -0
  8. package/dist/document.js +33 -35
  9. package/dist/edit-regions.js +3 -4
  10. package/dist/enter.d.ts +2 -0
  11. package/dist/enter.js +11 -9
  12. package/dist/fold-roles.js +2 -2
  13. package/dist/lexical-folds.d.ts +0 -1
  14. package/dist/lexical-folds.js +1 -4
  15. package/dist/lexical.d.ts +11 -5
  16. package/dist/lexical.js +13 -17
  17. package/dist/line-commands.js +7 -15
  18. package/dist/line-text.d.ts +2 -0
  19. package/dist/line-text.js +4 -0
  20. package/dist/markup-regions.js +2 -3
  21. package/dist/paste.js +2 -7
  22. package/dist/structure.js +2 -1
  23. package/dist/typing-context.js +5 -15
  24. package/package.json +2 -2
  25. package/src/block-folds.ts +39 -2
  26. package/src/bracket-tracker.ts +55 -12
  27. package/src/brackets.ts +35 -42
  28. package/src/closer-tracker.ts +6 -1
  29. package/src/comments.ts +103 -0
  30. package/src/doc-comments.ts +19 -1
  31. package/src/document.ts +505 -36
  32. package/src/edit-regions.ts +26 -4
  33. package/src/enter.ts +104 -9
  34. package/src/fold-roles.ts +34 -2
  35. package/src/index.ts +2 -0
  36. package/src/languages.ts +11 -0
  37. package/src/lexical-folds.ts +21 -5
  38. package/src/lexical.ts +31 -23
  39. package/src/line-commands.ts +81 -17
  40. package/src/line-text.ts +7 -0
  41. package/src/markup-regions.ts +101 -3
  42. package/src/offsets.ts +10 -0
  43. package/src/paste.ts +20 -7
  44. package/src/php-markup.ts +23 -0
  45. package/src/preserve-case.ts +12 -0
  46. package/src/rope.ts +70 -0
  47. package/src/script-source.ts +10 -0
  48. package/src/search.ts +38 -0
  49. package/src/structure.ts +29 -1
  50. package/src/text-span.ts +53 -0
  51. package/src/typing-context.ts +65 -41
  52. package/src/typing-handlers.ts +28 -0
  53. 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: BracketRules, text: string, from: number, to: number, offset: number, visitor: BracketVisitor): void {
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.phpAttributes && next === '[') && (!rules.hashAtWordStart || startsWord(text, at)))
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
- lexBrackets(initialBracketState(), bracketRules(language), text, 0, text.length, 0, {
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
  }
@@ -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
  }