Skip to content

Commit 06bba9a

Browse files
authored
Merge branch 'main' into bump-vsce-helper
2 parents 7bd2ba4 + 3877ead commit 06bba9a

9 files changed

Lines changed: 296 additions & 190 deletions

File tree

src/desktop/extension.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ export const activate = async (context: ExtensionContext): Promise<CsolutionExte
224224
commandsProvider,
225225
configurationProvider,
226226
csolutionService,
227+
externalFileOpener,
227228
);
228229
context.subscriptions.push(window.registerCustomEditorProvider(
229230
ManageSolutionCustomEditorProvider.viewType,

src/views/common/components/cmsis-codicon.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,35 @@ const CMSIS_CODICON_CODEPOINTS = {
2424

2525
export type CmsisCodiconName = keyof typeof CMSIS_CODICON_CODEPOINTS;
2626

27-
type Props = {
28-
name: CmsisCodiconName;
29-
title?: string;
30-
className?: string;
31-
style?: React.CSSProperties;
27+
type Props = React.ComponentPropsWithoutRef<'span'> & {
28+
name: CmsisCodiconName | string;
3229
fontFamily?: string; // default is your custom webview font
3330
};
3431

3532
export const CmsisCodicon: React.FC<Props> = ({
3633
name,
37-
title,
3834
className,
3935
style,
4036
fontFamily = 'cmsis-codicon',
37+
...spanProps
4138
}) => {
42-
const codepoint = CMSIS_CODICON_CODEPOINTS[name];
39+
const codepoint = CMSIS_CODICON_CODEPOINTS[name as CmsisCodiconName];
40+
if (codepoint !== undefined) {
41+
return (
42+
<span
43+
{...spanProps}
44+
className={className ?? ''}
45+
style={{ fontFamily, display: 'inline-block', lineHeight: 1, ...style }}
46+
>
47+
{String.fromCodePoint(codepoint)}
48+
</span>
49+
);
50+
}
4351
return (
4452
<span
45-
title={title}
46-
className={className}
47-
style={{ fontFamily, display: 'inline-block', lineHeight: 1, ...style }}
48-
>
49-
{String.fromCodePoint(codepoint)}
50-
</span>
53+
{...spanProps}
54+
className={`codicon codicon-${name}${className ? ` ${className}` : ''}`}
55+
style={{ display: 'inline-block', lineHeight: 1, ...style }}
56+
/>
5157
);
5258
};

src/views/manage-components-packs/components-packs-webview-main.ts

Lines changed: 70 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { BuildContext, Project, TargetSetData } from './components-data';
3131
import { ComponentsPacksActions, CurrentProject, normalizeForCompare } from './components-packs-actions';
3232
import { ComponentRowDataType, ComponentScope } from './data/component-tools';
3333
import { componentTreeWalker } from './data/component-tree-walker';
34-
import { uniqWith } from 'lodash';
34+
import { uniqWith, cloneDeep } from 'lodash';
3535
import { parsePackId } from './data/pack-parse';
3636
import { lineOf, readTextFile } from '../../utils/fs-utils';
3737
import { stripTwoExtensions } from '../../utils/string-utils';
@@ -131,6 +131,12 @@ export class ComponentsPacksWebviewMain {
131131
return; // nothing to show
132132
}
133133

134+
const reload = this.projectFromPath(this.currentProject?.project.projectId) !== this.projectFromPath(cprojectPath);
135+
const csolution = this.solutionManager.getCsolution();
136+
if (csolution) {
137+
this.currentProject = { solutionPath: csolution.solutionPath, project: createProject(cprojectPath) };
138+
}
139+
134140
if (clayerPath) {
135141
const selectedTarget = this.findTargetSetFromPath(clayerPath);
136142
if (selectedTarget) {
@@ -141,7 +147,6 @@ export class ComponentsPacksWebviewMain {
141147
}
142148
this.webviewManager.createOrShowPanel();
143149

144-
const reload = this.projectFromPath(this.currentProject?.project.projectId) !== this.projectFromPath(cprojectPath);
145150
await this.debounce_load(cprojectPath, reload);
146151
await this.sendDirtyState();
147152
}
@@ -204,37 +209,39 @@ export class ComponentsPacksWebviewMain {
204209
return undefined;
205210
}
206211

207-
private async isDirty(): Promise<boolean> {
212+
private async isDirty(usedItems?: UsedItems): Promise<boolean> {
208213
const actx = this.getActiveContext();
209214

210215
if (this.solutionManager.getCsolution()?.cbuildPackFile.isModified()) {
211216
return true;
212217
}
213218

214-
const usedItems = await this.csolutionService.getUsedItems({ context: actx });
215-
if (this.usedItems?.packs.length !== usedItems.packs.length || this.usedItems?.components.length !== usedItems.components.length) {
219+
const latestUsedItems = usedItems ?? await this.csolutionService.getUsedItems({ context: actx });
220+
if (this.usedItems?.packs.length !== latestUsedItems.packs.length || this.usedItems?.components.length !== latestUsedItems.components.length) {
216221
return true;
217222
}
218223

219224
const componentMapper = (c: ComponentInstance) => ({ id: c.id, variant: c.resolvedComponent?.pack });
220225
const packMapper = (p: PackReference) => ({ pack: p.pack, origin: normalizeForCompare(p.origin) });
221226
const localUsedItemsSorted = {
222-
components: this.usedItems?.components.sort((a, b) => a.id.localeCompare(b.id)).map(componentMapper) ?? [],
223-
packs: this.usedItems?.packs.sort((a, b) => a.pack.localeCompare(b.pack)).map(packMapper) ?? [],
227+
components: [...(this.usedItems?.components ?? [])].sort((a, b) => a.id.localeCompare(b.id)).map(componentMapper),
228+
packs: [...(this.usedItems?.packs ?? [])].sort((a, b) => a.pack.localeCompare(b.pack)).map(packMapper),
224229
};
225230
const usedItemsSorted = {
226-
components: usedItems.components.sort((a, b) => a.id.localeCompare(b.id)).map(componentMapper),
227-
packs: usedItems.packs.sort((a, b) => a.pack.localeCompare(b.pack)).map(packMapper),
231+
components: [...latestUsedItems.components].sort((a, b) => a.id.localeCompare(b.id)).map(componentMapper),
232+
packs: [...latestUsedItems.packs].sort((a, b) => a.pack.localeCompare(b.pack)).map(packMapper),
228233
};
229234
const usedItemsChanged = !isDeepStrictEqual(localUsedItemsSorted, usedItemsSorted);
230235
return usedItemsChanged;
231236
}
232237

233-
private async sendDirtyState(): Promise<void> {
238+
private async sendDirtyState(options?: { skipApply?: boolean, usedItems?: UsedItems }): Promise<void> {
234239
const actx = this.getActiveContext();
235-
await this.csolutionService.apply({ context: actx });
240+
if (!options?.skipApply) {
241+
await this.csolutionService.apply({ context: actx });
242+
}
236243

237-
const isDirty = await this.isDirty();
244+
const isDirty = await this.isDirty(options?.usedItems);
238245
await this.webviewManager.sendMessage({ type: 'IS_DIRTY', isDirty: isDirty });
239246
}
240247

@@ -368,7 +375,7 @@ export class ComponentsPacksWebviewMain {
368375
label: `Layer: ${layerLabel}`,
369376
key: layer.absolutePath,
370377
path: backToForwardSlashes(layer.absolutePath),
371-
relativePath: backToForwardSlashes(path.relative(dirname(this.currentProject?.solutionPath ?? ''), layer.absolutePath)),
378+
relativePath: this.getRelativePath(this.getSolutionDir(), layer.absolutePath),
372379
type: 'layer' as const
373380
};
374381

@@ -413,11 +420,12 @@ export class ComponentsPacksWebviewMain {
413420
const activeContext = this.getActiveContext();
414421
const state = await this.csolutionService.apply({ context: activeContext });
415422
this.usedItems = await this.csolutionService.getUsedItems({ context: activeContext });
423+
const usedItemsForProjectFileUpdate = cloneDeep(this.usedItems);
416424
const projectFileName = this.currentProject?.project.projectId ?? '';
417425
const requestAll = this.scope === ComponentScope.All;
418426
this.componentTree = this.manageComponentsActions.mapComponentsFromService(await this.csolutionService.getComponentsTree({ context: activeContext, all: requestAll }));
419427
this.validations = await this.csolutionService.validateComponents({ context: activeContext });
420-
await this.projectFileUpdater.updateUsedItems(activeContext, projectFileName, this.usedItems);
428+
await this.projectFileUpdater.updateUsedItems(activeContext, projectFileName, usedItemsForProjectFileUpdate);
421429

422430
await Promise.all([
423431
this.webviewManager.sendMessage({ type: 'SET_ERROR_MESSAGES', messages: [] }),
@@ -426,7 +434,7 @@ export class ComponentsPacksWebviewMain {
426434
if (state.success === false) {
427435
this.webviewManager.sendMessage({ type: 'SET_SOLUTION_STATE', stateMessage: state.message ?? 'Unspecified error when writing solution information' });
428436
}
429-
await this.sendDirtyState();
437+
await this.sendDirtyState({ skipApply: true, usedItems: usedItemsForProjectFileUpdate });
430438
}
431439

432440
private async handleOpenFile(message: Messages.OutgoingMessage): Promise<void> {
@@ -447,9 +455,7 @@ export class ComponentsPacksWebviewMain {
447455
);
448456

449457
await this.sendDirtyState();
450-
const validations = await this.csolutionService.validateComponents({ context: activeContext });
451-
this.componentTree = this.manageComponentsActions.mapComponentsFromService(await this.csolutionService.getComponentsTree({ context: activeContext, all: this.scope === ComponentScope.All }));
452-
await this.webviewManager?.sendMessage({ type: 'SET_COMPONENT_TREE', tree: this.componentTree, validations: validations.validation });
458+
await this.refreshComponentTree(activeContext);
453459
}
454460
}
455461
}
@@ -465,9 +471,7 @@ export class ComponentsPacksWebviewMain {
465471
variant
466472
);
467473
await this.sendDirtyState();
468-
this.componentTree = this.manageComponentsActions.mapComponentsFromService(await this.csolutionService.getComponentsTree({ context: activeContext, all: this.scope === ComponentScope.All }));
469-
const validations = await this.csolutionService.validateComponents({ context: activeContext });
470-
await this.webviewManager?.sendMessage({ type: 'SET_COMPONENT_TREE', tree: this.componentTree, validations: validations.validation });
474+
await this.refreshComponentTree(activeContext);
471475
}
472476
}
473477
}
@@ -483,10 +487,7 @@ export class ComponentsPacksWebviewMain {
483487
bundle
484488
);
485489
await this.sendDirtyState();
486-
const requestAll = this.scope === ComponentScope.All;
487-
this.componentTree = this.manageComponentsActions.mapComponentsFromService(await this.csolutionService.getComponentsTree({ context: activeContext, all: requestAll }));
488-
this.validations = await this.csolutionService.validateComponents({ context: activeContext });
489-
await this.webviewManager.sendMessage({ type: 'SET_COMPONENT_TREE', tree: this.componentTree, validations: this.validations.validation ?? [], scope: this.scope });
490+
await this.refreshComponentTree(activeContext);
490491
}
491492
}
492493
}
@@ -596,37 +597,40 @@ export class ComponentsPacksWebviewMain {
596597
}
597598
};
598599

600+
private async handlePackageSelectionChange(
601+
target: string,
602+
packId: string,
603+
stateMessage: string,
604+
action: (actx: string, target: string, packId: string) => Promise<void>
605+
): Promise<void> {
606+
try {
607+
await this.webviewManager.sendMessage({ type: 'SET_SOLUTION_STATE', stateMessage });
608+
const actx = this.getActiveContext();
609+
await action(actx, target, packId);
610+
const requestAll = this.scope === ComponentScope.All;
611+
const packs = this.mapPacksFromService(await this.csolutionService.getPacksInfo({ context: actx, all: requestAll }));
612+
await this.webviewManager.sendMessage({ type: 'SET_PACKS_INFO', packs: packs?.packs || [] });
613+
await this.sendDirtyState();
614+
} finally {
615+
await this.webviewManager.sendMessage({ type: 'SET_SOLUTION_STATE', stateMessage: undefined });
616+
}
617+
}
618+
599619
private async selectPackage(message: Messages.OutgoingMessage): Promise<void> {
600620
if (isSelectPackageMessage(message)) {
601-
try {
602-
await this.webviewManager.sendMessage({ type: 'SET_SOLUTION_STATE', stateMessage: 'Selecting Pack' });
603-
604-
const actx = this.getActiveContext();
605-
await this.manageComponentsActions.selectPackage(actx, message.target, message.packId);
606-
const requestAll = this.scope === ComponentScope.All;
607-
const packs = this.mapPacksFromService(await this.csolutionService?.getPacksInfo({ context: actx, all: requestAll }));
608-
await this.webviewManager?.sendMessage({ type: 'SET_PACKS_INFO', packs: packs?.packs || [] });
609-
await this.sendDirtyState();
610-
} finally {
611-
await this.webviewManager.sendMessage({ type: 'SET_SOLUTION_STATE', stateMessage: undefined });
612-
}
621+
await this.handlePackageSelectionChange(
622+
message.target, message.packId, 'Selecting Pack',
623+
(actx, target, packId) => this.manageComponentsActions.selectPackage(actx, target, packId)
624+
);
613625
}
614626
}
615627

616628
private async unselectPackage(message: Messages.OutgoingMessage): Promise<void> {
617629
if (isUnselectPackageMessage(message)) {
618-
try {
619-
await this.webviewManager.sendMessage({ type: 'SET_SOLUTION_STATE', stateMessage: 'Unselecting Pack' });
620-
621-
const actx = this.getActiveContext();
622-
await this.manageComponentsActions.unselectPackage(actx, message.target, message.packId);
623-
const requestAll = this.scope === ComponentScope.All;
624-
const packs = this.mapPacksFromService(await this.csolutionService?.getPacksInfo({ context: actx, all: requestAll }));
625-
await this.webviewManager?.sendMessage({ type: 'SET_PACKS_INFO', packs: packs?.packs || [] });
626-
await this.sendDirtyState();
627-
} finally {
628-
await this.webviewManager.sendMessage({ type: 'SET_SOLUTION_STATE', stateMessage: undefined });
629-
}
630+
await this.handlePackageSelectionChange(
631+
message.target, message.packId, 'Unselecting Pack',
632+
(actx, target, packId) => this.manageComponentsActions.unselectPackage(actx, target, packId)
633+
);
630634
}
631635
}
632636

@@ -658,14 +662,14 @@ export class ComponentsPacksWebviewMain {
658662
const activeContext = this.getActiveContext();
659663
const requestAll = this.scope === ComponentScope.All;
660664

661-
this.componentTree = this.manageComponentsActions.mapComponentsFromService(await this.csolutionService.getComponentsTree({ context: activeContext, all: requestAll }));
662-
this.validations = await this.csolutionService.validateComponents({ context: activeContext });
663-
const packsInfo = this.mapPacksFromService(await this.csolutionService.getPacksInfo({ context: activeContext, all: requestAll }));
664-
665665
if (!this.availablePacksCache || Object.keys(this.availablePacksCache).length === 0) {
666666
this.availablePacksCache = await this.filterAvailablePacks(activeContext);
667667
}
668668

669+
this.componentTree = this.manageComponentsActions.mapComponentsFromService(await this.csolutionService.getComponentsTree({ context: activeContext, all: requestAll }));
670+
this.validations = await this.csolutionService.validateComponents({ context: activeContext });
671+
const packsInfo = this.mapPacksFromService(await this.csolutionService.getPacksInfo({ context: activeContext, all: requestAll }));
672+
669673
componentTreeWalker(this.componentTree, (node, type) => {
670674
if (type === 'aggregate' && (node as CtAggregate).options?.layer) {
671675
(node as CtAggregate).options!.layer = (node as CtAggregate).options!.layer || '';
@@ -776,6 +780,19 @@ export class ComponentsPacksWebviewMain {
776780
await this.webviewManager.sendMessage(programMessage);
777781
}
778782

783+
private async refreshComponentTree(activeContext: string): Promise<void> {
784+
this.componentTree = this.manageComponentsActions.mapComponentsFromService(
785+
await this.csolutionService.getComponentsTree({ context: activeContext, all: this.scope === ComponentScope.All })
786+
);
787+
this.validations = await this.csolutionService.validateComponents({ context: activeContext });
788+
await this.webviewManager.sendMessage({
789+
type: 'SET_COMPONENT_TREE',
790+
tree: this.componentTree,
791+
validations: this.validations.validation ?? [],
792+
scope: this.scope
793+
});
794+
}
795+
779796
private async openFile(filePath: string, openExternal?: boolean, focusOn?: string): Promise<void> {
780797
if (openExternal) {
781798
this.openFileExternal.openFile(filePath);

src/views/manage-solution/manage-solution-custom-editor.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { ConfigurationProvider } from '../../vscode-api/configuration-provider';
2626
import { CsolutionService } from '../../json-rpc/csolution-rpc-client';
2727
import { SolutionData } from './view/state/manage-solution-state';
2828
import { COMMAND_OPEN_SOLUTION } from '../../solutions/active-solution-tracker';
29+
import { IOpenFileExternal } from '../../open-file-external-if';
2930

3031
type EditEntry = {
3132
label: string;
@@ -118,6 +119,7 @@ export class ManageSolutionCustomEditorProvider implements vscode.CustomEditorPr
118119
private readonly commandsProvider: CommandsProvider,
119120
private readonly configurationProvider: ConfigurationProvider,
120121
private readonly csolutionService: CsolutionService,
122+
private readonly openFileExternal: IOpenFileExternal,
121123
) { }
122124

123125
private getOrCreateWebviewMain(): ManageSolutionWebviewMain {
@@ -134,6 +136,7 @@ export class ManageSolutionCustomEditorProvider implements vscode.CustomEditorPr
134136
this.context,
135137
this.solutionManager,
136138
this.commandsProvider,
139+
this.openFileExternal,
137140
this.configurationProvider,
138141
this.csolutionService,
139142
(label, before, after) => this.activeDocument?.recordEdit(label, before, after),

src/views/manage-solution/manage-solution-webview-main.factories.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { solutionManagerFactory } from '../../solutions/solution-manager.factori
2525
import { DataManager } from '../../data-manager/data-manager';
2626
import { DebugAdaptersYamlFile } from '../../debug/debug-adapters-yaml-file';
2727
import { configurationProviderFactory } from '../../vscode-api/configuration-provider.factories';
28+
import { IOpenFileExternal } from '../../open-file-external-if';
29+
import { openFileExternalFactory } from '../../open-file-external.factories';
2830
import { ETextFileResult } from '../../generic/text-file';
2931
import { SolutionData } from './view/state/manage-solution-state';
3032
import { ManageSolutionController } from './manage-solution-controller';
@@ -36,6 +38,7 @@ export type ManageSolutionWebviewMainFactoryOptions = {
3638
commandsProvider?: MockCommandsProvider;
3739
dataManager?: DataManager;
3840
debugAdaptersYmlFile?: DebugAdaptersYamlFile;
41+
openFileExternal?: IOpenFileExternal;
3942
configurationProvider?: ReturnType<typeof configurationProviderFactory>;
4043
csolutionService?: CsolutionService,
4144
onEdit?: (label: string, before: SolutionData, after: SolutionData) => void,
@@ -76,6 +79,7 @@ export function manageSolutionWebviewMainFactory(options?: ManageSolutionWebview
7679
{ subscriptions: [] } as unknown as vscode.ExtensionContext,
7780
options?.solutionManager ?? solutionManagerFactory(),
7881
options?.commandsProvider ?? commandsProviderFactory(),
82+
options?.openFileExternal ?? openFileExternalFactory(),
7983
options?.configurationProvider ?? configurationProviderFactory(),
8084
options?.csolutionService ?? jest.mocked<CsolutionService>({
8185
getDeviceList: async function (_args: GetDeviceListParams): Promise<DeviceList> { throw new Error('Function not implemented.'); },

0 commit comments

Comments
 (0)