Skip to content
Open
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
8 changes: 8 additions & 0 deletions __mocks__/vscode.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ const StatusBarAlignment = {
Right: 2
};

const ConfigurationTarget = {
Global: 1,
Workspace: 2,
};

const MockTreeItemCollapsibleState = {
None: 0,
Collapsed: 1,
Expand Down Expand Up @@ -117,6 +122,8 @@ module.exports = {
workspace: {
getConfiguration: jest.fn(() => ({
get: jest.fn(),
update: jest.fn().mockResolvedValue(undefined),
inspect: jest.fn().mockReturnValue(undefined),
})),
fs: {
readFile: jest.fn(uri => {
Expand Down Expand Up @@ -162,4 +169,5 @@ module.exports = {
},
EnvironmentVariableMutatorType,
StatusBarAlignment,
ConfigurationTarget,
};
76 changes: 73 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
]
},
"commands": [
{
"command": "vscode-cmsis-debugger.resetDynamicViewState",
"title": "Reset All Dynamic View States",
"category": "CMSIS Debugger"
},
{
"command": "vscode-cmsis-debugger.openDisassemblyView",
"title": "Open Disassembly View",
Expand Down Expand Up @@ -178,11 +183,13 @@
{
"command": "vscode-cmsis-debugger.componentViewer.enablePeriodicUpdate",
"title": "Enable Periodic Update",
"icon": "$(sync)",
"category": "Component Viewer"
},
{
"command": "vscode-cmsis-debugger.componentViewer.disablePeriodicUpdate",
"title": "Disable Periodic Update",
"icon": "$(sync-ignored)",
"category": "Component Viewer"
},
{
Expand Down Expand Up @@ -218,11 +225,13 @@
{
"command": "vscode-cmsis-debugger.corePeripherals.enablePeriodicUpdate",
"title": "Enable Periodic Update",
"icon": "$(sync)",
"category": "Core Peripherals"
},
{
"command": "vscode-cmsis-debugger.corePeripherals.disablePeriodicUpdate",
"title": "Disable Periodic Update",
"icon": "$(sync-ignored)",
"category": "Core Peripherals"
},
{
Expand Down Expand Up @@ -274,6 +283,10 @@
}
],
"commandPalette": [
{
"command": "vscode-cmsis-debugger.resetDynamicViewState",
"when": "true"
},
{
"command": "vscode-cmsis-debugger.openDisassemblyView",
"when": "false"
Expand Down Expand Up @@ -414,12 +427,12 @@
{
"command": "vscode-cmsis-debugger.componentViewer.expandAll",
"when": "view == cmsis-debugger.componentViewer",
"group": "navigation@3"
"group": "navigation@4"
},
{
"command": "vscode-cmsis-debugger.corePeripherals.expandAll",
"when": "view == cmsis-debugger.corePeripherals",
"group": "navigation@3"
"group": "navigation@4"
},
{
"command": "vscode-cmsis-debugger.componentViewer.filterTree",
Expand All @@ -440,6 +453,26 @@
"command": "vscode-cmsis-debugger.corePeripherals.clearFilter",
"when": "view == cmsis-debugger.corePeripherals && corePeripherals.filterActive",
"group": "navigation@2"
},
{
"command": "vscode-cmsis-debugger.componentViewer.disablePeriodicUpdate",
"when": "view == cmsis-debugger.componentViewer && componentViewer.periodicUpdateEnabled",
"group": "navigation@3"
},
{
"command": "vscode-cmsis-debugger.componentViewer.enablePeriodicUpdate",
"when": "view == cmsis-debugger.componentViewer && !componentViewer.periodicUpdateEnabled",
"group": "navigation@3"
},
{
"command": "vscode-cmsis-debugger.corePeripherals.disablePeriodicUpdate",
"when": "view == cmsis-debugger.corePeripherals && corePeripherals.periodicUpdateEnabled",
"group": "navigation@3"
},
{
"command": "vscode-cmsis-debugger.corePeripherals.enablePeriodicUpdate",
"when": "view == cmsis-debugger.corePeripherals && !corePeripherals.periodicUpdateEnabled",
"group": "navigation@3"
}
],
"view/item/context": [
Expand Down Expand Up @@ -556,7 +589,44 @@
}
}
}
]
],
"configuration": {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really get what is happening here in the configurations section

"title": "CMSIS Debugger",
"properties": {
"vscode-cmsis-debugger.viewState": {
"type": "object",
"markdownDescription": "Persisted dynamic view state per debug configuration.",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"componentViewer": {
"type": "object",
"markdownDescription": "Persisted dynamic view state for the Component Viewer.",
"additionalProperties": false,
"properties": {
"periodicUpdateEnabled": { "type": "boolean" },
"filterPattern": { "type": "string" }
}
},
"corePeripherals": {
"type": "object",
"markdownDescription": "Persisted dynamic view state for the Core Peripherals view.",
"additionalProperties": false,
"properties": {
"periodicUpdateEnabled": { "type": "boolean" },
"filterPattern": { "type": "string" }
}
},
"cpuStates": {
"type": "boolean",
"markdownDescription": "Persisted CPU time enable/disable state."
}
}
}
}
}
}
},
"scripts": {
"prepare": "npm run build",
Expand Down
3 changes: 3 additions & 0 deletions src/cbuild-run/cbuild-run-reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,7 @@ export class CbuildRunReader {
return pnameProcessors.map(p => p.pname!);
}

public getTargetType(): string | undefined {
return this.cbuildRun?.['target-type'];
}
}
13 changes: 8 additions & 5 deletions src/debug-session/__test__/debug-session.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import { GDBTargetDebugSession, GDBTargetDebugTracker, TargetState } from '..';
export type OnRefreshCallback = (session: Session) => void;

