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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@
{
"category": "CMSIS",
"command": "cmsis-csolution.mergeFile",
"title": "Merge Updated Config File",
"title": "Open Merge View",
"icon": "$(git-merge)"
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,12 @@ describe('FileItem', () => {

// check attributes and merge features for each file node
const fileLabels = ['RTX_Config.c', 'RTX_Config.h'];
const fileStatuses = ['- (X) \'RTX_Config.c\' is incompatible. A file update is mandatory.', '- (?) \'RTX_Config.h\' has corrections. A file update is suggested.'];
const fileDescriptions = ['(X)', '(?)'];
createdChildren.forEach((child, idx) => {
expect(child.getTag()).toBe('file');
expect(child.getAttribute('label')).toContain(fileLabels[idx]);
expect(child.getAttribute('update')).toContain('update');
expect(child.getAttribute('base')).toContain('base');
expect(child.getAttribute('description')).toContain(fileDescriptions[idx]);
expect(child.getAttribute('tooltip')).toContain(fileStatuses[idx]);
expect(child.getAttribute('description')).toBeUndefined();
});

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import path from 'path';
import { CTreeItem, ITreeItem } from '../../../generic/tree-item';
import { FILE_TAGS } from '../../../solutions/constants';
import { COutlineItem } from './solution-outline-item';
import { getStatusTooltip, setContextMenuAttributes, setHeaderContext, setMergeDescription, setMergeFileContext } from './solution-outline-utils';
import { setContextMenuAttributes, setHeaderContext, setMergeFileContext } from './solution-outline-utils';
import { matchesContext } from '../../../utils/context-utils';
import { SolutionOutlineItemBuilder } from './solution-outline-item-builder';
import { CSolution } from '../../../solutions/csolution';
Expand Down Expand Up @@ -131,24 +131,6 @@ export class FileItemBuilder extends SolutionOutlineItemBuilder {

// assign merge context
setMergeFileContext(cfileItem);

// assign description
setMergeDescription(cfileItem, fileStatus);

// set tooltip
const existingTooltip = cfileItem.getValue('tooltip');
const label = cfileItem.getValue('label');

if (label) {
const statusTooltip = getStatusTooltip(label, fileStatus);

if (existingTooltip) {
cfileItem.setAttribute('tooltip', existingTooltip + '\n' + statusTooltip);
} else {
cfileItem.setAttribute('tooltip', statusTooltip);
}
}

cfileItem.setAttribute('local', localPath);
cfileItem.setAttribute('update', updatePath);
cfileItem.setAttribute('base', basePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ describe('HardwareItemBuilder', () => {
const gotBase = base ? path.basename(base) : '';
const wantBase = 'Hello+CS300.dbgconf.base@0.0.1';
expect(gotBase).toEqual(wantBase);

expect(device?.getAttribute('tooltip')).toContain('- (?) \'Hello+CS300.dbgconf\' has corrections. A file update is suggested.');
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ import { FileItemBuilder } from './solution-outline-file-item';
import { COutlineItem } from './solution-outline-item';
import * as manifest from '../../../manifest';
import { CSolution } from '../../../solutions/csolution';
import { getMapFilePath, getStatusTooltip, setDocContext, setHeaderContext, setLinkerContext, setMergeDescription, setMergeUpdate } from './solution-outline-utils';
import { getMapFilePath, setDocContext, setHeaderContext, setLinkerContext } from './solution-outline-utils';
import { CProjectYamlFile } from '../../../solutions/files/cproject-yaml-file';
import { SolutionOutlineItemBuilder } from './solution-outline-item-builder';

export class ProjectItemsBuilder extends SolutionOutlineItemBuilder {
private _lastPrioritizedComponentList: COutlineItem[] = [];
private readonly _lastPrioritizedComponentList: COutlineItem[] = [];

public get lastPrioritizedComponentList(): COutlineItem[] {
return this._lastPrioritizedComponentList;
Expand Down Expand Up @@ -222,62 +222,9 @@ export class ProjectItemsBuilder extends SolutionOutlineItemBuilder {
}

this.addComponentOptions(componentNodes);

// add merge description
const components = Array.from(componentNodes.values());
const fileStatus = this.getMergeDescriptionAtParentComponentLevel(components);
if (fileStatus) {
// assign description
setMergeDescription(componentsItem, fileStatus);

// assign tooltip with component ids
const prioritizedList = this._lastPrioritizedComponentList;
let newTooltip = 'Components with updated configuration files:';
for (const comp of prioritizedList) {
const compId = comp.getAttribute('label');
const compStatus = comp.getAttribute('status');
if (compId && compStatus) {
const update = comp.getAttribute('update');
newTooltip += `\n- ${update} ${compId}: ${compStatus}`;
}
}
componentsItem.setAttribute('tooltip', newTooltip);
}
return true; // do have components to edit
}

private getMergeDescriptionAtParentComponentLevel(components: COutlineItem[]): string | undefined {
let result: string | undefined = undefined;
const updateRequired: COutlineItem[] = [];
const updateRecommended: COutlineItem[] = [];
const updateSuggested: COutlineItem[] = [];

for (const component of components) {
const status = component.getAttribute('status');
if (!status) {
continue;
}
if (status == 'update required') {
updateRequired.push(component);
} else if (status == 'update recommended') {
updateRecommended.push(component);
} else if (status == 'update suggested') {
updateSuggested.push(component);
}
}

const prioritizedList = [...updateRequired, ...updateRecommended, ...updateSuggested];
this._lastPrioritizedComponentList = prioritizedList;
const prioritizedFile = prioritizedList[0];

const fileStatus = prioritizedFile?.getAttribute('status');
if (fileStatus) {
result = fileStatus;
}

return result;
}

private addComponentOptions(componentNodes: Map<string, COutlineItem>) {
const components = componentNodes.values();

Expand Down Expand Up @@ -437,31 +384,6 @@ export class ProjectItemsBuilder extends SolutionOutlineItemBuilder {

// set status at component level
node.setAttribute('status', fileStatus);

// assign description
setMergeDescription(node, fileStatus);

// assign status symbol for merge update action
setMergeUpdate(node, fileStatus);

// set tooltip
const prevTooltip = node.getValue('tooltip');
let newTooltip: string = '';
for (const file of prioritizedList) {
const fileLabel = file.getValue('file');
const fileStatus = file.getValue('status');
if (fileLabel && fileStatus) {
const tooltip = getStatusTooltip(fileLabel, fileStatus);
newTooltip += `\n ${tooltip}`;
}
}

if (prevTooltip) {
node.setAttribute('tooltip', prevTooltip + '\n' + newTooltip);
} else {
node.setAttribute('tooltip', newTooltip);
}

}

private getPrioritizedMergeFile(files: ITreeItem<CTreeItem>[]): ITreeItem<CTreeItem>[] {
Expand Down
21 changes: 0 additions & 21 deletions src/views/solution-outline/tree-structure/solution-outline-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import * as manifest from '../../../manifest';
import { HardwareItemBuilder } from './solution-outline-hardware-item';
import { ProjectItemsBuilder } from './solution-outline-project-items';
import { getFileNameNoExt } from '../../../utils/path-utils';
import { setMergeDescription } from './solution-outline-utils';
import { CProjectYamlFile } from '../../../solutions/files/cproject-yaml-file';
import { SolutionOutlineItemBuilder } from './solution-outline-item-builder';

Expand Down Expand Up @@ -122,26 +121,6 @@ export class SolutionOutlineTree extends SolutionOutlineItemBuilder {
if (cproject) {
const projectItems = new ProjectItemsBuilder(this.csolution, this.rpcData, context);
projectItems.addProjectChildren(this.csolution, cprojectItem, cprojectFile, cbuild);

// get prioritized component list and set merge description if available
const prioritizedList = projectItems.lastPrioritizedComponentList;
if (prioritizedList && prioritizedList.length > 0) {
const fileStatus = prioritizedList[0].getAttribute('status');
if (fileStatus) {
setMergeDescription(cprojectItem, fileStatus);

// set tooltip
const existingTooltip = cprojectItem.getAttribute('tooltip');
const description = cprojectItem.getAttribute('description');
const newTooltip = `- ${description} Component config files: ${fileStatus}`;

if (existingTooltip) {
cprojectItem.setAttribute('tooltip', existingTooltip + '\n' + newTooltip);
} else {
cprojectItem.setAttribute('tooltip', newTooltip);
}
}
}
} else {
cprojectItem.setAttribute('description', 'error loading project');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,6 @@ export function setMergeFiles(component: COutlineItem, file: ITreeItem<CTreeItem
component.setAttribute('base', basePath);
}

export function getStatusTooltip(label: string, status: string): string | undefined {
switch (status) {
case 'update suggested':
return `- (?) '${label}' has corrections. A file update is suggested.`;
case 'update recommended':
return `- (!) '${label}' has new features. A file update is recommended.`;
case 'update required':
return `- (X) '${label}' is incompatible. A file update is mandatory.`;
default:
return undefined;
}
}

export function setLinkerContext(node: COutlineItem, mapFilePath: string): void {
node.addFeature(`${manifest.LINKER_CONTEXT}`);
node.setAttribute('type', 'linkerMapFile');
Expand All @@ -83,20 +70,6 @@ export function getMapFilePath(cbuild: CTreeItem): string | undefined {
return mapFile ? path.join(outDirPath, mapFile) : findFirstMapFile(outDirPath);
}

export function setMergeDescription(node: COutlineItem, fileStatus: string): void {
const desc = getMergeStatusSymbol(fileStatus);
if (desc !== undefined) {
node.setAttribute('description', desc);
}
}

export function setMergeUpdate(node: COutlineItem, fileStatus: string): void {
const update = getMergeStatusSymbol(fileStatus);
if (update !== undefined) {
node.setAttribute('update', update);
}
}

function getOutdirPath(cbuild: CTreeItem): string | undefined {
const outputDirs = cbuild.getChild('output-dirs');
const outdir = outputDirs?.getValue('outdir');
Expand Down Expand Up @@ -128,15 +101,3 @@ function findFirstMapFile(dirPath: string): string | undefined {
return undefined;
}

function getMergeStatusSymbol(fileStatus: string): string | undefined {
switch (fileStatus) {
case 'update required':
return '(X)';
case 'update recommended':
return '(!)';
case 'update suggested':
return '(?)';
default:
return undefined;
}
}
73 changes: 73 additions & 0 deletions src/views/solution-outline/treeview-decoration-provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,77 @@ describe('provideFileDecoration', () => {

expect(refreshSpy).toHaveBeenCalled();
});

it('should return merge decoration for files with merge feature', () => {
const filePath = path.join('src', 'merge', 'file.c');
const uri = URI.file(filePath);

const root = new COutlineItem('root');
const project = root.createChild('project');
const group = project.createChild('group');
const file = group.createChild('file');
file.setTag('file');
file.setAttribute('resourcePath', uri.fsPath);
file.addFeature('mergeFile:');

treeViewDecorationProvider.setTreeRoot(root);

const result = treeViewDecorationProvider.provideFileDecoration(uri);

expect(result).toEqual({
badge: TreeViewFileDecorationProvider.mergeBadge,
tooltip: TreeViewFileDecorationProvider.mergeTooltip,
color: { id: TreeViewFileDecorationProvider.mergeColor },
});
});

it('should prioritize excluded decoration over merge decoration', () => {
const filePath = path.join('src', 'merge', 'excluded.c');
const uri = URI.file(filePath);

const root = new COutlineItem('root');
const project = root.createChild('project');
const group = project.createChild('group');
const file = group.createChild('file');
file.setTag('file');
file.setAttribute('resourcePath', uri.fsPath);
file.addFeature('mergeFile:');
file.setAttribute('excluded', '1');

treeViewDecorationProvider.setTreeRoot(root);

const result = treeViewDecorationProvider.provideFileDecoration(uri);

expect(result).toEqual({
badge: TreeViewFileDecorationProvider.excludedBadge,
tooltip: TreeViewFileDecorationProvider.excludedTooltip,
color: { id: TreeViewFileDecorationProvider.excludedColor },
});
});

it('should prioritize merge decoration over pack-sourced decoration', () => {
const packCachePath = 'MOCKED_CMSIS_PACK_ROOT';
jest.spyOn(path_utils, 'getCmsisPackRoot').mockReturnValue(packCachePath);

const filePath = path.join(packCachePath, 'root', 'merge.c');
const uri = URI.file(filePath);

const root = new COutlineItem('root');
const project = root.createChild('project');
const group = project.createChild('group');
const file = group.createChild('file');
file.setTag('file');
file.setAttribute('resourcePath', uri.fsPath);
file.addFeature('mergeFile:');

treeViewDecorationProvider.setTreeRoot(root);

const result = treeViewDecorationProvider.provideFileDecoration(uri);

expect(result).toEqual({
badge: TreeViewFileDecorationProvider.mergeBadge,
tooltip: TreeViewFileDecorationProvider.mergeTooltip,
color: { id: TreeViewFileDecorationProvider.mergeColor },
});
});
});
15 changes: 15 additions & 0 deletions src/views/solution-outline/treeview-decoration-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ import { ThemeProvider } from '../../vscode-api/theme-provider';
import { URI } from 'vscode-uri';
import { getCmsisPackRoot } from '../../utils/path-utils';
import { COutlineItem } from './tree-structure/solution-outline-item';
import * as manifest from '../../manifest';

export class TreeViewFileDecorationProvider implements vscode.FileDecorationProvider {
static readonly badge: string = 'P';
static readonly tooltip: string = 'Pack sourced';
static readonly themeColor: string = 'descriptionForeground';

static readonly mergeBadge: string = 'N';
static readonly mergeTooltip: string = 'New Version Available for Merge';
static readonly mergeColor: string = 'charts.blue';
Comment thread
mguzmanm marked this conversation as resolved.

static readonly excludedBadge: string = 'X';
static readonly excludedTooltip: string = 'Excluded from build';
static readonly excludedColor: string = 'errorForeground';
Expand Down Expand Up @@ -60,6 +65,16 @@ export class TreeViewFileDecorationProvider implements vscode.FileDecorationProv
};
}

// Merge-enabled files have higher priority than pack-sourced files
const features = fileItem?.getFeatures().split(';') ?? [];
if (features.includes(manifest.MERGE_FILE_CONTEXT)) {
return {
badge: TreeViewFileDecorationProvider.mergeBadge,
tooltip: TreeViewFileDecorationProvider.mergeTooltip,
color: this.themeProvider.getThemeColor(TreeViewFileDecorationProvider.mergeColor),
};
}

// Check for pack-sourced files
const cmsisPackRoot = getCmsisPackRoot();
const cmsisPackRootUri = URI.file(cmsisPackRoot);
Expand Down
Loading