@@ -29,11 +29,23 @@ import {
2929} from "./assets/function-docs.js" ;
3030import { collectCompletionIntent } from "./parser/index.js" ;
3131import { getDocumentText } from "./parser/utils.js" ;
32- import { formatSequenceType } from "./static-typecheck/types.js" ;
32+ import {
33+ formatSequenceType ,
34+ formatTypeDefinition ,
35+ type ObjectTypeDefinition ,
36+ } from "./static-typecheck/types.js" ;
37+ import { getTypeAtPositionFromSource } from "./type-at-position/service.js" ;
3338
3439const VARIABLE_PREFIX_PATTERN = / \$ [ A - Z a - z 0 - 9 _ . : - ] * $ / ;
40+ const OBJECT_FIELD_PREFIX_PATTERN = / [ A - Z a - z _ ] [ A - Z a - z 0 - 9 _ : - ] * $ / ;
3541const GENERIC_BUILTIN_PARAMETER_PREFIX = "$arg" ;
3642
43+ interface DotCompletionContext {
44+ dotOffset : number ;
45+ fieldPrefix : string ;
46+ syntheticSource : string ;
47+ }
48+
3749export function findCompletions ( document : TextDocument , position : Position ) : CompletionItem [ ] {
3850 const source = getDocumentText ( document ) ;
3951 const cursorOffset = document . offsetAt ( position ) ;
@@ -103,6 +115,85 @@ export function findCompletions(document: TextDocument, position: Position): Com
103115 ] ) ;
104116}
105117
118+ export async function findCompletionsWithTypeInfo (
119+ document : TextDocument ,
120+ position : Position ,
121+ ) : Promise < CompletionItem [ ] > {
122+ const source = getDocumentText ( document ) ;
123+ const cursorOffset = document . offsetAt ( position ) ;
124+ const intent = collectCompletionIntent ( document , cursorOffset ) ;
125+ const dotContext = getDotCompletionContext ( source , cursorOffset ) ;
126+
127+ if (
128+ dotContext !== null &&
129+ intent ?. allowObjectLookup &&
130+ intent . objectLookupDotOffset === dotContext . dotOffset
131+ ) {
132+ /// Return only dot completions because it's more relevant
133+ return findDotCompletions ( document , dotContext ) ;
134+ }
135+
136+ return findCompletions ( document , position ) ;
137+ }
138+
139+ async function findDotCompletions (
140+ document : TextDocument ,
141+ context : DotCompletionContext ,
142+ ) : Promise < CompletionItem [ ] > {
143+ const result = await getTypeAtPositionFromSource (
144+ document . uri ,
145+ context . syntheticSource ,
146+ document . positionAt ( context . dotOffset ) ,
147+ ) ;
148+ const objectType = result . sequenceType ?. itemType ;
149+
150+ if ( objectType ?. kind !== "object" ) {
151+ return [ ] ;
152+ }
153+
154+ const replaceRange = {
155+ start : document . positionAt ( context . dotOffset + 1 ) ,
156+ end : document . positionAt ( context . dotOffset + 1 + context . fieldPrefix . length ) ,
157+ } ;
158+
159+ return withSortText (
160+ objectFieldCompletions ( objectType , context . fieldPrefix ) . map ( ( [ fieldName , fieldType ] ) => ( {
161+ label : fieldName ,
162+ kind : CompletionItemKind . Field ,
163+ detail : formatTypeDefinition ( fieldType ) ,
164+ textEdit : TextEdit . replace ( replaceRange , fieldName ) ,
165+ } ) ) ,
166+ ) ;
167+ }
168+
169+ function objectFieldCompletions (
170+ objectType : ObjectTypeDefinition ,
171+ fieldPrefix : string ,
172+ ) : Array < [ string , ObjectTypeDefinition [ "fields" ] [ string ] ] > {
173+ return Object . entries ( objectType . fields ) . filter ( ( [ fieldName ] ) =>
174+ fieldName . startsWith ( fieldPrefix ) ,
175+ ) ;
176+ }
177+
178+ function getDotCompletionContext (
179+ source : string ,
180+ cursorOffset : number ,
181+ ) : DotCompletionContext | null {
182+ const prefix = source . slice ( 0 , cursorOffset ) ;
183+ const fieldPrefix = prefix . match ( OBJECT_FIELD_PREFIX_PATTERN ) ?. [ 0 ] ?? "" ;
184+ const dotOffset = cursorOffset - fieldPrefix . length - 1 ;
185+
186+ if ( dotOffset < 0 || source [ dotOffset ] !== "." ) {
187+ return null ;
188+ }
189+
190+ return {
191+ dotOffset,
192+ fieldPrefix,
193+ syntheticSource : source . slice ( 0 , dotOffset ) + source . slice ( cursorOffset ) ,
194+ } ;
195+ }
196+
106197function toCompletionItem ( declaration : BaseDefinition ) : CompletionItem {
107198 const name = definitionNameToString ( declaration ) ;
108199 if ( isSourceFunctionDefinition ( declaration ) ) {
0 commit comments