Skip to content

Commit 610b433

Browse files
Add edit to group context menu
1 parent 8b4f91f commit 610b433

4 files changed

Lines changed: 133 additions & 0 deletions

File tree

package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,10 @@
784784
"command": "cmsis-csolution.list.find",
785785
"title": "Search"
786786
},
787+
{
788+
"command": "cmsis-csolution.edit",
789+
"title": "Edit"
790+
},
787791
{
788792
"command": "cmsis-csolution.showSolutionOutline",
789793
"title": "Show Solution Outline"
@@ -929,6 +933,10 @@
929933
"command": "cmsis-csolution.addToGroup",
930934
"when": "false"
931935
},
936+
{
937+
"command": "cmsis-csolution.edit",
938+
"when": "false"
939+
},
932940
{
933941
"command": "cmsis-csolution.showConfigWizardPreview",
934942
"when": "false"
@@ -1145,6 +1153,11 @@
11451153
"when": "view == cmsis-csolution.outline && viewItem =~ /group|file/",
11461154
"group": "contextMenu"
11471155
},
1156+
{
1157+
"command": "cmsis-csolution.edit",
1158+
"when": "view == cmsis-csolution.outline && viewItem =~ /group/",
1159+
"group": "contextMenu"
1160+
},
11481161
{
11491162
"command": "cmsis-csolution.runGenerator",
11501163
"when": "view == cmsis-csolution.outline && viewItem =~ /component-gen/",

src/desktop/extension.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import { CreateSolutionWebviewMain } from '../views/create-solutions/create-solu
5555
import { ManageLayersWebviewMain } from '../views/manage-layers/manage-layers-webview-main';
5656
import { AddToGroupCommand } from '../views/solution-outline/commands/add-to-group-command';
5757
import { DeleteCommand } from '../views/solution-outline/commands/delete-command';
58+
import { EditCommand } from '../views/solution-outline/commands/edit-command';
5859
import { OpenCommand } from '../views/solution-outline/commands/open-command';
5960
import { FindCommand } from '../views/solution-outline/commands/find-command';
6061
import { MergeCommand } from '../views/solution-outline/commands/merge-command';
@@ -210,6 +211,7 @@ export const activate = async (context: ExtensionContext): Promise<CsolutionExte
210211

211212
const addToGroupCommand = new AddToGroupCommand(workspaceFsProvider, commandsProvider, solutionManager);
212213
const deleteCommand = new DeleteCommand(commandsProvider, workspaceFsProvider);
214+
const editCommand = new EditCommand(commandsProvider);
213215
const copyHeaderCommand = new CopyHeaderCommand(commandsProvider);
214216
const openCommand = new OpenCommand(solutionManager, commandsProvider, externalFileOpener);
215217
const findCommand = new FindCommand(commandsProvider);
@@ -273,6 +275,7 @@ export const activate = async (context: ExtensionContext): Promise<CsolutionExte
273275
solutionLanguageFeatures.activate(context),
274276
addToGroupCommand.activate(context),
275277
deleteCommand.activate(context),
278+
editCommand.activate(context),
276279
copyHeaderCommand.activate(context),
277280
openCommand.activate(context),
278281
findCommand.activate(context),
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* Copyright 2026 Arm Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as vscode from 'vscode';
18+
import * as yaml from 'yaml';
19+
import { CommandsProvider } from '../../../vscode-api/commands-provider';
20+
import * as manifest from '../../../manifest';
21+
import { COutlineItem } from '../tree-structure/solution-outline-item';
22+
import { getGroupPathArray } from '../utils';
23+
import { buildPathFromContentToGroup } from '../../../solutions/edit/manage-group-items';
24+
import { getYamlNodeAtPath, listItem, mapKey } from '../../../solutions/edit/edit-yaml';
25+
import { readTextFile } from '../../../utils/fs-utils';
26+
27+
export class EditCommand {
28+
public static readonly editCommandId = `${manifest.PACKAGE_NAME}.edit`;
29+
30+
constructor(
31+
private readonly commandsProvider: CommandsProvider,
32+
) { }
33+
34+
public async activate(context: Pick<vscode.ExtensionContext, 'subscriptions'>) {
35+
context.subscriptions.push(
36+
this.commandsProvider.registerCommand(EditCommand.editCommandId, async (node: COutlineItem) => {
37+
await this.editGroup(node);
38+
}, this),
39+
);
40+
}
41+
42+
private async editGroup(node: COutlineItem): Promise<void> {
43+
if (node.getTag() !== 'group') {
44+
return;
45+
}
46+
47+
const filePath = node.originFilePath;
48+
if (!filePath) {
49+
return;
50+
}
51+
52+
const groupPath = getGroupPathArray(node);
53+
if (groupPath.length === 0) {
54+
return;
55+
}
56+
57+
const parentType = this.getParentTypeFromNode(node);
58+
const offset = this.findGroupOffset(filePath, parentType, groupPath) ?? 0;
59+
60+
const document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath));
61+
const position = document.positionAt(offset);
62+
await vscode.window.showTextDocument(document, {
63+
selection: new vscode.Range(position, position),
64+
preview: false,
65+
});
66+
}
67+
68+
private findGroupOffset(filePath: string, parentType: 'project' | 'layer', groupPath: string[]): number | undefined {
69+
const input = readTextFile(filePath);
70+
if (!input) {
71+
return undefined;
72+
}
73+
74+
const yamlDocument = yaml.parseDocument(input);
75+
const contents = yamlDocument.contents;
76+
if (!contents) {
77+
return undefined;
78+
}
79+
80+
const targetGroupName = groupPath[groupPath.length - 1];
81+
if (!targetGroupName) {
82+
return undefined;
83+
}
84+
85+
const pathToParentGroup = buildPathFromContentToGroup(groupPath.slice(0, -1), [mapKey(parentType)]);
86+
const pathToTargetGroup = [
87+
...pathToParentGroup,
88+
mapKey('groups'),
89+
listItem(item => yaml.isMap(item) && item.get('group') === targetGroupName),
90+
];
91+
92+
const targetGroupNode = getYamlNodeAtPath(contents, pathToTargetGroup);
93+
return (targetGroupNode && yaml.isNode(targetGroupNode) && targetGroupNode.range)
94+
? targetGroupNode.range[0]
95+
: undefined;
96+
}
97+
98+
private getParentTypeFromNode(node: COutlineItem): 'project' | 'layer' {
99+
return node.getAttribute('layerUri') ? 'layer' : 'project';
100+
}
101+
}

