add editing

This commit is contained in:
Connor Peet
2024-02-14 13:02:22 -08:00
parent e2b57f4dea
commit 2ea614ec22
3 changed files with 136 additions and 6 deletions

View File

@ -7,6 +7,10 @@
{
"id": "base64Decoder",
"when": "variableValue =~ /^['\"]?[A-Za-z0-9=\\/+]+['\"]?$/ && variableType == string"
},
{
"id": "inlineBase64Decoder",
"when": "variableValue =~ /^['\"]?[A-Za-z0-9=\\/+]+['\"]?$/ && variableType == string"
}
]
},

View File

@ -25,6 +25,62 @@ export function activate(context: vscode.ExtensionContext) {
return [v]
},
}));
context.subscriptions.push(vscode.debug.registerDebugVisualizationTreeProvider<vscode.DebugTreeItem & { byte?: number; buffer: Buffer, context: vscode.DebugVisualizationContext }>('inlineBase64Decoder', {
getTreeItem(context) {
const decoded = Buffer.from(context.variable.value, 'base64')
return {
label: context.variable.name.toString(),
description: decoded.toString(),
collapsibleState: vscode.TreeItemCollapsibleState.Expanded,
buffer: decoded,
canEdit: true,
context,
}
},
getChildren(element) {
if (element.buffer) {
return [...element.buffer].map((byte, i) => ({
label: String(i),
description: '0x' + byte.toString(16),
canEdit: !!element.context.variable.evaluateName,
byte: i,
buffer: element.buffer,
context: element.context,
}));
}
},
editItem(item, value) {
if ('byte' in item) {
const n = value.startsWith('0x') ? parseInt(value.slice(2), 16) : Math.floor(+value);
if (isNaN(n)) {
throw new Error(`cannot parse "${value}" as a number`);
}
item.buffer[item.byte!] = n;
item.label = '0x' + n.toString(16);
} else {
item.buffer = Buffer.from(value);
item.description = item.buffer.toString();
}
item.context.session.customRequest('setExpression', {
expression: item.context.variable.evaluateName,
frameId: item.context.frameId,
value: JSON.stringify(item.buffer.toString('base64')),
});
return item;
},
}));
context.subscriptions.push(vscode.debug.registerDebugVisualizationProvider('inlineBase64Decoder', {
provideDebugVisualization(context, token) {
const v = new vscode.DebugVisualization('inline base64');
v.iconPath = new vscode.ThemeIcon('rocket');
v.visualization = { treeId: 'inlineBase64Decoder' }
return [v];
},
}));
}
const openUntitledEditor = async (contents: string) => {

View File

@ -16,6 +16,79 @@ declare module 'vscode' {
id: string,
provider: DebugVisualizationProvider<T>
): Disposable;
/**
* Registers a tree that can be referenced by {@link DebugVisualization.visualization}.
* @param id
* @param provider
*/
export function registerDebugVisualizationTreeProvider<T extends DebugTreeItem>(
id: string,
provider: DebugVisualizationTree<T>
): Disposable;
}
/**
* An item from the {@link DebugVisualizationTree}
*/
export interface DebugTreeItem {
/**
* A human-readable string describing this item.
*/
label: string;
/**
* A human-readable string which is rendered less prominent.
*/
description?: string;
/**
* {@link TreeItemCollapsibleState} of the tree item.
*/
collapsibleState?: TreeItemCollapsibleState;
/**
* Context value of the tree item. This can be used to contribute item specific actions in the tree.
* For example, a tree item is given a context value as `folder`. When contributing actions to `view/item/context`
* using `menus` extension point, you can specify context value for key `viewItem` in `when` expression like `viewItem == folder`.
* ```json
* "contributes": {
* "menus": {
* "view/item/context": [
* {
* "command": "extension.deleteFolder",
* "when": "viewItem == folder"
* }
* ]
* }
* }
* ```
* This will show action `extension.deleteFolder` only for items with `contextValue` is `folder`.
*/
contextValue?: string;
/**
* Whether this item can be edited by the user.
*/
canEdit?: boolean;
}
/**
* Provides a tree that can be referenced in debug visualizations.
*/
export interface DebugVisualizationTree<T extends DebugTreeItem = DebugTreeItem> {
/**
* Gets the tree item for an element or the base context item.
*/
getTreeItem(context: DebugVisualizationContext): ProviderResult<T>;
/**
* Gets children for the tree item or the best context item.
*/
getChildren(element: T): ProviderResult<T[]>;
/**
* Handles the user editing an item.
*/
editItem?(item: T, value: string): ProviderResult<T>;
}
export class DebugVisualization {
@ -32,12 +105,9 @@ declare module 'vscode' {
/**
* Visualization to use for the variable. This may be either:
* - A command to run when the visualization is selected for a variable.
* - A {@link TreeDataProvider} which is used to display the data in-line
* where the variable is shown. If a single root item is returned from
* the data provider, it will replace the variable in its tree.
* Otherwise, the items will be shown as children of the variable.
* - A reference to a previously-registered {@link DebugVisualizationTree}
*/
visualization?: Command | TreeDataProvider<unknown>;
visualization?: Command | { treeId: string };
/**
* Creates a new debug visualization object.
@ -80,7 +150,7 @@ declare module 'vscode' {
* that came from user evaluations in the Debug Console.
* @see https://microsoft.github.io/debug-adapter-protocol/specification#Types_Variable
*/
containerId?: string;
containerId?: number;
/**
* The ID of the Debug Adapter Protocol StackFrame in which the variable was found,
* for variables that came from scopes in a stack frame.