{
- // Reveal the file in the current editor tab instead of opening a new one
- await vscode.commands.executeCommand(
- 'workbench.action.revertAndCloseActiveEditor'
- );
- await vscode.commands.executeCommand(
- 'vscode.openWith',
- document.uri,
- 'default',
- {
- preview: false,
- preserveFocus: false
- }
- );
- telemetry.sendAction('openWithTextEditor');
- logger.info(
- 'File opened with text editor in current tab: ' + document.uri.fsPath
- );
- }
- private getHtmlForWebview(webview: vscode.Webview): string {
- // Use a nonce to whitelist which scripts can be run
- const nonce = getNonce();
- const scriptUri = getUri(webview, this.context.extensionUri, [
- 'out',
- 'editors',
- 'ui',
- 'webview-ui',
- 'main.js'
- ]);
-
- // prettier-ignore
- const html =
- `
-
-
-
-
- Open this file with Qt Widgets Designer
-
-
-
-
- Open this file with Qt Widgets Designer
- Open this file with Text Editor
-
-
-
- `;
- return html;
- }
-}
diff --git a/qt-ui/src/editors/ui/webview-ui/main.mts b/qt-ui/src/editors/ui/webview-ui/main.mts
deleted file mode 100644
index 43e937ae9..000000000
--- a/qt-ui/src/editors/ui/webview-ui/main.mts
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (C) 2024 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import {
- provideVSCodeDesignSystem,
- vsCodeButton
-} from '@vscode/webview-ui-toolkit';
-
-declare function acquireVsCodeApi(): { postMessage(message: unknown): void };
-
-provideVSCodeDesignSystem().register(vsCodeButton());
-
-const vscode = acquireVsCodeApi();
-
-window.addEventListener('load', main);
-
-function main() {
- const openWithDesignerButton = document.getElementById(
- 'openWithDesignerButton'
- );
- const openWithTextEditorButton = document.getElementById(
- 'openWithTextEditorButton'
- );
- if (openWithDesignerButton) {
- openWithDesignerButton.focus();
- }
- function onOpenWithDesignerButtonClick() {
- vscode.postMessage({
- type: 'run'
- });
- }
- function onOpenWithTextEditorButtonClick() {
- vscode.postMessage({
- type: 'openWithTextEditor'
- });
- }
- openWithDesignerButton?.addEventListener(
- 'click',
- onOpenWithDesignerButtonClick
- );
- openWithDesignerButton?.addEventListener('keydown', function (event) {
- if (event.key === 'Enter') {
- event.preventDefault();
- onOpenWithDesignerButtonClick();
- }
- });
- openWithTextEditorButton?.addEventListener(
- 'click',
- onOpenWithTextEditorButtonClick
- );
- openWithTextEditorButton?.addEventListener('keydown', function (event) {
- if (event.key === 'Enter') {
- event.preventDefault();
- onOpenWithTextEditorButtonClick();
- }
- });
- document.addEventListener('keydown', function (event) {
- // Toggle focus between the two buttons with arrow keys
- if (
- event.key === 'ArrowLeft' ||
- event.key === 'ArrowUp'
- ) {
- event.preventDefault();
- openWithDesignerButton?.focus();
- } else if (
- event.key === 'ArrowRight' ||
- event.key === 'ArrowDown'
- ) {
- event.preventDefault();
- openWithTextEditorButton?.focus();
- }
- });
-}
diff --git a/qt-ui/src/editors/util.ts b/qt-ui/src/editors/util.ts
deleted file mode 100644
index 58f577796..000000000
--- a/qt-ui/src/editors/util.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (C) 2024 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import { Uri, Webview } from 'vscode';
-
-export function getNonce() {
- let text = '';
- const possible =
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- for (let i = 0; i < 32; i++) {
- text += possible.charAt(Math.floor(Math.random() * possible.length));
- }
- return text;
-}
-
-export function getUri(
- webview: Webview,
- extensionUri: Uri,
- pathList: string[]
-) {
- return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList));
-}
diff --git a/qt-ui/src/extension.ts b/qt-ui/src/extension.ts
deleted file mode 100644
index a64f19707..000000000
--- a/qt-ui/src/extension.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (C) 2024 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import * as vscode from 'vscode';
-
-import {
- CoreAPI,
- getCoreApi,
- createLogger,
- initLogger,
- telemetry
-} from 'qt-lib';
-import { EXTENSION_ID } from '@/constants';
-import { openWidgetDesigner, lastSpawnedDesignerRef } from '@/commands';
-import { UIProjectManager } from '@/project-manager';
-import { UIEditorProvider } from '@/editors/ui/ui-editor';
-
-const logger = createLogger('extension');
-
-export let coreAPI: CoreAPI | undefined;
-export let projectManager: UIProjectManager;
-
-export async function activate(context: vscode.ExtensionContext) {
- initLogger(EXTENSION_ID);
- logger.info(`Activating ${context.extension.id}`);
- telemetry.activate(context);
-
- await initCoreApi();
- await initProjectManager(context);
-
- context.subscriptions.push(
- UIEditorProvider.register(context),
- vscode.commands.registerCommand(
- `${EXTENSION_ID}.openWidgetDesigner`,
- openWidgetDesigner
- )
- );
-
- telemetry.sendEvent('activated');
- if (process.env.QT_TESTING === '1') {
- return { lastSpawnedDesignerRef };
- }
- return {};
-}
-
-export function deactivate() {
- logger.info(`Deactivating ${EXTENSION_ID}`);
- telemetry.dispose();
- projectManager.dispose();
-}
-
-async function initCoreApi() {
- coreAPI = await getCoreApi();
- if (!coreAPI) {
- const msg = 'Failed to get CoreAPI';
- logger.error(msg);
- throw new Error(msg);
- }
-}
-
-async function initProjectManager(context: vscode.ExtensionContext) {
- projectManager = new UIProjectManager(context);
- await projectManager.init();
-}
diff --git a/qt-ui/src/project-manager.ts b/qt-ui/src/project-manager.ts
deleted file mode 100644
index 44fe400d0..000000000
--- a/qt-ui/src/project-manager.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (C) 2025 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import * as vscode from 'vscode';
-
-import {
- QtWorkspaceConfigMessage,
- ProjectManager,
- createLogger,
- QtWorkspaceFeatures,
- CoreKey,
- PySideEnvData
-} from 'qt-lib';
-import * as consts from '@/constants';
-import { coreAPI } from '@/extension';
-import { createUIProject, UIProject } from '@/project';
-
-const logger = createLogger('project-manager');
-
-export class UIProjectManager extends ProjectManager {
- public constructor(context: vscode.ExtensionContext) {
- super(context, createUIProject);
-
- this._disposables.push(
- this.onProjectAdded(UIProjectManager._onProjectAdded),
- this.onProjectRemoved(UIProjectManager._onProjectRemoved),
- vscode.workspace.onDidChangeConfiguration(this._onWorkspaceConfigChanged)
- );
- }
-
- public async init() {
- for (const folder of vscode.workspace.workspaceFolders ?? []) {
- const project = await createUIProject(folder, this.context);
- await project.init();
- this.addProject(project);
- }
-
- if (coreAPI) {
- this._disposables.push(
- coreAPI.onValueChanged(this._onCoreConfigMessasge)
- );
- }
- }
-
- private readonly _onCoreConfigMessasge = async (
- msg: QtWorkspaceConfigMessage
- ) => {
- logger.info('Received config message:', msg.config as unknown as string);
-
- if (typeof msg.workspaceFolder === 'string') {
- // do nothing if workspace folder is a string
- return;
- }
-
- const folder = msg.workspaceFolder;
- const project = this.getProject(folder);
- if (!project) {
- logger.error(`Project not found: folder = ${folder.uri.fsPath}`);
- return;
- }
-
- for (const key of msg.config.keys()) {
- if (key === CoreKey.SELECTED_QT_PATHS) {
- const value = coreAPI?.getValue(folder, key);
- await project.setSelectedQtPaths(value);
- continue;
- }
-
- if (key === CoreKey.WORKSPACE_FEATURES) {
- await project.setWorkspaceFeatures(
- coreAPI?.getValue(folder, key)
- );
- continue;
- }
-
- if (key === CoreKey.PYSIDE_ENV_DATA) {
- const value = coreAPI?.getValue(folder, key);
- await project.setPySideEnv(value);
- }
- }
- };
-
- private readonly _onWorkspaceConfigChanged = async (
- ev: vscode.ConfigurationChangeEvent
- ) => {
- const key = consts.CONF_CUSTOM_WIDGETS_DESIGNER_EXE_PATH;
- const section = `${consts.EXTENSION_ID}.${key}`;
-
- for (const project of this.getProjects()) {
- if (ev.affectsConfiguration(section, project.folder)) {
- await project.tryReloadCustomExePath();
- }
- }
- };
-
- private static readonly _onProjectAdded = async (project: UIProject) => {
- logger.info('Adding project:', project.folder.uri.fsPath);
- await project.init();
- };
-
- private static readonly _onProjectRemoved = (project: UIProject) => {
- logger.info('Project removed:', project.folder.uri.fsPath);
- };
-}
diff --git a/qt-ui/src/project.ts b/qt-ui/src/project.ts
deleted file mode 100644
index 3074488ea..000000000
--- a/qt-ui/src/project.ts
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (C) 2024 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import * as vscode from 'vscode';
-import * as fs from 'fs';
-
-import {
- Project,
- createLogger,
- resolveConfiguration,
- QtWorkspaceFeatures,
- CoreKey,
- PySideEnvData
-} from 'qt-lib';
-import * as consts from '@/constants';
-import { coreAPI } from '@/extension';
-import { DesignerClient } from '@/designer-client';
-import { DesignerServer } from '@/designer-server';
-import {
- locateDesignerFromQtPaths,
- locateDesignerFromVenvBinPaths
-} from '@/util';
-
-type UpdateReason =
- | 'init'
- | 'customExeChanged'
- | 'workspaceFeatureChanged'
- | 'selectedKitPathChanged'
- | 'selectedQtPathsChanged'
- | 'pythonEnvDataChanged';
-
-const logger = createLogger('project');
-
-export async function createUIProject(
- folder: vscode.WorkspaceFolder,
- context: vscode.ExtensionContext
-) {
- const project = new UIProject(folder, context);
- return Promise.resolve(project);
-}
-
-// Project class represents a workspace folder in the extension.
-export class UIProject implements Project {
- private _customExePath: string | undefined;
- private _workspaceFeatures: QtWorkspaceFeatures | undefined;
- private _selectedQtPaths: string | undefined;
- private _pythonEnvData: PySideEnvData | undefined;
-
- private _designerClient: DesignerClient | undefined;
- private readonly _designerServer: DesignerServer;
-
- public constructor(
- readonly _folder: vscode.WorkspaceFolder,
- readonly _context: vscode.ExtensionContext
- ) {
- this._designerServer = new DesignerServer();
- }
-
- dispose() {
- this._designerServer.dispose();
- this._designerClient?.dispose();
- }
-
- get folder() {
- return this._folder;
- }
-
- get designerServer() {
- return this._designerServer;
- }
-
- get designerClient() {
- return this._designerClient;
- }
-
- get workspaceFeatures() {
- return this._workspaceFeatures;
- }
-
- public async init() {
- const read = coreAPI?.getValue.bind(coreAPI);
- if (!read) {
- return;
- }
-
- this._customExePath = this._readCustomExePath();
- this._workspaceFeatures = read(
- this._folder,
- CoreKey.WORKSPACE_FEATURES
- );
- this._selectedQtPaths = read(
- this._folder,
- CoreKey.SELECTED_QT_PATHS
- );
- this._pythonEnvData = read(
- this._folder,
- CoreKey.PYSIDE_ENV_DATA
- );
-
- await this._updateClient('init');
- }
-
- public async tryReloadCustomExePath() {
- const exe = this._readCustomExePath();
-
- if (this._customExePath !== exe) {
- this._customExePath = exe;
- await this._updateClient('customExeChanged');
- }
- }
-
- public async setWorkspaceFeatures(features: QtWorkspaceFeatures | undefined) {
- if (this._workspaceFeatures !== features) {
- this._workspaceFeatures = features;
- await this._updateClient('workspaceFeatureChanged');
- }
- }
-
- public async setSelectedQtPaths(exePath: string | undefined) {
- if (this._selectedQtPaths !== exePath) {
- this._selectedQtPaths = exePath;
- await this._updateClient('selectedQtPathsChanged');
- }
- }
-
- public async setPySideEnv(data: PySideEnvData | undefined) {
- if (this._pythonEnvData !== data) {
- this._pythonEnvData = data;
- await this._updateClient('pythonEnvDataChanged');
- }
- }
-
- private async _updateClient(reason: UpdateReason) {
- const exe = await this._resolveDesignerExe();
- if (!exe) {
- this._clearClient();
- return;
- }
-
- const prev = this._designerClient?.exe;
- if (!prev && prev === exe) {
- return;
- }
-
- this._clearClient();
- this._designerClient = new DesignerClient(
- exe,
- this._designerServer.getPort()
- );
-
- // clean up
- if (reason === 'selectedKitPathChanged') {
- this._selectedQtPaths = undefined;
- }
- }
-
- private _clearClient() {
- this._designerClient?.detach();
- this._designerClient?.dispose();
- this._designerClient = undefined;
- }
-
- private async _resolveDesignerExe() {
- if (this._customExePath) {
- if (fs.existsSync(this._customExePath)) {
- return this._customExePath;
- }
-
- const msg =
- 'Qt Widgets Designer executable not found at: ' +
- `"${this._customExePath}"`;
-
- logger.error(msg);
- void vscode.window.showWarningMessage(msg);
- }
-
- if (this._workspaceFeatures?.projectTypes.pyside) {
- if (this._pythonEnvData?.venvBinPath) {
- return locateDesignerFromVenvBinPaths(this._pythonEnvData.venvBinPath);
- }
- }
-
- if (this._workspaceFeatures?.projectTypes.cmake) {
- if (this._selectedQtPaths) {
- return locateDesignerFromQtPaths(this._selectedQtPaths);
- }
- }
-
- return undefined;
- }
-
- private _readCustomExePath() {
- const folder = this.folder;
- const config = vscode.workspace
- .getConfiguration(consts.EXTENSION_ID, folder)
- .get(consts.CONF_CUSTOM_WIDGETS_DESIGNER_EXE_PATH, '');
- const value = resolveConfiguration(config);
-
- logger.info(
- 'Read custom desinger exe path: ',
- `value = ${value}, `,
- `folder = '${folder.uri.fsPath}'`
- );
-
- return value;
- }
-}
diff --git a/qt-ui/src/util.ts b/qt-ui/src/util.ts
deleted file mode 100644
index b29068d29..000000000
--- a/qt-ui/src/util.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (C) 2024 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import * as path from 'path';
-
-import {
- IsMacOS,
- IsWindows,
- OSExeSuffix,
- exists,
- searchForExeInQtInfo,
- findQtPathsInInstallationPath
-} from 'qt-lib';
-import { coreAPI } from '@/extension';
-
-export async function delay(ms: number) {
- return new Promise((resolve) => setTimeout(resolve, ms));
-}
-
-export async function locateDesignerFromKit(
- selectedKitPath: string,
- qtPathsFallback = true
-) {
- let exe = getDesignerExePathFromBin(path.join(selectedKitPath, 'bin'));
- if (await exists(exe)) {
- return exe;
- }
-
- if (qtPathsFallback) {
- const qtPaths = findQtPathsInInstallationPath(selectedKitPath);
- const exeFromQtPaths =
- qtPaths && (await locateDesignerFromQtPaths(qtPaths));
- if (exeFromQtPaths) {
- return exeFromQtPaths;
- }
- }
-
- if (!IsWindows) {
- exe = '/usr/bin/designer';
- if (await exists(exe)) {
- return exe;
- }
- }
-
- return undefined;
-}
-
-export async function locateDesignerFromQtPaths(qtPaths: string) {
- const info = coreAPI?.getQtInfoFromPath(qtPaths).info;
- if (!info) {
- return undefined;
- }
-
- return searchForExeInQtInfo(info, getDesignerExePathFromBin);
-}
-
-export async function locateDesignerFromVenvBinPaths(venvBinPath: string) {
- const candidate = path.join(venvBinPath, 'pyside6-designer' + OSExeSuffix);
- return (await exists(candidate)) ? candidate : undefined;
-}
-
-function getDesignerExePathFromBin(selectedQtBinPath: string) {
- return path.join(
- selectedQtBinPath,
- IsMacOS ? 'Designer.app/Contents/MacOS/Designer' : 'designer' + OSExeSuffix
- );
-}
diff --git a/qt-ui/test/helper.mts b/qt-ui/test/helper.mts
deleted file mode 100644
index 06afa89a9..000000000
--- a/qt-ui/test/helper.mts
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (C) 2025 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import * as sinon from 'sinon';
-import * as vscode from 'vscode';
-import { isDeepStrictEqual } from 'util';
-
-/**
- * Mocha lifecycle wiring for a shared Sinon sandbox.
- * - creates a sandbox once
- * - (optionally) activates the extension once
- * - resets sandbox before each test
- * - verifies & restores after each test
- */
-export function setupSandboxLifecycleHooks(
- assign: (sb: sinon.SinonSandbox) => void,
- activate?: () => Thenable | void
-): void {
- let sb: sinon.SinonSandbox;
-
- before('create sandbox', () => {
- sb = sinon.createSandbox();
- assign(sb);
- });
-
- if (activate) {
- before('activate extension', activate);
- }
-
- beforeEach('reset sandbox', () => {
- sb = sinon.createSandbox();
- assign(sb);
- });
-
- afterEach('verify and restore sandbox', () => {
- sb.verifyAndRestore();
- });
-}
-
-/** Let VS Code flush microtasks (useful between command execution and assertions). */
-export async function waitForVSCodeIdle(): Promise {
- return new Promise((resolve) => setImmediate(resolve));
-}
-
-/**
- * Ensure the qt-cpp extension is activated.
- * Throws if it isn't found (helps fail fast in tests).
- */
-export async function activateQtUi(): Promise {
- const ext = vscode.extensions.getExtension('theqtcompany.qt-ui');
- if (!ext) throw new Error('qt-ui extension not found');
- if (!ext.isActive) await ext.activate();
-}
-
-/**
- * Stub `vscode.commands.executeCommand` and record calls that match the provided
- * command + args. Uses Node's deep equal (no lodash-es dependency).
- *
- * Usage:
- * const spy = stubExecuteCommandWithSpy(sb, ['cmake.scanForKits']);
- * await vscode.commands.executeCommand('cmake.scanForKits');
- * expect(spy.calledOnce).to.be.true;
- */
-export type CommandArgs = [string, ...unknown[]];
-export type CommandInput = CommandArgs | CommandArgs[];
-
-export function stubExecuteCommandWithSpy(
- sb: sinon.SinonSandbox,
- input: CommandInput
-): sinon.SinonSpy {
- const real = vscode.commands.executeCommand.bind(vscode.commands);
- const list = Array.isArray(input[0])
- ? (input as CommandArgs[])
- : [input as CommandArgs];
- const spy = sinon.spy();
-
- sb.stub(vscode.commands, 'executeCommand').callsFake(
- (cmd: string, ...args: unknown[]) => {
- for (const [expectedCmd, ...expectedArgs] of list) {
- if (
- cmd === expectedCmd &&
- expectedArgs.length === args.length &&
- expectedArgs.every((exp, i) => isDeepStrictEqual(exp, args[i]))
- ) {
- spy(cmd, ...args);
- return Promise.resolve();
- }
- }
- return real(cmd, ...args);
- }
- );
-
- return spy;
-}
diff --git a/qt-ui/test/runTest.ts b/qt-ui/test/runTest.ts
deleted file mode 100644
index 536bef0a1..000000000
--- a/qt-ui/test/runTest.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (C) 2025 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-process.env.QT_TESTING = '1';
-
-import * as path from 'path';
-import * as fs from 'fs';
-
-const QT_INS_ROOT_CONFIG_NAME = 'qtInstallationRoot';
-
-import {
- downloadAndUnzipVSCode,
- resolveCliArgsFromVSCodeExecutablePath,
- runTests
-} from '@vscode/test-electron';
-
-import {
- getLocalQtCore,
- getQuietVSCodeArgs
-} from '../../qt-lib/src/test-constants';
-
-import {
- parseVSCodeDirs,
- installExtensionWithRetry,
- debugListExtensions,
- assertExtensionsInstalled,
- getDebugLevel
-} from '../../qt-lib/src/test-vscode-install.js';
-
-// --- CLI arg parsing (no deps) ---------------------------------------------
-function getCliArg(name: string): string | undefined {
- const flag = `--${name}`;
- const argv = process.argv.slice(2);
-
- for (let i = 0; i < argv.length; i++) {
- const a: string = argv[i]!;
- if (a === flag) {
- const next = argv[i + 1];
- return next ? next.trim() : undefined;
- }
- if (a.startsWith(flag + '=')) {
- return a.slice(flag.length + 1).trim();
- }
- }
- return undefined;
-}
-
-async function main() {
- try {
- // The folder containing the Extension Manifest package.json
- // Passed to `--extensionDevelopmentPath`
- const extensionDevelopmentPath = path.resolve(__dirname, '../../');
-
- // The path to the extension test script
- // Passed to --extensionTestsPath
- const extensionTestsPath = path.resolve(__dirname, './suite/index');
- // Path to the local qt-core extension to be used during testing
- const localQtCoreVsix = path.normalize(
- path.resolve(__dirname, getLocalQtCore())
- );
- // Check that qt-core .vsix exists
- if (!fs.existsSync(localQtCoreVsix)) {
- console.error(`Required extension not found: ${localQtCoreVsix}`);
- process.exit(1); // Fail early
- }
-
- const vscodeExecutablePath = await downloadAndUnzipVSCode();
- const [cli, ...args] =
- resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath);
-
- //--------------------
- // Read from env (set this when launching tests)
- // Prefer CLI over env
- const cliQtRoot = getCliArg('qt-root');
- const envQtRoot = process.env.QT_TEST_QT_ROOT?.trim();
- const qtRoot = (cliQtRoot ?? envQtRoot)?.trim();
-
- if (!qtRoot) {
- console.error(
- [
- 'Qt root is required. Provide either:',
- ' 1) CLI: --qt-root /absolute/path/to/Qt',
- ' 2) ENV: QT_TEST_QT_ROOT=/absolute/path/to/Qt',
- '',
- 'Examples:',
- ' npm run test -- --qt-root /Users/me/Qt',
- ' QT_TEST_QT_ROOT=/Users/me/Qt npm run test'
- ].join('\n')
- );
- process.exit(1);
- }
-
- // Use the SAME profile/dirs that test-electron sets up
- const { userDataDir, extensionsDir } = parseVSCodeDirs(args);
- if (getDebugLevel() >= 1) {
- console.log('[runTest][qt-ui] CLI:', cli, 'args:', args.join(' '));
- console.log('[runTest][qt-ui] userDataDir:', userDataDir);
- console.log('[runTest][qt-ui] extensionsDir:', extensionsDir);
- }
-
- // Seed VS Code settings in that SAME user-data-dir
- if (!userDataDir) {
- console.error(
- '[runTest] Could not determine userDataDir from VS Code args.'
- );
- process.exit(1);
- }
- const userDir = path.join(userDataDir, 'User');
- fs.mkdirSync(userDir, { recursive: true });
-
- const settingsPath = path.join(userDir, 'settings.json');
- const settings = {
- // VS Code setting key that qt-core reads:
- [`qt-core.${QT_INS_ROOT_CONFIG_NAME}`]: qtRoot,
- // Silence CMake Tools logs (trace/debug/info/warn → only errors)
- 'cmake.loggingLevel': 'error'
- };
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
- console.log('[runTest] Wrote settings to:', settingsPath);
-
- const quietArgs = [...args, ...getQuietVSCodeArgs()];
- const requiredIds = ['theqtcompany.qt-core'];
- // Install required extensions into the SAME profile/dir combo
- installExtensionWithRetry(cli as string, quietArgs, {
- idOrVsix: localQtCoreVsix
- });
- debugListExtensions(cli as string, args);
- assertExtensionsInstalled(cli as string, args, requiredIds);
-
- // Download VS Code, unzip it and run the integration test
- await runTests({ extensionDevelopmentPath, extensionTestsPath });
- } catch (e: Error | unknown) {
- console.error('Failed to run tests');
- console.error(e);
- process.exit(1);
- }
-}
-
-main();
diff --git a/qt-ui/test/suite/commands.test.mts b/qt-ui/test/suite/commands.test.mts
deleted file mode 100644
index feb008e27..000000000
--- a/qt-ui/test/suite/commands.test.mts
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (C) 2025 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import { expect } from 'chai';
-import * as sinon from 'sinon';
-import * as vscode from 'vscode';
-import * as fs from 'fs';
-
-import { delay } from 'qt-lib';
-
-import {
- setupSandboxLifecycleHooks,
- waitForVSCodeIdle,
- activateQtUi
-} from '../helper.mts';
-
-describe('command: openQtWidgetDesigner', () => {
- let sb: sinon.SinonSandbox;
- setupSandboxLifecycleHooks(
- (_sb) => (sb = _sb),
- async () => activateQtUi()
- );
- before(function () {
- const qtRoot =
- vscode.workspace
- .getConfiguration('qt-core')
- .get('qtInstallationRoot') ?? '';
- if (!qtRoot) {
- throw new Error(
- 'qt-core.qtInstallationRoot is not set.\n' +
- 'Make sure you run tests via runTest.mts (with --qt-root / QT_TEST_QT_ROOT)\n' +
- 'or configure it in your VS Code settings when debugging.'
- );
- }
- });
-
- // Function to run the command and wait for VS Code to be idle
- async function runOpenWidgetDesignerCommand(): Promise {
- await vscode.commands.executeCommand('qt-ui.openWidgetDesigner');
- await waitForVSCodeIdle();
- }
-
- it('picks a Designer and that path exists, triggers no "Qt Designer" error messages', async function () {
- const ext = vscode.extensions.getExtension('theqtcompany.qt-ui')!;
- const api = ext.isActive ? ext.exports : await ext.activate();
- const { lastSpawnedDesignerRef } = api as {
- lastSpawnedDesignerRef: { proc?: import('child_process').ChildProcess };
- };
- let selected: vscode.QuickPickItem | undefined;
-
- const quickPickStub = sb
- .stub(vscode.window, 'showQuickPick')
- .callsFake(async (items: any, _opts?: vscode.QuickPickOptions) => {
- // handle both array or Thenable defensively:
- const list = Array.isArray(items)
- ? items
- : Array.isArray(await items)
- ? await items
- : [];
- selected = list[0]; // auto-select first item
- return selected; // simulate user choice
- });
-
- // Spy on showErrorMessage
- const showErrorSpy = sb.spy(vscode.window, 'showErrorMessage');
-
- await runOpenWidgetDesignerCommand();
- await waitForVSCodeIdle();
- await new Promise((r) => setTimeout(r, 3000)); // add short delay to give time for possible error events to fire
-
- const proc = lastSpawnedDesignerRef.proc;
- expect(proc, 'Designer process should exist').to.exist;
-
- //Assert the quick pick was shown and we captured a selection
- expect(quickPickStub.called, 'quick pick should be shown').to.equal(true);
- expect(selected, 'a Designer version should be selected').to.exist;
- expect(
- typeof selected!.description,
- 'selected description should be a path string'
- ).to.equal('string');
-
- // Filter only error messages mentioning "Qt Designer"
- const qtDesignerErrors = showErrorSpy
- .getCalls()
- .map((c) => c.args[0])
- .filter(
- (msg): msg is string =>
- typeof msg === 'string' &&
- msg.includes('Error while opening Qt Designer')
- );
-
- // Assert none of those occurred
- expect(
- qtDesignerErrors.length,
- `Unexpected "Qt Designer" error messages: ${qtDesignerErrors.join('; ')}`
- ).to.equal(0);
-
- //Check the selected path actually exists
- const path = selected!.description as string;
- expect(
- fs.existsSync(path),
- `designer path should exist on disk: ${path}`
- ).to.equal(true);
-
- if (proc && !proc.killed) {
- if (process.platform === 'win32') {
- // Windows: task kill the tree
- const { execFile } = await import('child_process');
- await new Promise((resolve) => {
- execFile('taskkill', ['/PID', String(proc.pid), '/T', '/F'], () =>
- resolve()
- );
- });
- } else {
- // POSIX: SIGTERM then wait a bit
- proc.kill('SIGTERM');
- await Promise.race([
- new Promise((r) => proc.once('exit', r)),
- delay(3000)
- ]);
- }
- }
- });
-});
diff --git a/qt-ui/test/suite/extension.test.mts b/qt-ui/test/suite/extension.test.mts
deleted file mode 100644
index 8f7643715..000000000
--- a/qt-ui/test/suite/extension.test.mts
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) 2025 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import { expect } from 'chai';
-import * as vscode from 'vscode';
-import {
- isExtensionActive,
- assertAllDependenciesAreActive,
- assertAllCommandsAreRegistered
-} from 'qt-lib';
-
-const packageJson = require('../../package.json');
-
-describe('extension', () => {
- before('activate', async function () {
- const ext = vscode.extensions.getExtension('theqtcompany.qt-ui');
- if (!ext) throw new Error('qt-ui extension not found');
- await ext.activate();
- });
-
- it('activates the qt-ui extension', () => {
- expect(isExtensionActive('theqtcompany.qt-ui')).to.be.true;
- });
- it('activates all declared extension dependencies', () => {
- assertAllDependenciesAreActive(packageJson);
- });
- it('registers all contributed commands', async () => {
- await assertAllCommandsAreRegistered(packageJson);
- });
-});
diff --git a/qt-ui/test/suite/index.ts b/qt-ui/test/suite/index.ts
deleted file mode 100644
index 87a94fe53..000000000
--- a/qt-ui/test/suite/index.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
-
-import * as path from 'path';
-import Mocha from 'mocha';
-import * as glob from 'glob';
-
-export function run(): Promise {
- // Create the mocha test
- const mocha = new Mocha({
- // decribe, it
- ui: 'bdd',
- color: true
- });
- const testsRoot = path.resolve(__dirname);
- return new Promise((c, e) => {
- const testFiles = new glob.Glob('**.test.js', { cwd: testsRoot });
- const testFileStream = testFiles.stream();
- testFileStream.on('data', (file) => {
- mocha.addFile(path.resolve(testsRoot, file));
- });
- testFileStream.on('error', (err) => {
- e(new Error(err as string));
- });
- testFileStream.on('end', () => {
- try {
- // Run the mocha test
- mocha.timeout(10000);
- // Log the name of each test before it starts.
- const beforeEach: Mocha.Func = function (
- this: Mocha.Context,
- done: Mocha.Done
- ) {
- console.log(
- `Starting test: ${this.currentTest?.parent?.title} - ${this.currentTest?.title}`
- );
- done();
- };
- mocha.rootHooks({ beforeEach });
- // Run the mocha test
- mocha.run((failures) => {
- if (failures > 0) {
- e(new Error(`${failures} tests failed.`));
- } else {
- c();
- }
- });
- } catch (err) {
- console.error(err);
- e(new Error(err as string));
- }
- });
- });
-}
diff --git a/qt-ui/tsconfig.json b/qt-ui/tsconfig.json
deleted file mode 100644
index 6330acfdc..000000000
--- a/qt-ui/tsconfig.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "compilerOptions": {
- "esModuleInterop": true,
- "noEmit": true,
- "allowImportingTsExtensions": true,
- "forceConsistentCasingInFileNames": true,
- "module": "node16",
- "moduleResolution": "node16",
- "target": "ES2020",
- "types": ["node"],
- "outDir": "out",
- "lib": ["ES2020", "DOM"],
- "sourceMap": true,
- "rootDirs": ["src", "test"],
- "strict": true /* enable all strict type-checking options */,
- "noImplicitOverride": true,
- "noUncheckedIndexedAccess": true,
- "allowUnusedLabels": false,
- "incremental": true,
- "allowUnreachableCode": false,
- "noImplicitReturns": true,
- "exactOptionalPropertyTypes": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "paths": {
- "@/*": ["./src/*"],
- "@cmd/*": ["./src/commands/*"]
- }
- },
- "include": ["src/**/*", "test/**/*"]
-}
diff --git a/scripts/all_dev.ts b/scripts/all_dev.ts
index 8ad16154d..021b58984 100644
--- a/scripts/all_dev.ts
+++ b/scripts/all_dev.ts
@@ -51,7 +51,7 @@ function main() {
}
const script = path.join(extensionRoot, 'scripts', 'install-ext.ts');
if (targetExtension === 'all') {
- const extensions = ['qt-core', 'qt-cpp', 'qt-qml', 'qt-ui', 'qt-python'];
+ const extensions = ['qt-core', 'qt-cpp', 'qt-qml', 'qt-python'];
for (const ext of extensions) {
const targetRoot = path.join(extensionRoot, ext);
execSync(
diff --git a/scripts/test.ts b/scripts/test.ts
index a74e09325..671603d7e 100644
--- a/scripts/test.ts
+++ b/scripts/test.ts
@@ -17,12 +17,12 @@ function main() {
console.error('Error: --extension parameter is required');
console.log('Usage: ts-node test.ts --extension=');
console.log(
- 'Available extensions: qt-core, qt-cpp, qt-qml, qt-ui, qt-python, all'
+ 'Available extensions: qt-core, qt-cpp, qt-qml, qt-python, all'
);
process.exit(1);
}
- const extensions = ['qt-core', 'qt-cpp', 'qt-qml', 'qt-ui', 'qt-python'];
+ const extensions = ['qt-core', 'qt-cpp', 'qt-qml', 'qt-python'];
if (targetExtension === 'all') {
for (const ext of extensions) {