@@ -8,10 +8,17 @@ export interface RequiredCompletionParts {
8
8
9
9
export interface ValidationError {
10
10
message : string ;
11
+ line : number ;
11
12
startColumn : number ;
12
13
endColumn : number ;
13
14
}
14
15
16
+ interface Token {
17
+ text : string ;
18
+ line : number ;
19
+ column : number ;
20
+ }
21
+
15
22
export type WordCompletion = RequiredCompletionParts & Partial < monaco . languages . CompletionItem > ;
16
23
17
24
export interface AbstractWord {
@@ -89,35 +96,66 @@ export class NegatableWord implements AbstractWord {
89
96
}
90
97
91
98
export class AutoCompleteTree {
92
- private content : string [ ] ;
93
- /** value matches the start column of the value at the same index in content */
94
- private startColumns : number [ ] ;
95
- private length : number ;
99
+ private content : Token [ ] ;
96
100
97
101
constructor ( private roots : AutoCompleteNode [ ] ) {
98
102
this . content = [ ] ;
99
- this . startColumns = [ ] ;
100
- this . length = 0 ;
101
103
}
102
104
103
105
/**
104
106
* Sets the content of the tree for the next analyzing cycle
105
107
*/
106
- private setContent ( line : string ) {
107
- if ( ! line ) {
108
- line = "" ;
108
+ private setContent ( text : string ) {
109
+ if ( ! text ) {
110
+ text = "" ;
109
111
}
110
- if ( line . length == 0 ) {
112
+ if ( text . length == 0 ) {
111
113
this . content = [ ] ;
112
- this . length = 0 ;
113
114
return ;
114
115
}
115
- this . content = line . split ( " " ) ;
116
- this . startColumns = this . content . map ( ( ) => 0 ) ;
117
- for ( let i = 1 ; i < this . content . length ; i ++ ) {
118
- this . startColumns [ i ] = this . startColumns [ i - 1 ] + this . content [ i - 1 ] . length + 1 ;
116
+
117
+ let currentToken = "" ;
118
+ let currentLine = 1 ;
119
+ let currentColumn = 0 ;
120
+ this . content = [ ] ;
121
+ let index = 0 ;
122
+ while ( index < text . length ) {
123
+ const char = text [ index ] ;
124
+ if ( char === "\n" ) {
125
+ if ( currentToken . length > 0 ) {
126
+ this . content . push ( {
127
+ text : currentToken ,
128
+ line : currentLine ,
129
+ column : currentColumn - currentToken . length + 1 ,
130
+ } ) ;
131
+ }
132
+ currentToken = "" ;
133
+ currentLine ++ ;
134
+ currentColumn = 1 ;
135
+ } else if ( char === " " || char === "\t" ) {
136
+ if ( currentToken . length > 0 ) {
137
+ this . content . push ( {
138
+ text : currentToken ,
139
+ line : currentLine ,
140
+ column : currentColumn - currentToken . length + 1 ,
141
+ } ) ;
142
+ }
143
+ currentToken = "" ;
144
+ currentColumn += 1 ;
145
+ } else {
146
+ currentToken += char ;
147
+ currentColumn += 1 ;
148
+ }
149
+ index ++ ;
150
+ }
151
+ if ( currentToken . length > 0 ) {
152
+ this . content . push ( {
153
+ text : currentToken ,
154
+ line : currentLine ,
155
+ column : currentColumn - currentToken . length + 1 ,
156
+ } ) ;
119
157
}
120
- this . length = line . length ;
158
+ this . content = this . content . map ( ( c ) => ( { ... c , text : c . text . trim ( ) } ) ) . filter ( ( c ) => c . text . length > 0 ) ;
121
159
}
122
160
123
161
/**
@@ -130,23 +168,37 @@ export class AutoCompleteTree {
130
168
}
131
169
132
170
private verifyNode ( nodes : AutoCompleteNode [ ] , index : number , comesFromFinal : boolean ) : ValidationError [ ] {
171
+ if ( comesFromFinal && this . content [ index ] . column == 0 ) {
172
+ const checkStart = this . verifyNode ( this . roots , index , true ) ;
173
+ if ( checkStart . length > 0 ) {
174
+ return checkStart ;
175
+ }
176
+ }
133
177
if ( index >= this . content . length ) {
134
178
if ( nodes . length == 0 || comesFromFinal ) {
135
179
return [ ] ;
136
180
} else {
137
- return [ { message : "Unexpected end of line" , startColumn : this . length - 1 , endColumn : this . length } ] ;
181
+ return [
182
+ {
183
+ message : "Unexpected end of line" ,
184
+ line : this . content [ index - 1 ] . line ,
185
+ startColumn : this . content [ index - 1 ] . column + this . content [ index - 1 ] . text . length - 1 ,
186
+ endColumn : this . content [ index - 1 ] . column + this . content [ index - 1 ] . text . length ,
187
+ } ,
188
+ ] ;
138
189
}
139
190
}
140
191
141
192
const foundErrors : ValidationError [ ] = [ ] ;
142
193
let childErrors : ValidationError [ ] = [ ] ;
143
194
for ( const n of nodes ) {
144
- const v = n . word . verifyWord ( this . content [ index ] ) ;
195
+ const v = n . word . verifyWord ( this . content [ index ] . text ) ;
145
196
if ( v . length > 0 ) {
146
197
foundErrors . push ( {
147
198
message : v [ 0 ] ,
148
- startColumn : this . startColumns [ index ] ,
149
- endColumn : this . startColumns [ index ] + this . content [ index ] . length ,
199
+ startColumn : this . content [ index ] . column ,
200
+ endColumn : this . content [ index ] . column + this . content [ index ] . text . length ,
201
+ line : this . content [ index ] . line ,
150
202
} ) ;
151
203
continue ;
152
204
}
@@ -167,7 +219,7 @@ export class AutoCompleteTree {
167
219
/**
168
220
* Calculates the completion options for the current content
169
221
*/
170
- public getCompletion ( line : string , lineNumber = 1 ) : monaco . languages . CompletionItem [ ] {
222
+ public getCompletion ( line : string ) : monaco . languages . CompletionItem [ ] {
171
223
this . setContent ( line ) ;
172
224
let result : WordCompletion [ ] = [ ] ;
173
225
if ( this . content . length == 0 ) {
@@ -177,46 +229,52 @@ export class AutoCompleteTree {
177
229
} else {
178
230
result = this . completeNode ( this . roots , 0 ) ;
179
231
}
180
- return this . transformResults ( result , lineNumber ) ;
232
+ return this . transformResults ( result ) ;
181
233
}
182
234
183
235
private completeNode ( nodes : AutoCompleteNode [ ] , index : number ) : WordCompletion [ ] {
184
236
let result : WordCompletion [ ] = [ ] ;
185
237
if ( index == this . content . length - 1 ) {
186
238
for ( const node of nodes ) {
187
- result = result . concat ( node . word . completionOptions ( this . content [ index ] ) ) ;
239
+ result = result . concat ( node . word . completionOptions ( this . content [ index ] . text ) ) ;
188
240
}
189
241
return result ;
190
242
}
191
243
for ( const n of nodes ) {
192
- if ( ! n . word . verifyWord ( this . content [ index ] ) ) {
244
+ if ( ! n . word . verifyWord ( this . content [ index ] . text ) ) {
193
245
continue ;
194
246
}
195
247
result = result . concat ( this . completeNode ( n . children , index + 1 ) ) ;
196
248
}
197
249
return result ;
198
250
}
199
251
200
- private transformResults ( comp : WordCompletion [ ] , lineNumber = 1 ) : monaco . languages . CompletionItem [ ] {
252
+ private transformResults ( comp : WordCompletion [ ] ) : monaco . languages . CompletionItem [ ] {
201
253
const result : monaco . languages . CompletionItem [ ] = [ ] ;
202
254
const filtered = comp . filter (
203
255
( c , idx ) => comp . findIndex ( ( c2 ) => c2 . insertText === c . insertText && c2 . kind === c . kind ) === idx ,
204
256
) ;
205
257
for ( const c of filtered ) {
206
- const r = this . transformResult ( c , lineNumber ) ;
258
+ const r = this . transformResult ( c ) ;
207
259
result . push ( r ) ;
208
260
}
209
261
return result ;
210
262
}
211
263
212
- private transformResult ( comp : WordCompletion , lineNumber = 1 ) : monaco . languages . CompletionItem {
213
- const wordStart = this . content . length == 0 ? 1 : this . length - this . content [ this . content . length - 1 ] . length + 1 ;
264
+ private transformResult ( comp : WordCompletion ) : monaco . languages . CompletionItem {
265
+ const wordStart = this . content . length == 0 ? 1 : this . content [ this . content . length - 1 ] . column - 1 ;
266
+ const lineNumber = this . content . length == 0 ? 1 : this . content [ this . content . length - 1 ] . line ;
214
267
return {
215
268
insertText : comp . insertText ,
216
269
kind : comp . kind ,
217
270
label : comp . label ?? comp . insertText ,
218
271
insertTextRules : comp . insertTextRules ,
219
- range : new monaco . Range ( lineNumber , wordStart + ( comp . startOffset ?? 0 ) , lineNumber , this . length + 1 ) ,
272
+ range : new monaco . Range (
273
+ lineNumber ,
274
+ wordStart + ( comp . startOffset ?? 0 ) ,
275
+ lineNumber ,
276
+ wordStart + ( comp . startOffset ?? 0 ) + comp . insertText . length ,
277
+ ) ,
220
278
} ;
221
279
}
222
280
}
0 commit comments