@@ -8,10 +8,17 @@ export interface RequiredCompletionParts {
88
99export interface ValidationError {
1010 message : string ;
11+ line : number ;
1112 startColumn : number ;
1213 endColumn : number ;
1314}
1415
16+ interface Token {
17+ text : string ;
18+ line : number ;
19+ column : number ;
20+ }
21+
1522export type WordCompletion = RequiredCompletionParts & Partial < monaco . languages . CompletionItem > ;
1623
1724export interface AbstractWord {
@@ -89,35 +96,66 @@ export class NegatableWord implements AbstractWord {
8996}
9097
9198export 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 [ ] ;
96100
97101 constructor ( private roots : AutoCompleteNode [ ] ) {
98102 this . content = [ ] ;
99- this . startColumns = [ ] ;
100- this . length = 0 ;
101103 }
102104
103105 /**
104106 * Sets the content of the tree for the next analyzing cycle
105107 */
106- private setContent ( line : string ) {
107- if ( ! line ) {
108- line = "" ;
108+ private setContent ( text : string ) {
109+ if ( ! text ) {
110+ text = "" ;
109111 }
110- if ( line . length == 0 ) {
112+ if ( text . length == 0 ) {
111113 this . content = [ ] ;
112- this . length = 0 ;
113114 return ;
114115 }
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+ } ) ;
119157 }
120- this . length = line . length ;
158+ this . content = this . content . map ( ( c ) => ( { ... c , text : c . text . trim ( ) } ) ) . filter ( ( c ) => c . text . length > 0 ) ;
121159 }
122160
123161 /**
@@ -130,23 +168,37 @@ export class AutoCompleteTree {
130168 }
131169
132170 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+ }
133177 if ( index >= this . content . length ) {
134178 if ( nodes . length == 0 || comesFromFinal ) {
135179 return [ ] ;
136180 } 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+ ] ;
138189 }
139190 }
140191
141192 const foundErrors : ValidationError [ ] = [ ] ;
142193 let childErrors : ValidationError [ ] = [ ] ;
143194 for ( const n of nodes ) {
144- const v = n . word . verifyWord ( this . content [ index ] ) ;
195+ const v = n . word . verifyWord ( this . content [ index ] . text ) ;
145196 if ( v . length > 0 ) {
146197 foundErrors . push ( {
147198 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 ,
150202 } ) ;
151203 continue ;
152204 }
@@ -167,7 +219,7 @@ export class AutoCompleteTree {
167219 /**
168220 * Calculates the completion options for the current content
169221 */
170- public getCompletion ( line : string , lineNumber = 1 ) : monaco . languages . CompletionItem [ ] {
222+ public getCompletion ( line : string ) : monaco . languages . CompletionItem [ ] {
171223 this . setContent ( line ) ;
172224 let result : WordCompletion [ ] = [ ] ;
173225 if ( this . content . length == 0 ) {
@@ -177,46 +229,52 @@ export class AutoCompleteTree {
177229 } else {
178230 result = this . completeNode ( this . roots , 0 ) ;
179231 }
180- return this . transformResults ( result , lineNumber ) ;
232+ return this . transformResults ( result ) ;
181233 }
182234
183235 private completeNode ( nodes : AutoCompleteNode [ ] , index : number ) : WordCompletion [ ] {
184236 let result : WordCompletion [ ] = [ ] ;
185237 if ( index == this . content . length - 1 ) {
186238 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 ) ) ;
188240 }
189241 return result ;
190242 }
191243 for ( const n of nodes ) {
192- if ( ! n . word . verifyWord ( this . content [ index ] ) ) {
244+ if ( ! n . word . verifyWord ( this . content [ index ] . text ) ) {
193245 continue ;
194246 }
195247 result = result . concat ( this . completeNode ( n . children , index + 1 ) ) ;
196248 }
197249 return result ;
198250 }
199251
200- private transformResults ( comp : WordCompletion [ ] , lineNumber = 1 ) : monaco . languages . CompletionItem [ ] {
252+ private transformResults ( comp : WordCompletion [ ] ) : monaco . languages . CompletionItem [ ] {
201253 const result : monaco . languages . CompletionItem [ ] = [ ] ;
202254 const filtered = comp . filter (
203255 ( c , idx ) => comp . findIndex ( ( c2 ) => c2 . insertText === c . insertText && c2 . kind === c . kind ) === idx ,
204256 ) ;
205257 for ( const c of filtered ) {
206- const r = this . transformResult ( c , lineNumber ) ;
258+ const r = this . transformResult ( c ) ;
207259 result . push ( r ) ;
208260 }
209261 return result ;
210262 }
211263
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 ;
214267 return {
215268 insertText : comp . insertText ,
216269 kind : comp . kind ,
217270 label : comp . label ?? comp . insertText ,
218271 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+ ) ,
220278 } ;
221279 }
222280}
0 commit comments