diff --git a/src/AzureRMTools.ts b/src/AzureRMTools.ts index 8e3fb6ee7..9f645ae3a 100644 --- a/src/AzureRMTools.ts +++ b/src/AzureRMTools.ts @@ -26,7 +26,7 @@ import { getNormalizedDocumentKey } from './documents/templates/getNormalizedDoc import { gotoResources } from './documents/templates/gotoResources'; import { getItemTypeQuickPicks, InsertItem } from "./documents/templates/insertItem"; import { LinkedFileLoadState } from './documents/templates/linkedTemplates/LinkedFileLoadState'; -import { assignTemplateGraphToDeploymentTemplate, INotifyTemplateGraphArgs, openLinkedTemplateFile } from './documents/templates/linkedTemplates/linkedTemplates'; +import { assignTemplateGraphToDeploymentTemplate, INotifyTemplateGraphArgs, openLinkedTemplateFile, tryOpenNonLocalLinkedFile } from './documents/templates/linkedTemplates/linkedTemplates'; import { allSchemas, getPreferredSchema } from './documents/templates/schemas'; import { getQuickPickItems, sortTemplate } from "./documents/templates/sortTemplate"; import { mightBeDeploymentParameters, mightBeDeploymentTemplate, setLangIdToArm, templateDocumentSelector, templateOrParameterDocumentSelector } from "./documents/templates/supported"; @@ -1017,7 +1017,7 @@ export class AzureRMTools implements IProvideOpenedDocuments { const linkedTemplateDocumentProvider: vscode.TextDocumentContentProvider = { provideTextDocumentContent: async (uri: vscode.Uri, _token: vscode.CancellationToken): Promise => { - return this.provideContentForNonlocalUri(uri); + return await this.provideContentForNonlocalUri(uri); } }; ext.context.subscriptions.push( @@ -1040,8 +1040,15 @@ export class AzureRMTools implements IProvideOpenedDocuments { * linked-template:https%3A//raw.githubusercontent.com/StephenWeatherford/template-examples/master/linkedTemplates/uri/child.json */ private async provideContentForNonlocalUri(uri: vscode.Uri): Promise { - return callWithTelemetryAndErrorHandlingSync('provideContentForNonlocalUris', () => { - const dt = this.getOpenedDeploymentDocument(uri); + return callWithTelemetryAndErrorHandling('provideContentForNonlocalUris', async (context: IActionContext) => { + context.errorHandling.rethrow = true; + + let dt = this.getOpenedDeploymentDocument(uri); + if (!dt) { + await tryOpenNonLocalLinkedFile(uri, context, false); //asdf handle linked-template: + dt = this.getOpenedDeploymentDocument(uri); + } + return dt?.documentText; }); } @@ -1077,7 +1084,7 @@ export class AzureRMTools implements IProvideOpenedDocuments { const fullValidationOn = deploymentTemplate.templateGraph?.fullValidationStatus.fullValidationEnabled ?? templateFileHasParamFile; isWarning = !fullValidationOn; statusBarText = isWarning ? - `$(warning) WARNING: Full template validation off. Add parameter file or top-level default values to enable.` : + `$(warning) WARNING: Full template validation off. Add parameter file or top-level default values to parameters to enable.` : statusBarText; this._paramsStatusBarItem.command = "azurerm-vscode-tools.selectParameterFile"; diff --git a/src/documents/templates/getNormalizedDocumentKey.ts b/src/documents/templates/getNormalizedDocumentKey.ts index 4456aea01..e54f23b53 100644 --- a/src/documents/templates/getNormalizedDocumentKey.ts +++ b/src/documents/templates/getNormalizedDocumentKey.ts @@ -10,5 +10,5 @@ import { removeLinkedTemplateScheme } from "../../util/prependLinkedTemplateSche export function getNormalizedDocumentKey(documentUri: vscode.Uri): string { // We want a normalized file path to use as key, but also need to differentiate documents with different URI schemes const uri = removeLinkedTemplateScheme(documentUri); - return `${uri.scheme}|${normalizePath(uri)}`; + return normalizePath(uri); } diff --git a/src/documents/templates/linkedTemplates/linkedTemplates.ts b/src/documents/templates/linkedTemplates/linkedTemplates.ts index 46ddd3afd..0796bd2d1 100644 --- a/src/documents/templates/linkedTemplates/linkedTemplates.ts +++ b/src/documents/templates/linkedTemplates/linkedTemplates.ts @@ -15,7 +15,7 @@ import { httpGet } from '../../../util/httpGet'; import { normalizePath } from '../../../util/normalizePath'; import { ofType } from '../../../util/ofType'; import { pathExists } from '../../../util/pathExists'; -import { prependLinkedTemplateScheme } from '../../../util/prependLinkedTemplateScheme'; +import { prependLinkedTemplateScheme, removeLinkedTemplateScheme } from '../../../util/prependLinkedTemplateScheme'; import { DeploymentTemplateDoc } from '../../templates/DeploymentTemplateDoc'; import { LinkedTemplateScope } from '../../templates/scopes/templateScopes'; import { setLangIdToArm } from '../../templates/supported'; @@ -111,18 +111,7 @@ export async function onRequestOpenLinkedFile( } else { // Something else (http etc). Try to retrieve the content and return it directly try { - const content = await httpGet(requestedLinkUri.toString()); - assert(ext.provideOpenedDocuments, "ext.provideOpenedDocuments"); - const newUri = prependLinkedTemplateScheme(requestedLinkUri); - - // We need to place it into our docs immediately because our text document content provider will be queried - // for content before we get the document open event - const dt = new DeploymentTemplateDoc(content, newUri, 0); - ext.provideOpenedDocuments.setOpenedDeploymentDocument(newUri, dt); - - const doc = await workspace.openTextDocument(newUri); - setLangIdToArm(doc, context); - + const content = await tryOpenNonLocalLinkedFile(requestedLinkUri, context, true); return { content }; } catch (error) { return { loadErrorMessage: parseError(error).message }; @@ -131,6 +120,25 @@ export async function onRequestOpenLinkedFile( }); } +export async function tryOpenNonLocalLinkedFile(uri: Uri, context: IActionContext, open: boolean): Promise { + uri = removeLinkedTemplateScheme(uri); + const content = await httpGet(uri.toString()); + assert(ext.provideOpenedDocuments, "ext.provideOpenedDocuments"); + const newUri = prependLinkedTemplateScheme(uri); + + // We need to place it into our docs immediately because our text document content provider will be queried + // for content before we get the document open event + const dt = new DeploymentTemplateDoc(content, newUri, 0); + ext.provideOpenedDocuments.setOpenedDeploymentDocument(newUri, dt); + + if (open) { + const doc = await workspace.openTextDocument(newUri); + setLangIdToArm(doc, context); + } + + return content; +} + /** * Attempts to load the given file into a text document in VS Code so that * it will get sent to the language server. diff --git a/src/util/normalizePath.ts b/src/util/normalizePath.ts index 4d3120bf2..b2e1984d4 100644 --- a/src/util/normalizePath.ts +++ b/src/util/normalizePath.ts @@ -4,18 +4,20 @@ import * as path from 'path'; import { Uri } from "vscode"; -import { isWin32 } from '../constants'; +import { documentSchemes, isWin32 } from '../constants'; -export function normalizePath(filePath: Uri | string): string { - const suffix: string = (typeof filePath === 'string' || !filePath.query) - ? '' - : `?${filePath.query}`; +export function normalizePath(pathOrUri: Uri | string): string { + if (pathOrUri instanceof Uri && pathOrUri.scheme === documentSchemes.file) { + pathOrUri = pathOrUri.fsPath; + } - const fsPath: string = typeof filePath === 'string' ? filePath : filePath.fsPath; - let normalizedPath = path.normalize(fsPath); - if (isWin32) { - normalizedPath = normalizedPath.toLowerCase(); + if (typeof pathOrUri === 'string') { + let normalizedPath = path.normalize(pathOrUri); + if (isWin32) { + normalizedPath = normalizedPath.toLowerCase(); + } + pathOrUri = Uri.parse(normalizedPath); } - return normalizedPath + suffix; + return pathOrUri.toString(); } diff --git a/src/vscodeIntegration/Treeview.ts b/src/vscodeIntegration/Treeview.ts index 9f0e7be6a..74568de38 100644 --- a/src/vscodeIntegration/Treeview.ts +++ b/src/vscodeIntegration/Treeview.ts @@ -252,7 +252,7 @@ export class JsonOutlineProvider implements vscode.TreeDataProvider