Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single LanguageClient #834

Closed
wants to merge 14 commits into from
Closed

Single LanguageClient #834

wants to merge 14 commits into from

Conversation

jpogran
Copy link
Contributor

@jpogran jpogran commented Nov 4, 2021

  • Update extension tests
  • Refactor to Single LanguageClient
  • Extract supported commands to class property
  • Simplify creating TerraformLanguageClient
  • Extract resolvePathToBinary to ServerPath
  • Fix ModuleProvider starting before client ready
  • Enable LS in main activation flow
  • Brand OutputChannel
  • figure out if onDidChangeWorkspaceFolders still needed
  • simplify creating language clients
  • strongly type extension activation

Close #816

Relies on test fixes in #828

@jpogran jpogran self-assigned this Nov 4, 2021
@jpogran jpogran added bug Something isn't working enhancement New feature or request labels Nov 4, 2021
@jpogran jpogran linked an issue Nov 4, 2021 that may be closed by this pull request
Refactors ClientHandler to only use one `LanguageClient` per extension activation. Removes the Map of `LanguageClients` and ensures that any attempt to use a `LanguageClient` or method happens after the onReady event finishes.

Previously the VS Code extension would create a `LanguageClient` for each folder that was added to the current workspace. Each `LanguageClient` would handle all events and receive notifications/requests from the LS for the folders it was responsible for.

This was handled by a `Map` of clients created at activation and populated each time a client was created. However there were conditions in which an event would occur before a client was created or finished being ready, so an attempt to access the `Map` would result in an unhandled exception. A common example was having an file that was already opened when VS Code was opened. The file would trigger an `onDidChangeVisibleTextEditors` event, which would try to get the list of module calls used, which would fail because the client had not started yet.

The terraform-ls sever implemented multi-folder/workspace support in hashicorp/terraform-ls#502. This means the VS Code extension no longer needs multiple clients to track how many folders are added to the current workspace and which event for which file needs to be sent at certain times.
Moves the list of supported commands to a private property of the ClientHandler class and populates it when the client and LS are initialized.

Previously you could attempt to ask the server what commands were supported before the client and server had finished the initialization process. This would result in an unhandled exception and leave the client in an unknown state.

Moving the query to the `onReady` function ensures we only ask after the server has finished initializing and is ready to respond.
Refactor the createTerraformClient method to reduce complexity and verbosity by using language constructs. Move variables closer to usage for future method extraction.

In d707a6d we moved to a single LanguageClient in the extension. This means we no longer need to track the `location` or `workspaceFolder` to pull settings or display information per folder. This greatly simplifies the code accessing settings and creating the LanguageClient.
Extract `resolvePathToBinary` method to the ServerPath class. The `resolvedPathToBinary` resolves the LS filesystem path and uses methods inside the ServerPath class. The ClientHandler class is only responsible for LanguageClients, and so does not need this private method.
Only enable the ModuleProvider if the LS is enabled, as it requires functionality from the LS to operate.
Directly call `updateLanguageServer` in the main execution flow and await return instead of inside a `executeCommand` call.

The `terraform.enableLanguageServer` command checks if the LS is enabled, then returns `updateLanguageServer`. We already checked if the LS is enabled before calling `terraform.enableLanguageServer`, so we are duplicating effort here. There is also no reason to nest the async calls to the main functionality of our extension inside a `executeCommand` call.

Technically `executeCommand` calls are supposed to be commands that initiate actions/commands/things inside the workspace, not long running operations. This does not match well with running the primary execution work flow of our extension.
Move creation of the OutputChannel to the main flow and only create one outputChannel for the entire extension. Use 'HashiCorp Terraform' as the name the OutputChannel to brand our extension.

The OutputChannel is the main way to log information for the user to see. By convention there is one for each extension and the content is meant to be human readable. The `name` is displayed in a drop down in the `Output` pane in the editor, so it should be reconizable and readable.

Currently we set `terraform-ls` or `terraform-ls 'location'` for the name. This lower cased name is hard to find in the drop down, espcially compared to other extensions that use their company name and language to disambiguate from others.

Setting the name to `HashiCorp Terraform` ensures we are easy to read and differentiate from other extensions. Creating only one for the entire extension makes it easier for users to find out information as well as allowing us to automate collecting logs for bug report submission.
@jpogran jpogran force-pushed the single-language-client branch from aa878d2 to ebc76b4 Compare November 5, 2021 14:40
}

const experimentalFeatures = config('terraform-ls').get('experimentalFeatures');
const initializationOptions = Object.assign(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wondering if something like this is more readable:

const initializationOptions = {
      ...experimentalFeatures,
      ...(terraformExecPath.length > 0 && { terraformExecPath }),
      ...(terraformExecTimeout.length > 0 && { terraformExecTimeout }),
      ...
    };

@jpogran jpogran force-pushed the single-language-client branch from 6e4cd98 to 49ddf6f Compare November 5, 2021 15:24
@jpogran jpogran force-pushed the single-language-client branch from 49ddf6f to 69f59d9 Compare November 5, 2021 15:43
@jpogran
Copy link
Contributor Author

jpogran commented Nov 10, 2021

Superseded by #845

@jpogran jpogran closed this Nov 10, 2021
@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 11, 2021
@jpogran jpogran deleted the single-language-client branch January 26, 2022 15:34
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Drop support of (old) LS without multiple folders
2 participants