提交 a32a8024 编写于 作者: A Alex Dima

Add getIndentLevel() to TextModel and ModelLine

上级 27d5c0e2
...@@ -1563,6 +1563,11 @@ export interface ITextModel { ...@@ -1563,6 +1563,11 @@ export interface ITextModel {
*/ */
getLineContent(lineNumber:number): string; getLineContent(lineNumber:number): string;
/**
* @internal
*/
getIndentLevel(lineNumber:number): number;
/** /**
* Get the text for all lines. * Get the text for all lines.
*/ */
......
...@@ -425,6 +425,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -425,6 +425,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
private _applyEdits(operations:IValidatedEditOperation[]): void { private _applyEdits(operations:IValidatedEditOperation[]): void {
const tabSize = this._options.tabSize;
// Sort operations descending // Sort operations descending
operations.sort(EditableTextModel._sortOpsDescending); operations.sort(EditableTextModel._sortOpsDescending);
...@@ -461,7 +463,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -461,7 +463,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
} }
this._invalidateLine(currentLineNumber - 1); this._invalidateLine(currentLineNumber - 1);
this._lines[currentLineNumber - 1].applyEdits(deferredEventsBuilder.changedMarkers, lineEditsQueue.slice(currentLineNumberStart, i)); this._lines[currentLineNumber - 1].applyEdits(deferredEventsBuilder.changedMarkers, lineEditsQueue.slice(currentLineNumberStart, i), tabSize);
if (this._lineStarts) { if (this._lineStarts) {
// update prefix sum // update prefix sum
this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length);
...@@ -473,7 +475,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -473,7 +475,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
} }
this._invalidateLine(currentLineNumber - 1); this._invalidateLine(currentLineNumber - 1);
this._lines[currentLineNumber - 1].applyEdits(deferredEventsBuilder.changedMarkers, lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length)); this._lines[currentLineNumber - 1].applyEdits(deferredEventsBuilder.changedMarkers, lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length), tabSize);
if (this._lineStarts) { if (this._lineStarts) {
// update prefix sum // update prefix sum
this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length); this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length);
...@@ -535,7 +537,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -535,7 +537,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
let spliceStartLineNumber = startLineNumber + editingLinesCnt; let spliceStartLineNumber = startLineNumber + editingLinesCnt;
let spliceStartColumn = this.getLineMaxColumn(spliceStartLineNumber); let spliceStartColumn = this.getLineMaxColumn(spliceStartLineNumber);
let endLineRemains = this._lines[endLineNumber - 1].split(deferredEventsBuilder.changedMarkers, endColumn, false); let endLineRemains = this._lines[endLineNumber - 1].split(deferredEventsBuilder.changedMarkers, endColumn, false, tabSize);
this._invalidateLine(spliceStartLineNumber - 1); this._invalidateLine(spliceStartLineNumber - 1);
let spliceCnt = endLineNumber - spliceStartLineNumber; let spliceCnt = endLineNumber - spliceStartLineNumber;
...@@ -554,7 +556,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -554,7 +556,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
} }
// Reconstruct first line // Reconstruct first line
this._lines[spliceStartLineNumber - 1].append(deferredEventsBuilder.changedMarkers, endLineRemains); this._lines[spliceStartLineNumber - 1].append(deferredEventsBuilder.changedMarkers, endLineRemains, tabSize);
if (this._lineStarts) { if (this._lineStarts) {
// update prefix sum // update prefix sum
this._lineStarts.changeValue(spliceStartLineNumber - 1, this._lines[spliceStartLineNumber - 1].text.length + this._EOL.length); this._lineStarts.changeValue(spliceStartLineNumber - 1, this._lines[spliceStartLineNumber - 1].text.length + this._EOL.length);
...@@ -578,7 +580,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -578,7 +580,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
} }
// Split last line // Split last line
let leftoverLine = this._lines[spliceLineNumber - 1].split(deferredEventsBuilder.changedMarkers, spliceColumn, op.forceMoveMarkers); let leftoverLine = this._lines[spliceLineNumber - 1].split(deferredEventsBuilder.changedMarkers, spliceColumn, op.forceMoveMarkers, tabSize);
if (this._lineStarts) { if (this._lineStarts) {
// update prefix sum // update prefix sum
this._lineStarts.changeValue(spliceLineNumber - 1, this._lines[spliceLineNumber - 1].text.length + this._EOL.length); this._lineStarts.changeValue(spliceLineNumber - 1, this._lines[spliceLineNumber - 1].text.length + this._EOL.length);
...@@ -591,7 +593,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -591,7 +593,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
let newLinesLengths:number[] = []; let newLinesLengths:number[] = [];
for (let j = editingLinesCnt + 1; j <= insertingLinesCnt; j++) { for (let j = editingLinesCnt + 1; j <= insertingLinesCnt; j++) {
let newLineNumber = startLineNumber + j; let newLineNumber = startLineNumber + j;
this._lines.splice(newLineNumber - 1, 0, new ModelLine(newLineNumber, op.lines[j])); this._lines.splice(newLineNumber - 1, 0, new ModelLine(newLineNumber, op.lines[j], tabSize));
newLinesContent.push(op.lines[j]); newLinesContent.push(op.lines[j]);
newLinesLengths.push(op.lines[j].length + this._EOL.length); newLinesLengths.push(op.lines[j].length + this._EOL.length);
} }
...@@ -602,7 +604,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito ...@@ -602,7 +604,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
} }
// Last line // Last line
this._lines[startLineNumber + insertingLinesCnt - 1].append(deferredEventsBuilder.changedMarkers, leftoverLine); this._lines[startLineNumber + insertingLinesCnt - 1].append(deferredEventsBuilder.changedMarkers, leftoverLine, tabSize);
if (this._lineStarts) { if (this._lineStarts) {
// update prefix sum // update prefix sum
this._lineStarts.changeValue(startLineNumber + insertingLinesCnt - 1, this._lines[startLineNumber + insertingLinesCnt - 1].text.length + this._EOL.length); this._lineStarts.changeValue(startLineNumber + insertingLinesCnt - 1, this._lines[startLineNumber + insertingLinesCnt - 1].text.length + this._EOL.length);
......
...@@ -18,6 +18,8 @@ export interface IMirrorModelEvents { ...@@ -18,6 +18,8 @@ export interface IMirrorModelEvents {
contentChanged: editorCommon.IModelContentChangedEvent[]; contentChanged: editorCommon.IModelContentChangedEvent[];
} }
const NO_TAB_SIZE = 0;
export class AbstractMirrorModel extends TextModelWithTokens implements editorCommon.IMirrorModel { export class AbstractMirrorModel extends TextModelWithTokens implements editorCommon.IMirrorModel {
_associatedResource:URI; _associatedResource:URI;
...@@ -207,7 +209,7 @@ export class MirrorModel extends AbstractMirrorModel implements editorCommon.IMi ...@@ -207,7 +209,7 @@ export class MirrorModel extends AbstractMirrorModel implements editorCommon.IMi
endColumn: Number.MAX_VALUE, endColumn: Number.MAX_VALUE,
text: e.detail, text: e.detail,
forceMoveMarkers: false forceMoveMarkers: false
}]); }], NO_TAB_SIZE);
if (this._lineStarts) { if (this._lineStarts) {
// update prefix sum // update prefix sum
this._lineStarts.changeValue(e.lineNumber - 1, this._lines[e.lineNumber - 1].text.length + this._EOL.length); this._lineStarts.changeValue(e.lineNumber - 1, this._lines[e.lineNumber - 1].text.length + this._EOL.length);
...@@ -247,7 +249,7 @@ export class MirrorModel extends AbstractMirrorModel implements editorCommon.IMi ...@@ -247,7 +249,7 @@ export class MirrorModel extends AbstractMirrorModel implements editorCommon.IMi
let newLengths:number[] = []; let newLengths:number[] = [];
for (lineIndex = e.fromLineNumber - 1, i = 0; lineIndex < e.toLineNumber; lineIndex++, i++) { for (lineIndex = e.fromLineNumber - 1, i = 0; lineIndex < e.toLineNumber; lineIndex++, i++) {
this._lines.splice(lineIndex, 0, new ModelLine(0, splitLines[i])); this._lines.splice(lineIndex, 0, new ModelLine(0, splitLines[i], NO_TAB_SIZE));
newLengths.push(splitLines[i].length + this._EOL.length); newLengths.push(splitLines[i].length + this._EOL.length);
} }
if (this._lineStarts) { if (this._lineStarts) {
......
...@@ -71,6 +71,35 @@ enum MarkerMoveSemantics { ...@@ -71,6 +71,35 @@ enum MarkerMoveSemantics {
ForceStay = 2 ForceStay = 2
} }
/**
* Returns:
* - 0 => the line consists of whitespace
* - otherwise => the indent level is returned value - 1
*/
function computePlusOneIndentLevel(line: string, tabSize: number): number {
let indent = 0;
let i = 0;
let len = line.length;
while (i < len) {
let chCode = line.charCodeAt(i);
if (chCode === 32 /*space*/) {
indent++;
} else if (chCode === 9 /*\t*/) {
indent = indent - indent % tabSize + tabSize;
} else {
break;
}
i++;
}
if (i === len) {
return 0; // line only consists of whitespace
}
return indent + 1;
}
export class ModelLine { export class ModelLine {
private _lineNumber:number; private _lineNumber:number;
public get lineNumber():number { return this._lineNumber; } public get lineNumber():number { return this._lineNumber; }
...@@ -78,19 +107,51 @@ export class ModelLine { ...@@ -78,19 +107,51 @@ export class ModelLine {
private _text:string; private _text:string;
public get text():string { return this._text; } public get text():string { return this._text; }
private _isInvalid:boolean; /**
public get isInvalid():boolean { return this._isInvalid; } * bits 31 - 1 => indentLevel
public set isInvalid(value:boolean) { this._isInvalid = value; } * bit 0 => isInvalid
*/
private _metadata:number;
public get isInvalid(): boolean {
return (this._metadata & 0x00000001) ? true : false;
}
public set isInvalid(value:boolean) {
this._metadata = (this._metadata & 0xfffffffe) | (value ? 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));
}
}
private _state:IState; private _state:IState;
private _modeTransitions: ModeTransition[]; private _modeTransitions: ModeTransition[];
private _lineTokens: LineTokens; private _lineTokens: LineTokens;
private _markers:ILineMarker[]; private _markers:ILineMarker[];
constructor(lineNumber:number, text:string) { constructor(lineNumber:number, text:string, tabSize:number) {
this._lineNumber = lineNumber|0; this._lineNumber = lineNumber|0;
this._text = text; this._metadata = 0;
this._isInvalid = false; this._setText(text, tabSize);
this._state = null; this._state = null;
this._modeTransitions = null; this._modeTransitions = null;
this._lineTokens = null; this._lineTokens = null;
...@@ -207,8 +268,14 @@ export class ModelLine { ...@@ -207,8 +268,14 @@ export class ModelLine {
}; };
} }
private _setText(text:string): void { private _setText(text:string, tabSize:number): void {
this._text = text; this._text = text;
if (tabSize === 0) {
// don't care mark
this._metadata = this._metadata & 0x00000001;
} else {
this._setPlusOneIndentLevel(computePlusOneIndentLevel(text, tabSize));
}
if (this._lineTokens) { if (this._lineTokens) {
let map = this._lineTokens.getBinaryEncodedTokensMap(), let map = this._lineTokens.getBinaryEncodedTokensMap(),
...@@ -342,7 +409,7 @@ export class ModelLine { ...@@ -342,7 +409,7 @@ export class ModelLine {
}; };
} }
public applyEdits(changedMarkers: IChangedMarkers, edits:ILineEdit[]): number { public applyEdits(changedMarkers: IChangedMarkers, edits:ILineEdit[], tabSize:number): number {
let deltaColumn = 0; let deltaColumn = 0;
let resultText = this._text; let resultText = this._text;
...@@ -393,12 +460,12 @@ export class ModelLine { ...@@ -393,12 +460,12 @@ export class ModelLine {
markersAdjuster.finish(deltaColumn, resultText.length); markersAdjuster.finish(deltaColumn, resultText.length);
// Save the resulting text // Save the resulting text
this._setText(resultText); this._setText(resultText, tabSize);
return deltaColumn; return deltaColumn;
} }
public split(changedMarkers: IChangedMarkers, splitColumn:number, forceMoveMarkers:boolean): ModelLine { public split(changedMarkers: IChangedMarkers, splitColumn:number, forceMoveMarkers:boolean, tabSize:number): ModelLine {
// console.log('--> split @ ' + splitColumn + '::: ' + this._printMarkers()); // console.log('--> split @ ' + splitColumn + '::: ' + this._printMarkers());
var myText = this._text.substring(0, splitColumn - 1); var myText = this._text.substring(0, splitColumn - 1);
var otherText = this._text.substring(splitColumn - 1); var otherText = this._text.substring(splitColumn - 1);
...@@ -439,20 +506,20 @@ export class ModelLine { ...@@ -439,20 +506,20 @@ export class ModelLine {
} }
} }
this._setText(myText); this._setText(myText, tabSize);
var otherLine = new ModelLine(this._lineNumber + 1, otherText); var otherLine = new ModelLine(this._lineNumber + 1, otherText, tabSize);
if (otherMarkers) { if (otherMarkers) {
otherLine.addMarkers(otherMarkers); otherLine.addMarkers(otherMarkers);
} }
return otherLine; return otherLine;
} }
public append(changedMarkers: IChangedMarkers, other:ModelLine): void { public append(changedMarkers: IChangedMarkers, other:ModelLine, tabSize:number): void {
// console.log('--> append: THIS :: ' + this._printMarkers()); // console.log('--> append: THIS :: ' + this._printMarkers());
// console.log('--> append: OTHER :: ' + this._printMarkers()); // console.log('--> append: OTHER :: ' + this._printMarkers());
var thisTextLength = this._text.length; var thisTextLength = this._text.length;
this._setText(this._text + other._text); this._setText(this._text + other._text, tabSize);
let otherLineTokens = other._lineTokens; let otherLineTokens = other._lineTokens;
if (otherLineTokens) { if (otherLineTokens) {
......
...@@ -93,10 +93,15 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo ...@@ -93,10 +93,15 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
} }
} }
if (typeof newOpts.tabSize !== 'undefined') { if (typeof newOpts.tabSize !== 'undefined') {
if (this._options.tabSize !== newOpts.tabSize) { let newTabSize = newOpts.tabSize | 0;
if (this._options.tabSize !== newTabSize) {
somethingChanged = true; somethingChanged = true;
changed.tabSize = true; changed.tabSize = true;
this._options.tabSize = newOpts.tabSize; this._options.tabSize = newTabSize;
for (let i = 0, len = this._lines.length; i < len; i++) {
this._lines[i].updateTabSize(newTabSize);
}
} }
} }
if (typeof newOpts.trimAutoWhitespace !== 'undefined') { if (typeof newOpts.trimAutoWhitespace !== 'undefined') {
...@@ -461,6 +466,14 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo ...@@ -461,6 +466,14 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
return this._lines[lineNumber - 1].text; return this._lines[lineNumber - 1].text;
} }
public getIndentLevel(lineNumber:number): number {
if (lineNumber < 1 || lineNumber > this.getLineCount()) {
throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
}
return this._lines[lineNumber - 1].getIndentLevel();
}
public getLinesContent(): string[] { public getLinesContent(): string[] {
var r: string[] = []; var r: string[] = [];
for (var i = 0, len = this._lines.length; i < len; i++) { for (var i = 0, len = this._lines.length; i < len; i++) {
...@@ -648,13 +661,12 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo ...@@ -648,13 +661,12 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo
} }
_constructLines(rawText:editorCommon.IRawText): void { _constructLines(rawText:editorCommon.IRawText): void {
var rawLines = rawText.lines, const tabSize = rawText.options.tabSize;
modelLines: ModelLine[] = [], let rawLines = rawText.lines;
i: number, let modelLines: ModelLine[] = [];
len: number;
for (i = 0, len = rawLines.length; i < len; i++) { for (let i = 0, len = rawLines.length; i < len; i++) {
modelLines.push(new ModelLine(i + 1, rawLines[i])); modelLines[i] = new ModelLine(i + 1, rawLines[i], tabSize);
} }
this._BOM = rawText.BOM; this._BOM = rawText.BOM;
this._EOL = rawText.EOL; this._EOL = rawText.EOL;
......
...@@ -16,7 +16,7 @@ export function computeRanges(model: IModel, tabSize: number, minimumRangeSize: ...@@ -16,7 +16,7 @@ export function computeRanges(model: IModel, tabSize: number, minimumRangeSize:
previousRegions.push({ indent: -1, line: model.getLineCount() + 1 }); // sentinel, to make sure there's at least one entry previousRegions.push({ indent: -1, line: model.getLineCount() + 1 }); // sentinel, to make sure there's at least one entry
for (let line = model.getLineCount(); line > 0; line--) { for (let line = model.getLineCount(); line > 0; line--) {
let indent = computeIndentLevel(model.getLineContent(line), tabSize); let indent = model.getIndentLevel(line);
if (indent === -1) { if (indent === -1) {
continue; // only whitespace continue; // only whitespace
} }
...@@ -46,27 +46,6 @@ export function computeRanges(model: IModel, tabSize: number, minimumRangeSize: ...@@ -46,27 +46,6 @@ export function computeRanges(model: IModel, tabSize: number, minimumRangeSize:
return result.reverse(); return result.reverse();
} }
export function computeIndentLevel(line: string, tabSize: number): number {
let i = 0;
let indent = 0;
while (i < line.length) {
let ch = line.charAt(i);
if (ch === ' ') {
indent++;
} else if (ch === '\t') {
indent = indent - indent % tabSize + tabSize;
} else {
break;
}
i++;
}
if (i === line.length) {
return -1; // line only consists of whitespace
}
return indent;
}
/** /**
* Limits the number of folding ranges by removing ranges with larger indent levels * Limits the number of folding ranges by removing ranges with larger indent levels
*/ */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import * as assert from 'assert'; import * as assert from 'assert';
import {Model} from 'vs/editor/common/model/model'; import {Model} from 'vs/editor/common/model/model';
import {IFoldingRange} from 'vs/editor/contrib/folding/common/foldingRange'; import {IFoldingRange} from 'vs/editor/contrib/folding/common/foldingRange';
import {computeRanges, limitByIndent, computeIndentLevel} from 'vs/editor/contrib/folding/common/indentFoldStrategy'; import {computeRanges, limitByIndent} from 'vs/editor/contrib/folding/common/indentFoldStrategy';
suite('Indentation Folding', () => { suite('Indentation Folding', () => {
function assertRanges(lines: string[], tabSize: number, expected:IFoldingRange[]): void { function assertRanges(lines: string[], tabSize: number, expected:IFoldingRange[]): void {
...@@ -127,18 +127,4 @@ suite('Indentation Folding', () => { ...@@ -127,18 +127,4 @@ suite('Indentation Folding', () => {
assert.deepEqual(limitByIndent(ranges, 0), []); assert.deepEqual(limitByIndent(ranges, 0), []);
}); });
test('Compute indent level', () => {
assert.equal(computeIndentLevel('Hello', 4), 0);
assert.equal(computeIndentLevel(' Hello', 4), 1);
assert.equal(computeIndentLevel(' Hello', 4), 3);
assert.equal(computeIndentLevel('\tHello', 4), 4);
assert.equal(computeIndentLevel(' \tHello', 4), 4);
assert.equal(computeIndentLevel(' \tHello', 4), 4);
assert.equal(computeIndentLevel(' \tHello', 4), 4);
assert.equal(computeIndentLevel(' \tHello', 4), 8);
assert.equal(computeIndentLevel(' \tHello', 4), 8);
assert.equal(computeIndentLevel('\t Hello', 4), 5);
assert.equal(computeIndentLevel('\t \tHello', 4), 8);
});
}); });
...@@ -15,6 +15,8 @@ import {Model} from 'vs/editor/common/model/model'; ...@@ -15,6 +15,8 @@ import {Model} from 'vs/editor/common/model/model';
import {ILineEdit, ModelLine} from 'vs/editor/common/model/modelLine'; import {ILineEdit, ModelLine} from 'vs/editor/common/model/modelLine';
import {MockConfiguration} from 'vs/editor/test/common/mocks/mockConfiguration'; import {MockConfiguration} from 'vs/editor/test/common/mocks/mockConfiguration';
const NO_TAB_SIZE = 0;
function testCommand(lines:string[], selection:Selection, edits:IIdentifiedSingleEditOperation[], expectedLines:string[], expectedSelection:Selection): void { function testCommand(lines:string[], selection:Selection, edits:IIdentifiedSingleEditOperation[], expectedLines:string[], expectedSelection:Selection): void {
let model = Model.createFromString(lines.join('\n')); let model = Model.createFromString(lines.join('\n'));
let config = new MockConfiguration(null); let config = new MockConfiguration(null);
...@@ -36,7 +38,7 @@ function testCommand(lines:string[], selection:Selection, edits:IIdentifiedSingl ...@@ -36,7 +38,7 @@ function testCommand(lines:string[], selection:Selection, edits:IIdentifiedSingl
} }
function testLineEditMarker(text:string, column:number, stickToPreviousCharacter:boolean, edit:ILineEdit, expectedColumn: number): void { function testLineEditMarker(text:string, column:number, stickToPreviousCharacter:boolean, edit:ILineEdit, expectedColumn: number): void {
var line = new ModelLine(1, text); var line = new ModelLine(1, text, NO_TAB_SIZE);
line.addMarker({ line.addMarker({
id: '1', id: '1',
line: null, line: null,
...@@ -46,7 +48,7 @@ function testLineEditMarker(text:string, column:number, stickToPreviousCharacter ...@@ -46,7 +48,7 @@ function testLineEditMarker(text:string, column:number, stickToPreviousCharacter
oldColumn: 0, oldColumn: 0,
}); });
line.applyEdits({}, [edit]); line.applyEdits({}, [edit], NO_TAB_SIZE);
assert.equal(line.getMarkers()[0].column, expectedColumn); assert.equal(line.getMarkers()[0].column, expectedColumn);
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
import * as assert from 'assert'; import * as assert from 'assert';
import {ILineTokens} from 'vs/editor/common/editorCommon'; import {ILineTokens} from 'vs/editor/common/editorCommon';
import * as modelLine from 'vs/editor/common/model/modelLine'; import {ModelLine, ILineEdit, ILineMarker} from 'vs/editor/common/model/modelLine';
import {LineMarker} from 'vs/editor/common/model/textModelWithMarkers'; import {LineMarker} from 'vs/editor/common/model/textModelWithMarkers';
import {TokensInflatorMap} from 'vs/editor/common/model/tokensBinaryEncoding'; import {TokensInflatorMap} from 'vs/editor/common/model/tokensBinaryEncoding';
import {IToken} from 'vs/editor/common/modes'; import {IToken} from 'vs/editor/common/modes';
...@@ -17,15 +17,42 @@ function assertLineTokens(actual:ILineTokens, expected:IToken[]): void { ...@@ -17,15 +17,42 @@ function assertLineTokens(actual:ILineTokens, expected:IToken[]): void {
assert.deepEqual(inflatedActual, expected, 'Line tokens are equal'); assert.deepEqual(inflatedActual, expected, 'Line tokens are equal');
} }
const NO_TAB_SIZE = 0;
suite('ModelLine - getIndentLevel', () => {
function assertIndentLevel(text:string, expected:number, tabSize:number = 4): void {
let modelLine = new ModelLine(1, text, tabSize);
let actual = modelLine.getIndentLevel();
assert.equal(actual, expected, text);
}
test('getIndentLevel', () => {
assertIndentLevel('', -1);
assertIndentLevel(' ', -1);
assertIndentLevel(' \t', -1);
assertIndentLevel('Hello', 0);
assertIndentLevel(' Hello', 1);
assertIndentLevel(' Hello', 3);
assertIndentLevel('\tHello', 4);
assertIndentLevel(' \tHello', 4);
assertIndentLevel(' \tHello', 4);
assertIndentLevel(' \tHello', 4);
assertIndentLevel(' \tHello', 8);
assertIndentLevel(' \tHello', 8);
assertIndentLevel('\t Hello', 5);
assertIndentLevel('\t \tHello', 8);
});
});
suite('Editor Model - modelLine.applyEdits text', () => { suite('Editor Model - modelLine.applyEdits text', () => {
function testEdits(initial:string, edits:modelLine.ILineEdit[], expected:string): void { function testEdits(initial:string, edits:ILineEdit[], expected:string): void {
var line = new modelLine.ModelLine(1, initial); var line = new ModelLine(1, initial, NO_TAB_SIZE);
line.applyEdits({}, edits); line.applyEdits({}, edits, NO_TAB_SIZE);
assert.equal(line.text, expected); assert.equal(line.text, expected);
} }
function editOp(startColumn: number, endColumn: number, text:string): modelLine.ILineEdit { function editOp(startColumn: number, endColumn: number, text:string): ILineEdit {
return { return {
startColumn: startColumn, startColumn: startColumn,
endColumn: endColumn, endColumn: endColumn,
...@@ -167,8 +194,8 @@ suite('Editor Model - modelLine.applyEdits text', () => { ...@@ -167,8 +194,8 @@ suite('Editor Model - modelLine.applyEdits text', () => {
suite('Editor Model - modelLine.split text', () => { suite('Editor Model - modelLine.split text', () => {
function testLineSplit(initial:string, splitColumn:number, expected1:string, expected2:string): void { function testLineSplit(initial:string, splitColumn:number, expected1:string, expected2:string): void {
var line = new modelLine.ModelLine(1, initial); var line = new ModelLine(1, initial, NO_TAB_SIZE);
var newLine = line.split({}, splitColumn, false); var newLine = line.split({}, splitColumn, false, NO_TAB_SIZE);
assert.equal(line.text, expected1); assert.equal(line.text, expected1);
assert.equal(newLine.text, expected2); assert.equal(newLine.text, expected2);
} }
...@@ -204,9 +231,9 @@ suite('Editor Model - modelLine.split text', () => { ...@@ -204,9 +231,9 @@ suite('Editor Model - modelLine.split text', () => {
suite('Editor Model - modelLine.append text', () => { suite('Editor Model - modelLine.append text', () => {
function testLineAppend(a:string, b:string, expected:string): void { function testLineAppend(a:string, b:string, expected:string): void {
var line1 = new modelLine.ModelLine(1, a); var line1 = new ModelLine(1, a, NO_TAB_SIZE);
var line2 = new modelLine.ModelLine(2, b); var line2 = new ModelLine(2, b, NO_TAB_SIZE);
line1.append({}, line2); line1.append({}, line2, NO_TAB_SIZE);
assert.equal(line1.text, expected); assert.equal(line1.text, expected);
} }
...@@ -236,25 +263,25 @@ suite('Editor Model - modelLine.append text', () => { ...@@ -236,25 +263,25 @@ suite('Editor Model - modelLine.append text', () => {
}); });
suite('Editor Model - modelLine.applyEdits text & tokens', () => { suite('Editor Model - modelLine.applyEdits text & tokens', () => {
function testLineEditTokens(initialText:string, initialTokens: LineToken[], edits:modelLine.ILineEdit[], expectedText:string, expectedTokens: LineToken[]): void { function testLineEditTokens(initialText:string, initialTokens: LineToken[], edits:ILineEdit[], expectedText:string, expectedTokens: LineToken[]): void {
var line = new modelLine.ModelLine(1, initialText); var line = new ModelLine(1, initialText, NO_TAB_SIZE);
line.setTokens(new TokensInflatorMap(), initialTokens, null, []); line.setTokens(new TokensInflatorMap(), initialTokens, null, []);
line.applyEdits({}, edits); line.applyEdits({}, edits, NO_TAB_SIZE);
assert.equal(line.text, expectedText); assert.equal(line.text, expectedText);
assertLineTokens(line.getTokens(), expectedTokens); assertLineTokens(line.getTokens(), expectedTokens);
} }
test('insertion on empty line', () => { test('insertion on empty line', () => {
var line = new modelLine.ModelLine(1, 'some text'); var line = new ModelLine(1, 'some text', NO_TAB_SIZE);
var map = new TokensInflatorMap(); var map = new TokensInflatorMap();
line.setTokens(map, [new LineToken(0, 'bar')], null, []); line.setTokens(map, [new LineToken(0, 'bar')], null, []);
line.applyEdits({}, [{startColumn:1, endColumn:10, text:'', forceMoveMarkers: false}]); line.applyEdits({}, [{startColumn:1, endColumn:10, text:'', forceMoveMarkers: false}], NO_TAB_SIZE);
line.setTokens(map, [], null, []); line.setTokens(map, [], null, []);
line.applyEdits({}, [{startColumn:1, endColumn:1, text:'a', forceMoveMarkers: false}]); line.applyEdits({}, [{startColumn:1, endColumn:1, text:'a', forceMoveMarkers: false}], NO_TAB_SIZE);
assertLineTokens(line.getTokens(), [{ assertLineTokens(line.getTokens(), [{
startIndex: 0, startIndex: 0,
type:'' type:''
...@@ -811,10 +838,10 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => { ...@@ -811,10 +838,10 @@ suite('Editor Model - modelLine.applyEdits text & tokens', () => {
suite('Editor Model - modelLine.split text & tokens', () => { suite('Editor Model - modelLine.split text & tokens', () => {
function testLineSplitTokens(initialText:string, initialTokens: LineToken[], splitColumn:number, expectedText1:string, expectedText2:string, expectedTokens: LineToken[]): void { function testLineSplitTokens(initialText:string, initialTokens: LineToken[], splitColumn:number, expectedText1:string, expectedText2:string, expectedTokens: LineToken[]): void {
var line = new modelLine.ModelLine(1, initialText); var line = new ModelLine(1, initialText, NO_TAB_SIZE);
line.setTokens(new TokensInflatorMap(), initialTokens, null, []); line.setTokens(new TokensInflatorMap(), initialTokens, null, []);
var other = line.split({}, splitColumn, false); var other = line.split({}, splitColumn, false, NO_TAB_SIZE);
assert.equal(line.text, expectedText1); assert.equal(line.text, expectedText1);
assert.equal(other.text, expectedText2); assert.equal(other.text, expectedText2);
...@@ -895,13 +922,13 @@ suite('Editor Model - modelLine.append text & tokens', () => { ...@@ -895,13 +922,13 @@ suite('Editor Model - modelLine.append text & tokens', () => {
function testLineAppendTokens(aText:string, aTokens: LineToken[], bText:string, bTokens:LineToken[], expectedText:string, expectedTokens:IToken[]): void { function testLineAppendTokens(aText:string, aTokens: LineToken[], bText:string, bTokens:LineToken[], expectedText:string, expectedTokens:IToken[]): void {
var inflator = new TokensInflatorMap(); var inflator = new TokensInflatorMap();
var a = new modelLine.ModelLine(1, aText); var a = new ModelLine(1, aText, NO_TAB_SIZE);
a.setTokens(inflator, aTokens, null, []); a.setTokens(inflator, aTokens, null, []);
var b = new modelLine.ModelLine(2, bText); var b = new ModelLine(2, bText, NO_TAB_SIZE);
b.setTokens(inflator, bTokens, null, []); b.setTokens(inflator, bTokens, null, []);
a.append({}, b); a.append({}, b, NO_TAB_SIZE);
assert.equal(a.text, expectedText); assert.equal(a.text, expectedText);
assertLineTokens(a.getTokens(), expectedTokens); assertLineTokens(a.getTokens(), expectedTokens);
...@@ -1024,7 +1051,7 @@ suite('Editor Model - modelLine.applyEdits text & markers', () => { ...@@ -1024,7 +1051,7 @@ suite('Editor Model - modelLine.applyEdits text & markers', () => {
return new LineMarker(String(id), column, stickToPreviousCharacter); return new LineMarker(String(id), column, stickToPreviousCharacter);
} }
function toLightWeightMarker(marker:modelLine.ILineMarker): ILightWeightMarker { function toLightWeightMarker(marker:ILineMarker): ILightWeightMarker {
return { return {
id: marker.id, id: marker.id,
column: marker.column, column: marker.column,
...@@ -1032,12 +1059,12 @@ suite('Editor Model - modelLine.applyEdits text & markers', () => { ...@@ -1032,12 +1059,12 @@ suite('Editor Model - modelLine.applyEdits text & markers', () => {
}; };
} }
function testLineEditMarkers(initialText:string, initialMarkers: LineMarker[], edits:modelLine.ILineEdit[], expectedText:string, expectedChangedMarkers:number[], _expectedMarkers: LineMarker[]): void { function testLineEditMarkers(initialText:string, initialMarkers: LineMarker[], edits:ILineEdit[], expectedText:string, expectedChangedMarkers:number[], _expectedMarkers: LineMarker[]): void {
var line = new modelLine.ModelLine(1, initialText); var line = new ModelLine(1, initialText, NO_TAB_SIZE);
line.addMarkers(initialMarkers); line.addMarkers(initialMarkers);
var changedMarkers = Object.create(null); var changedMarkers = Object.create(null);
line.applyEdits(changedMarkers, edits); line.applyEdits(changedMarkers, edits, NO_TAB_SIZE);
assert.equal(line.text, expectedText, 'text'); assert.equal(line.text, expectedText, 'text');
...@@ -1840,7 +1867,7 @@ suite('Editor Model - modelLine.split text & markers', () => { ...@@ -1840,7 +1867,7 @@ suite('Editor Model - modelLine.split text & markers', () => {
return new LineMarker(String(id), column, stickToPreviousCharacter); return new LineMarker(String(id), column, stickToPreviousCharacter);
} }
function toLightWeightMarker(marker:modelLine.ILineMarker): ILightWeightMarker { function toLightWeightMarker(marker:ILineMarker): ILightWeightMarker {
return { return {
id: marker.id, id: marker.id,
column: marker.column, column: marker.column,
...@@ -1849,11 +1876,11 @@ suite('Editor Model - modelLine.split text & markers', () => { ...@@ -1849,11 +1876,11 @@ suite('Editor Model - modelLine.split text & markers', () => {
} }
function testLineSplitMarkers(initialText:string, initialMarkers: LineMarker[], splitColumn:number, forceMoveMarkers:boolean, expectedText1:string, expectedText2:string, expectedChangedMarkers:number[], _expectedMarkers1: LineMarker[], _expectedMarkers2: LineMarker[]): void { function testLineSplitMarkers(initialText:string, initialMarkers: LineMarker[], splitColumn:number, forceMoveMarkers:boolean, expectedText1:string, expectedText2:string, expectedChangedMarkers:number[], _expectedMarkers1: LineMarker[], _expectedMarkers2: LineMarker[]): void {
var line = new modelLine.ModelLine(1, initialText); var line = new ModelLine(1, initialText, NO_TAB_SIZE);
line.addMarkers(initialMarkers); line.addMarkers(initialMarkers);
var changedMarkers = Object.create(null); var changedMarkers = Object.create(null);
var otherLine = line.split(changedMarkers, splitColumn, forceMoveMarkers); var otherLine = line.split(changedMarkers, splitColumn, forceMoveMarkers, NO_TAB_SIZE);
assert.equal(line.text, expectedText1, 'text'); assert.equal(line.text, expectedText1, 'text');
assert.equal(otherLine.text, expectedText2, 'text'); assert.equal(otherLine.text, expectedText2, 'text');
...@@ -2108,7 +2135,7 @@ suite('Editor Model - modelLine.append text & markers', () => { ...@@ -2108,7 +2135,7 @@ suite('Editor Model - modelLine.append text & markers', () => {
return new LineMarker(String(id), column, stickToPreviousCharacter); return new LineMarker(String(id), column, stickToPreviousCharacter);
} }
function toLightWeightMarker(marker:modelLine.ILineMarker): ILightWeightMarker { function toLightWeightMarker(marker:ILineMarker): ILightWeightMarker {
return { return {
id: marker.id, id: marker.id,
column: marker.column, column: marker.column,
...@@ -2117,14 +2144,14 @@ suite('Editor Model - modelLine.append text & markers', () => { ...@@ -2117,14 +2144,14 @@ suite('Editor Model - modelLine.append text & markers', () => {
} }
function testLinePrependMarkers(aText:string, aMarkers: LineMarker[], bText:string, bMarkers: LineMarker[], expectedText:string, expectedChangedMarkers:number[], _expectedMarkers: LineMarker[]): void { function testLinePrependMarkers(aText:string, aMarkers: LineMarker[], bText:string, bMarkers: LineMarker[], expectedText:string, expectedChangedMarkers:number[], _expectedMarkers: LineMarker[]): void {
var a = new modelLine.ModelLine(1, aText); var a = new ModelLine(1, aText, NO_TAB_SIZE);
a.addMarkers(aMarkers); a.addMarkers(aMarkers);
var b = new modelLine.ModelLine(1, bText); var b = new ModelLine(1, bText, NO_TAB_SIZE);
b.addMarkers(bMarkers); b.addMarkers(bMarkers);
var changedMarkers = Object.create(null); var changedMarkers = Object.create(null);
a.append(changedMarkers, b); a.append(changedMarkers, b, NO_TAB_SIZE);
assert.equal(a.text, expectedText, 'text'); assert.equal(a.text, expectedText, 'text');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册