@@ -31,6 +31,41 @@ let scriptPropertiesPath: string;
3131let extensionsFolder : string ;
3232let languageData : Map < string , Map < string , string > > = new Map ( ) ;
3333
34+ // // Extract property completion logic into a function
35+ // function getPropertyCompletions(document: vscode.TextDocument, position: vscode.Position): vscode.CompletionItem[] {
36+ // if (getDocumentScriptType(document) === '') {
37+ // return []; // Skip if the document is not valid
38+ // }
39+
40+ // // Get the current line up to the cursor position
41+ // const linePrefix = document.lineAt(position).text.substring(0, position.character);
42+
43+ // // First scenario: . was just typed
44+ // if (linePrefix.endsWith('.')) {
45+ // return Loc;
46+ // }
47+
48+ // // Second scenario: We're editing an existing variable
49+ // // Find the last $ character before the cursor
50+ // const lastDollarIndex = linePrefix.lastIndexOf('$');
51+ // if (lastDollarIndex >= 0) {
52+ // // Check if we're within a variable (no whitespace or special chars between $ and cursor)
53+ // const textBetweenDollarAndCursor = linePrefix.substring(lastDollarIndex + 1);
54+
55+ // // If this text is a valid variable name part
56+ // if (/^[a-zA-Z0-9_]*$/.test(textBetweenDollarAndCursor)) {
57+ // // Get the partial variable name we're typing (without the $)
58+ // const partialName = textBetweenDollarAndCursor;
59+ // // Get all variables and filter them by the current prefix
60+ // const allVariables = variableTracker.getAllVariablesForDocument(document.uri, partialName);
61+ // // Filter variables that match the partial name
62+ // return allVariables.filter((item) => item.label.toString().toLowerCase().startsWith(partialName.toLowerCase()));
63+ // }
64+ // }
65+
66+ // return []; // No completions if not in a variable context
67+ // }
68+
3469// Extract variable completion logic into a function
3570function getVariableCompletions ( document : vscode . TextDocument , position : vscode . Position ) : vscode . CompletionItem [ ] {
3671 if ( getDocumentScriptType ( document ) === '' ) {
@@ -163,24 +198,27 @@ function getActionCompletions(document: vscode.TextDocument, position: vscode.Po
163198}
164199
165200// Function to check if we're in a specialized completion context
166- function isSpecializedCompletionContext ( document : vscode . TextDocument , position : vscode . Position ) : boolean {
201+ function specializedCompletionContext (
202+ document : vscode . TextDocument ,
203+ position : vscode . Position
204+ ) : vscode . CompletionItem [ ] {
167205 // Check if any of the specialized completion functions return results
168206 const variableCompletions = getVariableCompletions ( document , position ) ;
169207 if ( variableCompletions . length > 0 ) {
170- return true ;
208+ return variableCompletions ;
171209 }
172210
173211 const labelCompletions = getLabelCompletions ( document , position ) ;
174212 if ( labelCompletions . length > 0 ) {
175- return true ;
213+ return labelCompletions ;
176214 }
177215
178216 const actionCompletions = getActionCompletions ( document , position ) ;
179217 if ( actionCompletions . length > 0 ) {
180- return true ;
218+ return actionCompletions ;
181219 }
182220
183- return false ;
221+ return [ ] ;
184222}
185223
186224// Flag to indicate if specialized completion is active
@@ -250,16 +288,23 @@ class TypeEntry {
250288 properties : Map < string , string > = new Map < string , string > ( ) ;
251289 supertype ?: string ;
252290 literals : Set < string > = new Set < string > ( ) ;
291+ details : Map < string , string > = new Map < string , string > ( ) ;
253292 addProperty ( value : string , type : string = '' ) {
254293 this . properties . set ( value , type ) ;
255294 }
256295 addLiteral ( value : string ) {
257296 this . literals . add ( value ) ;
258297 }
298+ addDetail ( key : string , value : string ) {
299+ this . details . set ( key , value ) ;
300+ }
259301}
260302
261303class CompletionDict implements vscode . CompletionItemProvider {
262304 typeDict : Map < string , TypeEntry > = new Map < string , TypeEntry > ( ) ;
305+ allProp : Map < string , string > = new Map < string , string > ( ) ;
306+ allPropItems : vscode . CompletionItem [ ] = [ ] ;
307+ defaultCompletions : vscode . CompletionList ;
263308 addType ( key : string , supertype ?: string ) : void {
264309 const k = cleanStr ( key ) ;
265310 let entry = this . typeDict . get ( k ) ;
@@ -283,14 +328,26 @@ class CompletionDict implements vscode.CompletionItemProvider {
283328 entry . addLiteral ( v ) ;
284329 }
285330
286- addProperty ( key : string , prop : string , type ?: string ) : void {
331+ addProperty ( key : string , prop : string , type ?: string , details ?: string ) : void {
287332 const k = cleanStr ( key ) ;
288333 let entry = this . typeDict . get ( k ) ;
289334 if ( entry === undefined ) {
290335 entry = new TypeEntry ( ) ;
291336 this . typeDict . set ( k , entry ) ;
292337 }
293338 entry . addProperty ( prop , type ) ;
339+ if ( details !== undefined ) {
340+ entry . addDetail ( prop , details ) ;
341+ }
342+ const shortProp = prop . split ( '.' ) [ 0 ] ;
343+ if ( this . allProp . has ( shortProp ) ) {
344+ // If the commonDict already has this property, we can skip adding it again
345+ return ;
346+ } else if ( type !== undefined ) {
347+ this . allProp . set ( shortProp , type ) ;
348+ const item = new vscode . CompletionItem ( shortProp ) ;
349+ this . allPropItems . push ( item ) ;
350+ }
294351 }
295352
296353 addItem ( items : Map < string , vscode . CompletionItem > , complete : string , info ?: string ) : void {
@@ -306,16 +363,13 @@ class CompletionDict implements vscode.CompletionItemProvider {
306363 return ;
307364 }
308365
309- const result = new vscode . CompletionItem ( complete ) ;
310- if ( info !== undefined ) {
311- result . detail = info ;
312- } else {
313- result . detail = complete ;
314- }
366+ const item = new vscode . CompletionItem ( complete , vscode . CompletionItemKind . Property ) ;
367+ item . documentation = info ? new vscode . MarkdownString ( info ) : undefined ;
368+
315369 if ( exceedinglyVerbose ) {
316- logger . info ( '\t\tAdded completion: ' + complete + ' info: ' + result . detail ) ;
370+ logger . info ( '\t\tAdded completion: ' + complete + ' info: ' + item . detail ) ;
317371 }
318- items . set ( complete , result ) ;
372+ items . set ( complete , item ) ;
319373 }
320374 buildProperty (
321375 prefix : string ,
@@ -330,9 +384,9 @@ class CompletionDict implements vscode.CompletionItemProvider {
330384 return ;
331385 }
332386 // TODO handle better
333- if ( [ '' , 'boolean' , 'int' , 'string' , 'list' , 'datatype' ] . indexOf ( typeName ) > - 1 ) {
334- return ;
335- }
387+ // if (['', 'boolean', 'int', 'string', 'list', 'datatype'].indexOf(typeName) > -1) {
388+ // return;
389+ // }
336390 if ( exceedinglyVerbose ) {
337391 logger . info ( '\tBuilding Property' , typeName + '.' + propertyName , 'depth: ' , depth , 'prefix: ' , prefix ) ;
338392 }
@@ -354,8 +408,8 @@ class CompletionDict implements vscode.CompletionItemProvider {
354408 // return;
355409 // });
356410 // } else {
357- this . addItem ( items , completion , typeName + '.' + propertyName ) ;
358- this . buildType ( completion , propertyType , items , depth + 1 ) ;
411+ this . addItem ( items , completion , /* typeName + '.' + */ propertyName ) ;
412+ // this.buildType(completion, propertyType, items, depth /* + 1 */ );
359413 // }
360414 }
361415
@@ -378,9 +432,9 @@ class CompletionDict implements vscode.CompletionItemProvider {
378432 return ;
379433 }
380434
381- if ( depth > - 1 && prefix !== '' ) {
382- this . addItem ( items , typeName ) ;
383- }
435+ // if (depth > -1 && prefix !== '') {
436+ // this.addItem(items, typeName);
437+ // }
384438
385439 if ( items . size > 1000 ) {
386440 if ( exceedinglyVerbose ) {
@@ -390,13 +444,14 @@ class CompletionDict implements vscode.CompletionItemProvider {
390444 }
391445
392446 for ( const prop of entry . properties . entries ( ) ) {
393- this . buildProperty ( prefix , typeName , prop [ 0 ] , prop [ 1 ] , items , depth + 1 ) ;
447+ // this.buildProperty('', typeName, prop[0], prop[1], items, depth /* + 1 */);
448+ this . addItem ( items , prop [ 0 ] , '**' + [ typeName , prop [ 0 ] ] . join ( '.' ) + '**: ' + entry . details . get ( prop [ 0 ] ) ) ;
394449 }
395450 if ( entry . supertype !== undefined ) {
396451 if ( exceedinglyVerbose ) {
397452 logger . info ( 'Recursing on supertype: ' , entry . supertype ) ;
398453 }
399- this . buildType ( typeName , entry . supertype , items , depth + 1 ) ;
454+ this . buildType ( typeName , entry . supertype , items , depth /* + 1 */ ) ;
400455 }
401456 }
402457 makeCompletionList ( items : Map < string , vscode . CompletionItem > ) : vscode . CompletionList {
@@ -409,8 +464,9 @@ class CompletionDict implements vscode.CompletionItemProvider {
409464 }
410465
411466 // Check if we're in a specialized completion context (variables, labels, actions)
412- if ( isSpecializedCompletionContext ( document , position ) ) {
413- return undefined ; // Let the specialized providers handle it
467+ let specializedCompletion = specializedCompletionContext ( document , position ) ;
468+ if ( specializedCompletion . length > 0 ) {
469+ return specializedCompletion ;
414470 }
415471
416472 const items = new Map < string , vscode . CompletionItem > ( ) ;
@@ -422,31 +478,37 @@ class CompletionDict implements vscode.CompletionItemProvider {
422478 }
423479 return this . makeCompletionList ( items ) ;
424480 }
425- const prevToken = interesting [ 0 ] ;
481+ let prevToken = interesting [ 0 ] ;
426482 const newToken = interesting [ 1 ] ;
427483 if ( exceedinglyVerbose ) {
428484 logger . info ( 'Previous token: ' , interesting [ 0 ] , ' New token: ' , interesting [ 1 ] ) ;
429485 }
430486 // If we have a previous token & it's in the typeDictionary, only use that's entries
431487 if ( prevToken !== '' ) {
432- const entry = this . typeDict . get ( prevToken ) ;
488+ let entry = this . typeDict . get ( prevToken ) ;
489+ if ( entry === undefined && this . allProp . has ( prevToken ) ) {
490+ prevToken = this . allProp . get ( prevToken ) || '' ;
491+ if ( prevToken !== '' ) {
492+ entry = this . typeDict . get ( prevToken ) ;
493+ }
494+ }
433495 if ( entry === undefined ) {
434496 if ( exceedinglyVerbose ) {
435497 logger . info ( 'Missing previous token!' ) ;
436498 }
437- // TODO backtrack & search
438- return ;
499+
500+ return this . defaultCompletions ;
439501 } else {
440502 if ( exceedinglyVerbose ) {
441503 logger . info ( 'Matching on type!' ) ;
442504 }
443-
444- entry . properties . forEach ( ( v , k ) => {
445- if ( exceedinglyVerbose ) {
446- logger . info ( 'Top level property: ' , k , v ) ;
447- }
448- this . buildProperty ( '' , prevToken , k , v , items , 0 ) ;
449- } ) ;
505+ this . buildType ( '' , prevToken , items , 0 ) ;
506+ // entry.properties.forEach((v, k) => {
507+ // if (exceedinglyVerbose) {
508+ // logger.info('Top level property: ' + k + ' ' + v);
509+ // }
510+ // this.buildProperty('', prevToken, k, v, items, 0);
511+ // });
450512 return this . makeCompletionList ( items ) ;
451513 }
452514 }
@@ -495,7 +557,7 @@ class LocationDict implements vscode.DefinitionProvider {
495557
496558 addLocation ( name : string , file : string , start : vscode . Position , end : vscode . Position ) : void {
497559 const range = new vscode . Range ( start , end ) ;
498- const uri = vscode . Uri . parse ( ' file://' + file ) ;
560+ const uri = vscode . Uri . file ( file ) ;
499561 this . dict . set ( cleanStr ( name ) , new vscode . Location ( uri , range ) ) ;
500562 }
501563 addLocationForRegexMatch ( rawData : string , rawIdx : number , name : string ) {
@@ -1394,8 +1456,7 @@ function readScriptProperties(filepath: string) {
13941456 // Process keywords and datatypes here, return the completed results
13951457 keywords = processKeywords ( rawData , result [ 'scriptproperties' ] [ 'keyword' ] ) ;
13961458 datatypes = processDatatypes ( rawData , result [ 'scriptproperties' ] [ 'datatype' ] ) ;
1397-
1398- completionProvider . addTypeLiteral ( 'boolean' , '==true' ) ;
1459+ completionProvider . defaultCompletions = new vscode . CompletionList ( completionProvider . allPropItems , true ) ;
13991460 completionProvider . addTypeLiteral ( 'boolean' , '==false' ) ;
14001461 logger . info ( 'Parsed scriptproperties.xml' ) ;
14011462 } ) ;
@@ -1417,7 +1478,7 @@ function processProperty(rawData: string, parent: string, parentType: string, pr
14171478 logger . info ( '\tProperty read: ' , name ) ;
14181479 }
14191480 definitionProvider . addPropertyLocation ( rawData , name , parent , parentType ) ;
1420- completionProvider . addProperty ( parent , name , prop . $ . type ) ;
1481+ completionProvider . addProperty ( parent , name , prop . $ . type , prop . $ . result ) ;
14211482}
14221483
14231484function processKeyword ( rawData : string , e : Keyword ) {
@@ -2191,8 +2252,12 @@ export function activate(context: vscode.ExtensionContext) {
21912252 if ( definitionProvider . dict . has ( relevant ) ) {
21922253 return definitionProvider . dict . get ( relevant ) ;
21932254 }
2194- relevant = relevant . substring ( relevant . indexOf ( '.' ) + 1 ) ;
2195- } while ( relevant . indexOf ( '.' ) !== - 1 ) ;
2255+ if ( relevant . indexOf ( '.' ) !== - 1 ) {
2256+ relevant = relevant . substring ( relevant . indexOf ( '.' ) + 1 ) ;
2257+ } else {
2258+ break ; // No more dots to process
2259+ }
2260+ } while ( relevant . length > 0 ) ;
21962261
21972262 return undefined ;
21982263 } ;
@@ -2263,7 +2328,7 @@ export function activate(context: vscode.ExtensionContext) {
22632328 if ( cursorPos . character < line . text . length ) {
22642329 nextPos = cursorPos . translate ( 0 , 1 ) ;
22652330 }
2266- if ( isSpecializedCompletionContext ( event . document , nextPos ) ) {
2331+ if ( specializedCompletionContext ( event . document , nextPos ) . length > 0 ) {
22672332 // Programmatically trigger suggestions
22682333 vscode . commands . executeCommand ( 'editor.action.triggerSuggest' ) ;
22692334 }
0 commit comments