@@ -6,6 +6,7 @@ import { Directory } from "./Directory";
66import { File } from "./File" ;
77import { fireOtherStudioAction , OtherStudioAction } from "../../commands/studio" ;
88import { StudioOpenDialog } from "../../queries" ;
9+ import { redirectDotvscodeRoot } from "../../utils/index" ;
910
1011declare function setTimeout ( callback : ( ...args : any [ ] ) => void , ms : number , ...args : any [ ] ) : NodeJS . Timeout ;
1112
@@ -61,29 +62,63 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
6162 } else {
6263 filter = "*.cls,*.inc,*.mac,*.int" ;
6364 }
64- const folder = csp ? ( uri . path . endsWith ( "/" ) ? uri . path : uri . path + "/" ) : uri . path . replace ( / \/ / g, "." ) ;
65+ const folder = ! csp
66+ ? uri . path . replace ( / \/ / g, "." )
67+ : uri . path === "/"
68+ ? ""
69+ : uri . path . endsWith ( "/" )
70+ ? uri . path
71+ : uri . path + "/" ;
6572 const spec = csp ? folder + filter : folder . length > 1 ? folder . slice ( 1 ) + "/" + filter : filter ;
6673 const dir = "1" ;
6774 const orderBy = "1" ;
6875 const system = api . ns === "%SYS" ? "1" : "0" ;
6976 const flat = query . flat && query . flat . length ? query . flat . toString ( ) : "0" ;
7077 const notStudio = "0" ;
7178 const generated = query . generated && query . generated . length ? query . generated . toString ( ) : "0" ;
79+ // get all web apps that have a filepath (Studio dialog used below returns REST ones too)
80+ const cspApps = csp ? await api . getCSPApps ( ) . then ( ( data ) => data . result . content || [ ] ) : [ ] ;
81+ const cspSubfolderMap = new Map < string , vscode . FileType > ( ) ;
82+ const prefix = folder === "" ? "/" : folder ;
83+ for ( const app of cspApps ) {
84+ if ( ( app + "/" ) . startsWith ( prefix ) ) {
85+ const subfolder = app . slice ( prefix . length ) . split ( "/" ) [ 0 ] ;
86+ if ( subfolder ) {
87+ cspSubfolderMap . set ( subfolder , vscode . FileType . Directory ) ;
88+ }
89+ }
90+ }
91+ const cspSubfolders = Array . from ( cspSubfolderMap . entries ( ) ) ;
92+ // Assemble the results
7293 return api
7394 . actionQuery ( sql , [ spec , dir , orderBy , system , flat , notStudio , generated ] )
7495 . then ( ( data ) => data . result . content || [ ] )
75- . then ( ( data ) =>
76- data . map ( ( item : StudioOpenDialog ) => {
77- const name = item . Name ;
78- const fullName = folder === "" ? name : folder + "/" + name ;
79- if ( item . Type === "10" || item . Type === "9" ) {
80- parent . entries . set ( name , new Directory ( name , fullName ) ) ;
81- return [ name , vscode . FileType . Directory ] ;
82- } else {
83- return [ name , vscode . FileType . File ] ;
84- }
85- } )
86- )
96+ . then ( ( data ) => {
97+ const results = data
98+ . filter ( ( item : StudioOpenDialog ) =>
99+ item . Type === "10"
100+ ? csp && ! item . Name . includes ( "/" ) // ignore web apps here because there may be REST ones
101+ : item . Type === "9" // class package
102+ ? ! csp
103+ : csp
104+ ? item . Type === "5" // web app file
105+ : true
106+ )
107+ . map ( ( item : StudioOpenDialog ) => {
108+ const name = item . Name ;
109+ const fullName = folder === "" ? name : csp ? folder + name : folder + "/" + name ;
110+ if ( item . Type === "10" || item . Type === "9" ) {
111+ parent . entries . set ( name , new Directory ( name , fullName ) ) ;
112+ return [ name , vscode . FileType . Directory ] ;
113+ } else {
114+ return [ name , vscode . FileType . File ] ;
115+ }
116+ } ) ;
117+ if ( ! csp ) {
118+ return results ;
119+ }
120+ return results . concat ( cspSubfolders ) ;
121+ } )
87122 . catch ( ( error ) => {
88123 error && console . error ( error ) ;
89124 } ) ;
@@ -138,7 +173,8 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
138173 overwrite : boolean ;
139174 }
140175 ) : void | Thenable < void > {
141- if ( uri . path . match ( / \/ \. [ ^ / ] * \/ / ) ) {
176+ uri = redirectDotvscodeRoot ( uri ) ;
177+ if ( uri . path . startsWith ( "/." ) ) {
142178 throw vscode . FileSystemError . NoPermissions ( "dot-folders not supported by server" ) ;
143179 }
144180 const { query } = url . parse ( decodeURIComponent ( uri . toString ( ) ) , true ) ;
@@ -235,14 +271,17 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
235271 private async _lookup ( uri : vscode . Uri ) : Promise < Entry > {
236272 const parts = uri . path . split ( "/" ) ;
237273 let entry : Entry = this . root ;
238- for ( const part of parts ) {
274+ for ( let i = 0 ; i < parts . length ; i ++ ) {
275+ const part = parts [ i ] ;
239276 if ( ! part ) {
240277 continue ;
241278 }
242279 let child : Entry | undefined ;
243280 if ( entry instanceof Directory ) {
244281 child = entry . entries . get ( part ) ;
245- if ( ! part . includes ( "." ) ) {
282+ // If the last element of path is dotted and is one we haven't already cached as a directory
283+ // then it is assumed to be a file.
284+ if ( ! part . includes ( "." ) || i + 1 < parts . length ) {
246285 const fullName = entry . name === "" ? part : entry . fullName + "/" + part ;
247286 child = new Directory ( part , fullName ) ;
248287 entry . entries . set ( part , child ) ;
@@ -274,10 +313,11 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
274313
275314 // Fetch from server and cache it
276315 private async _lookupAsFile ( uri : vscode . Uri ) : Promise < File > {
277- // Reject attempts to access files in .-folders such as .vscode and .git
278- if ( uri . path . match ( / \/ \. [ ^ / ] * \/ / ) ) {
279- throw vscode . FileSystemError . FileNotFound ( "dot-folders not supported by server" ) ;
316+ uri = redirectDotvscodeRoot ( uri ) ;
317+ if ( uri . path . startsWith ( "/." ) ) {
318+ throw vscode . FileSystemError . NoPermissions ( "dot-folders not supported by server" ) ;
280319 }
320+
281321 const { query } = url . parse ( decodeURIComponent ( uri . toString ( ) ) , true ) ;
282322 const csp = query . csp === "" || query . csp === "1" ;
283323 const fileName = csp ? uri . path : uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) ;
0 commit comments