export type Session = {
session: { id: string };
getCbuildRun: () => Promise<{ getScvdFilePaths: () => string[] } | undefined>;
session: { id: string; configuration?: { name: string } };
getCbuildRun: () => Promise<{ getScvdFilePaths: () => string[]; getTargetType: () => string | undefined } | undefined>;
getConfigStateKey: () => Promise<string>;
getPname: () => Promise<string | undefined>;
refreshTimer: { onRefresh: (cb: OnRefreshCallback) => void };
targetState?: TargetState;
Expand Down Expand Up @@ -88,11 +89,13 @@ export const debugSessionFactory = (
// Ensure same object returned for multiple calls to getCbuildRun.
const cbuildRunMock = hasCbuildRun ? {
getContents: jest.fn(),
getScvdFilePaths: () => paths
getScvdFilePaths: () => paths,
getTargetType: jest.fn<string | undefined, []>(() => undefined),
} : undefined;
return {
session: { id },
getCbuildRun: async () => cbuildRunMock,
session: { id, configuration: { name: id } },
getCbuildRun: jest.fn().mockResolvedValue(cbuildRunMock),
getConfigStateKey: jest.fn().mockResolvedValue(id),
getPname: async () => pname,
refreshTimer: {
onRefresh: jest.fn(),
Expand Down
7 changes: 7 additions & 0 deletions src/debug-session/gdbtarget-debug-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ export class GDBTargetDebugSession {
return pname;
}

public async getConfigStateKey(): Promise<string> {
const cbuildRun = await this.getCbuildRun();
const targetType = cbuildRun?.getTargetType();
const configStateKey = targetType ? `${targetType}::${this.session.configuration.name}` : this.session.configuration.name;
return configStateKey;
}

/**
* Check if first stop attempt for session is done by 'terminate' request.
* Notes:
Expand Down
13 changes: 13 additions & 0 deletions src/desktop/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { GenericCommands } from '../features/generic-commands';
import { ComponentViewer } from '../views/component-viewer/component-viewer';
import { ComponentViewerTreeDataProvider } from '../views/component-viewer/component-viewer-tree-view';
import { CorePeripherals } from '../views/core-peripherals/core-peripherals';
import { clearAllViewState } from '../views/dynamic-view-states';

const BUILTIN_TOOLS_PATHS = [
'tools/pyocd/pyocd',
Expand Down Expand Up @@ -85,6 +86,18 @@ export const activate = async (context: vscode.ExtensionContext): Promise<void>
canCompleteActivation = false;
}

// Register reset dynamic view state command
context.subscriptions.push(
vscode.commands.registerCommand('vscode-cmsis-debugger.resetDynamicViewState', async () => {
await clearAllViewState();
await Promise.all([
cpuStates.resetViewState(),
componentViewer.resetViewState(),
corePeripherals.resetViewState(),
]);
})
);

if (!canCompleteActivation) {
logger.debug('CMSIS Debugger activation incomplete');
// Let promise float, we reload the window.
Expand Down
14 changes: 13 additions & 1 deletion src/features/cpu-states/cpu-states-statusbar-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class CpuStatesStatusBarItem {
}

protected async handleItemCommand(): Promise<void> {
const cpuEnabled = this.cpuStates?.isEnabled ?? true;
const items: QuickPickHandlerItem[] = [
{
label: 'CPU Time',
Expand All @@ -76,7 +77,18 @@ export class CpuStatesStatusBarItem {
label: 'Reset CPU Time',
detail: 'Reset CPU execution time and history',
handler: () => vscode.commands.executeCommand(CpuStatesCommands.resetCpuTimeHistoryID)
}
},
cpuEnabled
? {
label: 'Disable CPU Timer',
detail: 'Stop collecting CPU execution time',
handler: () => vscode.commands.executeCommand(CpuStatesCommands.disableCpuTimer)
}
: {
label: 'Enable CPU Timer',
detail: 'Start collecting CPU execution time',
handler: () => vscode.commands.executeCommand(CpuStatesCommands.enableCpuTimer)
}
];
const selection = await vscode.window.showQuickPick(items);
if (!selection) {
Expand Down
88 changes: 86 additions & 2 deletions src/features/cpu-states/cpu-states.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,13 @@ describe('CpuStates', () => {
it('enable cpu states sets enableCpuStates flag to true', async () => {
cpuStates.activate(tracker);
await cpuStates.enableCpuStates();
expect((cpuStates as unknown as { enableCpuStatesFlag: boolean }).enableCpuStatesFlag).toEqual(true);
expect(cpuStates.activeCpuStates?.enableCpuStatesFlag).toEqual(true);
});

it('disable cpu states sets enableCpuStates flag to false', async () => {
cpuStates.activate(tracker);
await cpuStates.disableCpuStates();
expect((cpuStates as unknown as { enableCpuStatesFlag: boolean }).enableCpuStatesFlag).toEqual(false);
expect(cpuStates.activeCpuStates?.enableCpuStatesFlag).toEqual(false);
});
});

Expand Down Expand Up @@ -488,5 +488,89 @@ describe('CpuStates', () => {

});

describe('CPU timer enable/disable state persists to and restores from settings', () => {
beforeEach(() => {
jest.spyOn(gdbtargetDebugSession, 'getCbuildRun').mockResolvedValue({
getTargetType: () => 'My-Target',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any);
});

afterEach(() => {
jest.restoreAllMocks();
});

it('restores CPU timer enabled state from settings on connect', async () => {
jest.spyOn(vscode.workspace, 'getConfiguration').mockReturnValue({
inspect: jest.fn().mockReturnValue({
globalValue: {
'My-Target::Debug': {
cpuStates: false,
},
},
workspaceValue: {},
}),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any);
cpuStates.activate(tracker);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onWillStartSession.fire(gdbtargetDebugSession);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onDidChangeActiveDebugSession.fire(gdbtargetDebugSession);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onConnected.fire(gdbtargetDebugSession);
await waitForMs(0);

expect(cpuStates.activeCpuStates?.enableCpuStatesFlag).toEqual(false);
});

it('toolbar button state switches when changing the active debug session', async () => {
const executeCommandSpy = jest.spyOn(vscode.commands, 'executeCommand').mockResolvedValue(undefined);
const debugConfig2 = gdbTargetConfiguration({ name: 'Debug2' });
const debugSession2 = debugSessionFactory(debugConfig2, '{session-id-2}');
const gdbtargetDebugSession2 = new GDBTargetDebugSession(debugSession2);
cpuStates.activate(tracker);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onWillStartSession.fire(gdbtargetDebugSession);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onWillStartSession.fire(gdbtargetDebugSession2);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(cpuStates as any).sessionCpuStates.get(gdbtargetDebugSession2.session.id)!.enableCpuStatesFlag = false;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onDidChangeActiveDebugSession.fire(gdbtargetDebugSession);
expect(executeCommandSpy).toHaveBeenCalledWith('setContext', 'vscode-cmsis-debugger.cpuTimerEnabled', true);
executeCommandSpy.mockClear();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onDidChangeActiveDebugSession.fire(gdbtargetDebugSession2);
expect(executeCommandSpy).toHaveBeenCalledWith('setContext', 'vscode-cmsis-debugger.cpuTimerEnabled', false);
executeCommandSpy.mockClear();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onDidChangeActiveDebugSession.fire(undefined);
expect(executeCommandSpy).toHaveBeenCalledWith('setContext', 'vscode-cmsis-debugger.cpuTimerEnabled', false);
});

it('re-enables sessions and updates the toolbar context', async () => {
jest.spyOn(vscode.workspace, 'getConfiguration').mockReturnValue({
update: jest.fn().mockResolvedValue(undefined),
inspect: jest.fn().mockReturnValue({ globalValue: {}, workspaceValue: {} }),
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any);
const executeCommandSpy = jest.spyOn(vscode.commands, 'executeCommand').mockResolvedValue(undefined);
cpuStates.activate(tracker);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(tracker as any)._onWillStartSession.fire(gdbtargetDebugSession);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(cpuStates as any).sessionCpuStates.get(gdbtargetDebugSession.session.id)!.enableCpuStatesFlag = false;
await cpuStates.resetViewState();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect((cpuStates as any).sessionCpuStates.get(gdbtargetDebugSession.session.id)!.enableCpuStatesFlag).toBe(true);
expect(executeCommandSpy).toHaveBeenCalledWith('setContext', 'vscode-cmsis-debugger.cpuTimerEnabled', true);
});

});
});

Loading
Loading