Skip to content

Commit

Permalink
Show inline values (#384)
Browse files Browse the repository at this point in the history
* Add inline provider

* add inlineProvider

* Add inlie provider

* Add tests

* fix import

* fix lint

* Update inline function to remove strins values

* Add unit test for class type

* fix merge
  • Loading branch information
paulacamargo25 authored Jul 19, 2024
1 parent 481ccdb commit 695d259
Show file tree
Hide file tree
Showing 6 changed files with 421 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/extension/common/vscodeapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,7 @@ export function startDebugging(
) {
debug.startDebugging(folder, nameOrConfiguration, parentSession);
}

export function customRequest(command: string, args?: any): any {
return debug.activeDebugSession?.customRequest(command, args);
}
127 changes: 127 additions & 0 deletions src/extension/debugger/inlineValue/pythonInlineValueProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

import {
InlineValue,
InlineValueContext,
InlineValuesProvider,
Range,
TextDocument,
InlineValueVariableLookup,
InlineValueEvaluatableExpression,
} from 'vscode';
import { customRequest } from '../../common/vscodeapi';

export class PythonInlineValueProvider implements InlineValuesProvider {
public async provideInlineValues(
document: TextDocument,
viewPort: Range,
context: InlineValueContext,
): Promise<InlineValue[]> {
let scopesRequest = await customRequest('scopes', { frameId: context.frameId });
let variablesRequest = await customRequest('variables', {
variablesReference: scopesRequest.scopes[0].variablesReference,
});

//https://docs.python.org/3/reference/lexical_analysis.html#keywords
const pythonKeywords = [
'False',
'await',
'else',
'import ',
'pass',
'None',
'break',
'except',
'in',
'raise',
'True',
'class',
'finally',
'is',
'return',
'and',
'continue',
'for',
'lambda',
'try',
'as',
'def',
'from',
'nonlocal',
'while',
'assert',
'del',
'global',
'not',
'with',
'async',
'elif',
'if',
'or',
'yield',
'self',
];

const pythonVariables: any[] = variablesRequest.variables
.filter((variable: any) => variable.type)
.map((variable: any) => variable.name);

let variableRegex = new RegExp(
'(?:self.)?' + //match self. if present
'[a-zA-Z_][a-zA-Z0-9_]*', //math variable name
'g',
);

const allValues: InlineValue[] = [];
for (let l = viewPort.start.line; l <= viewPort.end.line; l++) {
const line = document.lineAt(l);
// Skip comments
if (line.text.trimStart().startsWith('#')) {
continue;
}

let code = removeCharsOutsideBraces(line.text);

for (let match = variableRegex.exec(code); match; match = variableRegex.exec(code)) {
let varName = match[0];
// Skip python keywords
if (pythonKeywords.includes(varName)) {
continue;
}
if (pythonVariables.includes(varName.split('.')[0])) {
if (varName.includes('self')) {
const rng = new Range(l, match.index, l, match.index + varName.length);
allValues.push(new InlineValueEvaluatableExpression(rng, varName));
} else {
const rng = new Range(l, match.index, l, match.index + varName.length);
allValues.push(new InlineValueVariableLookup(rng, varName, false));
}
}
}
}
return allValues;
}
}

function removeCharsOutsideBraces(code: string): string {
// Regular expression to find Python strings
const stringRegex = /(["'])(?:(?=(\\?))\2.)*?\1/g;

//Regular expression to match values inside {}
const insideBracesRegex = /{[^{}]*}/g;

return code.replace(stringRegex, (match) => {
const content = match.slice(1, -1);

let result = '';
let tempMatch;

while ((tempMatch = insideBracesRegex.exec(content)) !== null) {
result += tempMatch[0];
}
const processedContent = result || content;

return match[0] + processedContent + match[0];
});
}
6 changes: 6 additions & 0 deletions src/extension/extensionInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { openReportIssue } from './common/application/commands/reportIssueComman
import { buildApi } from './api';
import { IExtensionApi } from './apiTypes';
import { registerHexDebugVisualizationTreeProvider } from './debugger/visualizers/inlineHexDecoder';
import { PythonInlineValueProvider } from './debugger/inlineValue/pythonInlineValueProvider';

export async function registerDebugger(context: IExtensionContext): Promise<IExtensionApi> {
const childProcessAttachService = new ChildProcessAttachService();
Expand Down Expand Up @@ -136,6 +137,7 @@ export async function registerDebugger(context: IExtensionContext): Promise<IExt
context.subscriptions.push(
debug.registerDebugAdapterDescriptorFactory(DebuggerTypeName, debugAdapterDescriptorFactory),
);

context.subscriptions.push(
debug.onDidStartDebugSession((debugSession) => {
const shouldTerminalFocusOnStart = getConfiguration('python', debugSession.workspaceFolder?.uri)?.terminal
Expand Down Expand Up @@ -195,6 +197,10 @@ export async function registerDebugger(context: IExtensionContext): Promise<IExt
>('inlineHexDecoder', registerHexDebugVisualizationTreeProvider()),
);

context.subscriptions.push(
languages.registerInlineValuesProvider({ language: 'python' }, new PythonInlineValueProvider()),
);

context.subscriptions.push(
debug.registerDebugVisualizationProvider('inlineHexDecoder', {
provideDebugVisualization(_context, _token) {
Expand Down
10 changes: 10 additions & 0 deletions src/test/pythonFiles/testClassVarType.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def greet(self):
return f"Hello, my name is {self.name} and I a {self.age} years old."

person1 = Person("John Doe", 30)
person1.greet()
6 changes: 6 additions & 0 deletions src/test/pythonFiles/testVarTypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var1 = 5
var2 = 7
var3 = "hola"
var4 = {"a": 1, "b": 2}
var5 = [1, 2, 3]
var6 =var1 + var2
Loading

0 comments on commit 695d259

Please sign in to comment.