From 81ab00e3165a70755c1c2fc742b550d80cdd2b09 Mon Sep 17 00:00:00 2001 From: Stephen Weatherford Date: Thu, 8 Jul 2021 16:43:32 -0700 Subject: [PATCH 1/2] Only support JSON snippets for empty files --- assets/armsnippets.jsonc | 4 +- assets/jsonsnippets.jsonc | 80 ---------- package.json | 10 -- src/AzureRMTools.ts | 113 +++++++++---- src/documents/DeploymentDocument.ts | 124 +------------- src/documents/JsonDocument.ts | 151 ++++++++++++++++++ src/documents/UnsupportedJsonDocument.ts | 21 +++ src/util/CompletionsSpy.ts | 6 +- .../toVsCodeCompletionItem.ts | 8 +- 9 files changed, 267 insertions(+), 250 deletions(-) delete mode 100644 assets/jsonsnippets.jsonc create mode 100644 src/documents/JsonDocument.ts create mode 100644 src/documents/UnsupportedJsonDocument.ts diff --git a/assets/armsnippets.jsonc b/assets/armsnippets.jsonc index 16b6f6a10..b8ccf3e29 100644 --- a/assets/armsnippets.jsonc +++ b/assets/armsnippets.jsonc @@ -2,13 +2,13 @@ /* Known contexts (see KnownContexts.ts) - empty-document + empty-document (also works for plain JSON files) parameter-definitions parameter-values userfunc-parameter-definitions resource-body - If a location in a template document does not match ones of the above, then it will + If a location in a template document does not match one of the above, then it will be set to the name of the property containing the current array or object (e.g. "resources" or "outputs"), if any. */ diff --git a/assets/jsonsnippets.jsonc b/assets/jsonsnippets.jsonc deleted file mode 100644 index f8cd5e04b..000000000 --- a/assets/jsonsnippets.jsonc +++ /dev/null @@ -1,80 +0,0 @@ -{ - "$schema": "./schemas/snippets.schema.json", - "Azure Resource Manager (ARM) Template": { - "prefix": "arm!", - "body": [ - "{", - "\t\"\\$schema\": \"https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#\",", - "\t\"contentVersion\": \"1.0.0.0\",", - "\t\"parameters\": {},", - "\t\"functions\": [],", - "\t\"variables\": {},", - "\t\"resources\": [],", - "\t\"outputs\": {}", - "}" - ], - "description": "Resource Group Template", - "context": "empty" - }, - "Azure Resource Manager (ARM) Template Subscription": { - "prefix": "arm!s", - "body": [ - "{", - "\t\"\\$schema\": \"https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#\",", - "\t\"contentVersion\": \"1.0.0.0\",", - "\t\"parameters\": {},", - "\t\"functions\": [],", - "\t\"variables\": {},", - "\t\"resources\": [],", - "\t\"outputs\": {}", - "}" - ], - "description": "Subscription Template", - "context": "empty" - }, - "Azure Resource Manager (ARM) Template Management Group": { - "prefix": "arm!mg", - "body": [ - "{", - "\t\"\\$schema\": \"https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#\",", - "\t\"contentVersion\": \"1.0.0.0\",", - "\t\"parameters\": {},", - "\t\"functions\": [],", - "\t\"variables\": {},", - "\t\"resources\": [],", - "\t\"outputs\": {}", - "}" - ], - "description": "Management Group Template", - "context": "empty" - }, - "Azure Resource Manager (ARM) Template Tenant": { - "prefix": "arm!t", - "body": [ - "{", - "\t\"\\$schema\": \"https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#\",", - "\t\"contentVersion\": \"1.0.0.0\",", - "\t\"parameters\": {},", - "\t\"functions\": [],", - "\t\"variables\": {},", - "\t\"resources\": [],", - "\t\"outputs\": {}", - "}" - ], - "description": "Tenant Template", - "context": "empty" - }, - "Azure Resource Manager (ARM) Parameters Template": { - "prefix": "armp!", - "body": [ - "{", - "\t\"\\$schema\": \"https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#\",", - "\t\"contentVersion\": \"1.0.0.0\",", - "\t\"parameters\": {", - "\t}", - "}" - ], - "description": "Parameters Template", - "context": "empty" - } -} diff --git a/package.json b/package.json index 0169accc1..cd3311258 100644 --- a/package.json +++ b/package.json @@ -80,16 +80,6 @@ "path": "dist/grammars/arm-expression-string.tmLanguage.json" } ], - "snippets": [ - { - "language": "json", - "path": "./assets/jsonsnippets.jsonc" - }, - { - "language": "jsonc", - "path": "./assets/jsonsnippets.jsonc" - } - ], "configuration": { "type": "object", "title": "Azure Resource Manager Tools", diff --git a/src/AzureRMTools.ts b/src/AzureRMTools.ts index b5e708bb2..8f7bafe0a 100644 --- a/src/AzureRMTools.ts +++ b/src/AzureRMTools.ts @@ -24,12 +24,14 @@ import { DeploymentTemplateDoc } from "./documents/templates/DeploymentTemplateD import { ExtractItem } from './documents/templates/ExtractItem'; import { getNormalizedDocumentKey } from './documents/templates/getNormalizedDocumentKey'; import { gotoResources } from './documents/templates/gotoResources'; +import { IJsonDocument } from './documents/templates/IJsonDocument'; import { getItemTypeQuickPicks, InsertItem } from "./documents/templates/insertItem"; import { assignTemplateGraphToDeploymentTemplate, INotifyTemplateGraphArgs, openLinkedTemplateFileCommand, tryLoadNonLocalLinkedFile } 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"; import { TemplateSectionType } from "./documents/templates/TemplateSectionType"; +import { UnsupportedJsonDocument } from './documents/UnsupportedJsonDocument'; import { ext } from "./extensionVariables"; import { assert } from './fixed_assert'; import { IProvideOpenedDocuments } from './IProvideOpenedDocuments'; @@ -40,6 +42,8 @@ import { ReferenceList } from "./language/ReferenceList"; import { Span } from "./language/Span"; import { getAvailableResourceTypesAndVersions } from './languageclient/getAvailableResourceTypesAndVersions'; import { notifyTemplateGraphAvailable, startArmLanguageServerInBackground, waitForLanguageServerAvailable } from "./languageclient/startArmLanguageServer"; +import { InsertionContext } from './snippets/InsertionContext'; +import { KnownContexts } from './snippets/KnownContexts'; import { showInsertionContext } from "./snippets/showInsertionContext"; import { SnippetManager } from "./snippets/SnippetManager"; import { survey } from "./survey"; @@ -57,6 +61,7 @@ import { parseUri } from './util/uri'; import { IncorrectArgumentsCountIssue } from "./visitors/IncorrectArgumentsCountIssue"; import { UnrecognizedBuiltinFunctionIssue } from "./visitors/UnrecognizedFunctionIssues"; import { IAddMissingParametersArgs, IGotoParameterValueArgs, IGotoResourcesArgs } from "./vscodeIntegration/commandArguments"; +import { Item } from './vscodeIntegration/Completion'; import { ConsoleOutputChannelWrapper } from "./vscodeIntegration/ConsoleOutputChannelWrapper"; import { IHoverInfo } from './vscodeIntegration/IHoverInfo'; import { RenameCodeActionProvider } from "./vscodeIntegration/RenameCodeActionProvider"; @@ -333,6 +338,34 @@ export class AzureRMTools implements IProvideOpenedDocuments { this._diagnosticsCollection = vscode.languages.createDiagnosticCollection("azurerm-tools-expressions"); context.subscriptions.push(this._diagnosticsCollection); + // Hook up completion provider immediately because it also handles unsupported JSON files (for non-template JSON files) + const completionProvider: vscode.CompletionItemProvider = { + provideCompletionItems: async ( + document: vscode.TextDocument, + position: vscode.Position, + token: vscode.CancellationToken, + context: vscode.CompletionContext + ): Promise => { + return await this.onProvideCompletions(document, position, token, context); + }, + resolveCompletionItem: (item: vscode.CompletionItem, token: vscode.CancellationToken): vscode.CompletionItem => { + return this.onResolveCompletionItem(item, token); + } + }; + ext.context.subscriptions.push( + vscode.languages.registerCompletionItemProvider( + templateOrParameterDocumentSelector, + completionProvider, + "'", + "[", + ".", + '"', + '(', + ',', + ' ', + '{' + )); + const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor; if (activeEditor) { const activeDocument = activeEditor.document; @@ -958,34 +991,6 @@ export class AzureRMTools implements IProvideOpenedDocuments { } )); - // tslint:disable-next-line:no-suspicious-comment - const completionProvider: vscode.CompletionItemProvider = { - provideCompletionItems: async ( - document: vscode.TextDocument, - position: vscode.Position, - token: vscode.CancellationToken, - context: vscode.CompletionContext - ): Promise => { - return await this.onProvideCompletions(document, position, token, context); - }, - resolveCompletionItem: (item: vscode.CompletionItem, token: vscode.CancellationToken): vscode.CompletionItem => { - return this.onResolveCompletionItem(item, token); - } - }; - ext.context.subscriptions.push( - vscode.languages.registerCompletionItemProvider( - templateOrParameterDocumentSelector, - completionProvider, - "'", - "[", - ".", - '"', - '(', - ',', - ' ', - '{' - )); - // tslint:disable-next-line:no-suspicious-comment const definitionProvider: vscode.DefinitionProvider = { provideDefinition: async (document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise => { @@ -1342,15 +1347,20 @@ export class AzureRMTools implements IProvideOpenedDocuments { return await callWithTelemetryAndErrorHandling('provideCompletionItems', async (actionContext: IActionContext): Promise => { actionContext.telemetry.suppressIfSuccessful = true; actionContext.errorHandling.suppressDisplay = true; + actionContext.telemetry.properties.langId = document.languageId; const cancel = new Cancellation(token, actionContext); const pc: PositionContext | undefined = await this.getPositionContext(document, position, cancel); + let jsonDocument: IJsonDocument | undefined; + let items: Item[] | undefined; if (pc) { + jsonDocument = pc.document; const triggerCharacter = context.triggerKind === vscode.CompletionTriggerKind.TriggerCharacter ? context.triggerCharacter : undefined; - const { items, triggerSuggest } = await pc.getCompletionItems(triggerCharacter, defaultTabSize); + let triggerSuggest: boolean | undefined; + ({ items, triggerSuggest } = await pc.getCompletionItems(triggerCharacter, defaultTabSize)); if (triggerSuggest) { // The user typed the beginning of a parent object, open up the completions context menu because it's // likely they want to use a snippet immediately @@ -1361,15 +1371,52 @@ export class AzureRMTools implements IProvideOpenedDocuments { vscode.commands.executeCommand('editor.action.triggerSuggest'); }); return undefined; - } else { - const vsCodeItems = items.map(c => toVsCodeCompletionItem(pc.document, c, position)); - ext.completionItemsSpy.postCompletionItemsResult(pc.document, items, vsCodeItems); - return new vscode.CompletionList(vsCodeItems, true); } + } else { + const result = await this.getUnsupportedJsonSnippets(actionContext, document, position); + jsonDocument = result.jsonDocument; + items = result.items; + } + + if (jsonDocument && items) { + const vsCodeItems = items.map(c => toVsCodeCompletionItem(jsonDocument!, c, position)); + ext.completionItemsSpy.postCompletionItemsResult(jsonDocument, items, vsCodeItems); + return new vscode.CompletionList(vsCodeItems, true); } }); } + /** + * Retrieve snippets for a JSON file that is not a deployment or parameters file + * @param actionContext Re + * @param document + * @param position + */ + private async getUnsupportedJsonSnippets( + actionContext: IActionContext, + document: vscode.TextDocument, + position: vscode.Position + ): Promise<{ jsonDocument?: IJsonDocument, items?: Item[] }> { + const text = document.getText(); + if (text.length > 100 /*limit size of strings we trim*/ || text.trim() !== '') { + return {}; + } + + // It's an empty (or whitespace) document, so we can try with the empty-document context + actionContext.telemetry.properties.isEmptyDoc = 'true'; + const insertionContext: InsertionContext = { + context: KnownContexts.emptyDocument, + parents: [] + }; + const jsonDocument: IJsonDocument = new UnsupportedJsonDocument(document.getText(), document.uri); + + const index = jsonDocument.getDocumentCharacterIndex(position.line, position.character); + const span = new Span(index, 0); + const items: Item[] = await ext.snippetManager.value.getSnippetsAsCompletionItems(insertionContext, span); + + return { jsonDocument, items }; + } + private onResolveCompletionItem(item: vscode.CompletionItem, _token: vscode.CancellationToken): vscode.CompletionItem { ext.completionItemsSpy.postCompletionItemResolution(item); return item; diff --git a/src/documents/DeploymentDocument.ts b/src/documents/DeploymentDocument.ts index b7802cc80..a1c4b4274 100644 --- a/src/documents/DeploymentDocument.ts +++ b/src/documents/DeploymentDocument.ts @@ -5,42 +5,27 @@ import { CodeAction, CodeActionContext, CodeLens, Command, Position, Range, Selection, Uri } from "vscode"; import { INamedDefinition } from "../language/INamedDefinition"; import { Issue } from "../language/Issue"; -import * as Json from "../language/json/JSON"; -import { LineColPos } from "../language/LineColPos"; import { ReferenceList } from "../language/ReferenceList"; -import { ContainsBehavior, Span } from "../language/Span"; -import { CachedValue } from "../util/CachedValue"; +import { Span } from "../language/Span"; import { __debugMarkPositionInString, __debugMarkRangeInString } from "../util/debugMarkStrings"; -import { nonNullValue } from "../util/nonNull"; import { getVSCodeRangeFromSpan } from "../vscodeIntegration/vscodePosition"; +import { JsonDocument } from "./JsonDocument"; import { IParameterValuesSourceProvider } from "./parameters/IParameterValuesSourceProvider"; import { PositionContext } from "./positionContexts/PositionContext"; -import { IJsonDocument } from "./templates/IJsonDocument"; import { TemplateScope } from "./templates/scopes/TemplateScope"; /** * Represents a deployment-related JSON file */ -export abstract class DeploymentDocument implements IJsonDocument { - // Parse result for the template JSON document as a whole - private _jsonParseResult: Json.ParseResult; - - // The JSON node for the top-level JSON object (if the JSON is not empty or malformed) - private _topLevelValue: Json.ObjectValue | undefined; - - private _schema: CachedValue = new CachedValue(); - +export abstract class DeploymentDocument extends JsonDocument { /** * Constructor * * @param _documentText The string text of the document * @param _documentUri The location of the document */ - constructor(private _documentText: string, private _documentUri: Uri, public readonly documentVersion: number) { - nonNullValue(_documentUri, "_documentUri"); - - this._jsonParseResult = Json.parse(_documentText); - this._topLevelValue = Json.asObjectValue(this._jsonParseResult.value); + constructor(documentText: string, documentUri: Uri, public readonly documentVersion: number) { + super(documentText, documentUri); } // tslint:disable-next-line:function-name @@ -59,107 +44,10 @@ export abstract class DeploymentDocument implements IJsonDocument { } } - /** - * Get the document text as a string. - */ - public get documentText(): string { - return this._documentText; - } - - /** - * Retrieves a section of the document text - */ - public getDocumentText(span: Span, offsetIndex?: number): string { - return span.getText(this.documentText, offsetIndex); - } - - /** - * The unique identifier for this deployment template, which indicates its location - */ - public get documentUri(): Uri { - return this._documentUri; - } - - // Parse result for the template JSON document as a whole - public get jsonParseResult(): Json.ParseResult { - return this._jsonParseResult; - } - - // The JSON node for the top-level JSON object (if the JSON is not empty or malformed) - public get topLevelValue(): Json.ObjectValue | undefined { - return this._topLevelValue; - } - - public get schemaUri(): string | undefined { - const schema = this.schemaValue; - return schema ? schema.unquotedValue : undefined; - } - - public get schemaValue(): Json.StringValue | undefined { - return this._schema.getOrCacheValue(() => { - return this.topLevelValue?.getPropertyValue("$schema")?.asStringValue; - }); - } - - public getMaxLineLength(): number { - let max = 0; - for (let len of this.jsonParseResult.lineLengths) { - if (len > max) { - max = len; - } - } - - return max; - } - - public getCommentCount(): number { - return this.jsonParseResult.commentCount; - } - - /** - * Get the number of lines that are in the file. - */ - public get lineCount(): number { - return this._jsonParseResult.lineLengths.length; - } - - /** - * Get the maximum column index for the provided line. For the last line in the file, - * the maximum column index is equal to the line length. For every other line in the file, - * the maximum column index is less than the line length (because line length includes - * the CR/LF terminating characters, but the last line doesn't). - */ - public getMaxColumnIndex(lineIndex: number): number { - return this._jsonParseResult.getMaxColumnIndex(lineIndex); - } - - /** - * Get the maximum document character index for this deployment template. - */ - public get maxCharacterIndex(): number { - return this._jsonParseResult.maxCharacterIndex; - } - public abstract getContextFromDocumentLineAndColumnIndexes(documentLineIndex: number, documentColumnIndex: number, associatedTemplate: DeploymentDocument | undefined): PositionContext; public abstract getContextFromDocumentCharacterIndex(documentCharacterIndex: number, associatedTemplate: DeploymentDocument | undefined): PositionContext; - public getDocumentCharacterIndex(documentLineIndex: number, documentColumnIndex: number, options?: { allowOutOfBounds?: boolean }): number { - return this._jsonParseResult.getCharacterIndex(documentLineIndex, documentColumnIndex, options); - } - - public getDocumentPosition(documentCharacterIndex: number): LineColPos { - return this._jsonParseResult.getPositionFromCharacterIndex(documentCharacterIndex); - } - - public getJSONTokenAtDocumentCharacterIndex(documentCharacterIndex: number): Json.Token | undefined { - return this._jsonParseResult.getTokenAtCharacterIndex(documentCharacterIndex); - } - - public getJSONValueAtDocumentCharacterIndex(documentCharacterIndex: number, containsBehavior: ContainsBehavior): Json.Value | undefined { - return this._jsonParseResult.getValueAtCharacterIndex(documentCharacterIndex, containsBehavior); - } - /** * Find all references in this document to the given named definition (which may or may not be in this document) */ @@ -201,7 +89,7 @@ export abstract class DeploymentDocument implements IJsonDocument { public abstract getWarnings(): Issue[]; } -export abstract class ResolvableCodeLens extends CodeLens { +export abstract class ResolvableCodeLens extends CodeLens { //asdf move public constructor( public readonly scope: TemplateScope, public readonly span: Span diff --git a/src/documents/JsonDocument.ts b/src/documents/JsonDocument.ts new file mode 100644 index 000000000..f623b8e3e --- /dev/null +++ b/src/documents/JsonDocument.ts @@ -0,0 +1,151 @@ +// ---------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ---------------------------------------------------------------------------- + +import { Position, Range, Uri } from "vscode"; +import * as Json from "../language/json/JSON"; +import { LineColPos } from "../language/LineColPos"; +import { ContainsBehavior, Span } from "../language/Span"; +import { CachedValue } from "../util/CachedValue"; +import { __debugMarkPositionInString, __debugMarkRangeInString } from "../util/debugMarkStrings"; +import { nonNullValue } from "../util/nonNull"; +import { IJsonDocument } from "./templates/IJsonDocument"; + +/** + * Represents any JSON document + */ +export abstract class JsonDocument implements IJsonDocument { + // Parse result for the template JSON document as a whole + private _jsonParseResult: Json.ParseResult; + + // The JSON node for the top-level JSON object (if the JSON is not empty or malformed) + private _topLevelValue: Json.ObjectValue | undefined; + + private _schema: CachedValue = new CachedValue(); + + /** + * Constructor + * + * @param _documentText The string text of the document + * @param _documentUri The location of the document + */ + constructor(private _documentText: string, private _documentUri: Uri) { + nonNullValue(_documentUri, "_documentUri"); + + this._jsonParseResult = Json.parse(_documentText); + this._topLevelValue = Json.asObjectValue(this._jsonParseResult.value); + } + + // tslint:disable-next-line:function-name + public _debugShowTextAt(positionOrRange: number | Span | Range | Position): string { + if (positionOrRange instanceof Span) { + return __debugMarkRangeInString(this.documentText, positionOrRange.startIndex, positionOrRange.length); + } else if (positionOrRange instanceof Range) { + const startIndex = this.getDocumentCharacterIndex(positionOrRange.start.line, positionOrRange.start.character, { allowOutOfBounds: true }); + const endIndex = this.getDocumentCharacterIndex(positionOrRange.end.line, positionOrRange.end.character, { allowOutOfBounds: true }); + return __debugMarkRangeInString(this.documentText, startIndex, endIndex - startIndex); + } else if (positionOrRange instanceof Position) { + const index = this.getDocumentCharacterIndex(positionOrRange.line, positionOrRange.character, { allowOutOfBounds: true }); + return __debugMarkPositionInString(this.documentText, index); + } else { + return __debugMarkPositionInString(this.documentText, positionOrRange); + } + } + + /** + * Get the document text as a string. + */ + public get documentText(): string { + return this._documentText; + } + + /** + * Retrieves a section of the document text + */ + public getDocumentText(span: Span, offsetIndex?: number): string { + return span.getText(this.documentText, offsetIndex); + } + + /** + * The unique identifier for this deployment template, which indicates its location + */ + public get documentUri(): Uri { + return this._documentUri; + } + + // Parse result for the template JSON document as a whole + public get jsonParseResult(): Json.ParseResult { + return this._jsonParseResult; + } + + // The JSON node for the top-level JSON object (if the JSON is not empty or malformed) + public get topLevelValue(): Json.ObjectValue | undefined { + return this._topLevelValue; + } + + public get schemaUri(): string | undefined { + const schema = this.schemaValue; + return schema ? schema.unquotedValue : undefined; + } + + public get schemaValue(): Json.StringValue | undefined { + return this._schema.getOrCacheValue(() => { + return this.topLevelValue?.getPropertyValue("$schema")?.asStringValue; + }); + } + + public getMaxLineLength(): number { + let max = 0; + for (let len of this.jsonParseResult.lineLengths) { + if (len > max) { + max = len; + } + } + + return max; + } + + public getCommentCount(): number { + return this.jsonParseResult.commentCount; + } + + /** + * Get the number of lines that are in the file. + */ + public get lineCount(): number { + return this._jsonParseResult.lineLengths.length; + } + + /** + * Get the maximum column index for the provided line. For the last line in the file, + * the maximum column index is equal to the line length. For every other line in the file, + * the maximum column index is less than the line length (because line length includes + * the CR/LF terminating characters, but the last line doesn't). + */ + public getMaxColumnIndex(lineIndex: number): number { + return this._jsonParseResult.getMaxColumnIndex(lineIndex); + } + + /** + * Get the maximum document character index for this deployment template. + */ + public get maxCharacterIndex(): number { + return this._jsonParseResult.maxCharacterIndex; + } + + public getDocumentCharacterIndex(documentLineIndex: number, documentColumnIndex: number, options?: { allowOutOfBounds?: boolean }): number { + return this._jsonParseResult.getCharacterIndex(documentLineIndex, documentColumnIndex, options); + } + + public getDocumentPosition(documentCharacterIndex: number): LineColPos { + return this._jsonParseResult.getPositionFromCharacterIndex(documentCharacterIndex); + } + + public getJSONTokenAtDocumentCharacterIndex(documentCharacterIndex: number): Json.Token | undefined { + return this._jsonParseResult.getTokenAtCharacterIndex(documentCharacterIndex); + } + + public getJSONValueAtDocumentCharacterIndex(documentCharacterIndex: number, containsBehavior: ContainsBehavior): Json.Value | undefined { + return this._jsonParseResult.getValueAtCharacterIndex(documentCharacterIndex, containsBehavior); + } +} diff --git a/src/documents/UnsupportedJsonDocument.ts b/src/documents/UnsupportedJsonDocument.ts new file mode 100644 index 000000000..cf45fc2a7 --- /dev/null +++ b/src/documents/UnsupportedJsonDocument.ts @@ -0,0 +1,21 @@ +// ---------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// ---------------------------------------------------------------------------- + +import { Uri } from "vscode"; +import { JsonDocument } from "./JsonDocument"; + +/** + * Represents a JSON document that is not a deployment or parameter file + */ +export class UnsupportedJsonDocument extends JsonDocument { + /** + * Constructor + * + * @param _documentText The string text of the document + * @param _documentUri The location of the document + */ + constructor(documentText: string, documentUri: Uri) { + super(documentText, documentUri); + } +} diff --git a/src/util/CompletionsSpy.ts b/src/util/CompletionsSpy.ts index 1d73622fb..03ab59d06 100644 --- a/src/util/CompletionsSpy.ts +++ b/src/util/CompletionsSpy.ts @@ -4,10 +4,10 @@ import { CompletionItem, Event, EventEmitter } from "vscode"; import { Completion } from "../../extension.bundle"; -import { DeploymentDocument } from "../documents/DeploymentDocument"; +import { IJsonDocument } from "../documents/templates/IJsonDocument"; export interface ICompletionsSpyResult { - document: DeploymentDocument; + document: IJsonDocument; completionItems: Completion.Item[]; vsCodeCompletionItems: CompletionItem[]; } @@ -20,7 +20,7 @@ export class CompletionsSpy { public readonly onCompletionItemResolved: Event = this._resolveEmitter.event; public postCompletionItemsResult( - document: DeploymentDocument, + document: IJsonDocument, completionItems: Completion.Item[], vsCodeCompletionItems: CompletionItem[] ): void { diff --git a/src/vscodeIntegration/toVsCodeCompletionItem.ts b/src/vscodeIntegration/toVsCodeCompletionItem.ts index 4e5062707..f2e1dac38 100644 --- a/src/vscodeIntegration/toVsCodeCompletionItem.ts +++ b/src/vscodeIntegration/toVsCodeCompletionItem.ts @@ -5,14 +5,14 @@ import * as vscode from 'vscode'; import { IActionContext } from 'vscode-azureextensionui'; -import { DeploymentDocument } from '../documents/DeploymentDocument'; +import { IJsonDocument } from '../documents/templates/IJsonDocument'; import { assert } from '../fixed_assert'; import { assertNever } from '../util/assertNever'; import * as Completion from './Completion'; import { getVSCodeRangeFromSpan } from './vscodePosition'; -export function toVsCodeCompletionItem(deploymentFile: DeploymentDocument, item: Completion.Item, cursorPosition: vscode.Position): vscode.CompletionItem { - const range: vscode.Range = getVSCodeRangeFromSpan(deploymentFile, item.span); +export function toVsCodeCompletionItem(jsonDocument: IJsonDocument, item: Completion.Item, cursorPosition: vscode.Position): vscode.CompletionItem { + const range: vscode.Range = getVSCodeRangeFromSpan(jsonDocument, item.span); const vscodeItem = new vscode.CompletionItem(item.label); vscodeItem.range = range; @@ -46,7 +46,7 @@ export function toVsCodeCompletionItem(deploymentFile: DeploymentDocument, item: if (item.additionalEdits) { vscodeItem.additionalTextEdits = item.additionalEdits.map( e => new vscode.TextEdit( - getVSCodeRangeFromSpan(deploymentFile, e.span), + getVSCodeRangeFromSpan(jsonDocument, e.span), e.insertText ) ); From 7ac1207fe053c66700ce8be5e262f0b488923e78 Mon Sep 17 00:00:00 2001 From: Stephen Weatherford Date: Thu, 8 Jul 2021 18:02:38 -0700 Subject: [PATCH 2/2] lint --- src/AzureRMTools.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/AzureRMTools.ts b/src/AzureRMTools.ts index 8f7bafe0a..b12ab1527 100644 --- a/src/AzureRMTools.ts +++ b/src/AzureRMTools.ts @@ -344,9 +344,9 @@ export class AzureRMTools implements IProvideOpenedDocuments { document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, - context: vscode.CompletionContext + ctx: vscode.CompletionContext ): Promise => { - return await this.onProvideCompletions(document, position, token, context); + return await this.onProvideCompletions(document, position, token, ctx); }, resolveCompletionItem: (item: vscode.CompletionItem, token: vscode.CancellationToken): vscode.CompletionItem => { return this.onResolveCompletionItem(item, token); @@ -1379,6 +1379,7 @@ export class AzureRMTools implements IProvideOpenedDocuments { } if (jsonDocument && items) { + // tslint:disable-next-line:no-non-null-assertion // Guarded with if const vsCodeItems = items.map(c => toVsCodeCompletionItem(jsonDocument!, c, position)); ext.completionItemsSpy.postCompletionItemsResult(jsonDocument, items, vsCodeItems); return new vscode.CompletionList(vsCodeItems, true); @@ -1388,15 +1389,12 @@ export class AzureRMTools implements IProvideOpenedDocuments { /** * Retrieve snippets for a JSON file that is not a deployment or parameters file - * @param actionContext Re - * @param document - * @param position */ private async getUnsupportedJsonSnippets( actionContext: IActionContext, document: vscode.TextDocument, position: vscode.Position - ): Promise<{ jsonDocument?: IJsonDocument, items?: Item[] }> { + ): Promise<{ jsonDocument?: IJsonDocument; items?: Item[] }> { const text = document.getText(); if (text.length > 100 /*limit size of strings we trim*/ || text.trim() !== '') { return {};