diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e7af68..096c565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # What's New? +## 2.1.6 + +- [#79](https://github.com/denis-shienkov/vscode-qbs/issues/79) +Fixed that, artifacts with a long paths are displayed as a view +with the hierarchical subfolders in the project tree. + ## 2.1.5 - Added new **Qbs: Export Build Profiles** command to diff --git a/src/projectexplorer/qbsbasenode.ts b/src/projectexplorer/qbsbasenode.ts index 40289a9..06a4925 100644 --- a/src/projectexplorer/qbsbasenode.ts +++ b/src/projectexplorer/qbsbasenode.ts @@ -13,6 +13,7 @@ export enum QbsBaseNodeContext { RootProject = 'root-project-node', SourceArtifact = 'source-artifact-node', SubProject = 'sub-project-node', + Folder = 'folder-node', } export enum QbsBaseNodeTheme { diff --git a/src/projectexplorer/qbsfolderdata.ts b/src/projectexplorer/qbsfolderdata.ts new file mode 100644 index 0000000..c253de9 --- /dev/null +++ b/src/projectexplorer/qbsfolderdata.ts @@ -0,0 +1,43 @@ +import * as path from 'path'; + +import { isChildOf } from '../qbsutils'; + +import { QbsProtocolSourceArtifactData } from '../protocol/qbsprotocolsourceartifactdata'; + +export class QbsFolderData { + private readonly folders: QbsFolderData[] + private readonly sources: QbsProtocolSourceArtifactData[] + + public constructor( + allSources: QbsProtocolSourceArtifactData[], + private readonly fsPath: string) { + + this.folders = allSources + .map(artifactData => { + return path.dirname(artifactData.getFilePath() || ""); + }) + .filter(fsPath => { + if (fsPath && (fsPath.length > 0)) + return isChildOf(fsPath, this.fsPath); + }) + .map(fsPath => { + const parts = path.relative(this.fsPath, fsPath).split(path.sep); + return (parts.length > 0) ? path.join(this.fsPath, parts[0]) : ""; + }).filter((fsPath, index, self) => { + return (fsPath && (index === self.indexOf(fsPath))); + }).map(fsPath => { + return new QbsFolderData(allSources, fsPath); + }); + + this.sources = allSources.filter(artifactData => { + const fsPath = artifactData.getFilePath(); + if (fsPath) + return (path.normalize(path.dirname(fsPath)) === path.normalize(this.fsPath)); + }); + } + + public getFolders(): QbsFolderData[] { return this.folders; } + public getSources(): QbsProtocolSourceArtifactData[] { return this.sources; } + public getPath(): string { return this.fsPath; } + public getName(): string { return path.basename(this.fsPath); } +} diff --git a/src/projectexplorer/qbsfoldernode.ts b/src/projectexplorer/qbsfoldernode.ts new file mode 100644 index 0000000..6e4d39b --- /dev/null +++ b/src/projectexplorer/qbsfoldernode.ts @@ -0,0 +1,51 @@ +import * as vscode from 'vscode'; + +import { QbsBaseNode } from './qbsbasenode'; +import { QbsFolderData } from './qbsfolderdata'; +import { QbsProtocolSourceArtifactData } from '../protocol/qbsprotocolsourceartifactdata'; +import { QbsSourceArtifactNode } from './qbssourceartifactnode'; + +enum QbsFolderNodeIcon { + Folder = 'folder', +} + +/** The data type encapsulates the Qbs files folder object to display in the project tree. */ +export class QbsFolderNode extends QbsBaseNode { + private readonly name: string + private readonly folders: QbsFolderData[] + private readonly sources: QbsProtocolSourceArtifactData[] + + public constructor( + resourcesPath: string, + showDisabledNodes: boolean, + folderData: QbsFolderData, + private readonly isEnabled: boolean) { + super(resourcesPath, showDisabledNodes); + + const name = folderData.getName(); + if (!name) + throw new Error('Unable to create folder node because the name is undefined'); + this.name = name; + + this.folders = folderData.getFolders(); + this.sources = folderData.getSources(); + } + + public getTreeItem(): vscode.TreeItem { + const item = new vscode.TreeItem(this.getLabel(), vscode.TreeItemCollapsibleState.Collapsed); + item.id = this.uuid; + item.iconPath = new vscode.ThemeIcon(QbsFolderNodeIcon.Folder); + return item; + } + + public getChildren(): QbsBaseNode[] { + return [ + ...this.folders.map(folderData => new QbsFolderNode( + this.resourcesPath, this.showDisabledNodes, folderData, this.isEnabled)), + ...this.sources.map(artifactData => new QbsSourceArtifactNode( + this.resourcesPath, this.showDisabledNodes, artifactData, this.isEnabled)) + ]; + } + + private getLabel(): string { return QbsBaseNode.createLabel(this.name, this.isEnabled); } +} diff --git a/src/projectexplorer/qbsgroupnode.ts b/src/projectexplorer/qbsgroupnode.ts index 6e9b396..9ec100b 100644 --- a/src/projectexplorer/qbsgroupnode.ts +++ b/src/projectexplorer/qbsgroupnode.ts @@ -1,13 +1,15 @@ +import * as path from 'path'; import * as vscode from 'vscode'; import { QbsBaseNode } from './qbsbasenode'; +import { QbsFolderData } from './qbsfolderdata'; +import { QbsFolderNode } from './qbsfoldernode'; import { QbsLocationNode } from './qbslocationnode'; import { QbsProtocolGroupData } from '../protocol/qbsprotocolgroupdata'; -import { QbsProtocolSourceArtifactData } from '../protocol/qbsprotocolsourceartifactdata'; -import { QbsSourceArtifactNode } from './qbssourceartifactnode'; import { QbsProtocolLocationData } from '../protocol/qbsprotocollocationdata'; +import { QbsSourceArtifactNode } from './qbssourceartifactnode'; -enum QbsPGroupNodeIcon { +enum QbsGroupNodeIcon { Group = 'files', } @@ -15,9 +17,7 @@ enum QbsPGroupNodeIcon { export class QbsGroupNode extends QbsBaseNode { private readonly name: string private readonly location: QbsProtocolLocationData - private readonly fsPath: string - private readonly sources: QbsProtocolSourceArtifactData[]; - private readonly wildcards: QbsProtocolSourceArtifactData[]; + private readonly folder: QbsFolderData private readonly isEnabled: boolean public constructor( @@ -39,17 +39,17 @@ export class QbsGroupNode extends QbsBaseNode { const fsPath = location.getFilePath(); if (!fsPath) throw new Error('Unable to create group node because the file path is undefined'); - this.fsPath = fsPath; + const fsParent = path.dirname(fsPath); - this.sources = groupData.getSourceArtifacts(); - this.wildcards = groupData.getSourceWildcardArtifacts(); + const allSources = [...groupData.getSourceArtifacts(), ...groupData.getSourceWildcardArtifacts()]; + this.folder = new QbsFolderData(allSources, fsParent); this.isEnabled = groupData.getIsEnabled() || false; } public getTreeItem(): vscode.TreeItem { const item = new vscode.TreeItem(this.getLabel(), vscode.TreeItemCollapsibleState.Collapsed); item.id = this.uuid; - item.iconPath = new vscode.ThemeIcon(QbsPGroupNodeIcon.Group); + item.iconPath = new vscode.ThemeIcon(QbsGroupNodeIcon.Group); return item; } @@ -57,9 +57,9 @@ export class QbsGroupNode extends QbsBaseNode { return [ ...[new QbsLocationNode( this.resourcesPath, this.showDisabledNodes, this.location, this.isEnabled, true)], - ...this.sources.map(artifactData => new QbsSourceArtifactNode( - this.resourcesPath, this.showDisabledNodes, artifactData, this.isEnabled)), - ...this.wildcards.map(artifactData => new QbsSourceArtifactNode( + ...this.folder.getFolders().map(folderData => new QbsFolderNode( + this.resourcesPath, this.showDisabledNodes, folderData, this.isEnabled)), + ...this.folder.getSources().map(artifactData => new QbsSourceArtifactNode( this.resourcesPath, this.showDisabledNodes, artifactData, this.isEnabled)) ]; }