提交 16c2b0ee 编写于 作者: A Alex Dima

Don't cache indent level in ModelLine

上级 78149f4e
......@@ -469,8 +469,6 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
private _doApplyEdits(operations: IValidatedEditOperation[]): void {
const tabSize = this._options.tabSize;
// Sort operations descending
operations.sort(EditableTextModel._sortOpsDescending);
......@@ -505,7 +503,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
}
this._invalidateLine(currentLineNumber - 1);
this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, i), tabSize);
this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, i));
this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text)
......@@ -516,7 +514,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
}
this._invalidateLine(currentLineNumber - 1);
this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length), tabSize);
this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length));
this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text)
......@@ -569,7 +567,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
const spliceStartLineNumber = startLineNumber + editingLinesCnt;
const endLineRemains = this._lines[endLineNumber - 1].split(endColumn, tabSize);
const endLineRemains = this._lines[endLineNumber - 1].split(endColumn);
this._invalidateLine(spliceStartLineNumber - 1);
const spliceCnt = endLineNumber - spliceStartLineNumber;
......@@ -578,7 +576,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
this._lineStarts.removeValues(spliceStartLineNumber, spliceCnt);
// Reconstruct first line
this._lines[spliceStartLineNumber - 1].append(endLineRemains, tabSize);
this._lines[spliceStartLineNumber - 1].append(endLineRemains);
this._lineStarts.changeValue(spliceStartLineNumber - 1, this._lines[spliceStartLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
......@@ -603,7 +601,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
}
// Split last line
let leftoverLine = this._lines[spliceLineNumber - 1].split(spliceColumn, tabSize);
let leftoverLine = this._lines[spliceLineNumber - 1].split(spliceColumn);
this._lineStarts.changeValue(spliceLineNumber - 1, this._lines[spliceLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLineChanged(spliceLineNumber, this._lines[spliceLineNumber - 1].text)
......@@ -615,7 +613,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
let newLinesContent: string[] = [];
let newLinesLengths = new Uint32Array(insertingLinesCnt - editingLinesCnt);
for (let j = editingLinesCnt + 1; j <= insertingLinesCnt; j++) {
newLines.push(this._createModelLine(op.lines[j], tabSize));
newLines.push(this._createModelLine(op.lines[j]));
newLinesContent.push(op.lines[j]);
newLinesLengths[j - editingLinesCnt - 1] = op.lines[j].length + this._EOL.length;
}
......@@ -624,7 +622,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
this._lineStarts.insertValues(startLineNumber + editingLinesCnt, newLinesLengths);
// Last line
this._lines[startLineNumber + insertingLinesCnt - 1].append(leftoverLine, tabSize);
this._lines[startLineNumber + insertingLinesCnt - 1].append(leftoverLine);
this._lineStarts.changeValue(startLineNumber + insertingLinesCnt - 1, this._lines[startLineNumber + insertingLinesCnt - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLinesContent.join('\n'))
......
......@@ -54,15 +54,6 @@ export function computeIndentLevel(line: string, tabSize: number): number {
return indent;
}
/**
* Returns:
* - 0 => the line consists of whitespace
* - otherwise => the indent level is returned value - 1
*/
function computePlusOneIndentLevel(line: string, tabSize: number): number {
return computeIndentLevel(line, tabSize) + 1;
}
export interface IModelLine {
readonly text: string;
......@@ -75,14 +66,10 @@ export interface IModelLine {
getTokens(topLevelLanguageId: LanguageId): LineTokens;
setTokens(topLevelLanguageId: LanguageId, tokens: Uint32Array): void;
// --- indentation
updateTabSize(tabSize: number): void;
getIndentLevel(): number;
// --- editing
applyEdits(edits: ILineEdit[], tabSize: number): number;
append(other: IModelLine, tabSize: number): void;
split(splitColumn: number, tabSize: number): IModelLine;
applyEdits(edits: ILineEdit[]): number;
append(other: IModelLine): void;
split(splitColumn: number): IModelLine;
}
export abstract class AbstractModelLine {
......@@ -93,13 +80,13 @@ export abstract class AbstractModelLine {
///
public abstract get text(): string;
protected abstract _setText(text: string, tabSize: number): void;
protected abstract _setText(text: string): void;
protected abstract _createTokensAdjuster(): ITokensAdjuster;
protected abstract _createModelLine(text: string, tabSize: number): IModelLine;
protected abstract _createModelLine(text: string): IModelLine;
///
public applyEdits(edits: ILineEdit[], tabSize: number): number {
public applyEdits(edits: ILineEdit[]): number {
let deltaColumn = 0;
let resultText = this.text;
......@@ -142,21 +129,21 @@ export abstract class AbstractModelLine {
tokensAdjuster.finish(deltaColumn, resultText.length);
// Save the resulting text
this._setText(resultText, tabSize);
this._setText(resultText);
return deltaColumn;
}
public split(splitColumn: number, tabSize: number): IModelLine {
public split(splitColumn: number): IModelLine {
const myText = this.text.substring(0, splitColumn - 1);
const otherText = this.text.substring(splitColumn - 1);
this._setText(myText, tabSize);
return this._createModelLine(otherText, tabSize);
this._setText(myText);
return this._createModelLine(otherText);
}
public append(other: IModelLine, tabSize: number): void {
this._setText(this.text + other.text, tabSize);
public append(other: IModelLine): void {
this._setText(this.text + other.text);
}
}
......@@ -165,59 +152,33 @@ export class ModelLine extends AbstractModelLine implements IModelLine {
private _text: string;
public get text(): string { return this._text; }
/**
* bits 31 - 1 => indentLevel
* bit 0 => isInvalid
*/
private _metadata: number;
private _isInvalid: boolean;
public isInvalid(): boolean {
return (this._metadata & 0x00000001) ? true : false;
return this._isInvalid;
}
public setIsInvalid(isInvalid: boolean): void {
this._metadata = (this._metadata & 0xfffffffe) | (isInvalid ? 1 : 0);
}
/**
* Returns:
* - -1 => the line consists of whitespace
* - otherwise => the indent level is returned value
*/
public getIndentLevel(): number {
return ((this._metadata & 0xfffffffe) >> 1) - 1;
}
private _setPlusOneIndentLevel(value: number): void {
this._metadata = (this._metadata & 0x00000001) | ((value & 0xefffffff) << 1);
}
public updateTabSize(tabSize: number): void {
if (tabSize === 0) {
// don't care mark
this._metadata = this._metadata & 0x00000001;
} else {
this._setPlusOneIndentLevel(computePlusOneIndentLevel(this._text, tabSize));
}
this._isInvalid = isInvalid;
}
private _state: IState;
private _lineTokens: ArrayBuffer;
constructor(text: string, tabSize: number) {
constructor(text: string) {
super();
this._metadata = 0;
this._setText(text, tabSize);
this._isInvalid = false;
this._setText(text);
this._state = null;
this._lineTokens = null;
}
protected _createModelLine(text: string, tabSize: number): IModelLine {
return new ModelLine(text, tabSize);
protected _createModelLine(text: string): IModelLine {
return new ModelLine(text);
}
public split(splitColumn: number, tabSize: number): IModelLine {
let result = super.split(splitColumn, tabSize);
public split(splitColumn: number): IModelLine {
let result = super.split(splitColumn);
// Mark overflowing tokens for deletion & delete marked tokens
this._deleteMarkedTokens(this._markOverflowingTokensForDeletion(0, this.text.length));
......@@ -225,10 +186,10 @@ export class ModelLine extends AbstractModelLine implements IModelLine {
return result;
}
public append(other: IModelLine, tabSize: number): void {
public append(other: IModelLine): void {
let thisTextLength = this.text.length;
super.append(other, tabSize);
super.append(other);
if (other instanceof ModelLine) {
let otherRawTokens = other._lineTokens;
......@@ -433,20 +394,14 @@ export class ModelLine extends AbstractModelLine implements IModelLine {
this._lineTokens = newTokens.buffer;
}
protected _setText(text: string, tabSize: number): void {
protected _setText(text: string): void {
this._text = text;
if (tabSize === 0) {
// don't care mark
this._metadata = this._metadata & 0x00000001;
} else {
this._setPlusOneIndentLevel(computePlusOneIndentLevel(text, tabSize));
}
}
}
/**
* A model line that cannot store any tokenization state, nor does it compute indentation levels.
* A model line that cannot store any tokenization state.
* It has no fields except the text.
*/
export class MinimalModelLine extends AbstractModelLine implements IModelLine {
......@@ -461,33 +416,21 @@ export class MinimalModelLine extends AbstractModelLine implements IModelLine {
public setIsInvalid(isInvalid: boolean): void {
}
/**
* Returns:
* - -1 => the line consists of whitespace
* - otherwise => the indent level is returned value
*/
public getIndentLevel(): number {
return 0;
}
public updateTabSize(tabSize: number): void {
}
constructor(text: string, tabSize: number) {
constructor(text: string) {
super();
this._setText(text, tabSize);
this._setText(text);
}
protected _createModelLine(text: string, tabSize: number): IModelLine {
return new MinimalModelLine(text, tabSize);
protected _createModelLine(text: string): IModelLine {
return new MinimalModelLine(text);
}
public split(splitColumn: number, tabSize: number): IModelLine {
return super.split(splitColumn, tabSize);
public split(splitColumn: number): IModelLine {
return super.split(splitColumn);
}
public append(other: IModelLine, tabSize: number): void {
super.append(other, tabSize);
public append(other: IModelLine): void {
super.append(other);
}
// --- BEGIN STATE
......@@ -523,7 +466,7 @@ export class MinimalModelLine extends AbstractModelLine implements IModelLine {
return NO_OP_TOKENS_ADJUSTER;
}
protected _setText(text: string, tabSize: number): void {
protected _setText(text: string): void {
this._text = text;
}
}
......
......@@ -121,11 +121,11 @@ export class TextModel implements editorCommon.ITextModel {
this._isDisposing = false;
}
protected _createModelLine(text: string, tabSize: number): IModelLine {
protected _createModelLine(text: string): IModelLine {
if (this._isTooLargeForTokenization) {
return new MinimalModelLine(text, tabSize);
return new MinimalModelLine(text);
}
return new ModelLine(text, tabSize);
return new ModelLine(text);
}
protected _assertNotDisposed(): void {
......@@ -167,13 +167,6 @@ export class TextModel implements editorCommon.ITextModel {
let e = this._options.createChangeEvent(newOpts);
this._options = newOpts;
if (e.tabSize) {
let newTabSize = this._options.tabSize;
for (let i = 0, len = this._lines.length; i < len; i++) {
this._lines[i].updateTabSize(newTabSize);
}
}
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelOptionsChanged, e);
}
......@@ -766,12 +759,11 @@ export class TextModel implements editorCommon.ITextModel {
}
private _constructLines(textSource: ITextSource): void {
const tabSize = this._options.tabSize;
let rawLines = textSource.lines;
let modelLines: IModelLine[] = new Array<IModelLine>(rawLines.length);
for (let i = 0, len = rawLines.length; i < len; i++) {
modelLines[i] = this._createModelLine(rawLines[i], tabSize);
modelLines[i] = this._createModelLine(rawLines[i]);
}
this._BOM = textSource.BOM;
this._mightContainRTL = textSource.containsRTL;
......
......@@ -23,6 +23,7 @@ import { TokenizationResult2 } from 'vs/editor/common/core/token';
import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource';
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
import { IndentRanges, computeRanges } from 'vs/editor/common/model/indentRanges';
import { computeIndentLevel } from 'vs/editor/common/model/modelLine';
class ModelTokensChangedEventBuilder {
......@@ -855,6 +856,10 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
return this._getIndentRanges();
}
private _computeIndentLevel(lineIndex: number): number {
return computeIndentLevel(this._lines[lineIndex].text, this._options.tabSize);
}
public getLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[] {
this._assertNotDisposed();
const lineCount = this.getLineCount();
......@@ -880,7 +885,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
let resultIndex = lineNumber - startLineNumber;
const currentIndent = this._lines[lineNumber - 1].getIndentLevel();
const currentIndent = this._computeIndentLevel(lineNumber - 1);
if (currentIndent >= 0) {
// This line has content (besides whitespace)
// Use the line's indent
......@@ -896,7 +901,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
// must find previous line with content
for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {
let indent = this._lines[lineIndex].getIndentLevel();
let indent = this._computeIndentLevel(lineIndex);
if (indent >= 0) {
aboveContentLineIndex = lineIndex;
aboveContentLineIndent = indent;
......@@ -911,7 +916,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
// must find next line with content
for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {
let indent = this._lines[lineIndex].getIndentLevel();
let indent = this._computeIndentLevel(lineIndex);
if (indent >= 0) {
belowContentLineIndex = lineIndex;
belowContentLineIndent = indent;
......
......@@ -6,7 +6,7 @@
import * as assert from 'assert';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
import { ModelLine, ILineEdit } from 'vs/editor/common/model/modelLine';
import { ModelLine, ILineEdit, computeIndentLevel } from 'vs/editor/common/model/modelLine';
import { MetadataConsts } from 'vs/editor/common/modes';
import { ViewLineToken, ViewLineTokenFactory } from 'vs/editor/common/core/viewLineToken';
......@@ -22,12 +22,9 @@ function assertLineTokens(_actual: LineTokens, _expected: TestToken[]): void {
assert.deepEqual(actual.map(decode), expected.map(decode));
}
const NO_TAB_SIZE = 0;
suite('ModelLine - getIndentLevel', () => {
function assertIndentLevel(text: string, expected: number, tabSize: number = 4): void {
let modelLine = new ModelLine(text, tabSize);
let actual = modelLine.getIndentLevel();
let actual = computeIndentLevel(text, tabSize);
assert.equal(actual, expected, text);
}
......@@ -52,8 +49,8 @@ suite('ModelLine - getIndentLevel', () => {
suite('Editor Model - modelLine.applyEdits text', () => {
function testEdits(initial: string, edits: ILineEdit[], expected: string): void {
var line = new ModelLine(initial, NO_TAB_SIZE);
line.applyEdits(edits, NO_TAB_SIZE);
var line = new ModelLine(initial);
line.applyEdits(edits);
assert.equal(line.text, expected);
}
......@@ -198,8 +195,8 @@ suite('Editor Model - modelLine.applyEdits text', () => {
suite('Editor Model - modelLine.split text', () => {
function testLineSplit(initial: string, splitColumn: number, expected1: string, expected2: string): void {
var line = new ModelLine(initial, NO_TAB_SIZE);
var newLine = line.split(splitColumn, NO_TAB_SIZE);
var line = new ModelLine(initial);
var newLine = line.split(splitColumn);
assert.equal(line.text, expected1);
assert.equal(newLine.text, expected2);
}
......@@ -235,9 +232,9 @@ suite('Editor Model - modelLine.split text', () => {
suite('Editor Model - modelLine.append text', () => {
function testLineAppend(a: string, b: string, expected: string): void {
var line1 = new ModelLine(a, NO_TAB_SIZE);
var line2 = new ModelLine(b, NO_TAB_SIZE);
line1.append(line2, NO_TAB_SIZE);
var line1 = new ModelLine(a);
var line2 = new ModelLine(b);
line1.append(line2);
assert.equal(line1.text, expected);
}
......@@ -296,23 +293,23 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => {
function testLineEditTokens(initialText: string, initialTokens: TestToken[], edits: ILineEdit[], expectedText: string, expectedTokens: TestToken[]): void {
let line = new ModelLine(initialText, NO_TAB_SIZE);
let line = new ModelLine(initialText);
line.setTokens(0, TestToken.toTokens(initialTokens));
line.applyEdits(edits, NO_TAB_SIZE);
line.applyEdits(edits);
assert.equal(line.text, expectedText);
assertLineTokens(line.getTokens(0), expectedTokens);
}
test('insertion on empty line', () => {
let line = new ModelLine('some text', NO_TAB_SIZE);
let line = new ModelLine('some text');
line.setTokens(0, TestToken.toTokens([new TestToken(0, 1)]));
line.applyEdits([{ startColumn: 1, endColumn: 10, text: '' }], NO_TAB_SIZE);
line.applyEdits([{ startColumn: 1, endColumn: 10, text: '' }]);
line.setTokens(0, new Uint32Array(0));
line.applyEdits([{ startColumn: 1, endColumn: 1, text: 'a' }], NO_TAB_SIZE);
line.applyEdits([{ startColumn: 1, endColumn: 1, text: 'a' }]);
assertLineTokens(line.getTokens(0), [new TestToken(0, 1)]);
});
......@@ -843,10 +840,10 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => {
suite('Editor Model - modelLine.split text & tokens', () => {
function testLineSplitTokens(initialText: string, initialTokens: TestToken[], splitColumn: number, expectedText1: string, expectedText2: string, expectedTokens: TestToken[]): void {
let line = new ModelLine(initialText, NO_TAB_SIZE);
let line = new ModelLine(initialText);
line.setTokens(0, TestToken.toTokens(initialTokens));
let other = line.split(splitColumn, NO_TAB_SIZE);
let other = line.split(splitColumn);
assert.equal(line.text, expectedText1);
assert.equal(other.text, expectedText2);
......@@ -927,13 +924,13 @@ suite('Editor Model - modelLine.split text & tokens', () => {
suite('Editor Model - modelLine.append text & tokens', () => {
function testLineAppendTokens(aText: string, aTokens: TestToken[], bText: string, bTokens: TestToken[], expectedText: string, expectedTokens: TestToken[]): void {
let a = new ModelLine(aText, NO_TAB_SIZE);
let a = new ModelLine(aText);
a.setTokens(0, TestToken.toTokens(aTokens));
let b = new ModelLine(bText, NO_TAB_SIZE);
let b = new ModelLine(bText);
b.setTokens(0, TestToken.toTokens(bTokens));
a.append(b, NO_TAB_SIZE);
a.append(b);
assert.equal(a.text, expectedText);
assertLineTokens(a.getTokens(0), expectedTokens);
......@@ -1047,9 +1044,9 @@ suite('Editor Model - modelLine.append text & tokens', () => {
suite('Editor Model - modelLine.applyEdits', () => {
function testLineEdit(initialText: string, edits: ILineEdit[], expectedText: string): void {
let line = new ModelLine(initialText, NO_TAB_SIZE);
let line = new ModelLine(initialText);
line.applyEdits(edits, NO_TAB_SIZE);
line.applyEdits(edits);
assert.equal(line.text, expectedText, 'text');
}
......@@ -1402,9 +1399,9 @@ suite('Editor Model - modelLine.applyEdits', () => {
suite('Editor Model - modelLine.split', () => {
function testLineSplit(initialText: string, splitColumn: number, forceMoveMarkers: boolean, expectedText1: string, expectedText2: string): void {
let line = new ModelLine(initialText, NO_TAB_SIZE);
let line = new ModelLine(initialText);
let otherLine = line.split(splitColumn, NO_TAB_SIZE);
let otherLine = line.split(splitColumn);
assert.equal(line.text, expectedText1, 'text');
assert.equal(otherLine.text, expectedText2, 'text');
......@@ -1484,10 +1481,10 @@ suite('Editor Model - modelLine.split', () => {
suite('Editor Model - modelLine.append', () => {
function testLinePrependMarkers(aText: string, bText: string, expectedText: string): void {
let a = new ModelLine(aText, NO_TAB_SIZE);
let b = new ModelLine(bText, NO_TAB_SIZE);
let a = new ModelLine(aText);
let b = new ModelLine(bText);
a.append(b, NO_TAB_SIZE);
a.append(b);
assert.equal(a.text, expectedText, 'text');
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册