| 
 | 1 | +diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java  | 
 | 2 | +index 891bfa328d..ed80b903a5 100644  | 
 | 3 | +--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java  | 
 | 4 | ++++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LspTemplateUI.java  | 
 | 5 | +@@ -27,6 +27,7 @@ import java.net.MalformedURLException;  | 
 | 6 | + import java.net.URI;  | 
 | 7 | + import java.net.URISyntaxException;  | 
 | 8 | + import java.net.URL;  | 
 | 9 | ++import java.nio.file.Paths;  | 
 | 10 | + import java.util.ArrayList;  | 
 | 11 | + import java.util.Arrays;  | 
 | 12 | + import java.util.Collections;  | 
 | 13 | +@@ -39,6 +40,7 @@ import java.util.function.Function;  | 
 | 14 | + import java.util.logging.Level;  | 
 | 15 | + import java.util.logging.Logger;  | 
 | 16 | + import java.util.stream.Collectors;  | 
 | 17 | ++import javax.lang.model.SourceVersion;  | 
 | 18 | + import org.eclipse.lsp4j.ExecuteCommandParams;  | 
 | 19 | + import org.eclipse.lsp4j.MessageParams;  | 
 | 20 | + import org.eclipse.lsp4j.MessageType;  | 
 | 21 | +@@ -73,14 +75,21 @@ import org.openide.util.Utilities;  | 
 | 22 | +     "CTL_TemplateUI_SelectGroup=Select Template Type",  | 
 | 23 | +     "CTL_TemplateUI_SelectTemplate=Select Template",  | 
 | 24 | +     "CTL_TemplateUI_SelectTarget=Where to put the object?",  | 
 | 25 | +-    "CTL_TemplateUI_SelectProjectTarget=Specify the project directory",  | 
 | 26 | ++    "CTL_TemplateUI_SelectProjectTarget=Specify the new project directory",  | 
 | 27 | +     "CTL_TemplateUI_SelectPackageName=Package name of your project?",  | 
 | 28 | +     "CTL_TemplateUI_SelectPackageNameSuggestion=org.yourcompany.yourproject",  | 
 | 29 | +     "CTL_TemplateUI_SelectName=Name of the object?",  | 
 | 30 | +     "# {0} - path",  | 
 | 31 | +-    "ERR_InvalidPath={0} isn't valid folder",  | 
 | 32 | ++    "ERR_InvalidPath={0} isn't a valid folder or is read-only",  | 
 | 33 | +     "# {0} - path",  | 
 | 34 | +     "ERR_ExistingPath={0} already exists",  | 
 | 35 | ++    "# {0} - packageName",  | 
 | 36 | ++    "ERR_InvalidPackageName={0} isn't valid package name",  | 
 | 37 | ++    "# {0} - path",  | 
 | 38 | ++    "ERR_InvalidNewPath={0} isn't a valid path or is read-only",  | 
 | 39 | ++    "# {0} - ObjectName",  | 
 | 40 | ++    "ERR_InvalidObjectName={0} isn't valid object name"  | 
 | 41 | ++  | 
 | 42 | + })  | 
 | 43 | + final class LspTemplateUI {  | 
 | 44 | +     /**  | 
 | 45 | +@@ -165,8 +174,20 @@ final class LspTemplateUI {  | 
 | 46 | +     }  | 
 | 47 | +   | 
 | 48 | +     private static CompletionStage<String> findPackage(CompletionStage<?> uiBefore, NbCodeLanguageClient client) {  | 
 | 49 | +-        return uiBefore.thenCompose((__) ->  | 
 | 50 | +-            client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectPackageName(), Bundle.CTL_TemplateUI_SelectPackageNameSuggestion()))  | 
 | 51 | ++        return uiBefore.thenCompose((__) -> {  | 
 | 52 | ++            class ValidatePackageName implements Function<String, CompletionStage<String>> {  | 
 | 53 | ++  | 
 | 54 | ++                @Override  | 
 | 55 | ++                public CompletionStage<String> apply(String packageName) {  | 
 | 56 | ++                    if (!SourceVersion.isName(packageName)) {  | 
 | 57 | ++                        client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidPackageName(packageName)));  | 
 | 58 | ++                        return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectPackageName(), Bundle.CTL_TemplateUI_SelectPackageNameSuggestion())).thenCompose(this);  | 
 | 59 | ++                    }  | 
 | 60 | ++                    return CompletableFuture.completedFuture(packageName);  | 
 | 61 | ++                }  | 
 | 62 | ++            }  | 
 | 63 | ++            return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectPackageName(), Bundle.CTL_TemplateUI_SelectPackageNameSuggestion())).thenCompose(new ValidatePackageName());  | 
 | 64 | ++        }  | 
 | 65 | +         );  | 
 | 66 | +     }  | 
 | 67 | +   | 
 | 68 | +@@ -188,8 +209,9 @@ final class LspTemplateUI {  | 
 | 69 | +                         if (path == null) {  | 
 | 70 | +                             throw raise(RuntimeException.class, new UserCancelException(path));  | 
 | 71 | +                         }  | 
 | 72 | +-                        FileObject fo = FileUtil.toFileObject(new File(path));  | 
 | 73 | +-                        if (fo == null || !fo.isFolder()) {  | 
 | 74 | ++                        File target = new File(path);  | 
 | 75 | ++                        FileObject fo = FileUtil.toFileObject(target);  | 
 | 76 | ++                        if (!target.canWrite() || fo == null || !fo.isFolder()) {  | 
 | 77 | +                             client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidPath(path)));  | 
 | 78 | +                             return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectTarget(), suggestion.getPrimaryFile().getPath())).thenCompose(this);  | 
 | 79 | +                         }  | 
 | 80 | +@@ -202,7 +224,7 @@ final class LspTemplateUI {  | 
 | 81 | +   | 
 | 82 | +     private static CompletionStage<Pair<DataFolder, String>> findTargetAndNameForProject(CompletionStage<DataObject> findTemplate, NbCodeLanguageClient client) {  | 
 | 83 | +         return findTemplate.thenCompose(__ -> client.workspaceFolders()).thenCompose(folders -> {  | 
 | 84 | +-            class VerifyNonExistingFolder implements Function<String, CompletionStage<Pair<DataFolder,String>>> {  | 
 | 85 | ++            class VerifyNewFolderCreation implements Function<String, CompletionStage<Pair<DataFolder,String>>> {  | 
 | 86 | +                 @Override  | 
 | 87 | +                 public CompletionStage<Pair<DataFolder,String>> apply(String path) {  | 
 | 88 | +                     if (path == null) {  | 
 | 89 | +@@ -215,12 +237,14 @@ final class LspTemplateUI {  | 
 | 90 | +                     }  | 
 | 91 | +                     targetPath.getParentFile().mkdirs();  | 
 | 92 | +                     FileObject fo = FileUtil.toFileObject(targetPath.getParentFile());  | 
 | 93 | +-                    if (fo == null || !fo.isFolder()) {  | 
 | 94 | ++                    if (fo == null || !fo.isFolder() || !targetPath.getParentFile().canWrite() || !SourceVersion.isName(targetPath.getName())) {  | 
 | 95 | ++                        client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidNewPath(path)));  | 
 | 96 | ++                        return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectProjectTarget(), suggestWorkspaceRoot(folders))).thenCompose(this);  | 
 | 97 | +                     }  | 
 | 98 | +                     return CompletableFuture.completedFuture(Pair.of(DataFolder.findFolder(fo), targetPath.getName()));  | 
 | 99 | +                 }  | 
 | 100 | +             }  | 
 | 101 | +-            return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectProjectTarget(), suggestWorkspaceRoot(folders))).thenCompose(new VerifyNonExistingFolder());  | 
 | 102 | ++            return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectProjectTarget(), suggestWorkspaceRoot(folders))).thenCompose(new VerifyNewFolderCreation());  | 
 | 103 | +         });  | 
 | 104 | +     }  | 
 | 105 | +   | 
 | 106 | +@@ -229,9 +253,21 @@ final class LspTemplateUI {  | 
 | 107 | +         FileObject template = desc.getTemplate();  | 
 | 108 | +         Object handler = template.getAttribute(FileBuilder.ATTR_TEMPLATE_HANDLER);  | 
 | 109 | +         if (handler == null) {  | 
 | 110 | +-            return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), desc.getProposedName())).thenApply(name -> {  | 
 | 111 | +-                return name != null ? builder.name(name) : null;  | 
 | 112 | +-            });  | 
 | 113 | ++            class ValidateJavaObjectName implements Function<String, CompletionStage<String>> {  | 
 | 114 | ++  | 
 | 115 | ++                @Override  | 
 | 116 | ++                public CompletionStage<String> apply(String name) {  | 
 | 117 | ++                    if (!SourceVersion.isName(name)) {  | 
 | 118 | ++                        client.showMessage(new MessageParams(MessageType.Error, Bundle.ERR_InvalidObjectName(name)));  | 
 | 119 | ++                        return client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), desc.getProposedName())).thenCompose(this);  | 
 | 120 | ++                    }  | 
 | 121 | ++                    return CompletableFuture.completedFuture(name);  | 
 | 122 | ++                }  | 
 | 123 | ++            }  | 
 | 124 | ++            boolean isJavaTemplate = "text/x-java".equals(FileUtil.getMIMEType(template));  | 
 | 125 | ++            CompletionStage<String> userInput = client.showInputBox(new ShowInputBoxParams(Bundle.CTL_TemplateUI_SelectName(), desc.getProposedName()));  | 
 | 126 | ++            if(isJavaTemplate) userInput = userInput.thenCompose(new ValidateJavaObjectName());  | 
 | 127 | ++            return userInput.thenApply(name -> {return name != null ? builder.name(name) : null;});   | 
 | 128 | +         }  | 
 | 129 | +         return CompletableFuture.completedFuture(builder);  | 
 | 130 | +     }  | 
 | 131 | +@@ -242,7 +278,7 @@ final class LspTemplateUI {  | 
 | 132 | +             suggestion = Utilities.toFile(new URI(folders.get(0).getUri())).getParent();  | 
 | 133 | +         } catch (URISyntaxException ex) {  | 
 | 134 | +         }  | 
 | 135 | +-        return suggestion;  | 
 | 136 | ++        return Paths.get(suggestion,"ProjectName").toString();  | 
 | 137 | +     }  | 
 | 138 | +   | 
 | 139 | +     private static CompletionStage<DataObject> findTemplate(DataFolder templates, NbCodeLanguageClient client, ExecuteCommandParams params) {  | 
0 commit comments