@@ -11,6 +11,7 @@ import { NodeKind } from "../java/nodeData";
11
11
import { DataNode } from "../views/dataNode" ;
12
12
import { resourceRoots } from "../views/packageRootNode" ;
13
13
import { checkJavaQualifiedName } from "./utility" ;
14
+ import { sendError , setUserError } from "vscode-extension-telemetry-wrapper" ;
14
15
15
16
// TODO: separate to two function to handle creation from menu bar and explorer.
16
17
export async function newJavaClass ( node ?: DataNode ) : Promise < void > {
@@ -278,3 +279,105 @@ interface ISourcePath {
278
279
projectName : string ;
279
280
projectType : string ;
280
281
}
282
+
283
+ export async function newFile ( node : DataNode ) : Promise < void > {
284
+ const basePath = getBasePath ( node ) ;
285
+ if ( ! basePath ) {
286
+ window . showErrorMessage ( "The selected node is invalid." ) ;
287
+ return ;
288
+ }
289
+
290
+ const fileName : string | undefined = await window . showInputBox ( {
291
+ placeHolder : "Input the file name" ,
292
+ ignoreFocusOut : true ,
293
+ validateInput : async ( value : string ) : Promise < string > => {
294
+ return validateNewFileFolder ( basePath , value ) ;
295
+ } ,
296
+ } ) ;
297
+
298
+ if ( ! fileName ) {
299
+ return ;
300
+ }
301
+
302
+ // any continues separator will be deduplicated.
303
+ const relativePath = fileName . replace ( / [ / \\ ] + / g, path . sep ) ;
304
+ const newFilePath = path . join ( basePath , relativePath ) ;
305
+ await createFile ( newFilePath ) ;
306
+ }
307
+
308
+ async function createFile ( newFilePath : string ) {
309
+ fse . createFile ( newFilePath , async ( err : Error ) => {
310
+ if ( err ) {
311
+ setUserError ( err ) ;
312
+ sendError ( err ) ;
313
+ const choice = await window . showErrorMessage (
314
+ err . message || "Failed to create file: " + path . basename ( newFilePath ) ,
315
+ "Retry"
316
+ ) ;
317
+ if ( choice === "Retry" ) {
318
+ await createFile ( newFilePath ) ;
319
+ }
320
+ } else {
321
+ window . showTextDocument ( Uri . file ( newFilePath ) ) ;
322
+ }
323
+ } ) ;
324
+ }
325
+
326
+ export async function newFolder ( node : DataNode ) : Promise < void > {
327
+ const basePath = getBasePath ( node ) ;
328
+ if ( ! basePath ) {
329
+ window . showErrorMessage ( "The selected node is invalid." ) ;
330
+ return ;
331
+ }
332
+
333
+ const folderName : string | undefined = await window . showInputBox ( {
334
+ placeHolder : "Input the folder name" ,
335
+ ignoreFocusOut : true ,
336
+ validateInput : async ( value : string ) : Promise < string > => {
337
+ return validateNewFileFolder ( basePath , value ) ;
338
+ } ,
339
+ } ) ;
340
+
341
+ if ( ! folderName ) {
342
+ return ;
343
+ }
344
+
345
+ // any continues separator will be deduplicated.
346
+ const relativePath = folderName . replace ( / [ / \\ ] + / g, path . sep ) ;
347
+ const newFolderPath = path . join ( basePath , relativePath ) ;
348
+ fse . mkdirs ( newFolderPath ) ;
349
+ }
350
+
351
+ async function validateNewFileFolder ( basePath : string , relativePath : string ) : Promise < string > {
352
+ relativePath = relativePath . replace ( / [ / \\ ] + / g, path . sep ) ;
353
+ if ( await fse . pathExists ( path . join ( basePath , relativePath ) ) ) {
354
+ return "A file or folder already exists in the target location." ;
355
+ }
356
+
357
+ return "" ;
358
+ }
359
+
360
+ function getBasePath ( node : DataNode ) : string | undefined {
361
+ if ( ! node . uri ) {
362
+ return undefined ;
363
+ }
364
+
365
+ const uri : Uri = Uri . parse ( node . uri ) ;
366
+ if ( uri . scheme !== "file" ) {
367
+ return undefined ;
368
+ }
369
+
370
+ const nodeKind = node . nodeData . kind ;
371
+ switch ( nodeKind ) {
372
+ case NodeKind . Project :
373
+ case NodeKind . PackageRoot :
374
+ case NodeKind . Package :
375
+ case NodeKind . Folder :
376
+ return Uri . parse ( node . uri ! ) . fsPath ;
377
+ case NodeKind . PrimaryType :
378
+ case NodeKind . File :
379
+ return path . dirname ( Uri . parse ( node . uri ) . fsPath ) ;
380
+ default :
381
+ return undefined ;
382
+ }
383
+ }
0 commit comments