提交 4d010f7b 编写于 作者: A Alex Dima

Align data types

上级 550fd30a
......@@ -14,7 +14,7 @@ import * as browser from 'vs/base/browser/browser';
import { MinimapCharRenderer, ParsedColor, MinimapTokensColorTracker, Constants } from 'vs/editor/common/view/minimapCharRenderer';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { CharCode } from 'vs/base/common/charCode';
import { IViewLayout, MinimapLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
import { IViewLayout, ViewLineData } from 'vs/editor/common/viewModel/viewModel';
import { ColorId } from 'vs/editor/common/modes';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/styleMutator';
import { IDisposable } from 'vs/base/common/lifecycle';
......@@ -414,14 +414,14 @@ export class Minimap extends ViewPart {
let end = performance.now();
console.log(`FETCHING MINIMAP DATA TOOK ${end - start} ms.`);
let start2 = performance.now();
// let start2 = performance.now();
let dy = 0;
for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
Minimap._renderLine(imageData, background, renderMinimap, charWidth, this._tokensColorTracker, this._minimapCharRenderer, dy, tabSize, data2.data[lineNumber - startLineNumber]);
dy += minimapLineHeight;
}
let end2 = performance.now();
console.log(`PAINTING MINIMAP TOOK ${end2 - start2} ms.`);
// let end2 = performance.now();
// console.log(`PAINTING MINIMAP TOOK ${end2 - start2} ms.`);
ctx.putImageData(imageData, 0, 0);
}
......@@ -435,7 +435,7 @@ export class Minimap extends ViewPart {
minimapCharRenderer: MinimapCharRenderer,
dy: number,
tabSize: number,
lineData: MinimapLineRenderingData
lineData: ViewLineData
): void {
const content = lineData.content;
const tokens = lineData.tokens;
......
......@@ -9,8 +9,7 @@ import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
import { PrefixSumComputerWithCache } from 'vs/editor/common/viewModel/prefixSumComputer';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { MinimapLineRenderingData, MinimapLinesRenderingData } from 'vs/editor/common/viewModel/viewModel';
import { ViewLineData } from 'vs/editor/common/viewModel/viewModel';
export class OutputPosition {
_outputPositionBrand: void;
......@@ -49,9 +48,8 @@ export interface ISplitLine {
getViewLineContent(model: IModel, modelLineNumber: number, outputLineIndex: number): string;
getViewLineMinColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number;
getViewLineMaxColumn(model: IModel, modelLineNumber: number, outputLineIndex: number): number;
getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData;
_getMinimapLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): MinimapLineRenderingData;
getMinimapLineRenderingData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: MinimapLineRenderingData[]): void;
getViewLineData(model: IModel, modelLineNumber: number, outputLineIndex: number): ViewLineData;
getViewLinesData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: ViewLineData[]): void;
getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number;
getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position;
......@@ -90,10 +88,10 @@ class VisibleIdentitySplitLine implements ISplitLine {
return model.getLineMaxColumn(modelLineNumber);
}
public getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData {
public getViewLineData(model: IModel, modelLineNumber: number, outputLineIndex: number): ViewLineData {
let lineTokens = model.getLineTokens(modelLineNumber, true);
let lineContent = lineTokens.getLineContent();
return new OutputLineRenderingData(
return new ViewLineData(
lineContent,
1,
lineContent.length + 1,
......@@ -101,26 +99,12 @@ class VisibleIdentitySplitLine implements ISplitLine {
);
}
public _getMinimapLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): MinimapLineRenderingData {
let lineTokens = model.getLineTokens(modelLineNumber, true);
let lineContent = lineTokens.getLineContent();
return new MinimapLineRenderingData(
lineContent,
lineTokens.inflate()
);
}
public getMinimapLineRenderingData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: MinimapLineRenderingData[]): void {
public getViewLinesData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: ViewLineData[]): void {
if (!needed[globalStartIndex]) {
result[globalStartIndex] = null;
return;
}
let lineTokens = model.getLineTokens(modelLineNumber, true);
let lineContent = lineTokens.getLineContent();
result[globalStartIndex] = new MinimapLineRenderingData(
lineContent,
lineTokens.inflate()
);
result[globalStartIndex] = this.getViewLineData(model, modelLineNumber, 0);
}
public getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number {
......@@ -165,15 +149,11 @@ class InvisibleIdentitySplitLine implements ISplitLine {
throw new Error('Not supported');
}
public getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData {
public getViewLineData(model: IModel, modelLineNumber: number, outputLineIndex: number): ViewLineData {
throw new Error('Not supported');
}
public _getMinimapLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): MinimapLineRenderingData {
throw new Error('Not supported');
}
public getMinimapLineRenderingData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: MinimapLineRenderingData[]): void {
public getViewLinesData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: ViewLineData[]): void {
throw new Error('Not supported');
}
......@@ -262,7 +242,7 @@ export class SplitLine implements ISplitLine {
return this.getViewLineContent(model, modelLineNumber, outputLineIndex).length + 1;
}
public getViewLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): OutputLineRenderingData {
public getViewLineData(model: IModel, modelLineNumber: number, outputLineIndex: number): ViewLineData {
if (!this._isVisible) {
throw new Error('Not supported');
}
......@@ -284,7 +264,7 @@ export class SplitLine implements ISplitLine {
}
let lineTokens = model.getLineTokens(modelLineNumber, true);
return new OutputLineRenderingData(
return new ViewLineData(
lineContent,
minColumn,
maxColumn,
......@@ -292,32 +272,7 @@ export class SplitLine implements ISplitLine {
);
}
public _getMinimapLineRenderingData(model: IModel, modelLineNumber: number, outputLineIndex: number): MinimapLineRenderingData {
if (!this._isVisible) {
throw new Error('Not supported');
}
let startOffset = this.getInputStartOffsetOfOutputLineIndex(outputLineIndex);
let endOffset = this.getInputEndOffsetOfOutputLineIndex(model, modelLineNumber, outputLineIndex);
let lineContent = model.getLineContent(modelLineNumber).substring(startOffset, endOffset);
if (outputLineIndex > 0) {
lineContent = this.wrappedIndent + lineContent;
}
let deltaStartIndex = 0;
if (outputLineIndex > 0) {
deltaStartIndex = this.wrappedIndentLength;
}
let lineTokens = model.getLineTokens(modelLineNumber, true);
return new MinimapLineRenderingData(
lineContent,
lineTokens.sliceAndInflate(startOffset, endOffset, deltaStartIndex)
);
}
public getMinimapLineRenderingData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: MinimapLineRenderingData[]): void {
public getViewLinesData(model: IModel, modelLineNumber: number, fromOuputLineIndex: number, toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: ViewLineData[]): void {
if (!this._isVisible) {
throw new Error('Not supported');
}
......@@ -328,7 +283,7 @@ export class SplitLine implements ISplitLine {
result[globalIndex] = null;
continue;
}
result[globalIndex] = this._getMinimapLineRenderingData(model, modelLineNumber, outputLineIndex);
result[globalIndex] = this.getViewLineData(model, modelLineNumber, outputLineIndex);
}
}
......@@ -796,17 +751,17 @@ export class SplitLinesCollection {
return this.lines[lineIndex].getViewLineMaxColumn(this.model, lineIndex + 1, remainder);
}
public getViewLineRenderingData(viewLineNumber: number): OutputLineRenderingData {
public getViewLineData(viewLineNumber: number): ViewLineData {
this._ensureValidState();
viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);
let lineIndex = r.index;
let remainder = r.remainder;
return this.lines[lineIndex].getViewLineRenderingData(this.model, lineIndex + 1, remainder);
return this.lines[lineIndex].getViewLineData(this.model, lineIndex + 1, remainder);
}
public getMinimapLinesRenderingData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): MinimapLinesRenderingData {
public getViewLinesData(viewStartLineNumber: number, viewEndLineNumber: number, needed: boolean[]): ViewLineData[] {
this._ensureValidState();
viewStartLineNumber = this._toValidViewLineNumber(viewStartLineNumber);
......@@ -817,7 +772,7 @@ export class SplitLinesCollection {
let startModelLineIndex = start.index;
let startRemainder = start.remainder;
let result: MinimapLineRenderingData[] = [];
let result: ViewLineData[] = [];
for (let modelLineIndex = startModelLineIndex, len = this.model.getLineCount(); modelLineIndex < len; modelLineIndex++) {
let line = this.lines[modelLineIndex];
if (!line.isVisible()) {
......@@ -833,7 +788,7 @@ export class SplitLinesCollection {
}
let toViewLineIndex = fromViewLineIndex + remainingViewLineCount;
line.getMinimapLineRenderingData(this.model, modelLineIndex + 1, fromViewLineIndex, toViewLineIndex, viewLineNumber - viewStartLineNumber, needed, result);
line.getViewLinesData(this.model, modelLineIndex + 1, fromViewLineIndex, toViewLineIndex, viewLineNumber - viewStartLineNumber, needed, result);
viewLineNumber += remainingViewLineCount;
......@@ -842,49 +797,8 @@ export class SplitLinesCollection {
}
}
let actual = new MinimapLinesRenderingData(
viewStartLineNumber,
viewEndLineNumber,
this.tabSize,
result
);
// TODO@minimap
// let alternative = this._getMinimapLinesRenderingData(viewStartLineNumber, viewEndLineNumber, needed);
// if (!actual.equals(alternative)) {
// throw new Error('mismatch!');
// }
return actual;
}
// TODO@minimap
// private _getMinimapLinesRenderingData(viewStartLineNumber: number, viewEndLineNumber: number, needed:boolean[]): MinimapLinesRenderingData {
// let result:MinimapLineRenderingData[] = [];
// for (let viewLineNumber = viewStartLineNumber; viewLineNumber <= viewEndLineNumber; viewLineNumber++) {
// let index = viewLineNumber - viewStartLineNumber;
// if (!needed[index]) {
// result[index] = null;
// continue;
// }
// result[index] = this._getMinimapLineRenderingData(viewLineNumber);
// }
// return new MinimapLinesRenderingData(
// viewStartLineNumber,
// viewEndLineNumber,
// this.tabSize,
// result
// );
// }
// private _getMinimapLineRenderingData(viewLineNumber: number): MinimapLineRenderingData {
// viewLineNumber = this._toValidViewLineNumber(viewLineNumber);
// let r = this.prefixSumComputer.getIndexOf(viewLineNumber - 1);
// let lineIndex = r.index;
// let remainder = r.remainder;
// return this.lines[lineIndex]._getMinimapLineRenderingData(this.model, lineIndex + 1, remainder);
// }
return result;
}
public validateViewPosition(viewLineNumber: number, viewColumn: number, expectedModelPosition: Position): Position {
this._ensureValidState();
......@@ -958,36 +872,3 @@ export class SplitLinesCollection {
return r;
}
}
export class OutputLineRenderingData {
_outputLineRenderingDataBrand: void;
/**
* The content at this view line.
*/
public readonly content: string;
/**
* The minimum allowed column at this view line.
*/
public readonly minColumn: number;
/**
* The maximum allowed column at this view line.
*/
public readonly maxColumn: number;
/**
* The tokens at this view line.
*/
public readonly tokens: ViewLineToken[];
constructor(
content: string,
minColumn: number,
maxColumn: number,
tokens: ViewLineToken[]
) {
this.content = content;
this.minColumn = minColumn;
this.maxColumn = maxColumn;
this.tokens = tokens;
}
}
......@@ -91,64 +91,33 @@ export interface IViewModel extends IEventEmitter {
}
export class MinimapLinesRenderingData {
public readonly startLineNumber: number;
public readonly endLineNumber: number;
public readonly tabSize: number;
public readonly data: MinimapLineRenderingData[];
public readonly data: ViewLineData[];
constructor(
startLineNumber: number,
endLineNumber: number,
tabSize: number,
data: MinimapLineRenderingData[]
data: ViewLineData[]
) {
this.startLineNumber = startLineNumber;
this.endLineNumber = endLineNumber;
this.tabSize = tabSize;
this.data = data;
}
// TODO@minimap
public equals(other: MinimapLinesRenderingData): boolean {
if (this.startLineNumber !== other.startLineNumber) {
return false;
}
if (this.endLineNumber !== other.endLineNumber) {
return false;
}
if (this.tabSize !== other.tabSize) {
return false;
}
let len1 = this.data.length;
let len2 = other.data.length;
if (len1 !== len2) {
return false;
}
for (let i = 0; i < len1; i++) {
let a = this.data[i];
let b = other.data[i];
if (!a && !b) {
continue;
}
if (!a || !b) {
return false;
}
if (a.content !== b.content) {
return false;
}
if (!ViewLineToken.equalsArr(a.tokens, b.tokens)) {
return false;
}
}
return true;
}
}
export class MinimapLineRenderingData {
export class ViewLineData {
_viewLineDataBrand: void;
/**
* The content at this view line.
*/
public readonly content: string;
/**
* The minimum allowed column at this view line.
*/
public readonly minColumn: number;
/**
* The maximum allowed column at this view line.
*/
public readonly maxColumn: number;
/**
* The tokens at this view line.
*/
......@@ -156,9 +125,13 @@ export class MinimapLineRenderingData {
constructor(
content: string,
minColumn: number,
maxColumn: number,
tokens: ViewLineToken[]
) {
this.content = content;
this.minColumn = minColumn;
this.maxColumn = maxColumn;
this.tokens = tokens;
}
}
......
......@@ -518,7 +518,7 @@ export class ViewModel extends EventEmitter implements IViewModel {
let mightContainRTL = this.model.mightContainRTL();
let mightContainNonBasicASCII = this.model.mightContainNonBasicASCII();
let tabSize = this.getTabSize();
let lineData = this.lines.getViewLineRenderingData(lineNumber);
let lineData = this.lines.getViewLineData(lineNumber);
let allInlineDecorations = this.decorations.getDecorationsViewportData(visibleRange).inlineDecorations;
let inlineDecorations = allInlineDecorations[lineNumber - visibleRange.startLineNumber];
......@@ -535,7 +535,11 @@ export class ViewModel extends EventEmitter implements IViewModel {
}
public getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData {
return this.lines.getMinimapLinesRenderingData(startLineNumber, endLineNumber, needed);
let result = this.lines.getViewLinesData(startLineNumber, endLineNumber, needed);
return new MinimapLinesRenderingData(
this.getTabSize(),
result
);
}
public getAllOverviewRulerDecorations(): ViewModelDecoration[] {
......
......@@ -17,7 +17,7 @@ import { NULL_STATE } from 'vs/editor/common/modes/nullMode';
import { TokenizationResult2 } from 'vs/editor/common/core/token';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { MinimapLineRenderingData, MinimapLinesRenderingData } from 'vs/editor/common/viewModel/viewModel';
import { ViewLineData } from 'vs/editor/common/viewModel/viewModel';
import { Range } from 'vs/editor/common/core/range';
suite('Editor ViewModel - SplitLinesCollection', () => {
......@@ -380,22 +380,26 @@ suite('SplitLinesCollection', () => {
interface ITestMinimapLineRenderingData {
content: string;
minColumn: number;
maxColumn: number;
tokens: ITestViewLineToken[];
}
function assertMinimapLineRenderingData(actual: MinimapLineRenderingData, expected: ITestMinimapLineRenderingData): void {
function assertMinimapLineRenderingData(actual: ViewLineData, expected: ITestMinimapLineRenderingData): void {
if (actual === null && expected === null) {
assert.ok(true);
return;
}
assert.equal(actual.content, expected.content);
assert.equal(actual.minColumn, expected.minColumn);
assert.equal(actual.maxColumn, expected.maxColumn);
assertViewLineTokens(actual.tokens, expected.tokens);
}
function assertMinimapLinesRenderingData(actual: MinimapLinesRenderingData, expected: ITestMinimapLineRenderingData[]): void {
assert.equal(actual.data.length, expected.length);
function assertMinimapLinesRenderingData(actual: ViewLineData[], expected: ITestMinimapLineRenderingData[]): void {
assert.equal(actual.length, expected.length);
for (let i = 0; i < expected.length; i++) {
assertMinimapLineRenderingData(actual.data[i], expected[i]);
assertMinimapLineRenderingData(actual[i], expected[i]);
}
}
......@@ -411,16 +415,16 @@ suite('SplitLinesCollection', () => {
needed[i] = (desired & (1 << i)) ? true : false;
expected[i] = (needed[i] ? all[start - 1 + i] : null);
}
let actual = splitLinesCollection.getMinimapLinesRenderingData(start, end, needed);
let actual = splitLinesCollection.getViewLinesData(start, end, needed);
assertMinimapLinesRenderingData(actual, expected);
// Remove break to test all possible combinations
// Comment out next line to test all possible combinations
break;
}
}
}
}
test('getMinimapLinesRenderingData - no wrapping', () => {
test('getViewLinesData - no wrapping', () => {
withSplitLinesCollection(model, -1, (splitLinesCollection) => {
assert.equal(splitLinesCollection.getViewLineCount(), 8);
assert.equal(splitLinesCollection.modelPositionIsVisible(1, 1), true);
......@@ -435,6 +439,8 @@ suite('SplitLinesCollection', () => {
let _expected: ITestMinimapLineRenderingData[] = [
{
content: 'class Nice {',
minColumn: 1,
maxColumn: 13,
tokens: [
{ endIndex: 5, value: 1 },
{ endIndex: 6, value: 2 },
......@@ -444,6 +450,8 @@ suite('SplitLinesCollection', () => {
},
{
content: ' function hi() {',
minColumn: 1,
maxColumn: 17,
tokens: [
{ endIndex: 1, value: 5 },
{ endIndex: 9, value: 6 },
......@@ -454,6 +462,8 @@ suite('SplitLinesCollection', () => {
},
{
content: ' console.log("Hello world");',
minColumn: 1,
maxColumn: 30,
tokens: [
{ endIndex: 2, value: 10 },
{ endIndex: 9, value: 11 },
......@@ -466,12 +476,16 @@ suite('SplitLinesCollection', () => {
},
{
content: ' }',
minColumn: 1,
maxColumn: 3,
tokens: [
{ endIndex: 2, value: 17 },
]
},
{
content: ' function hello() {',
minColumn: 1,
maxColumn: 20,
tokens: [
{ endIndex: 1, value: 18 },
{ endIndex: 9, value: 19 },
......@@ -482,6 +496,8 @@ suite('SplitLinesCollection', () => {
},
{
content: ' console.log("Hello world, this is a somewhat longer line");',
minColumn: 1,
maxColumn: 62,
tokens: [
{ endIndex: 2, value: 23 },
{ endIndex: 9, value: 24 },
......@@ -493,18 +509,20 @@ suite('SplitLinesCollection', () => {
]
},
{
minColumn: 1,
maxColumn: 3,
content: ' }',
tokens: [
{ endIndex: 2, value: 30 },
]
},
{
minColumn: 1,
maxColumn: 2,
content: '}',
tokens: [
{ endIndex: 1, value: 31 },
]
}
];
......@@ -540,7 +558,7 @@ suite('SplitLinesCollection', () => {
});
});
test('getMinimapLinesRenderingData - with wrapping', () => {
test('getViewLinesData - with wrapping', () => {
withSplitLinesCollection(model, 30, (splitLinesCollection) => {
assert.equal(splitLinesCollection.getViewLineCount(), 12);
assert.equal(splitLinesCollection.modelPositionIsVisible(1, 1), true);
......@@ -555,6 +573,8 @@ suite('SplitLinesCollection', () => {
let _expected: ITestMinimapLineRenderingData[] = [
{
content: 'class Nice {',
minColumn: 1,
maxColumn: 13,
tokens: [
{ endIndex: 5, value: 1 },
{ endIndex: 6, value: 2 },
......@@ -564,6 +584,8 @@ suite('SplitLinesCollection', () => {
},
{
content: ' function hi() {',
minColumn: 1,
maxColumn: 17,
tokens: [
{ endIndex: 1, value: 5 },
{ endIndex: 9, value: 6 },
......@@ -574,6 +596,8 @@ suite('SplitLinesCollection', () => {
},
{
content: ' console.log("Hello ',
minColumn: 1,
maxColumn: 22,
tokens: [
{ endIndex: 2, value: 10 },
{ endIndex: 9, value: 11 },
......@@ -585,6 +609,8 @@ suite('SplitLinesCollection', () => {
},
{
content: ' world");',
minColumn: 4,
maxColumn: 12,
tokens: [
{ endIndex: 9, value: 15 },
{ endIndex: 11, value: 16 },
......@@ -592,12 +618,16 @@ suite('SplitLinesCollection', () => {
},
{
content: ' }',
minColumn: 1,
maxColumn: 3,
tokens: [
{ endIndex: 2, value: 17 },
]
},
{
content: ' function hello() {',
minColumn: 1,
maxColumn: 20,
tokens: [
{ endIndex: 1, value: 18 },
{ endIndex: 9, value: 19 },
......@@ -608,6 +638,8 @@ suite('SplitLinesCollection', () => {
},
{
content: ' console.log("Hello ',
minColumn: 1,
maxColumn: 22,
tokens: [
{ endIndex: 2, value: 23 },
{ endIndex: 9, value: 24 },
......@@ -619,18 +651,24 @@ suite('SplitLinesCollection', () => {
},
{
content: ' world, this is a ',
minColumn: 4,
maxColumn: 21,
tokens: [
{ endIndex: 20, value: 28 },
]
},
{
content: ' somewhat longer ',
minColumn: 4,
maxColumn: 20,
tokens: [
{ endIndex: 19, value: 28 },
]
},
{
content: ' line");',
minColumn: 4,
maxColumn: 11,
tokens: [
{ endIndex: 8, value: 28 },
{ endIndex: 10, value: 29 },
......@@ -638,17 +676,19 @@ suite('SplitLinesCollection', () => {
},
{
content: ' }',
minColumn: 1,
maxColumn: 3,
tokens: [
{ endIndex: 2, value: 30 },
]
},
{
content: '}',
minColumn: 1,
maxColumn: 2,
tokens: [
{ endIndex: 1, value: 31 },
]
}
];
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册