diff --git a/src/qbsproject.ts b/src/qbsproject.ts index 4e1336c..56002de 100644 --- a/src/qbsproject.ts +++ b/src/qbsproject.ts @@ -4,10 +4,11 @@ import {basename} from 'path'; import * as QbsUtils from './qbsutils'; import {QbsSession} from './qbssession'; -import {QbsBuildStep, QbsRunStep, QbsProduct, QbsRunEnvironment} from './qbssteps'; +import {QbsBuildStep, QbsRunStep} from './qbssteps'; +import {QbsProjectData, QbsProductData, QbsRunEnvironmentData} from './qbstypes'; export class QbsProject implements vscode.Disposable { - private _data?: any; + private _data?: QbsProjectData; private _buildStep: QbsBuildStep = new QbsBuildStep(this); private _runStep: QbsRunStep = new QbsRunStep(this); @@ -23,39 +24,22 @@ export class QbsProject implements vscode.Disposable { name(): string { return this._uri ? basename(this._uri.fsPath) : 'unknown'; } filePath(): string { return QbsUtils.fixPathSeparators(this._uri?.fsPath || ''); } - async setData(response: any, withBuildSystemFiles: boolean) { - const data = response['project-data']; - if (data) { - this._data = data; + async setData(data: QbsProjectData, withBuildSystemFiles: boolean) { + if (!data.isEmpty()) { + const buildSystemFiles = this._data?.buildSystemFiles(); if (!withBuildSystemFiles) { - this._data['build-system-files'] = data['build-system-files']; + data.setBuildSystemFiles(buildSystemFiles); } + this._data = data; } } - data(): any | undefined { return this._data; } - setRunEnvironment(env: QbsRunEnvironment) { this._runStep.setup(undefined, undefined, env); } + data(): QbsProjectData | undefined { return this._data; } + setRunEnvironment(env: QbsRunEnvironmentData) { this._runStep.setup(undefined, undefined, env); } buildStep(): QbsBuildStep { return this._buildStep; } runStep(): QbsRunStep { return this._runStep; } - isEmpty(): boolean { return this._data; } - - async enumerateProducts(): Promise { - const products: QbsProduct[] = []; - const parseProject = async (project: any) => { - const datas = project ? (project['products'] || []) : []; - for (const data of datas) { - const product = new QbsProduct(data); - products.push(product); - } - - const subProjects = project ? (project['sub-projects'] || []) : []; - for (const subProject of subProjects) { - await parseProject(subProject); - } - }; - await parseProject(this._data); - return products; - } + isEmpty(): boolean { return this._data ? true : false; } + products(): QbsProductData[] { return this._data?.products() || []; } async updateSteps() { await this._buildStep.restore(); diff --git a/src/qbsprojectexplorer.ts b/src/qbsprojectexplorer.ts index d6846d0..73edc91 100644 --- a/src/qbsprojectexplorer.ts +++ b/src/qbsprojectexplorer.ts @@ -171,9 +171,8 @@ class QbsProjectDataProvider implements vscode.TreeDataProvider { if (node) { return node.getChildren(); } - const data = this._session.project()?.data(); - if (data) { - const project = new QbsProjectData(data); + const project = this._session.project()?.data(); + if (project) { return [ new QbsProjectNode(project, true) ]; } return []; diff --git a/src/qbsselectors.ts b/src/qbsselectors.ts index e161a22..1ee3ec2 100644 --- a/src/qbsselectors.ts +++ b/src/qbsselectors.ts @@ -3,7 +3,7 @@ import {basename} from 'path'; import {QbsSession} from './qbssession'; import {QbsProject} from './qbsproject'; -import {QbsProfile, QbsConfig, QbsProduct, QbsDebugger} from './qbssteps'; +import {QbsProfileData, QbsConfigData, QbsProductData, QbsDebuggerData} from './qbstypes'; export async function displayWorkspaceProjectSelector(session: QbsSession) { const projects = await QbsProject.enumerateWorkspaceProjects(); @@ -25,7 +25,7 @@ export async function displayWorkspaceProjectSelector(session: QbsSession) { export async function displayProfileSelector(session: QbsSession) { const profiles = await session.settings().enumerateProfiles(); interface QbsProfileQuickPickItem extends vscode.QuickPickItem { - profile: QbsProfile; + profile: QbsProfileData; } const items: QbsProfileQuickPickItem[] = profiles.map(profile => { return { @@ -42,7 +42,7 @@ export async function displayProfileSelector(session: QbsSession) { export async function displayConfigurationSelector(session: QbsSession) { const configurations = await session.settings().enumerateConfigurations(); interface QbsConfigQuickPickItem extends vscode.QuickPickItem { - configuration: QbsConfig; + configuration: QbsConfigData; } const items: QbsConfigQuickPickItem[] = configurations.map(configuration => { return { @@ -62,17 +62,17 @@ export async function displayConfigurationSelector(session: QbsSession) { placeHolder: 'Enter custom configuration name', }); const selectedCustomConfiguration = customConfigurationName - ? new QbsConfig(customConfigurationName) : undefined; + ? new QbsConfigData(customConfigurationName) : undefined; session.project()?.buildStep().setup(undefined, selectedCustomConfiguration, undefined); } } export async function displayBuildProductSelector(session: QbsSession) { const products = [ - new QbsProduct('all') - ].concat(await session.project()?.enumerateProducts() || []); + new QbsProductData('all') + ].concat(session.project()?.products() || []); interface QbsProductQuickPickItem extends vscode.QuickPickItem { - product: QbsProduct; + product: QbsProductData; } const items: QbsProductQuickPickItem[] = products?.map(product => { return { @@ -87,10 +87,10 @@ export async function displayBuildProductSelector(session: QbsSession) { } export async function displayRunProductSelector(session: QbsSession) { - const products = (await session.project()?.enumerateProducts() || []) + const products = (session.project()?.products() || []) .filter(product => product.isRunnable()); interface QbsProductQuickPickItem extends vscode.QuickPickItem { - product: QbsProduct; + product: QbsProductData; } const items: QbsProductQuickPickItem[] = products.map(product => { return { @@ -107,7 +107,7 @@ export async function displayRunProductSelector(session: QbsSession) { export async function displayDebuggerSelector(session: QbsSession) { const dbgs = (await session.settings().enumerateDebuggers()) || []; interface QbsDebuggerQuickPickItem extends vscode.QuickPickItem { - dbg: QbsDebugger; + dbg: QbsDebuggerData; } const items: QbsDebuggerQuickPickItem[] = dbgs.map(dbg => { return { diff --git a/src/qbssession.ts b/src/qbssession.ts index f225bc1..b07e49c 100644 --- a/src/qbssession.ts +++ b/src/qbssession.ts @@ -2,19 +2,18 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import {QbsProject} from './qbsproject'; -import {QbsRunEnvironment} from './qbssteps'; import {QbsSettings, QbsSettingsEvent} from './qbssettings'; import { QbsSessionProtocol, QbsSessionProtocolStatus } from './qbssessionprotocol'; import { - QbsOperation, + QbsOperation, QbsRunEnvironmentData, // Protocol requests. QbsGetRunEnvironmentRequest, QbsRequest, // Protocol responses. QbsHelloResponse, QbsProcessResponse, QbsTaskStartedResponse, QbsTaskProgressResponse, - QbsTaskMaxProgressResponse, QbsMessageResponse + QbsTaskMaxProgressResponse, QbsMessageResponse, QbsProjectData } from './qbstypes'; const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -211,12 +210,14 @@ export class QbsSession implements vscode.Disposable { const result = new QbsHelloResponse(response) this._onHelloReceived.fire(result); } else if (type === 'project-resolved') { - await this._project?.setData(response, true); + const data = new QbsProjectData(response['project-data']); + await this._project?.setData(data, true); await this._project?.updateSteps(); const result = new QbsMessageResponse(response['error']); this._onProjectResolved.fire(result); } else if (type === 'project-built' || type === 'build-done') { - await this._project?.setData(response, false); + const data = new QbsProjectData(response['project-data']); + await this._project?.setData(data, false); await this._project?.updateSteps(); const result = new QbsMessageResponse(response['error']); this._onProjectBuilt.fire(result); @@ -253,7 +254,7 @@ export class QbsSession implements vscode.Disposable { const result = new QbsProcessResponse(response); this._onProcessResultReceived.fire(result); } else if (type === 'run-environment') { - const env = new QbsRunEnvironment(response['full-environment']); + const env = new QbsRunEnvironmentData(response['full-environment']); this._project?.setRunEnvironment(env); const result = new QbsMessageResponse(response['error']); this._onRunEnvironmentResultReceived.fire(result); diff --git a/src/qbssettings.ts b/src/qbssettings.ts index d3b7858..98e44cb 100644 --- a/src/qbssettings.ts +++ b/src/qbssettings.ts @@ -12,7 +12,7 @@ import * as cp from 'child_process'; import * as QbsUtils from './qbsutils'; import {QbsSession} from './qbssession'; -import {QbsProfile, QbsConfig, QbsDebugger} from './qbssteps'; +import {QbsProfileData, QbsConfigData, QbsDebuggerData} from './qbstypes'; const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -197,8 +197,8 @@ export class QbsSettings implements vscode.Disposable { * * @note This function calls the Qbs executable and parses the output. */ - async enumerateProfiles(): Promise { - return new Promise((resolve, reject) => { + async enumerateProfiles(): Promise { + return new Promise((resolve, reject) => { const qbsPath = this.executablePath(); if (!qbsPath) { reject(undefined); @@ -212,7 +212,7 @@ export class QbsSettings implements vscode.Disposable { if (error) { reject(undefined); } else { - const profiles: QbsProfile[] = []; + const profiles: QbsProfileData[] = []; stdout.split('\n').map(function (line) { if (!line.startsWith('profiles')) return; @@ -220,7 +220,7 @@ export class QbsSettings implements vscode.Disposable { if (startIndex !== -1) { const endIndex = line.indexOf('.', startIndex + 1); if (endIndex != -1) { - const profile = new QbsProfile(line.substring(startIndex + 1, endIndex)); + const profile = new QbsProfileData(line.substring(startIndex + 1, endIndex)); if (profiles.map(profile => profile.name()).indexOf(profile.name()) === -1) profiles.push(profile); } @@ -239,19 +239,19 @@ export class QbsSettings implements vscode.Disposable { * @note Right now these are just two hardcoded configurations * @c debug and @c release. */ - async enumerateConfigurations(): Promise { + async enumerateConfigurations(): Promise { const configurations = []; - configurations.push(new QbsConfig( + configurations.push(new QbsConfigData( 'debug', localize('qbs.configuration.debug.label', 'Debug'), localize('qbs.configuration.debug.description', 'Disable optimizations.')) ); - configurations.push(new QbsConfig( + configurations.push(new QbsConfigData( 'release', localize('qbs.configuration.release.label', 'Release'), localize('qbs.configuration.release.description', 'Enable optimizations.')) ); - configurations.push(new QbsConfig( + configurations.push(new QbsConfigData( 'custom', localize('qbs.configuration.custom.label', '[Custom]'), localize('qbs.configuration.custom.description', 'Custom configuration.')) @@ -263,16 +263,16 @@ export class QbsSettings implements vscode.Disposable { * Returns the list of all available debug configurations * stored in the 'launch.json' files. */ - async enumerateDebuggers(): Promise { - return new Promise((resolve, reject) => { + async enumerateDebuggers(): Promise { + return new Promise((resolve, reject) => { const settingsPath = this.debuggerSettingsPath(); fs.readFile(settingsPath, (error, data) => { - const debuggers: QbsDebugger[] = []; + const debuggers: QbsDebuggerData[] = []; try { const json = JSON.parse(data.toString()); const configurations = (json['configurations'] || []); for (const configuration of configurations) { - debuggers.push(new QbsDebugger(configuration)); + debuggers.push(new QbsDebuggerData(configuration)); } } catch (e) { } diff --git a/src/qbssteps.ts b/src/qbssteps.ts index 6ff6bd3..27d0920 100644 --- a/src/qbssteps.ts +++ b/src/qbssteps.ts @@ -1,45 +1,15 @@ import * as vscode from 'vscode'; -import {QbsProject} from './qbsproject'; - -export class QbsProfile { - constructor(private readonly _name: string = '') {} - name(): string { return this._name; } -} - -export class QbsConfig { - constructor(private readonly _name: string, private readonly _displayName?: string, private readonly _description?: string) {} - name(): string { return this._name; } - displayName(): string | undefined { return this._displayName; } - description(): string | undefined { return this._description; } -} - -export class QbsProduct { - constructor(private readonly _data: any) {} - - fullDisplayName(): string { return (typeof this._data === 'string') - ? this._data.toString() : this._data['full-display-name']; } - targetExecutable(): string { return this._data['target-executable']; } - isRunnable(): boolean { return this._data['is-runnable']; } - isEnabled(): boolean { return this._data['is-enabled']; } - isEmpty(): boolean { return typeof this._data === 'string'; } -} - -export class QbsDebugger { - constructor(private readonly _data: any) {} - name(): string { return this._data['name']; } - data(): vscode.DebugConfiguration { return this._data; } -} - -export class QbsRunEnvironment { - constructor(private readonly _data: any) {} - data(): any { return this._data; } -} +import {QbsProject} from './qbsproject'; +import { + QbsProductData, QbsProfileData, QbsConfigData, + QbsDebuggerData, QbsRunEnvironmentData +} from './qbstypes' export class QbsBuildStep implements vscode.Disposable { - private _profile: QbsProfile = new QbsProfile(); - private _config: QbsConfig = new QbsConfig('debug'); - private _product: QbsProduct = new QbsProduct(''); + private _profile: QbsProfileData = new QbsProfileData(); + private _config: QbsConfigData = new QbsConfigData('debug'); + private _product: QbsProductData = new QbsProductData(''); private _onChanged: vscode.EventEmitter = new vscode.EventEmitter(); readonly onChanged: vscode.Event = this._onChanged.event; @@ -77,7 +47,7 @@ export class QbsBuildStep implements vscode.Disposable { } } - async setup(profile?: QbsProfile, configuration?: QbsConfig, product?: QbsProduct) { + async setup(profile?: QbsProfileData, configuration?: QbsConfigData, product?: QbsProductData) { let changed = false; let autoResolveRequred = false; if (this.setupProfile(profile)) { @@ -108,17 +78,17 @@ export class QbsBuildStep implements vscode.Disposable { const configurations = await this._project.session().settings().enumerateConfigurations(); const name = this._project.session().extensionContext().workspaceState.get(`${group}BuildConfigurationName`); const index = configurations.findIndex((configuration) => configuration.name() == name); - return (index !== -1) ? configurations[index] : (name ? new QbsConfig(name) : undefined); + return (index !== -1) ? configurations[index] : (name ? new QbsConfigData(name) : undefined); } private async extractProduct(group: string) { - const products = await this._project.enumerateProducts(); + const products = this._project.products(); const name = this._project.session().extensionContext().workspaceState.get(`${group}BuildProductName`); const index = products.findIndex((product) => product.fullDisplayName() == name); - return (index !== -1) ? products[index] : (name === 'all' ? new QbsProduct(name) : undefined); + return (index !== -1) ? products[index] : (name === 'all' ? new QbsProductData(name) : undefined); } - private setupProfile(profile?: QbsProfile): boolean { + private setupProfile(profile?: QbsProfileData): boolean { if (profile && profile.name() !== this._profile.name()) { this._profile = profile; return true; @@ -126,7 +96,7 @@ export class QbsBuildStep implements vscode.Disposable { return false; } - private setupConfiguration(configuration?: QbsConfig) { + private setupConfiguration(configuration?: QbsConfigData) { if (configuration && configuration.name() != this._config.name()) { this._config = configuration; return true; @@ -134,7 +104,7 @@ export class QbsBuildStep implements vscode.Disposable { return false; } - private setupProduct(product?: QbsProduct) { + private setupProduct(product?: QbsProductData) { if (product && product.fullDisplayName() !== this._product.fullDisplayName()) { this._product = product; return true; @@ -144,9 +114,9 @@ export class QbsBuildStep implements vscode.Disposable { } export class QbsRunStep implements vscode.Disposable { - private _product?: QbsProduct; - private _gdb?: QbsDebugger; - private _env?: QbsRunEnvironment; + private _product?: QbsProductData; + private _gdb?: QbsDebuggerData; + private _env?: QbsRunEnvironmentData; private _onChanged: vscode.EventEmitter = new vscode.EventEmitter(); readonly onChanged: vscode.Event = this._onChanged.event; @@ -158,8 +128,8 @@ export class QbsRunStep implements vscode.Disposable { project(): QbsProject { return this._project; } productName(): string { return this._product?.fullDisplayName() || ''; } targetExecutable(): string { return this._product?.targetExecutable() || ''; } - debugger(): QbsDebugger | undefined { return this._gdb; } - runEnvironment(): QbsRunEnvironment | undefined { return this._env; } + debugger(): QbsDebuggerData | undefined { return this._gdb; } + runEnvironment(): QbsRunEnvironmentData | undefined { return this._env; } debuggerName(): string | undefined { return this._gdb?.name(); } async restore() { @@ -173,7 +143,7 @@ export class QbsRunStep implements vscode.Disposable { await this._project.session().extensionContext().workspaceState.update(`${group}RunProductName`, this.productName()); } - async setup(product?: QbsProduct, dbg?: QbsDebugger, env?: QbsRunEnvironment ) { + async setup(product?: QbsProductData, dbg?: QbsDebuggerData, env?: QbsRunEnvironmentData) { let changed = false; let autoResolveRequred = false; if (this.setupProduct(product)) { @@ -192,14 +162,14 @@ export class QbsRunStep implements vscode.Disposable { } private async extractProduct(group: string) { - const products = (await this._project.session().project()?.enumerateProducts() || []) + const products = (this._project.session().project()?.products() || []) .filter(product => product.isRunnable()); const name = this._project.session().extensionContext().workspaceState.get(`${group}RunProductName`); const index = products.findIndex((product) => product.fullDisplayName() == name); return (index !== -1) ? products[index] : (products.length > 0 ? products[0] : undefined); } - private setupProduct(product?: QbsProduct): boolean { + private setupProduct(product?: QbsProductData): boolean { if (product) { this._product = product; return true; @@ -207,7 +177,7 @@ export class QbsRunStep implements vscode.Disposable { return false; } - private setupDebugger(gdb?: QbsDebugger): boolean { + private setupDebugger(gdb?: QbsDebuggerData): boolean { if (gdb && gdb.name() !== this._gdb?.name()) { this._gdb = gdb; return true; @@ -215,7 +185,7 @@ export class QbsRunStep implements vscode.Disposable { return false; } - private setupRunEnvironment(env?: QbsRunEnvironment): boolean { + private setupRunEnvironment(env?: QbsRunEnvironmentData): boolean { if (env) { this._env = env; return true; diff --git a/src/qbstypes.ts b/src/qbstypes.ts index fbae0ce..ad7d87b 100644 --- a/src/qbstypes.ts +++ b/src/qbstypes.ts @@ -1,3 +1,4 @@ +import * as vscode from 'vscode'; import * as fs from 'fs'; import {basename} from 'path'; @@ -262,6 +263,7 @@ export class QbsProjectData { name(): string { return this._data['name']; } buildDirectory(): string { return this._data['build-directory']; } location(): QbsLocationData { return new QbsLocationData(this._data['location']); } + isEmpty():boolean { return this._data === undefined; } products(): QbsProductData[] { const products: QbsProductData[] = []; @@ -282,15 +284,23 @@ export class QbsProjectData { } return projects; } + + setBuildSystemFiles(files: any) { this._data['build-system-files'] = files; } + buildSystemFiles(): any { return this._data['build-system-files']; } } export class QbsProductData { constructor(private readonly _data: any) {} id(): string { return this.buildDirectory(); } name(): string { return this._data['name']; } - fullDisplayName() { return this._data['full-display-name']; } + fullDisplayName(): string { return (typeof this._data === 'string') + ? this._data.toString() : this._data['full-display-name']; } buildDirectory(): string { return this._data['build-directory']; } location(): QbsLocationData { return new QbsLocationData(this._data['location']); } + targetExecutable(): string { return this._data['target-executable']; } + isRunnable(): boolean { return this._data['is-runnable']; } + isEnabled(): boolean { return this._data['is-enabled']; } + isEmpty(): boolean { return typeof this._data === 'string'; } groups(): QbsGroupData[] { const groups: QbsGroupData[] = []; @@ -338,3 +348,28 @@ export class QbsSourceArtifactData { fileName(): string { return basename(this.filePath()); } id(): string { return this.filePath(); } } + +// QBS project configurations. + +export class QbsProfileData { + constructor(private readonly _name: string = '') {} + name(): string { return this._name; } +} + +export class QbsConfigData { + constructor(private readonly _name: string, private readonly _displayName?: string, private readonly _description?: string) {} + name(): string { return this._name; } + displayName(): string | undefined { return this._displayName; } + description(): string | undefined { return this._description; } +} + +export class QbsDebuggerData { + constructor(private readonly _data: any) {} + name(): string { return this._data['name']; } + data(): vscode.DebugConfiguration { return this._data; } +} + +export class QbsRunEnvironmentData { + constructor(private readonly _data: any) {} + data(): any { return this._data; } +}