diff --git a/.changes/unreleased/ENHANCEMENTS-20240827-144543.yaml b/.changes/unreleased/ENHANCEMENTS-20240827-144543.yaml new file mode 100644 index 000000000..8d3358c11 --- /dev/null +++ b/.changes/unreleased/ENHANCEMENTS-20240827-144543.yaml @@ -0,0 +1,6 @@ +kind: ENHANCEMENTS +body: Document Terraform Stacks support +time: 2024-08-27T14:45:43.975259-04:00 +custom: + Issue: "1802" + Repository: terraform-ls diff --git a/docs/USAGE.md b/docs/USAGE.md index 8dc6feefb..8c0a3dbd2 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -8,14 +8,15 @@ The following filetypes are supported by the Terraform Language Server: - `terraform` - standard `*.tf` config files - `terraform-vars` - variable files (`*.tfvars`) +- `terraform-stack` - standard `*.tfstack.hcl` files +- `terraform-deploy` - standard `*.tfstack.hcl` files -*NOTE* Clients should be configured to follow the above language ID conventions +_NOTE:_ Clients should be configured to follow the above language ID conventions and do **not** send `*.tf.json`, `*.tfvars.json` nor Packer HCL config -nor any other HCL config files as the server is not -equipped to handle these file types. +nor any other HCL config files as the server is not equipped to handle these file types. -In most clients with a dedicated Terraform extension/plugin this is -already the default configuration, so you should not need to worry about it. +Most clients with a dedicated Terraform extension/plugin +already have the default configuration, so you should not need to worry about it. Instructions for popular IDEs are below and pull requests for updates or addition of more IDEs are welcomed. @@ -25,78 +26,53 @@ how you may configure the settings. ## Workspaces / Folders / Files -Most editors support opening folders. Such a root folder is commonly referred to -as "workspace". Opening folders is always preferred over individual files -as it allows the language server to index the whole folder and keep track -of changes more easily. We do however support "single-file mode" which provides -limited IntelliSense. +Most text editors allow you to open files to edit a single file, or a folder to +edit many files at once. When opening a folder, this is commonly referred to +as "workspace" or "root folder". -Indexing enables IntelliSense related to `module` blocks, -such as go-to-definition, completion of `module.*` references, -or workspace-wide symbol lookup. +Opening folders is always preferred over individual files as it allows +the language server to index the whole folder and keep track of changes +more easily. We do however support "single-file mode" which provides +limited IntelliSense. + +Indexing enables IntelliSense related to `module` blocks, such as +go-to-definition, completion of `module.*` references, or workspace-wide +symbol lookup. The server will _not_ index any folders or files above the workspace root initially opened in the editor. -## Emacs +## Editors -If you are using `use-package`, you can put this in the [init.el](https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html) -file to install `lsp-mode`: +### Visual Studio Code -```emacs-lisp -(use-package lsp-mode - :ensure t - :hook ((terraform-mode . lsp-deferred))) -``` +- Install the [Terraform VS Code Extension](https://marketplace.visualstudio.com/items?itemName=hashicorp.terraform) `>=2.24.0` +- The latest compatible version of [terraform-ls](https://github.com/hashicorp/terraform-ls) is bundled with the extension +- See [VS Code Configuration](https://github.com/hashicorp/vscode-terraform/blob/main/README.md#configuration) in case you need to tweak anything. Default settings should work for majority of users. -There are various other ways to install `lsp-mode` and they are -documented [here.](https://emacs-lsp.github.io/lsp-mode/page/installation/#installation) +### Sublime Text -The `lsp-mode` language client for Terraform supports various features -like semantic tokens, code lens for references etc. There is more -detailed documentation [here](https://emacs-lsp.github.io/lsp-mode/page/lsp-terraform-ls/). +- Install the [LSP package](https://github.com/sublimelsp/LSP#installation) +- Install the [LSP-terraform package](https://github.com/sublimelsp/LSP-terraform#installation) -## IntelliJ IDE +### Vim / NeoVim - - Install [LSP Support plugin](https://plugins.jetbrains.com/plugin/10209-lsp-support) - - Open Settings - - Go to `Languages & Frameworks → Language Server Protocol → Server Definitions` - - Pick `Executable` - - set `Extension` to `tf` - - set `Path` to `terraform-ls` - - set `Args` to `serve` - - Confirm by clicking `Apply` +#### coc.nvim -Please note that the [Terraform plugin](https://plugins.jetbrains.com/plugin/7808-hashicorp-terraform--hcl-language-support) -provides overlapping functionality (and more features at the time of writing). -As a result having both enabled at the same time may result in suboptimal UX, -such as duplicate completion candidates. - -## Sublime Text - - - Install the [LSP package](https://github.com/sublimelsp/LSP#installation) - - Install the [LSP-terraform package](https://github.com/sublimelsp/LSP-terraform#installation) - -## Vim / NeoVim -### coc.nvim - - - Install the [coc.nvim plugin](https://github.com/neoclide/coc.nvim) - - Add the following snippet to the `coc-setting.json` file (editable via `:CocConfig` in NeoVim) +- Install the [coc.nvim plugin](https://github.com/neoclide/coc.nvim) +- Add the following snippet to the `coc-setting.json` file (editable via `:CocConfig` in NeoVim) ```json { - "languageserver": { - "terraform": { - "command": "terraform-ls", - "args": ["serve"], - "filetypes": [ - "terraform", - "tf" - ], - "initializationOptions": {}, - "settings": {} - } - } + "languageserver": { + "terraform": { + "command": "terraform-ls", + "args": ["serve"], + "filetypes": ["terraform", "tf"], + "initializationOptions": {}, + "settings": {} + } + } } ``` @@ -107,14 +83,14 @@ Make sure to read through the [example vim configuration](https://github.com/neo inoremap coc#refresh() ``` -### vim-lsp +#### vim-lsp - - [Install](https://opensource.com/article/20/2/how-install-vim-plugins) the following plugins: - * [async.vim plugin](https://github.com/prabirshrestha/async.vim) - * [vim-lsp plugin](https://github.com/prabirshrestha/vim-lsp) - * [asyncomplete.vim plugin](https://github.com/prabirshrestha/asyncomplete.vim) - * [asyncomplete-lsp.vim plugin](https://github.com/prabirshrestha/asyncomplete-lsp.vim) - - Add the following to your `.vimrc`: +- [Install](https://opensource.com/article/20/2/how-install-vim-plugins) the following plugins: + - [async.vim plugin](https://github.com/prabirshrestha/async.vim) + - [vim-lsp plugin](https://github.com/prabirshrestha/vim-lsp) + - [asyncomplete.vim plugin](https://github.com/prabirshrestha/asyncomplete.vim) + - [asyncomplete-lsp.vim plugin](https://github.com/prabirshrestha/asyncomplete-lsp.vim) +- Add the following to your `.vimrc`: ```vim if executable('terraform-ls') @@ -126,10 +102,11 @@ if executable('terraform-ls') endif ``` -### YouCompleteMe - - [Install](https://opensource.com/article/20/2/how-install-vim-plugins) the following plugins: - * [YouCompleteMe plugin](https://github.com/ycm-core/YouCompleteMe) - - Add the following to your `.vimrc`: +#### YouCompleteMe + +- [Install](https://opensource.com/article/20/2/how-install-vim-plugins) the following plugins: + - [YouCompleteMe plugin](https://github.com/ycm-core/YouCompleteMe) +- Add the following to your `.vimrc`: ```vim " Remove this line if additional custom language servers are set elsewhere @@ -147,10 +124,10 @@ if executable('terraform-ls') endif ``` -### LanguageClient-neovim +#### LanguageClient-neovim - - Install the [LanguageClient-neovim plugin](https://github.com/autozimu/LanguageClient-neovim) - - Add the following to your `.vimrc`: +- Install the [LanguageClient-neovim plugin](https://github.com/autozimu/LanguageClient-neovim) +- Add the following to your `.vimrc`: ```vim let g:LanguageClient_serverCommands = { @@ -158,10 +135,10 @@ let g:LanguageClient_serverCommands = { \ } ``` -### Neovim v0.5.0+ +#### Neovim v0.5.0+ - - Install the [nvim-lspconfig plugin](https://github.com/neovim/nvim-lspconfig) - - Add the following to your `.vimrc` or `init.vim`: +- Install the [nvim-lspconfig plugin](https://github.com/neovim/nvim-lspconfig) +- Add the following to your `.vimrc` or `init.vim`: ```vim lua <=2.24.0` - - Latest compatible version of the language server is bundled with the extension - - See [Configuration](https://github.com/hashicorp/vscode-terraform/blob/main/README.md#configuration) in case you need to tweak anything. Default settings should work for majority of users though. +### IntelliJ IDE -## BBEdit +- Install [LSP Support plugin](https://plugins.jetbrains.com/plugin/10209-lsp-support) +- Open Settings +- Go to `Languages & Frameworks → Language Server Protocol → Server Definitions` + - Pick `Executable` + - set `Extension` to `tf` + - set `Path` to `terraform-ls` + - set `Args` to `serve` +- Confirm by clicking `Apply` -*BBEdit 14 [added support](https://www.barebones.com/support/bbedit/lsp-notes.html) for the Language Server Protocol so you'll need to upgrade to version 14 to use; this won't work for older versions of BBEdit*. +Please note that the [Terraform plugin](https://plugins.jetbrains.com/plugin/7808-hashicorp-terraform--hcl-language-support) +provides overlapping functionality (and more features at the time of writing). +As a result having both enabled at the same time may result in suboptimal UX, +such as duplicate completion candidates. + +### BBEdit + +_BBEdit 14 [added support](https://www.barebones.com/support/bbedit/lsp-notes.html) for the Language Server Protocol so you'll need to upgrade to version 14 to use; this won't work for older versions of BBEdit_. - Open Preferences > Languages -- In *Language-specific settings* section, add an entry for Terraform -- In the Server tab, Set *Command* to `terraform-ls` and *Arguments* to `serve` +- In _Language-specific settings_ section, add an entry for Terraform +- In the Server tab, Set _Command_ to `terraform-ls` and _Arguments_ to `serve` - Once you've correctly installed `terraform-ls` and configured BBEdit, the status indicator on this settings panel will flip to green -- If you'd like to pass any [settings](./SETTINGS.md) to the server you can do so via the *Arguments* field. +- If you'd like to pass any [settings](./SETTINGS.md) to the server you can do so via the _Arguments_ field. -## Kate +### Kate KDE [Kate editor](https://kate-editor.org/) supports LSP and is user configurable. - Install the `terraform-ls` package (or the equivalent package name appropriate to your distro) - Open Kate configuration (Settings Menu -> `Configure` Kate or Kate -> `Preferences` on macOS) -- Select *LSP Client* in the left pane -- Select *User Server Settings* tab -- Paste the following JSON and *Save*: +- Select _LSP Client_ in the left pane +- Select _User Server Settings_ tab +- Paste the following JSON and _Save_: + ```json { "servers": { @@ -241,4 +251,5 @@ KDE [Kate editor](https://kate-editor.org/) supports LSP and is user configurabl } } ``` -- Restart of the editor should *not* be necessary. + +- Restart of the editor should _not_ be necessary. diff --git a/docs/architecture.md b/docs/architecture.md index 917e75654..777612e43 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -90,6 +90,16 @@ The `jobs` package of each feature contains all the different indexing jobs need - `ObtainSchema` - obtains provider schemas via `terraform providers schema -json` - `ParseProviderVersions` is a job complimentary to `ObtainSchema` in that it obtains versions of providers/schemas from Terraform CLI's lock file +### Stack Feature Jobs + +- `ParseStackConfiguration` - parses `*.tfstack.hcl` and `*.tfdeploy.hcl` files to turn `[]byte` into `hcl` types (AST) +- `LoadStackMetadata` - uses [`earlydecoder`](https://pkg.go.dev/github.com/hashicorp/terraform-schema@main/stacks/earlydecoder) to do early TF version-agnostic decoding to obtain metadata (variables, outputs etc.) which can be used to do more detailed decoding in hot-path within `hcl-lang` decoder +- `PreloadEmbeddedSchema` – loads provider schemas based on provider requirements from the bundled schemas +- `DecodeReferenceTargets` - uses `hcl-lang` decoder to collect reference targets within `*.tfstack.hcl` and `*.tfdeploy.hcl` +- `DecodeReferenceOrigins` - uses `hcl-lang` decoder to collect reference origins within `*.tfstack.hcl` and `*.tfdeploy.hcl` +- `SchemaStackValidation` - does schema-based validation of module files (`*.tfstack.hcl` and `*.tfdeploy.hcl`) and produces diagnostics associated with any "invalid" parts of code +- `ReferenceValidation` - does validation based on (mis)matched reference origins and targets, to flag up "orphaned" references + ### Adding a new feature / "language" The existing `variables` feature is a good starting point when introducing a new language. Usually you need to roughly follow these steps to get a minimal working example: diff --git a/docs/language-clients.md b/docs/language-clients.md index 3f605220c..0069bd2bf 100644 --- a/docs/language-clients.md +++ b/docs/language-clients.md @@ -6,8 +6,10 @@ This document contains notes for language client developers. The following file types are currently supported and language IDs expected: - - `terraform` - standard `*.tf` config files - - `terraform-vars` - variable files (`*.tfvars`) +- `terraform` - standard `*.tf` config files +- `terraform-vars` - variable files (`*.tfvars`) +- `terraform-stack` - standard `*.tfstack.hcl` files +- `terraform-deploy` - standard `*.tfstack.hcl` files Client can choose to highlight other files locally, but such other files must **not** be send to the server as the server isn't equipped to handle those. @@ -44,7 +46,7 @@ This allows IntelliSense to remain accurate e.g. when switching branches in VCS or when there are any other changes made to these files outside the editor. If the client implements file watcher, it should watch for any changes -in `**/*.tf` and `**/*.tfvars` files in the workspace. +in `**/*.tf`, `**/*.tfvars`, `**/*.tfstack.hcl` and `**/*.tfstack.hcl` files in the workspace. Client should **not** send changes for any other files. @@ -85,8 +87,8 @@ Language server supports multiple folders natively from version `0.19`. Client is expected to always launch a single instance of the server and check for [`workspace.workspaceFolders.supported`](https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#workspaceFoldersServerCapabilities) server capability, and then: - - launch any more instances (_one instance per folder_) if multiple folders are _not supported_ - - avoid launching any more instances if multiple folders _are supported_ +- launch any more instances (_one instance per folder_) if multiple folders are _not supported_ +- avoid launching any more instances if multiple folders _are supported_ It is assumed that paths to these folders will be provided as part of `workspaceFolders` in the `initialize` request per LSP. @@ -105,7 +107,7 @@ A Code Action is an action that changes content in the active editor. Each Code In VS Code, code action can be _invoked manually_ or _automatically_ based on the respective [CodeActionTriggerKind](https://code.visualstudio.com/api/references/vscode-api#CodeActionTriggerKind). -**Manually invoked** actions come from the contextual in-line💡 icon inside the editor, and are chosen by the user. The user can choose which action is invoked and *then* invoke it. However, in order for the client to display the contextual actions, the client requests LS to "pre-calculate" any actions relevant to the cursor position. Then, when the user selects the action in the UI, the client applies the `edits` or executes the `command` as provided by the server. +**Manually invoked** actions come from the contextual in-line💡 icon inside the editor, and are chosen by the user. The user can choose which action is invoked and _then_ invoke it. However, in order for the client to display the contextual actions, the client requests LS to "pre-calculate" any actions relevant to the cursor position. Then, when the user selects the action in the UI, the client applies the `edits` or executes the `command` as provided by the server. **Automatically triggered** actions come from events such as "on save", as configured via the `editor.codeActionsOnSave` setting. These usually do not give much choice to the user, they are either on or off, as they cannot accept user input. For example, formatting a document or removing simple style errors don't prompt for user action before or during execution. @@ -154,11 +156,11 @@ For example: ```json { - "capabilities": { - "experimental": { - "showReferencesCommandId": "client.showReferences" - } + "capabilities": { + "experimental": { + "showReferencesCommandId": "client.showReferences" } + } } ``` @@ -168,13 +170,13 @@ The client-side command is executed with 2 arguments (position, reference contex ```json [ - { - "line": 0, - "character": 8 - }, - { - "includeDeclaration": false - } + { + "line": 0, + "character": 8 + }, + { + "includeDeclaration": false + } ] ``` @@ -184,7 +186,6 @@ that position and finally display received references in the editor. See [example implementation in the Terraform VS Code extension](https://github.com/hashicorp/vscode-terraform/pull/686). - ## Custom Commands Clients are encouraged to implement custom commands