11import { ChildProcess , spawn } from "child_process" ;
2+ import { ITarget } from "df/core/common" ;
23import { dataform } from "df/protos/ts" ;
34import {
45 createConnection ,
@@ -124,13 +125,12 @@ async function getProcessResult(childProcess: ChildProcess) {
124125function gatherAllActions (
125126 graph = CACHED_COMPILE_GRAPH
126127) : Array < dataform . Table | dataform . Declaration | dataform . Operation | dataform . Assertion > {
127- return [ ] . concat ( graph . tables , graph . operations , graph . assertions , graph . declarations ) ;
128- }
129-
130- function retrieveLinkedFileName ( ref : string ) {
131- const allActions = gatherAllActions ( ) ;
132- const foundCompileAction = allActions . find ( action => action . target . name === ref ) ;
133- return foundCompileAction . fileName ;
128+ return [ ] . concat (
129+ graph . tables ?? [ ] ,
130+ graph . operations ?? [ ] ,
131+ graph . assertions ?? [ ] ,
132+ graph . declarations ?? [ ]
133+ ) ;
134134}
135135
136136connection . onDefinition (
@@ -141,28 +141,82 @@ connection.onDefinition(
141141 end : { line : params . position . line + 1 , character : 0 }
142142 } ) ;
143143
144- const refRegex = new RegExp ( / (?< = r e f \( \" | ' \s * ) . * ? (? = \s * \" | ' \) ) / g) ; // tslint:disable-line
144+ const refRegex = new RegExp ( / r e f \s * \( \s * ( [ " ' ] . + ? [ " ' ] ) \s * \) / g) ; // tslint:disable-line
145145 const refContents = lineWithRef . match ( refRegex ) ;
146146 if ( ! refContents || refContents . length === 0 ) {
147147 return null ;
148148 }
149149
150- const minPosition = lineWithRef . search ( refRegex ) ;
151- const refStatement = refContents [ 0 ] ;
152- const maxPosition = minPosition + refStatement . length ;
153-
154- if ( params . position . character > minPosition && params . position . character < maxPosition ) {
155- // TODO: Make this work for multiple refs in one line
156- const linkedFileName = retrieveLinkedFileName ( refContents [ 0 ] ) ;
157- const fileString = `${ WORKSPACE_ROOT_FOLDER } /${ linkedFileName } ` ;
158- return {
159- uri : fileString ,
160- range : {
161- start : { line : 0 , character : 0 } ,
162- end : { line : 1 , character : 0 }
163- }
164- } as Location ;
150+ // if not compiled yet, we cannot jump to the definition
151+ if ( CACHED_COMPILE_GRAPH === null ) {
152+ connection . sendNotification ( "info" , "Project not compiled yet. Please compile first." ) ;
153+ return null ;
165154 }
155+
156+ // Jump to the one that was clicked or closest
157+ const clickedRef = refContents . map (
158+ ( refContent ) => ( {
159+ refContent,
160+ min : lineWithRef . indexOf ( refContent ) ,
161+ max : lineWithRef . indexOf ( refContent ) + refContent . length - 1
162+ } )
163+ ) . sort ( ( a , b ) => {
164+ // sort in priority of closest to the clicked position
165+ // if position is within the refContent, distance is 0
166+ let distanceToA = 0 ;
167+ if ( params . position . character < a . min ) {
168+ distanceToA = a . min - params . position . character ;
169+ } else if ( params . position . character > a . max ) {
170+ distanceToA = params . position . character - a . max ;
171+ }
172+
173+ let distanceToB = 0 ;
174+ if ( params . position . character < b . min ) {
175+ distanceToB = b . min - params . position . character ;
176+ } else if ( params . position . character > b . max ) {
177+ distanceToB = params . position . character - b . max ;
178+ }
179+
180+ return distanceToA - distanceToB ;
181+ } ) [ 0 ] . refContent ;
182+
183+ // split to dataset, schema and name
184+ const linkedTable : ITarget = { database : null , schema : null , name : null } ;
185+ const splitMatch = clickedRef . match ( / ^ r e f \s * \( \s * ( [ " ' ] ( .+ ?) [ " ' ] ) \s * ( , \s * [ " ' ] ( .+ ?) [ " ' ] \s * ) ? ( , \s * [ " ' ] ( .+ ?) [ " ' ] \s * ) ? , ? \s * \) $ / ) ; // tslint:disable-line
186+ if ( splitMatch [ 6 ] !== undefined ) {
187+ linkedTable . database = splitMatch [ 2 ] ;
188+ linkedTable . schema = splitMatch [ 4 ] ;
189+ linkedTable . name = splitMatch [ 6 ] ;
190+ } else if ( splitMatch [ 4 ] !== undefined ) {
191+ linkedTable . schema = splitMatch [ 2 ] ;
192+ linkedTable . name = splitMatch [ 4 ] ;
193+ } else if ( splitMatch [ 2 ] !== undefined ) {
194+ linkedTable . name = splitMatch [ 2 ] ;
195+ } else {
196+ return null ;
197+ }
198+
199+ const foundCompileAction = gatherAllActions ( ) . filter ( action => (
200+ ( linkedTable . database === null || action ?. target ?. database !== undefined && action . target . database === linkedTable . database )
201+ && ( linkedTable . schema === null || action ?. target ?. schema !== undefined && action . target . schema === linkedTable . schema )
202+ && action ?. target ?. name !== undefined && action . target . name === linkedTable . name
203+ ) ) ;
204+ if ( foundCompileAction . length === 0 ) {
205+ connection . sendNotification ( "error" , `Definition not found for ${ clickedRef } ` ) ;
206+ return null ;
207+ } else if ( foundCompileAction . length > 1 ) {
208+ connection . sendNotification ( "error" , `Multiple definitions found for ${ clickedRef } ` ) ;
209+ return null ;
210+ }
211+
212+ const fileString = `${ WORKSPACE_ROOT_FOLDER } /${ foundCompileAction [ 0 ] . fileName } ` ;
213+ return {
214+ uri : fileString ,
215+ range : {
216+ start : { line : 0 , character : 0 } ,
217+ end : { line : 1 , character : 0 }
218+ }
219+ } as Location ;
166220 }
167221) ;
168222
0 commit comments