swiftlang / vscode-swift

Visual Studio Code Extension for Swift
https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang
Apache License 2.0
709 stars 47 forks source link

Provide a UI workflow for selecting the swift toolchain #756

Closed daveyc123 closed 1 month ago

daveyc123 commented 2 months ago

Currently the extension provides a mechanism to discover installed toolchains and automatically sets a toolchain (via the vscode configuration settings).

Users should have the ability to run a command and select from the list of installed toolchains. When a toolchain isn't installed, they should be guided on how to install one.

matthewbastien commented 2 months ago

I can take this one.

adam-fowler commented 2 months ago

I guess on macOS you can check the version of macOS installed, contents of /Library/Developer/Toolchains and ~/Library/Developer/Toolchains. There is already a command that allows you to choose Xcode installs Swift: Select Xcode Developer Dir....

On Linux this would be some interaction with Swiftly. This could become a much bigger task.

Ideally swiftly could be used for toolchain management on all platforms and the VSCode extension would use it. In a similar manner to how the rust-analyzer extension works with rustup.

matthewbastien commented 1 month ago

Existing Functionality

There are currently two settings that control toolchain selection:

The swift.path setting is the primary method of setting the toolchain. The user must specify the full path to the usr/bin directory within the toolchain that they’ve installed. Failing to do so will yield a cryptic error message (see the Existing UI section below).

The DEVELOPER_DIR environment only works on MacOS. There’s an existing command for selecting an Xcode developer directory (Swift: Select Xcode Developer Dir...). This command is only shown in the command palette if the current platform is MacOS and will show the user a Quick Select to choose between different versions of Xcode installed on their machine. However, the swift toolchain path must be set manually.

On startup, the swift extension will check the swift.path setting. If the user has provided the path then it will use that, otherwise it uses one of the following platform specific methods to find the swift binary:

It then runs swift --version default to find out which version of swift is being used. Additionally, on Windows where swiftCore.dll is used to determine the path to the swift runtime. If either of these steps fails then the extension will fail to activate and show the following error messages:

failed_activation

In this state, none of the extension commands work. This includes the new project creation wizard which displays the following error when used:

create_project_failure

Proposed Functionality

The UI will have to vary based on platform much like the toolchain discovery. However, the entry point will be common between all of them: a Swift: Select Toolchain.... command that can be accessed via the command palette:

select_toolchain_command_palette

Another entry point to this workflow will be when the extension is unable to discover a swift toolchain on startup. The extension should successfully activate regardless of whether or not a swift binary is found, but should only allow a subset of functionality when doing so. We also should provide a better error message informing the user how to install swift:

toolchain_discovery_error

Selecting the Download option will open the user’s browser to https://swift.org/install/ where they can download and install a swift toolchain. As it stands right now, the swift extension must be reloaded in order for toolchain auto-discovery to happen again. A new warning message will appear asking them to reload the extension in this case:

reload_extension_warning

Selecting the Select Toolchain Folder option shows the open folder dialog for your platform. Selecting a folder in this way will update the swift.path setting.

macOS Toolchain Selection

macOS has a built-in way of discovering toolchains by finding Xcode installations. We can perform auto discovery in the following order on extension activation:

  1. Find the swift binary in PATH
  2. Find the currently selected Xcode - Xcode-select -p
  3. Find any swift toolchains in /Library/Developer/Toolchains and ~/Library/Developer/Toolchains
  4. Find available Xcode installs - mdfind "kMDItemCFBundleIdentifier == 'com.apple.dt.Xcode'"

When a user attempts to change the toolchain via the swift extension, we should show them the list of available Xcode installations or let them choose a path on their machine.

macOS_toolchain_selection

The user can also opt to download a toolchain from Swift.org or to manually select a toolchain directory. The latter option will configure swift.path to the directory that the user selects.

Linux Toolchain Selection

Linux doesn’t really have a built-in way to find swift toolchains other than by looking at PATH. For this platform the plan is to auto-detect Swiftly installations since this is the only other way to install toolchains aside from swift.org/install.

Toolchain discovery would be performed in the following order on extension activation:

  1. Find the swift binary in PATH
  2. Discover Swiftly toolchain installations using corresponding environment variables.

Swiftly has a configuration file ($SWIFTLY_HOME_DIR/config.json) that can be used to determine available toolchains:

{
  "installedToolchains" : [
    "5.10.0"
  ],
  "platform" : {
    "namePretty" : "Ubuntu 22.04.4 LTS",
    "name" : "ubuntu2204",
    "architecture" : "aarch64",
    "nameFull" : "ubuntu22.04"
  },
  "inUse" : "5.10.0"
}

Toolchains are stored in separate directories under $SWIFTLY_HOME_DIR/toolchains/ named as the corresponding version number in the config.json:

❯ ls "$SWIFTLY_HOME_DIR/toolchains"

5.10.0

We will show these options in the toolchain selection dialog. However, selecting the toolchain will only update the swift.path setting and not invoke swiftly at all:

linux_toolchain_selection

The user can also opt to download a toolchain from Swift.org or to manually select a toolchain directory. The latter option will configure swift.path to the directory that the user selects.

Windows Toolchain Selection

Right now on windows we can only offer the option to download swift from https://www.swift.org/install/ and have them switch toolchains by selecting the directory where swift is installed. Auto-detection will only involve looking for swift in PATH on extension activation. We will only offer two options for now:

windows_toolchain_selection

The first option opens the user’s browser to https://swift.org/install/ where they can download an install a swift version.

Opting to select the toolchain directory will open up the file explorer where the user can select a folder that will be populated into the swift.path setting.

Saving the Toolchain Configuration

After the user selects the toolchain they would like to use, we have to decide where to save this in the Visual Studio Code configuration. There are three possibilities:

If no Workspace is opened, then we can safely default to Global. However, in all other cases we must ask the user which configuration they would like to update. The example UI below shows the case where the user has a workspace open with two workspace folders named swift-executable and swift-library:

configuration_selection
matthewbastien commented 1 month ago

@adam-fowler I would love to get some feedback on this before I get around to implementing it.

adam-fowler commented 1 month ago

In the way rust-analyzer extensions uses rustup to manage rust toolchains, the swift extension should use swiftly to manage swift toolchains.

So the target is to get swiftly to be the standard swift install tool across all platforms. In a way I'd prefer that swiftly for macOS was implemented first. Then we wouldn't be wasting time setting up a macOS solution which we'd dump once swiftly became available.

Err yeah Windows. Not really got a solution here. You could use the file finder at the moment, but I'd prefer we are sure multiple toolchains on one machine works ok before even considering providing this. Also the recommended way to install on Windows is via a package manager eg Windows Package Manager or Scoop.

matthewbastien commented 1 month ago

Thanks for the feedback! My main issues with prompting users to install swiftly right now are:

I'd love to get swiftly to the point where it can be used as the recommended installation method, but I think a decent compromise in the meantime is to detect installed swiftly toolchains and allow the user to point the swift extension at a specific one. Using swiftly to download/install toolchains requires a separate discussion about what users expect the swift extension to do. E.g. right now swiftly use globally changes the swift version which would be problematic if the user wants to have multiple different toolchains to use on a per-project basis.

I'd rather read the swiftly configuration file's JSON format and make that API than have to parse the output from swiftly list. Though if the plan is to modify swiftly itself to support this then we could add a --json option or similar.

Yes, users are expected to download the toolchain themselves either via swift.org/install or swiftly if they choose to go that route. I can raise a separate follow up issue to discuss having the extension install toolchains via swiftly.