Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/unreleased/ENHANCEMENTS-20250701-174433.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: ENHANCEMENTS
body: Add support for Terraform Search files (.tfquery.hcl). This provides block and attribute completion, hover, and diagnostics along with syntax validation for Terraform Search files.
time: 2025-07-01T17:44:33.274267+05:30
custom:
Issue: "2062"
Repository: vscode-terraform
11 changes: 11 additions & 0 deletions assets/icons/terraform_search.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@
"light": "assets/icons/terraform_stacks.svg"
}
},
{
"id": "terraform-search",
"aliases": [
"Terraform Search"
],
"extensions": [
".tfquery.hcl"
],
"configuration": "./language-configuration.json",
"icon": {
"dark": "assets/icons/terraform_search.svg",
"light": "assets/icons/terraform_search.svg"
}
},
{
"id": "json",
"extensions": [
Expand Down Expand Up @@ -182,6 +196,11 @@
"language": "terraform-mock",
"scopeName": "source.hcl",
"path": "./syntaxes/hcl.tmGrammar.json"
},
{
"language": "terraform-search",
"scopeName": "source.hcl",
"path": "./syntaxes/hcl.tmGrammar.json"
}
],
"semanticTokenTypes": [
Expand Down
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const documentSelector: DocumentSelector = [
{ scheme: 'file', language: 'terraform-deploy' },
{ scheme: 'file', language: 'terraform-test' },
{ scheme: 'file', language: 'terraform-mock' },
{ scheme: 'file', language: 'terraform-search' },
];
const outputChannel = vscode.window.createOutputChannel(brand);
const tfcOutputChannel = vscode.window.createOutputChannel('HCP Terraform');
Expand Down Expand Up @@ -94,6 +95,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
vscode.workspace.createFileSystemWatcher('**/*.tfdeploy.hcl'),
vscode.workspace.createFileSystemWatcher('**/*.tftest.hcl'),
vscode.workspace.createFileSystemWatcher('**/*.tfmock.hcl'),
vscode.workspace.createFileSystemWatcher('**/*.tfquery.hcl'),
],
},
diagnosticCollectionName: 'HashiCorpTerraform',
Expand Down
1 change: 1 addition & 0 deletions src/status/language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const lsStatus = vscode.languages.createLanguageStatusItem('terraform-ls.status'
{ language: 'terraform-deploy' },
{ language: 'terraform-test' },
{ language: 'terraform-mock' },
{ language: 'terraform-search' },
]);
lsStatus.name = 'Terraform LS';
lsStatus.detail = 'Terraform LS';
Expand Down
99 changes: 99 additions & 0 deletions src/test/integration/search/search.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import * as vscode from 'vscode';
import { assert } from 'chai';
import { activateExtension, getDocUri, open, testCompletion } from '../../helper';

suite('search (.tfquery.hcl)', () => {
suite('root', function suite() {
const docUri = getDocUri('main.tfquery.hcl');

this.beforeAll(async () => {
await open(docUri);
await activateExtension();
});

this.afterAll(async () => {
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
});

test('language is registered', async () => {
const doc = await vscode.workspace.openTextDocument(docUri);
assert.equal(doc.languageId, 'terraform-search', 'document language should be `terraform-search`');
});

test('completes blocks available for search files', async () => {
const expected = [
new vscode.CompletionItem('list', vscode.CompletionItemKind.Class),
new vscode.CompletionItem('locals', vscode.CompletionItemKind.Class),
new vscode.CompletionItem('provider', vscode.CompletionItemKind.Class),
new vscode.CompletionItem('variable', vscode.CompletionItemKind.Class),
];

await testCompletion(docUri, new vscode.Position(1, 0), {
items: expected,
});
});
});

suite('list', function suite() {
const docUri = getDocUri('main.tfquery.hcl');

this.beforeAll(async () => {
await open(docUri);
await activateExtension();
});

this.afterAll(async () => {
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
});

this.afterEach(async () => {
// revert any changes made to the document after each test
await vscode.commands.executeCommand('workbench.action.files.revert');
});

test('language is registered', async () => {
const doc = await vscode.workspace.openTextDocument(docUri);
assert.equal(doc.languageId, 'terraform-search', 'document language should be `terraform-search`');
});

test('completes attributes of list block - provider', async () => {
const expected = [
new vscode.CompletionItem('aws.this', vscode.CompletionItemKind.Variable),
new vscode.CompletionItem('azurerm.this', vscode.CompletionItemKind.Variable),
];

await testCompletion(docUri, new vscode.Position(24, 21), {
items: expected,
});
});

test('completes attributes of list block - number variable', async () => {
const expected = [
new vscode.CompletionItem('count.index', vscode.CompletionItemKind.Variable),
new vscode.CompletionItem('local.number_local', vscode.CompletionItemKind.Variable),
new vscode.CompletionItem('var.number_variable', vscode.CompletionItemKind.Variable),
];

await testCompletion(docUri, new vscode.Position(25, 21), {
items: expected,
});
});

test('completes attributes of list block - boolean variable', async () => {
const expected = [
new vscode.CompletionItem('false', vscode.CompletionItemKind.EnumMember),
new vscode.CompletionItem('true', vscode.CompletionItemKind.EnumMember),
new vscode.CompletionItem('var.boolean_variable', vscode.CompletionItemKind.Variable),
];

await testCompletion(docUri, new vscode.Position(26, 21), {
items: expected,
});
});
});
});
12 changes: 12 additions & 0 deletions src/test/integration/search/workspace/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "=3.0.0"
}
}
}
32 changes: 32 additions & 0 deletions src/test/integration/search/workspace/main.tfquery.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

provider "aws" {
alias = "this"
}

provider "azurerm" {
alias = "this"
}

variable "boolean_variable" {
default = true
type = bool
}

locals {
number_local = 500
}

variable "number_variable" {
default = 10
type = number
}

list "concept_pet" "name_1" {
provider =
limit =
include_resource =
count = 10
config {

}
}
Loading