11import * as vscode from "vscode" ;
22import { AtelierAPI } from "../api" ;
3- import { currentWorkspaceFolder } from "../utils" ;
43import { DocumentContentProvider } from "./DocumentContentProvider" ;
54
65export class WorkspaceSymbolProvider implements vscode . WorkspaceSymbolProvider {
@@ -27,59 +26,154 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
2726 "SELECT Name, Parent->ID AS Parent, 'projection' AS Type FROM %Dictionary.ProjectionDefinition" +
2827 ") WHERE %SQLUPPER Name %MATCHES ?" ;
2928
30- public provideWorkspaceSymbols ( query : string ) : vscode . ProviderResult < vscode . SymbolInformation [ ] > {
29+ private sqlNoSystem : string =
30+ "SELECT dict.Name, dict.Parent, dict.Type FROM (" +
31+ "SELECT Name, Parent->ID AS Parent, 'method' AS Type FROM %Dictionary.MethodDefinition" +
32+ " UNION ALL %PARALLEL " +
33+ "SELECT Name, Parent->ID AS Parent, 'property' AS Type FROM %Dictionary.PropertyDefinition" +
34+ " UNION ALL %PARALLEL " +
35+ "SELECT Name, Parent->ID AS Parent, 'parameter' AS Type FROM %Dictionary.ParameterDefinition" +
36+ " UNION ALL %PARALLEL " +
37+ "SELECT Name, Parent->ID AS Parent, 'index' AS Type FROM %Dictionary.IndexDefinition" +
38+ " UNION ALL %PARALLEL " +
39+ "SELECT Name, Parent->ID AS Parent, 'foreignkey' AS Type FROM %Dictionary.ForeignKeyDefinition" +
40+ " UNION ALL %PARALLEL " +
41+ "SELECT Name, Parent->ID AS Parent, 'xdata' AS Type FROM %Dictionary.XDataDefinition" +
42+ " UNION ALL %PARALLEL " +
43+ "SELECT Name, Parent->ID AS Parent, 'query' AS Type FROM %Dictionary.QueryDefinition" +
44+ " UNION ALL %PARALLEL " +
45+ "SELECT Name, Parent->ID AS Parent, 'trigger' AS Type FROM %Dictionary.TriggerDefinition" +
46+ " UNION ALL %PARALLEL " +
47+ "SELECT Name, Parent->ID AS Parent, 'storage' AS Type FROM %Dictionary.StorageDefinition" +
48+ " UNION ALL %PARALLEL " +
49+ "SELECT Name, Parent->ID AS Parent, 'projection' AS Type FROM %Dictionary.ProjectionDefinition" +
50+ ") AS dict, (" +
51+ "SELECT Name FROM %Library.RoutineMgr_StudioOpenDialog(?,?,?,?,?,?,?)" +
52+ ") AS sod WHERE %SQLUPPER dict.Name %MATCHES ? AND {fn CONCAT(dict.Parent,'.cls')} = sod.Name" ;
53+
54+ private queryResultToSymbols ( data : any , folderUri : vscode . Uri ) {
55+ const result = [ ] ;
56+ const uris : Map < string , vscode . Uri > = new Map ( ) ;
57+ for ( const element of data . result . content ) {
58+ const kind : vscode . SymbolKind = ( ( ) => {
59+ switch ( element . Type ) {
60+ case "query" :
61+ case "method" :
62+ return vscode . SymbolKind . Method ;
63+ case "parameter" :
64+ return vscode . SymbolKind . Constant ;
65+ case "index" :
66+ return vscode . SymbolKind . Key ;
67+ case "xdata" :
68+ case "storage" :
69+ return vscode . SymbolKind . Struct ;
70+ case "property" :
71+ default :
72+ return vscode . SymbolKind . Property ;
73+ }
74+ } ) ( ) ;
75+
76+ let uri : vscode . Uri ;
77+ if ( uris . has ( element . Parent ) ) {
78+ uri = uris . get ( element . Parent ) ;
79+ } else {
80+ uri = DocumentContentProvider . getUri ( `${ element . Parent } .cls` , undefined , undefined , undefined , folderUri ) ;
81+ uris . set ( element . Parent , uri ) ;
82+ }
83+
84+ result . push ( {
85+ name : element . Name ,
86+ containerName :
87+ element . Type === "foreignkey" ? "ForeignKey" : element . Type . charAt ( 0 ) . toUpperCase ( ) + element . Type . slice ( 1 ) ,
88+ kind,
89+ location : {
90+ uri,
91+ } ,
92+ } ) ;
93+ }
94+ return result ;
95+ }
96+
97+ public async provideWorkspaceSymbols ( query : string ) : Promise < vscode . SymbolInformation [ ] > {
3198 if ( query . length === 0 ) {
3299 return null ;
33100 }
101+ // Convert query to a %MATCHES compatible pattern
34102 let pattern = "" ;
35103 for ( let i = 0 ; i < query . length ; i ++ ) {
36104 const char = query . charAt ( i ) ;
37105 pattern += char === "*" || char === "?" ? `*\\${ char } ` : `*${ char } ` ;
38106 }
39- const workspace = currentWorkspaceFolder ( ) ;
40- const api = new AtelierAPI ( workspace ) ;
41- return api . actionQuery ( this . sql , [ pattern . toUpperCase ( ) + "*" ] ) . then ( ( data ) => {
42- const result = [ ] ;
43- const uris : Map < string , vscode . Uri > = new Map ( ) ;
44- for ( const element of data . result . content ) {
45- const kind : vscode . SymbolKind = ( ( ) => {
46- switch ( element . Type ) {
47- case "query" :
48- case "method" :
49- return vscode . SymbolKind . Method ;
50- case "parameter" :
51- return vscode . SymbolKind . Constant ;
52- case "index" :
53- return vscode . SymbolKind . Key ;
54- case "xdata" :
55- case "storage" :
56- return vscode . SymbolKind . Struct ;
57- case "property" :
58- default :
59- return vscode . SymbolKind . Property ;
60- }
61- } ) ( ) ;
62-
63- let uri : vscode . Uri ;
64- if ( uris . has ( element . Parent ) ) {
65- uri = uris . get ( element . Parent ) ;
66- } else {
67- uri = DocumentContentProvider . getUri ( `${ element . Parent } .cls` , workspace ) ;
68- uris . set ( element . Parent , uri ) ;
69- }
70-
71- result . push ( {
72- name : element . Name ,
73- containerName :
74- element . Type === "foreignkey" ? "ForeignKey" : element . Type . charAt ( 0 ) . toUpperCase ( ) + element . Type . slice ( 1 ) ,
75- kind,
76- location : {
77- uri,
78- } ,
107+ pattern = pattern . toUpperCase ( ) + "*" ;
108+ // Filter the folders to search so we don't query the same ns on the same server twice
109+ const serversToQuery : {
110+ api : AtelierAPI ;
111+ uri : vscode . Uri ;
112+ system : boolean ;
113+ } [ ] = [ ] ;
114+ for ( const folder of vscode . workspace . workspaceFolders ) {
115+ const folderApi = new AtelierAPI ( folder . uri ) ;
116+ const found = serversToQuery . findIndex (
117+ ( server ) =>
118+ server . api . config . host . toLowerCase ( ) === folderApi . config . host . toLowerCase ( ) &&
119+ server . api . config . port === folderApi . config . port &&
120+ server . api . config . pathPrefix . toLowerCase ( ) === folderApi . config . pathPrefix . toLowerCase ( ) &&
121+ server . api . config . ns . toLowerCase ( ) === folderApi . config . ns . toLowerCase ( )
122+ ) ;
123+ if ( found === - 1 ) {
124+ serversToQuery . push ( {
125+ api : folderApi ,
126+ uri : folder . uri ,
127+ system : true ,
79128 } ) ;
129+ } else if ( serversToQuery [ found ] . uri . scheme . startsWith ( "isfs" ) && ! folder . uri . scheme . startsWith ( "isfs" ) ) {
130+ // If we have multiple folders connected to the same server and ns
131+ // and one is not isfs, keep the non-isfs one
132+ serversToQuery [ found ] . uri = folder . uri ;
80133 }
81- return result ;
134+ }
135+ serversToQuery . map ( ( server ) => {
136+ if ( server . api . config . ns . toLowerCase ( ) !== "%sys" ) {
137+ const found = serversToQuery . findIndex (
138+ ( server2 ) =>
139+ server2 . api . config . host . toLowerCase ( ) === server . api . config . host . toLowerCase ( ) &&
140+ server2 . api . config . port === server . api . config . port &&
141+ server2 . api . config . pathPrefix . toLowerCase ( ) === server . api . config . pathPrefix . toLowerCase ( ) &&
142+ server2 . api . config . ns . toLowerCase ( ) === "%sys"
143+ ) ;
144+ if ( found !== - 1 ) {
145+ server . system = false ;
146+ }
147+ }
148+ return server ;
82149 } ) ;
150+ return Promise . allSettled (
151+ serversToQuery
152+ . map ( ( server ) => {
153+ // Set the system property so we don't show system items multiple times if this
154+ // workspace is connected to both the %SYS and a non-%SYS namespace on the same server
155+ if ( server . api . config . ns . toLowerCase ( ) !== "%sys" ) {
156+ const found = serversToQuery . findIndex (
157+ ( server2 ) =>
158+ server2 . api . config . host . toLowerCase ( ) === server . api . config . host . toLowerCase ( ) &&
159+ server2 . api . config . port === server . api . config . port &&
160+ server2 . api . config . pathPrefix . toLowerCase ( ) === server . api . config . pathPrefix . toLowerCase ( ) &&
161+ server2 . api . config . ns . toLowerCase ( ) === "%sys"
162+ ) ;
163+ if ( found !== - 1 ) {
164+ server . system = false ;
165+ }
166+ }
167+ return server ;
168+ } )
169+ . map ( ( server ) =>
170+ server . system
171+ ? server . api . actionQuery ( this . sql , [ pattern ] ) . then ( ( data ) => this . queryResultToSymbols ( data , server . uri ) )
172+ : server . api
173+ . actionQuery ( this . sqlNoSystem , [ "*.cls" , "1" , "1" , "0" , "1" , "0" , "0" , pattern ] )
174+ . then ( ( data ) => this . queryResultToSymbols ( data , server . uri ) )
175+ )
176+ ) . then ( ( results ) => results . flatMap ( ( result ) => ( result . status === "fulfilled" ? result . value : [ ] ) ) ) ;
83177 }
84178
85179 resolveWorkspaceSymbol ( symbol : vscode . SymbolInformation ) : vscode . ProviderResult < vscode . SymbolInformation > {
0 commit comments