Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
with:
needs_token: true
# Linux
linux_exclude_swift_versions: '[{"swift_version": "nightly-6.1"},{"swift_version": "nightly-6.2"},{"swift_version": "nightly-main"}]'
linux_exclude_swift_versions: "${{ contains(github.event.pull_request.labels.*.name, 'full-test-run') && '[{\"swift_version\": \"nightly-6.1\"}]' || '[{\"swift_version\": \"nightly-6.1\"},{\"swift_version\": \"nightly-6.2\"},{\"swift_version\": \"nightly-main\"}]' }}"
linux_env_vars: |
NODE_VERSION=v20.19.0
NODE_PATH=/usr/local/nvm/versions/node/v20.19.0/bin
Expand All @@ -61,7 +61,7 @@ jobs:
linux_pre_build_command: . .github/workflows/scripts/setup-linux.sh
linux_build_command: ./scripts/test.sh
# Windows
windows_exclude_swift_versions: '[{"swift_version": "nightly-6.1"},{"swift_version": "nightly-6.2"},{"swift_version": "nightly"}]'
windows_exclude_swift_versions: "${{ contains(github.event.pull_request.labels.*.name, 'full-test-run') && '[{\"swift_version\": \"nightly-6.1\"},{\"swift_version\": \"nightly\"}]' || '[{\"swift_version\": \"nightly-6.1\"},{\"swift_version\": \"nightly-6.2\"},{\"swift_version\": \"nightly\"}]' }}"
windows_env_vars: |
CI=1
FAST_TEST_RUN=${{ contains(github.event.pull_request.labels.*.name, 'full-test-run') && '0' || '1'}}
Expand Down
20 changes: 20 additions & 0 deletions assets/test/documentation-live-preview/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "documentation-live-preview",
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "Library",
targets: ["Library"]),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "Library"),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Getting Started

