提交 9c118b9e 编写于 作者: I isidor

debug: support variable paging

#9537
上级 ba70479e
......@@ -18,20 +18,6 @@ import { Source } from 'vs/workbench/parts/debug/common/debugSource';
const MAX_REPL_LENGTH = 10000;
const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
function resolveChildren(debugService: debug.IDebugService, parent: debug.IExpressionContainer): TPromise<Variable[]> {
const session = debugService.getActiveSession();
// only variables with reference > 0 have children.
if (!session || parent.reference <= 0) {
return TPromise.as([]);
}
return session.variables({ variablesReference: parent.reference }).then(response => {
return arrays.distinct(response.body.variables.filter(v => !!v), v => v.name).map(
v => new Variable(parent, v.variablesReference, v.name, v.value, v.type)
);
}, (e: Error) => [new Variable(parent, 0, null, e.message, null, false)]);
}
function massageValue(value: string): string {
return value ? value.replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t') : value;
}
......@@ -53,6 +39,7 @@ export function evaluateExpression(session: debug.IRawDebugSession, stackFrame:
if (response.body) {
expression.value = response.body.result;
expression.reference = response.body.variablesReference;
expression.childrenCount = response.body.totalCount;
}
return expression;
......@@ -229,21 +216,46 @@ export class KeyValueOutputElement extends OutputElement {
export abstract class ExpressionContainer implements debug.IExpressionContainer {
private children: TPromise<debug.IExpression[]>;
public valueChanged: boolean;
public static allValues: { [id: string]: string } = {};
// Use chunks to support variable paging #9537
private static CHUNK_SIZE = 100;
public valueChanged: boolean;
private children: TPromise<debug.IExpression[]>;
private _value: string;
constructor(public reference: number, private id: string, private cacheChildren: boolean) {
this.children = null;
constructor(public reference: number, private id: string, private cacheChildren: boolean, public childrenCount: number, private chunkIndex = 0) {
// noop
}
public getChildren(debugService: debug.IDebugService): TPromise<debug.IExpression[]> {
if (!this.cacheChildren) {
return resolveChildren(debugService, this);
if (!this.cacheChildren || !this.children) {
const session = debugService.getActiveSession();
// only variables with reference > 0 have children.
if (!session || this.reference <= 0) {
this.children = TPromise.as([]);
} else {
if (this.childrenCount > ExpressionContainer.CHUNK_SIZE) {
// There are a lot of children, create fake intermediate values that represent chunks #9537
const chunks = [];
const numberOfChunks = this.childrenCount / ExpressionContainer.CHUNK_SIZE;
for (let i = 0; i < numberOfChunks; i++) {
const chunkName = `${i * ExpressionContainer.CHUNK_SIZE}..${(i + 1) * ExpressionContainer.CHUNK_SIZE - 1}`;
chunks.push(new Variable(this, this.reference, chunkName, '', ExpressionContainer.CHUNK_SIZE, null, true, i));
}
this.children = TPromise.as(chunks);
} else {
this.children = session.variables({
variablesReference: this.reference,
start: this.chunkIndex * ExpressionContainer.CHUNK_SIZE,
count: ExpressionContainer.CHUNK_SIZE
}).then(response => {
return arrays.distinct(response.body.variables.filter(v => !!v), v => v.name).map(
v => new Variable(this, v.variablesReference, v.name, v.value, v.totalCount, v.type)
);
}, (e: Error) => [new Variable(this, 0, null, e.message, 0, null, false)]);
}
}
if (!this.children) {
this.children = resolveChildren(debugService, this);
}
return this.children;
......@@ -271,7 +283,7 @@ export class Expression extends ExpressionContainer implements debug.IExpression
public available: boolean;
constructor(public name: string, cacheChildren: boolean, id = uuid.generateUuid()) {
super(0, id, cacheChildren);
super(0, id, cacheChildren, 0);
this.value = Expression.DEFAULT_VALUE;
this.available = false;
}
......@@ -282,16 +294,16 @@ export class Variable extends ExpressionContainer implements debug.IExpression {
// Used to show the error message coming from the adapter when setting the value #7807
public errorMessage: string;
constructor(public parent: debug.IExpressionContainer, reference: number, public name: string, value: string, public type: string = null, public available = true) {
super(reference, `variable:${ parent.getId() }:${ name }`, true);
constructor(public parent: debug.IExpressionContainer, reference: number, public name: string, value: string, childrenCount: number, public type: string = null, public available = true, chunkIndex = 0) {
super(reference, `variable:${ parent.getId() }:${ name }`, true, childrenCount, chunkIndex);
this.value = massageValue(value);
}
}
export class Scope extends ExpressionContainer implements debug.IScope {
constructor(private threadId: number, public name: string, reference: number, public expensive: boolean) {
super(reference, `scope:${threadId}:${name}:${reference}`, true);
constructor(private threadId: number, public name: string, reference: number, public expensive: boolean, childrenCount: number) {
super(reference, `scope:${threadId}:${name}:${reference}`, true, childrenCount);
}
}
......@@ -310,7 +322,7 @@ export class StackFrame implements debug.IStackFrame {
public getScopes(debugService: debug.IDebugService): TPromise<debug.IScope[]> {
if (!this.scopes) {
this.scopes = debugService.getActiveSession().scopes({ frameId: this.frameId }).then(response => {
return response.body.scopes.map(rs => new Scope(this.threadId, rs.name, rs.variablesReference, rs.expensive));
return response.body.scopes.map(rs => new Scope(this.threadId, rs.name, rs.variablesReference, rs.expensive, rs.totalCount));
}, err => []);
}
......
......@@ -623,7 +623,8 @@ export class DebugService implements debug.IDebugService {
pathFormat: 'path',
linesStartAt1: true,
columnsStartAt1: true,
supportsVariableType: true // #8858
supportsVariableType: true, // #8858
supportsVariablePaging: false // #9537
}).then((result: DebugProtocol.InitializeResponse) => {
if (!this.session) {
return TPromise.wrapError(new Error(nls.localize('debugAdapterCrash', "Debug adapter process has terminated unexpectedly")));
......
......@@ -352,11 +352,11 @@ suite('Debug - Model', () => {
assert.equal(debugmodel.getFullExpressionName(new debugmodel.Expression(null, false), type), null);
assert.equal(debugmodel.getFullExpressionName(new debugmodel.Expression('son', false), type), 'son');
const scope = new debugmodel.Scope(1, 'myscope', 1, false);
const son = new debugmodel.Variable(new debugmodel.Variable(new debugmodel.Variable(scope, 0, 'grandfather', '75'), 0, 'father', '45'), 0, 'son', '20');
const scope = new debugmodel.Scope(1, 'myscope', 1, false, 1);
const son = new debugmodel.Variable(new debugmodel.Variable(new debugmodel.Variable(scope, 0, 'grandfather', '75', 1), 0, 'father', '45', 1), 0, 'son', '20', 1);
assert.equal(debugmodel.getFullExpressionName(son, type), 'grandfather.father.son');
const grandson = new debugmodel.Variable(son, 0, '/weird_name', '1');
const grandson = new debugmodel.Variable(son, 0, '/weird_name', '1', 0);
assert.equal(debugmodel.getFullExpressionName(grandson, type), 'grandfather.father.son[\'/weird_name\']');
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册