src/views/solution-outline/commands/open-command.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { SolutionManager } from '../../../solutions/solution-manager';
2323
import { IOpenFileExternal } from '../../../open-file-external-if';
2424
import { contextDescriptorFromString } from '../../../solutions/descriptors/descriptors';
2525
import { existsSync } from 'fs';
26+
import { lineOf, readTextFile } from '../../../utils/fs-utils';
2627

2728

2829
export class OpenCommand {
@@ -83,11 +84,26 @@ export class OpenCommand {
8384
private async commandHandler(command: string, node: COutlineItem) {
8485
const filePath = this.getFilePathForCommand(command, node);
8586
if (filePath) {
87+
if (command === OpenCommand.openProjectCommandId) {
88+
this.openProjectFile(filePath);
89+
return;
90+
}
91+
8692
const openExternal = command === OpenCommand.openDocCommandId;
8793
this.openFile(filePath, openExternal);
8894
}
8995
}
9096

97+
private async openProjectFile(filePath: string): Promise<void> {
98+
const projectLine = lineOf(readTextFile(filePath), 'project:');
99+
const document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath));
100+
const position = new vscode.Position(projectLine, 0);
101+
await vscode.window.showTextDocument(document, {
102+
selection: new vscode.Range(position, position),
103+
preview: false,
104+
});
105+
}
106+
91107
private getFilePathForCommand(command: string, node: COutlineItem): string | undefined {
92108
if (command === OpenCommand.openDocCommandId) {
93109
return node.getAttribute('docPath');

0 commit comments

Comments
 (0)