This is the getting started page.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@Tutorial(time: 30) {
@Intro(title: "Library") {
Library Tutorial
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@Tutorials(name: "SlothCreator") {
@Intro(title: "Meet Library") {
Library Tutorial Overview
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book

/// The entry point for this arbitrary library.
///
/// Used for testing the Documentation Live Preview.
public struct EntryPoint {
/// The name of this EntryPoint
public let name: String

/// Creates a new EntryPoint
/// - Parameter name: the name of this entry point
public init(name: String) {
self.name = name
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Used to test Live Preview with an unsupported file.
7 changes: 3 additions & 4 deletions src/SwiftSnippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import * as vscode from "vscode";
import * as path from "path";
import contextKeys from "./contextKeys";
import { createSwiftTask } from "./tasks/SwiftTaskProvider";
import { WorkspaceContext } from "./WorkspaceContext";
import { createSnippetConfiguration, debugLaunchConfig } from "./debugger/launch";
Expand All @@ -30,16 +29,16 @@ export function setSnippetContextKey(ctx: WorkspaceContext) {
!ctx.currentDocument ||
ctx.currentFolder.swiftVersion.isLessThan({ major: 5, minor: 7, patch: 0 })
) {
contextKeys.fileIsSnippet = false;
ctx.contextKeys.fileIsSnippet = false;
return;
}

const filename = ctx.currentDocument.fsPath;
const snippetsFolder = path.join(ctx.currentFolder.folder.fsPath, "Snippets");
if (filename.startsWith(snippetsFolder)) {
contextKeys.fileIsSnippet = true;
ctx.contextKeys.fileIsSnippet = true;
} else {
contextKeys.fileIsSnippet = false;
ctx.contextKeys.fileIsSnippet = false;
}
return;
}
Expand Down
29 changes: 15 additions & 14 deletions src/WorkspaceContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { LanguageClientToolchainCoordinator } from "./sourcekit-lsp/LanguageClie
import { TaskManager } from "./tasks/TaskManager";
import { makeDebugConfigurations } from "./debugger/launch";
import configuration from "./configuration";
import contextKeys from "./contextKeys";
import { ContextKeys } from "./contextKeys";
import { setSnippetContextKey } from "./SwiftSnippets";
import { CommentCompletionProviders } from "./editor/CommentCompletion";
import { SwiftBuildStatus } from "./ui/SwiftBuildStatus";
Expand Down Expand Up @@ -77,6 +77,7 @@ export class WorkspaceContext implements vscode.Disposable {

constructor(
extensionContext: vscode.ExtensionContext,
public contextKeys: ContextKeys,
public logger: SwiftLogger,
public globalToolchain: SwiftToolchain
) {
Expand Down Expand Up @@ -233,9 +234,9 @@ export class WorkspaceContext implements vscode.Disposable {
*/
updateContextKeys(folderContext: FolderContext | null) {
if (!folderContext) {
contextKeys.hasPackage = false;
contextKeys.hasExecutableProduct = false;
contextKeys.packageHasDependencies = false;
this.contextKeys.hasPackage = false;
this.contextKeys.hasExecutableProduct = false;
this.contextKeys.packageHasDependencies = false;
return;
}

Expand All @@ -244,9 +245,9 @@ export class WorkspaceContext implements vscode.Disposable {
folderContext.swiftPackage.executableProducts,
folderContext.swiftPackage.dependencies,
]).then(([foundPackage, executableProducts, dependencies]) => {
contextKeys.hasPackage = foundPackage;
contextKeys.hasExecutableProduct = executableProducts.length > 0;
contextKeys.packageHasDependencies = dependencies.length > 0;
this.contextKeys.hasPackage = foundPackage;
this.contextKeys.hasExecutableProduct = executableProducts.length > 0;
this.contextKeys.packageHasDependencies = dependencies.length > 0;
});
}

Expand All @@ -258,23 +259,23 @@ export class WorkspaceContext implements vscode.Disposable {
const target = await this.currentFolder?.swiftPackage.getTarget(
this.currentDocument?.fsPath
);
contextKeys.currentTargetType = target?.type;
this.contextKeys.currentTargetType = target?.type;
} else {
contextKeys.currentTargetType = undefined;
this.contextKeys.currentTargetType = undefined;
}

if (this.currentFolder) {
const languageClient = this.languageClientManager.get(this.currentFolder);
await languageClient.useLanguageClient(async client => {
const experimentalCaps = client.initializeResult?.capabilities.experimental;
if (!experimentalCaps) {
contextKeys.supportsReindexing = false;
contextKeys.supportsDocumentationLivePreview = false;
this.contextKeys.supportsReindexing = false;
this.contextKeys.supportsDocumentationLivePreview = false;
return;
}
contextKeys.supportsReindexing =
this.contextKeys.supportsReindexing =
experimentalCaps[ReIndexProjectRequest.method] !== undefined;
contextKeys.supportsDocumentationLivePreview =
this.contextKeys.supportsDocumentationLivePreview =
experimentalCaps[DocCDocumentationRequest.method] !== undefined;
});
}
Expand All @@ -293,7 +294,7 @@ export class WorkspaceContext implements vscode.Disposable {
break;
}
}
contextKeys.packageHasPlugins = hasPlugins;
this.contextKeys.packageHasPlugins = hasPlugins;
}

/** Setup the vscode event listeners to catch folder changes and active window changes */
Expand Down
3 changes: 1 addition & 2 deletions src/commands/dependencies/updateDepViewList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@
//
//===----------------------------------------------------------------------===//

import contextKeys from "../../contextKeys";
import { FolderOperation, WorkspaceContext } from "../../WorkspaceContext";

export function updateDependenciesViewList(ctx: WorkspaceContext, flatList: boolean) {
if (ctx.currentFolder) {
contextKeys.flatDependenciesList = flatList;
ctx.contextKeys.flatDependenciesList = flatList;
void ctx.fireEvent(ctx.currentFolder, FolderOperation.packageViewUpdated);
}
}
11 changes: 2 additions & 9 deletions src/contextKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Version } from "./utilities/version";
*/

/** Interface for getting and setting the VS Code Swift extension's context keys */
interface ContextKeys {
export interface ContextKeys {
/**
* Whether or not the swift extension is activated.
*/
Expand Down Expand Up @@ -96,7 +96,7 @@ interface ContextKeys {
}

/** Creates the getters and setters for the VS Code Swift extension's context keys. */
function createContextKeys(): ContextKeys {
export function createContextKeys(): ContextKeys {
let isActivated: boolean = false;
let hasPackage: boolean = false;
let hasExecutableProduct: boolean = false;
Expand Down Expand Up @@ -292,10 +292,3 @@ function createContextKeys(): ContextKeys {
},
};
}

/**
* Type-safe wrapper around context keys used in `when` clauses.
*/
const contextKeys: ContextKeys = createContextKeys();

export default contextKeys;
9 changes: 4 additions & 5 deletions src/documentation/DocumentationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import * as vscode from "vscode";
import { DocumentationPreviewEditor } from "./DocumentationPreviewEditor";
import { WorkspaceContext } from "../WorkspaceContext";
import { WebviewContent } from "./webview/WebviewMessage";
import contextKeys from "../contextKeys";

export class DocumentationManager implements vscode.Disposable {
private previewEditor?: DocumentationPreviewEditor;
Expand All @@ -25,26 +24,26 @@ export class DocumentationManager implements vscode.Disposable {

constructor(
private readonly extension: vscode.ExtensionContext,
private readonly context: WorkspaceContext
private readonly workspaceContext: WorkspaceContext
) {}

onPreviewDidUpdateContent = this.editorUpdatedContentEmitter.event;
onPreviewDidRenderContent = this.editorRenderedEmitter.event;

async launchDocumentationPreview(): Promise<boolean> {
if (!contextKeys.supportsDocumentationLivePreview) {
if (!this.workspaceContext.contextKeys.supportsDocumentationLivePreview) {
return false;
}

if (!this.previewEditor) {
const folderContext = this.context.currentFolder;
const folderContext = this.workspaceContext.currentFolder;
if (!folderContext) {
return false;
}

this.previewEditor = await DocumentationPreviewEditor.create(
this.extension,
this.context
this.workspaceContext
);
const subscriptions: vscode.Disposable[] = [
this.previewEditor.onDidUpdateContent(content => {
Expand Down
5 changes: 5 additions & 0 deletions src/documentation/DocumentationPreviewEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export class DocumentationPreviewEditor implements vscode.Disposable {
private activeTextEditor?: vscode.TextEditor;
private activeTextEditorSelection?: vscode.Selection;
private subscriptions: vscode.Disposable[] = [];
private isDisposed: boolean = false;

private disposeEmitter = new vscode.EventEmitter<void>();
private renderEmitter = new vscode.EventEmitter<void>();
Expand Down Expand Up @@ -133,13 +134,17 @@ export class DocumentationPreviewEditor implements vscode.Disposable {
}

dispose() {
this.isDisposed = true;
this.subscriptions.forEach(subscription => subscription.dispose());
this.subscriptions = [];
this.webviewPanel.dispose();
this.disposeEmitter.fire();
}

private postMessage(message: WebviewMessage) {
if (this.isDisposed) {
return;
}
if (message.type === "update-content") {
this.updateContentEmitter.fire(message.content);
}
Expand Down
17 changes: 12 additions & 5 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ import { SwiftEnvironmentVariablesManager, SwiftTerminalProfileProvider } from "
import { resolveFolderDependencies } from "./commands/dependencies/resolve";
import { SelectedXcodeWatcher } from "./toolchain/SelectedXcodeWatcher";
import configuration, { handleConfigurationChangeEvent } from "./configuration";
import contextKeys from "./contextKeys";
import { registerSourceKitSchemaWatcher } from "./commands/generateSourcekitConfiguration";
import { SwiftLogger } from "./logging/SwiftLogger";
import { SwiftLoggerFactory } from "./logging/SwiftLoggerFactory";
import { ContextKeys, createContextKeys } from "./contextKeys";

/**
* External API as exposed by the extension. Can be queried by other extensions
Expand Down Expand Up @@ -65,7 +65,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {

checkAndWarnAboutWindowsSymlinks(logger);

const toolchain = await createActiveToolchain(logger);
const contextKeys = createContextKeys();
const toolchain = await createActiveToolchain(contextKeys, logger);

// If we don't have a toolchain, show an error and stop initializing the extension.
// This can happen if the user has not installed Swift or if the toolchain is not
Expand All @@ -82,7 +83,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<Api> {
};
}

const workspaceContext = new WorkspaceContext(context, logger, toolchain);
const workspaceContext = new WorkspaceContext(context, contextKeys, logger, toolchain);
context.subscriptions.push(workspaceContext);

context.subscriptions.push(new SwiftEnvironmentVariablesManager(context));
Expand Down Expand Up @@ -239,7 +240,10 @@ function handleFolderEvent(logger: SwiftLogger): (event: FolderEvent) => Promise
};
}

async function createActiveToolchain(logger: SwiftLogger): Promise<SwiftToolchain | undefined> {
async function createActiveToolchain(
contextKeys: ContextKeys,
logger: SwiftLogger
): Promise<SwiftToolchain | undefined> {
try {
const toolchain = await SwiftToolchain.create(undefined, logger);
toolchain.logDiagnostics(logger);
Expand All @@ -252,7 +256,10 @@ async function createActiveToolchain(logger: SwiftLogger): Promise<SwiftToolchai
}

async function deactivate(context: vscode.ExtensionContext): Promise<void> {
contextKeys.isActivated = false;
const workspaceContext = (context.extension.exports as Api).workspaceContext;
if (workspaceContext) {
workspaceContext.contextKeys.isActivated = false;
}
context.subscriptions.forEach(subscription => subscription.dispose());
context.subscriptions.length = 0;
}
9 changes: 4 additions & 5 deletions src/ui/ProjectPanelProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import * as path from "path";
import configuration from "../configuration";
import { WorkspaceContext } from "../WorkspaceContext";
import { FolderOperation } from "../WorkspaceContext";
import contextKeys from "../contextKeys";
import { Dependency, ResolvedDependency, Target } from "../SwiftPackage";
import { FolderContext } from "../FolderContext";
import { getPlatformConfig, resolveTaskCwd } from "../utilities/tasks";
Expand Down Expand Up @@ -485,9 +484,9 @@ export class ProjectPanelProvider implements vscode.TreeDataProvider<TreeNode> {

constructor(private workspaceContext: WorkspaceContext) {
// default context key to false. These will be updated as folders are given focus
contextKeys.hasPackage = false;
contextKeys.hasExecutableProduct = false;
contextKeys.packageHasDependencies = false;
workspaceContext.contextKeys.hasPackage = false;
workspaceContext.contextKeys.hasExecutableProduct = false;
workspaceContext.contextKeys.packageHasDependencies = false;

this.observeTasks(workspaceContext);
}
Expand Down Expand Up @@ -688,7 +687,7 @@ export class ProjectPanelProvider implements vscode.TreeDataProvider<TreeNode> {
}
const pkg = folderContext.swiftPackage;
const rootDeps = await pkg.rootDependencies;
if (contextKeys.flatDependenciesList) {
if (this.workspaceContext.contextKeys.flatDependenciesList) {
const existenceMap = new Map<string, boolean>();
const gatherChildren = (dependencies: ResolvedDependency[]): ResolvedDependency[] => {
const result: ResolvedDependency[] = [];
Expand Down
Loading