mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-23 18:19:12 +01:00
Fixes #3662: validate positions when converting them
This commit is contained in:
@@ -622,8 +622,20 @@ export class SplitLinesCollection implements ILinesCollection {
|
|||||||
return this.prefixSumComputer.getTotalValue();
|
return this.prefixSumComputer.getTotalValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _toValidOutputLineNumber(outputLineNumber: number): number {
|
||||||
|
if (outputLineNumber < 1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
let outputLineCount = this.getOutputLineCount();
|
||||||
|
if (outputLineNumber > outputLineCount) {
|
||||||
|
return outputLineCount;
|
||||||
|
}
|
||||||
|
return outputLineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
public getOutputLineContent(outputLineNumber: number): string {
|
public getOutputLineContent(outputLineNumber: number): string {
|
||||||
this._ensureValidState();
|
this._ensureValidState();
|
||||||
|
outputLineNumber = this._toValidOutputLineNumber(outputLineNumber);
|
||||||
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
||||||
var lineIndex = this.tmpIndexOfResult.index;
|
var lineIndex = this.tmpIndexOfResult.index;
|
||||||
var remainder = this.tmpIndexOfResult.remainder;
|
var remainder = this.tmpIndexOfResult.remainder;
|
||||||
@@ -633,6 +645,7 @@ export class SplitLinesCollection implements ILinesCollection {
|
|||||||
|
|
||||||
public getOutputLineMinColumn(outputLineNumber:number): number {
|
public getOutputLineMinColumn(outputLineNumber:number): number {
|
||||||
this._ensureValidState();
|
this._ensureValidState();
|
||||||
|
outputLineNumber = this._toValidOutputLineNumber(outputLineNumber);
|
||||||
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
||||||
var lineIndex = this.tmpIndexOfResult.index;
|
var lineIndex = this.tmpIndexOfResult.index;
|
||||||
var remainder = this.tmpIndexOfResult.remainder;
|
var remainder = this.tmpIndexOfResult.remainder;
|
||||||
@@ -642,6 +655,7 @@ export class SplitLinesCollection implements ILinesCollection {
|
|||||||
|
|
||||||
public getOutputLineMaxColumn(outputLineNumber: number): number {
|
public getOutputLineMaxColumn(outputLineNumber: number): number {
|
||||||
this._ensureValidState();
|
this._ensureValidState();
|
||||||
|
outputLineNumber = this._toValidOutputLineNumber(outputLineNumber);
|
||||||
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
||||||
var lineIndex = this.tmpIndexOfResult.index;
|
var lineIndex = this.tmpIndexOfResult.index;
|
||||||
var remainder = this.tmpIndexOfResult.remainder;
|
var remainder = this.tmpIndexOfResult.remainder;
|
||||||
@@ -651,6 +665,7 @@ export class SplitLinesCollection implements ILinesCollection {
|
|||||||
|
|
||||||
public getOutputLineTokens(outputLineNumber: number, inaccurateTokensAcceptable: boolean): editorCommon.IViewLineTokens {
|
public getOutputLineTokens(outputLineNumber: number, inaccurateTokensAcceptable: boolean): editorCommon.IViewLineTokens {
|
||||||
this._ensureValidState();
|
this._ensureValidState();
|
||||||
|
outputLineNumber = this._toValidOutputLineNumber(outputLineNumber);
|
||||||
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
this.prefixSumComputer.getIndexOf(outputLineNumber - 1, this.tmpIndexOfResult);
|
||||||
var lineIndex = this.tmpIndexOfResult.index;
|
var lineIndex = this.tmpIndexOfResult.index;
|
||||||
var remainder = this.tmpIndexOfResult.remainder;
|
var remainder = this.tmpIndexOfResult.remainder;
|
||||||
@@ -660,20 +675,23 @@ export class SplitLinesCollection implements ILinesCollection {
|
|||||||
|
|
||||||
public convertOutputPositionToInputPosition(viewLineNumber: number, viewColumn: number): editorCommon.IEditorPosition {
|
public convertOutputPositionToInputPosition(viewLineNumber: number, viewColumn: number): editorCommon.IEditorPosition {
|
||||||
this._ensureValidState();
|
this._ensureValidState();
|
||||||
|
viewLineNumber = this._toValidOutputLineNumber(viewLineNumber);
|
||||||
|
|
||||||
this.prefixSumComputer.getIndexOf(viewLineNumber - 1, this.tmpIndexOfResult);
|
this.prefixSumComputer.getIndexOf(viewLineNumber - 1, this.tmpIndexOfResult);
|
||||||
var lineIndex = this.tmpIndexOfResult.index;
|
var lineIndex = this.tmpIndexOfResult.index;
|
||||||
var remainder = this.tmpIndexOfResult.remainder;
|
var remainder = this.tmpIndexOfResult.remainder;
|
||||||
|
|
||||||
var inputColumn = this.lines[lineIndex].getInputColumnOfOutputPosition(remainder, viewColumn);
|
var inputColumn = this.lines[lineIndex].getInputColumnOfOutputPosition(remainder, viewColumn);
|
||||||
// console.log('out -> in ' + viewLineNumber + ',' + viewColumn + ' ===> ' + (lineIndex+1) + ',' + inputColumn);
|
// console.log('out -> in ' + viewLineNumber + ',' + viewColumn + ' ===> ' + (lineIndex+1) + ',' + inputColumn);
|
||||||
return new Position(lineIndex+1, inputColumn);
|
return this.model.validatePosition(new Position(lineIndex+1, inputColumn));
|
||||||
}
|
}
|
||||||
|
|
||||||
public convertInputPositionToOutputPosition(inputLineNumber: number, inputColumn: number): editorCommon.IEditorPosition {
|
public convertInputPositionToOutputPosition(_inputLineNumber: number, _inputColumn: number): editorCommon.IEditorPosition {
|
||||||
this._ensureValidState();
|
this._ensureValidState();
|
||||||
if (inputLineNumber > this.lines.length) {
|
|
||||||
inputLineNumber = this.lines.length;
|
let validPosition = this.model.validatePosition(new Position(_inputLineNumber, _inputColumn));
|
||||||
}
|
let inputLineNumber = validPosition.lineNumber;
|
||||||
|
let inputColumn = validPosition.column;
|
||||||
|
|
||||||
let lineIndex = inputLineNumber - 1, lineIndexChanged = false;
|
let lineIndex = inputLineNumber - 1, lineIndexChanged = false;
|
||||||
while (lineIndex > 0 && !this.lines[lineIndex].isVisible()) {
|
while (lineIndex > 0 && !this.lines[lineIndex].isVisible()) {
|
||||||
@@ -682,6 +700,7 @@ export class SplitLinesCollection implements ILinesCollection {
|
|||||||
}
|
}
|
||||||
if (lineIndex === 0 && !this.lines[lineIndex].isVisible()) {
|
if (lineIndex === 0 && !this.lines[lineIndex].isVisible()) {
|
||||||
// Could not reach a real line
|
// Could not reach a real line
|
||||||
|
// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + 1 + ',' + 1);
|
||||||
return new Position(1, 1);
|
return new Position(1, 1);
|
||||||
}
|
}
|
||||||
var deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1));
|
var deltaLineNumber = 1 + (lineIndex === 0 ? 0 : this.prefixSumComputer.getAccumulatedValue(lineIndex - 1));
|
||||||
@@ -693,7 +712,7 @@ export class SplitLinesCollection implements ILinesCollection {
|
|||||||
r = this.lines[inputLineNumber - 1].getOutputPositionOfInputPosition(deltaLineNumber, inputColumn);
|
r = this.lines[inputLineNumber - 1].getOutputPositionOfInputPosition(deltaLineNumber, inputColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r.column);
|
// console.log('in -> out ' + inputLineNumber + ',' + inputColumn + ' ===> ' + r.lineNumber + ',' + r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,9 +6,12 @@
|
|||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import {Position} from 'vs/editor/common/core/position';
|
import {Position} from 'vs/editor/common/core/position';
|
||||||
import {CharacterHardWrappingLineMapping} from 'vs/editor/common/viewModel/characterHardWrappingLineMapper';
|
import {CharacterHardWrappingLineMapping, CharacterHardWrappingLineMapperFactory} from 'vs/editor/common/viewModel/characterHardWrappingLineMapper';
|
||||||
import {PrefixSumComputer} from 'vs/editor/common/viewModel/prefixSumComputer';
|
import {PrefixSumComputer} from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||||
import {ILineMapping, IModel, SplitLine} from 'vs/editor/common/viewModel/splitLinesCollection';
|
import {ILineMapping, IModel, SplitLine, SplitLinesCollection} from 'vs/editor/common/viewModel/splitLinesCollection';
|
||||||
|
import {MockConfiguration} from 'vs/editor/test/common/mocks/mockConfiguration';
|
||||||
|
import {Model} from 'vs/editor/common/model/model';
|
||||||
|
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||||
|
|
||||||
suite('Editor ViewModel - SplitLinesCollection', () => {
|
suite('Editor ViewModel - SplitLinesCollection', () => {
|
||||||
test('SplitLine', () => {
|
test('SplitLine', () => {
|
||||||
@@ -76,6 +79,93 @@ suite('Editor ViewModel - SplitLinesCollection', () => {
|
|||||||
assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(2, 1 + col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')');
|
assert.deepEqual(line1.getOutputPositionOfInputPosition(0, col), pos(2, 1 + col - 13 - 14), 'getOutputPositionOfInputPosition(' + col + ')');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('issue #3662', () => {
|
||||||
|
let config = new MockConfiguration({});
|
||||||
|
|
||||||
|
let hardWrappingLineMapperFactory = new CharacterHardWrappingLineMapperFactory(
|
||||||
|
config.editor.wordWrapBreakBeforeCharacters,
|
||||||
|
config.editor.wordWrapBreakAfterCharacters,
|
||||||
|
config.editor.wordWrapBreakObtrusiveCharacters
|
||||||
|
);
|
||||||
|
|
||||||
|
let model = new Model([
|
||||||
|
'int main() {',
|
||||||
|
'\tprintf("Hello world!");',
|
||||||
|
'}',
|
||||||
|
'int main() {',
|
||||||
|
'\tprintf("Hello world!");',
|
||||||
|
'}',
|
||||||
|
].join('\n'), editorCommon.DefaultEndOfLine.LF, null);
|
||||||
|
|
||||||
|
let linesCollection = new SplitLinesCollection(
|
||||||
|
model,
|
||||||
|
hardWrappingLineMapperFactory,
|
||||||
|
config.getIndentationOptions().tabSize,
|
||||||
|
config.editor.wrappingInfo.wrappingColumn,
|
||||||
|
config.editor.typicalFullwidthCharacterWidth / config.editor.typicalHalfwidthCharacterWidth,
|
||||||
|
editorCommon.wrappingIndentFromString(config.editor.wrappingIndent)
|
||||||
|
);
|
||||||
|
|
||||||
|
linesCollection.setHiddenAreas([{
|
||||||
|
startLineNumber: 1,
|
||||||
|
startColumn: 1,
|
||||||
|
endLineNumber: 3,
|
||||||
|
endColumn: 1
|
||||||
|
}, {
|
||||||
|
startLineNumber: 5,
|
||||||
|
startColumn: 1,
|
||||||
|
endLineNumber: 6,
|
||||||
|
endColumn: 1
|
||||||
|
}], (eventType, payload) => {/*no-op*/});
|
||||||
|
|
||||||
|
let viewLineCount = linesCollection.getOutputLineCount();
|
||||||
|
assert.equal(viewLineCount, 1, 'getOutputLineCount()');
|
||||||
|
|
||||||
|
let modelLineCount = model.getLineCount();
|
||||||
|
for (let lineNumber = 0; lineNumber <= modelLineCount + 1; lineNumber++) {
|
||||||
|
let lineMinColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMinColumn(lineNumber) : 1;
|
||||||
|
let lineMaxColumn = (lineNumber >= 1 && lineNumber <= modelLineCount) ? model.getLineMaxColumn(lineNumber) : 1;
|
||||||
|
for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) {
|
||||||
|
let viewPosition = linesCollection.convertInputPositionToOutputPosition(lineNumber, column);
|
||||||
|
|
||||||
|
// validate view position
|
||||||
|
let viewLineNumber = viewPosition.lineNumber;
|
||||||
|
let viewColumn = viewPosition.column;
|
||||||
|
if (viewLineNumber < 1) {
|
||||||
|
viewLineNumber = 1;
|
||||||
|
}
|
||||||
|
var lineCount = linesCollection.getOutputLineCount();
|
||||||
|
if (viewLineNumber > lineCount) {
|
||||||
|
viewLineNumber = lineCount;
|
||||||
|
}
|
||||||
|
var viewMinColumn = linesCollection.getOutputLineMinColumn(viewLineNumber);
|
||||||
|
var viewMaxColumn = linesCollection.getOutputLineMaxColumn(viewLineNumber);
|
||||||
|
if (viewColumn < viewMinColumn) {
|
||||||
|
viewColumn = viewMinColumn;
|
||||||
|
}
|
||||||
|
if (viewColumn > viewMaxColumn) {
|
||||||
|
viewColumn = viewMaxColumn;
|
||||||
|
}
|
||||||
|
let validViewPosition = new Position(viewLineNumber, viewColumn);
|
||||||
|
assert.equal(viewPosition.toString(), validViewPosition.toString(), 'model->view for ' + lineNumber + ', ' + column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let lineNumber = 0; lineNumber <= viewLineCount + 1; lineNumber++) {
|
||||||
|
let lineMinColumn = linesCollection.getOutputLineMinColumn(lineNumber);
|
||||||
|
let lineMaxColumn = linesCollection.getOutputLineMaxColumn(lineNumber);
|
||||||
|
for (let column = lineMinColumn - 1; column <= lineMaxColumn + 1; column++) {
|
||||||
|
let modelPosition = linesCollection.convertOutputPositionToInputPosition(lineNumber, column);
|
||||||
|
let validModelPosition = model.validatePosition(modelPosition);
|
||||||
|
assert.equal(modelPosition.toString(), validModelPosition.toString(), 'view->model for ' + lineNumber + ', ' + column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linesCollection.dispose();
|
||||||
|
model.dispose();
|
||||||
|
config.dispose();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user