private Uri?TryGetNormalizedModulePath(Uri parentFileUri, ModuleDeclarationSyntax moduleDeclarationSyntax, out DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder) { var pathName = SyntaxHelper.TryGetModulePath(moduleDeclarationSyntax, out var getModulePathFailureBuilder); if (pathName == null) { failureBuilder = getModulePathFailureBuilder; return(null); } if (!ValidateModulePath(pathName, out var validateModulePathFailureBuilder)) { failureBuilder = validateModulePathFailureBuilder; return(null); } var moduleUri = fileResolver.TryResolveModulePath(parentFileUri, pathName); if (moduleUri == null) { failureBuilder = x => x.ModulePathCouldNotBeResolved(pathName, parentFileUri.LocalPath); return(null); } failureBuilder = null; return(moduleUri); }
private string?TryGetNormalizedModulePath(string parentFileName, ModuleDeclarationSyntax moduleDeclarationSyntax, out DiagnosticBuilder.ErrorBuilderDelegate?failureBuilder) { var pathName = SyntaxHelper.TryGetModulePath(moduleDeclarationSyntax, out var getModulePathFailureBuilder); if (pathName == null) { failureBuilder = getModulePathFailureBuilder; return(null); } if (pathName.Contains('\\')) { // enforce '/' rather than '\' for module paths for cross-platform compatibility failureBuilder = x => x.ModulePathBackslashUnsupported(); return(null); } var fullPath = fileResolver.TryResolveModulePath(parentFileName, pathName); if (fullPath == null) { failureBuilder = x => x.ModulePathCouldNotBeResolved(pathName, parentFileName); return(null); } failureBuilder = null; return(fullPath); }
private IEnumerable <CompletionItem> GetModulePathCompletions(SemanticModel model, BicepCompletionContext context) { if (!context.Kind.HasFlag(BicepCompletionContextKind.ModulePath)) { return(Enumerable.Empty <CompletionItem>()); } // To provide intellisense before the quotes are typed if (context.EnclosingDeclaration is not ModuleDeclarationSyntax declarationSyntax || declarationSyntax.Path is not StringSyntax stringSyntax || stringSyntax.TryGetLiteralValue() is not string entered) { entered = ""; } // These should only fail if we're not able to resolve cwd path or the entered string if (FileResolver.TryResolveModulePath(model.SyntaxTree.FileUri, ".") is not { } cwdUri || FileResolver.TryResolveModulePath(cwdUri, entered) is not { } query) { return(Enumerable.Empty <CompletionItem>()); } var files = Enumerable.Empty <Uri>(); var dirs = Enumerable.Empty <Uri>(); // technically bicep files do not have to follow the bicep extension, so // we are not enforcing *.bicep get files command if (FileResolver.TryDirExists(query)) { files = FileResolver.GetFiles(query, string.Empty); dirs = FileResolver.GetDirectories(query, string.Empty); } else if (FileResolver.TryResolveModulePath(query, ".") is {} queryParent) { files = FileResolver.GetFiles(queryParent, ""); dirs = FileResolver.GetDirectories(queryParent, ""); } // "./" will not be preserved when making relative Uris. We have to go and manually add it. // Prioritize .bicep files higher than other files. var fileItems = files .Where(file => file != model.SyntaxTree.FileUri) .Where(file => file.Segments.Last().EndsWith(LanguageServerConstants.LanguageFileExtension)) .Select(file => CreateModulePathCompletion( file.Segments.Last(), (entered.StartsWith("./") ? "./" : "") + cwdUri.MakeRelativeUri(file).ToString(), context.ReplacementRange, CompletionItemKind.File, file.Segments.Last().EndsWith(LanguageServerConstants.LanguageId) ? CompletionPriority.High : CompletionPriority.Medium)) .ToList(); var dirItems = dirs .Select(dir => CreateModulePathCompletion( dir.Segments.Last(), (entered.StartsWith("./") ? "./" : "") + cwdUri.MakeRelativeUri(dir).ToString(), context.ReplacementRange, CompletionItemKind.Folder, CompletionPriority.Medium) .WithCommand(new Command { Name = EditorCommands.RequestCompletions })) .ToList(); return(fileItems.Concat(dirItems)); }