Remove linesModel, use new APIs
This commit is contained in:
parent
2747ebef95
commit
8bccda9e42
|
@ -13,8 +13,6 @@ import nls = require('./utils/nls');
|
|||
|
||||
import {CompletionItem, CompletionItemKind, CompletionOptions, ITextDocument, TextDocumentIdentifier, TextDocumentPosition, Range, TextEdit} from 'vscode-languageserver';
|
||||
|
||||
import {LinesModel} from './utils/lines';
|
||||
|
||||
export interface ISuggestionsCollector {
|
||||
add(suggestion: CompletionItem): void;
|
||||
error(message: string): void;
|
||||
|
@ -28,16 +26,16 @@ export class JSONCompletion {
|
|||
this.schemaService = schemaService;
|
||||
}
|
||||
|
||||
public doSuggest(document: ITextDocument, textDocumentPosition: TextDocumentPosition, lines: LinesModel, doc: Parser.JSONDocument): Thenable<CompletionItem[]> {
|
||||
public doSuggest(document: ITextDocument, textDocumentPosition: TextDocumentPosition, doc: Parser.JSONDocument): Thenable<CompletionItem[]> {
|
||||
|
||||
var offset = lines.offsetAt(textDocumentPosition.position);
|
||||
var offset = document.offsetAt(textDocumentPosition.position);
|
||||
var node = doc.getNodeFromOffsetEndInclusive(offset);
|
||||
|
||||
var overwriteRange = null;
|
||||
var result: CompletionItem[] = [];
|
||||
|
||||
if (node && (node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
|
||||
overwriteRange = Range.create(lines.positionAt(node.start), lines.positionAt(node.end));
|
||||
overwriteRange = Range.create(document.positionAt(node.start), document.positionAt(node.end));
|
||||
}
|
||||
|
||||
var proposed: { [key: string]: boolean } = {};
|
||||
|
|
|
@ -10,14 +10,12 @@ import Strings = require('./utils/strings');
|
|||
|
||||
import {SymbolInformation, SymbolKind, ITextDocument, Range, Location} from 'vscode-languageserver';
|
||||
|
||||
import {LinesModel} from './utils/lines';
|
||||
|
||||
export class JSONDocumentSymbols {
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
public compute(document: ITextDocument, lines: LinesModel, doc: Parser.JSONDocument): Promise<SymbolInformation[]> {
|
||||
public compute(document: ITextDocument, doc: Parser.JSONDocument): Promise<SymbolInformation[]> {
|
||||
|
||||
let root = doc.root;
|
||||
if (!root) {
|
||||
|
@ -33,7 +31,7 @@ export class JSONDocumentSymbols {
|
|||
if (item.type === 'object') {
|
||||
let property = (<Parser.ObjectASTNode>item).getFirstProperty('key');
|
||||
if (property && property.value) {
|
||||
let location = Location.create(document.uri, Range.create(lines.positionAt(item.start), lines.positionAt(item.end)));
|
||||
let location = Location.create(document.uri, Range.create(document.positionAt(item.start), document.positionAt(item.end)));
|
||||
result.push({ name: property.value.getValue(), kind: SymbolKind.Function, location: location });
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +49,7 @@ export class JSONDocumentSymbols {
|
|||
let objectNode = <Parser.ObjectASTNode>node;
|
||||
|
||||
objectNode.properties.forEach((property: Parser.PropertyASTNode) => {
|
||||
let location = Location.create(document.uri, Range.create(lines.positionAt(property.start), lines.positionAt(property.end)));
|
||||
let location = Location.create(document.uri, Range.create(document.positionAt(property.start), document.positionAt(property.end)));
|
||||
let valueNode = property.value;
|
||||
if (valueNode) {
|
||||
let childContainerName = containerName ? containerName + '.' + property.key.name : property.key.name;
|
||||
|
|
|
@ -6,32 +6,31 @@
|
|||
|
||||
import Json = require('./json-toolbox/json');
|
||||
import {ITextDocument, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver';
|
||||
import {LinesModel} from './utils/lines';
|
||||
|
||||
export function format(document: ITextDocument, lines: LinesModel, range: Range, options: FormattingOptions): TextEdit[] {
|
||||
export function format(document: ITextDocument, range: Range, options: FormattingOptions): TextEdit[] {
|
||||
const documentText = document.getText();
|
||||
let initialIndentLevel: number;
|
||||
let value: string;
|
||||
let rangeOffset: number;
|
||||
if (range) {
|
||||
let startPosition = Position.create(range.start.line, 0);
|
||||
rangeOffset = lines.offsetAt(startPosition);
|
||||
rangeOffset = document.offsetAt(startPosition);
|
||||
|
||||
let endOffset = lines.offsetAt(Position.create(range.end.line + 1, 0));
|
||||
let endLineStart = lines.offsetAt(Position.create(range.end.line, 0));
|
||||
let endOffset = document.offsetAt(Position.create(range.end.line + 1, 0));
|
||||
let endLineStart = document.offsetAt(Position.create(range.end.line, 0));
|
||||
while (endOffset > endLineStart && isEOL(documentText, endOffset - 1)) {
|
||||
endOffset--;
|
||||
}
|
||||
range = Range.create(startPosition, lines.positionAt(endOffset));
|
||||
range = Range.create(startPosition, document.positionAt(endOffset));
|
||||
value = documentText.substring(rangeOffset, endOffset);
|
||||
initialIndentLevel = computeIndentLevel(value, 0, options);
|
||||
} else {
|
||||
value = documentText;
|
||||
range = Range.create(Position.create(0, 0), lines.positionAt(value.length));
|
||||
range = Range.create(Position.create(0, 0), document.positionAt(value.length));
|
||||
initialIndentLevel = 0;
|
||||
rangeOffset = 0;
|
||||
}
|
||||
let eol = getEOL(document, lines);
|
||||
let eol = getEOL(document);
|
||||
|
||||
let lineBreak = false;
|
||||
let indentLevel = 0;
|
||||
|
@ -59,7 +58,7 @@ export function format(document: ITextDocument, lines: LinesModel, range: Range,
|
|||
let editOperations: TextEdit[] = [];
|
||||
function addEdit(text: string, startOffset: number, endOffset: number) {
|
||||
if (documentText.substring(startOffset, endOffset) !== text) {
|
||||
let replaceRange = Range.create(lines.positionAt(startOffset), lines.positionAt(endOffset));
|
||||
let replaceRange = Range.create(document.positionAt(startOffset), document.positionAt(endOffset));
|
||||
editOperations.push(TextEdit.replace(replaceRange, text));
|
||||
}
|
||||
}
|
||||
|
@ -162,10 +161,10 @@ function computeIndentLevel(content: string, offset: number, options: Formatting
|
|||
return Math.floor(nChars / tabSize);
|
||||
}
|
||||
|
||||
function getEOL(document: ITextDocument, lines: LinesModel): string {
|
||||
function getEOL(document: ITextDocument): string {
|
||||
let text = document.getText();
|
||||
if (lines.lineCount > 1) {
|
||||
let to = lines.offsetAt(Position.create(1, 0));
|
||||
if (document.lineCount > 1) {
|
||||
let to = document.offsetAt(Position.create(1, 0));
|
||||
let from = to;
|
||||
while (from > 0 && isEOL(text, from - 1)) {
|
||||
from--;
|
||||
|
|
|
@ -10,8 +10,6 @@ import SchemaService = require('./jsonSchemaService');
|
|||
|
||||
import {Hover, ITextDocument, TextDocumentPosition, Range, MarkedString, RemoteConsole} from 'vscode-languageserver';
|
||||
|
||||
import {LinesModel} from './utils/lines';
|
||||
|
||||
export class JSONHover {
|
||||
|
||||
private schemaService: SchemaService.IJSONSchemaService;
|
||||
|
@ -20,9 +18,9 @@ export class JSONHover {
|
|||
this.schemaService = schemaService;
|
||||
}
|
||||
|
||||
public doHover(document: ITextDocument, textDocumentPosition: TextDocumentPosition, lines: LinesModel, doc: Parser.JSONDocument): Thenable<Hover> {
|
||||
public doHover(document: ITextDocument, textDocumentPosition: TextDocumentPosition, doc: Parser.JSONDocument): Thenable<Hover> {
|
||||
|
||||
let offset = lines.offsetAt(textDocumentPosition.position);
|
||||
let offset = document.offsetAt(textDocumentPosition.position);
|
||||
let node = doc.getNodeFromOffset(offset);
|
||||
let originalNode = node;
|
||||
|
||||
|
@ -56,7 +54,7 @@ export class JSONHover {
|
|||
});
|
||||
|
||||
if (description) {
|
||||
let range = Range.create(lines.positionAt(node.start), lines.positionAt(node.end));
|
||||
let range = Range.create(document.positionAt(node.start), document.positionAt(node.end));
|
||||
let result: Hover = {
|
||||
contents: [description],
|
||||
range: range
|
||||
|
|
|
@ -18,7 +18,6 @@ import path = require('path');
|
|||
import fs = require('fs');
|
||||
import URI from './utils/uri';
|
||||
import Strings = require('./utils/strings');
|
||||
import {create as createLinesModel, LinesModel} from './utils/lines';
|
||||
import {IWorkspaceContextService, ITelemetryService, JSONSchemaService, ISchemaContributions, ISchemaAssociations} from './jsonSchemaService';
|
||||
import {parse as parseJSON, ObjectASTNode, JSONDocument} from './jsonParser';
|
||||
import {JSONCompletion} from './jsonCompletion';
|
||||
|
@ -201,7 +200,6 @@ function validateTextDocument(textDocument: ITextDocument): void {
|
|||
}
|
||||
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
let lineModel = getLinesModel(textDocument);
|
||||
let added: { [signature: string]: boolean } = {};
|
||||
jsonDocument.errors.concat(jsonDocument.warnings).forEach((error, idx) => {
|
||||
// remove duplicated messages
|
||||
|
@ -209,8 +207,8 @@ function validateTextDocument(textDocument: ITextDocument): void {
|
|||
if (!added[signature]) {
|
||||
added[signature] = true;
|
||||
let range = {
|
||||
start: lineModel.positionAt(error.location.start),
|
||||
end: lineModel.positionAt(error.location.end)
|
||||
start: textDocument.positionAt(error.location.start),
|
||||
end: textDocument.positionAt(error.location.end)
|
||||
};
|
||||
diagnostics.push({
|
||||
severity: idx >= jsonDocument.errors.length ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error,
|
||||
|
@ -237,46 +235,36 @@ connection.onDidChangeWatchedFiles((change) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
function getLinesModel(document: ITextDocument): LinesModel {
|
||||
return createLinesModel(document.getText());
|
||||
}
|
||||
|
||||
function getJSONDocument(document: ITextDocument): JSONDocument {
|
||||
return parseJSON(document.getText());
|
||||
}
|
||||
|
||||
connection.onCompletion((textDocumentPosition: TextDocumentPosition): Thenable<CompletionItem[]> => {
|
||||
let document = documents.get(textDocumentPosition.uri);
|
||||
let lines = getLinesModel(document);
|
||||
let jsonDocument = getJSONDocument(document);
|
||||
return jsonCompletion.doSuggest(document, textDocumentPosition, lines, jsonDocument);
|
||||
return jsonCompletion.doSuggest(document, textDocumentPosition, jsonDocument);
|
||||
});
|
||||
|
||||
connection.onHover((textDocumentPosition: TextDocumentPosition): Thenable<Hover> => {
|
||||
let document = documents.get(textDocumentPosition.uri);
|
||||
let lines = getLinesModel(document);
|
||||
let jsonDocument = getJSONDocument(document);
|
||||
return jsonHover.doHover(document, textDocumentPosition, lines, jsonDocument);
|
||||
return jsonHover.doHover(document, textDocumentPosition, jsonDocument);
|
||||
});
|
||||
|
||||
connection.onDocumentSymbol((textDocumentIdentifier: TextDocumentIdentifier): Thenable<SymbolInformation[]> => {
|
||||
let document = documents.get(textDocumentIdentifier.uri);
|
||||
let lines = getLinesModel(document);
|
||||
let jsonDocument = getJSONDocument(document);
|
||||
return jsonDocumentSymbols.compute(document, lines, jsonDocument);
|
||||
return jsonDocumentSymbols.compute(document, jsonDocument);
|
||||
});
|
||||
|
||||
connection.onDocumentFormatting((formatParams: DocumentFormattingParams) => {
|
||||
let document = documents.get(formatParams.textDocument.uri);
|
||||
let lines = getLinesModel(document);
|
||||
return formatJSON(document, lines, null, formatParams.options);
|
||||
return formatJSON(document, null, formatParams.options);
|
||||
});
|
||||
|
||||
connection.onDocumentRangeFormatting((formatParams: DocumentRangeFormattingParams) => {
|
||||
let document = documents.get(formatParams.textDocument.uri);
|
||||
let lines = getLinesModel(document);
|
||||
return formatJSON(document, lines, formatParams.range, formatParams.options);
|
||||
return formatJSON(document, formatParams.range, formatParams.options);
|
||||
});
|
||||
|
||||
// Listen on the connection
|
||||
|
|
|
@ -10,7 +10,6 @@ import SchemaService = require('../jsonSchemaService');
|
|||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import {JSONCompletion} from '../jsonCompletion';
|
||||
import {IXHROptions, IXHRResponse} from '../utils/httpRequest';
|
||||
import {create as createLinesModel} from '../utils/lines';
|
||||
|
||||
import {CompletionItem, CompletionItemKind, CompletionOptions, ITextDocument, TextDocumentIdentifier, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver';
|
||||
|
||||
|
@ -40,9 +39,8 @@ suite('JSON Completion', () => {
|
|||
|
||||
var document = ITextDocument.create(uri, value);
|
||||
var textDocumentLocation = TextDocumentPosition.create(uri, Position.create(0, idx));
|
||||
var lines = createLinesModel(value);
|
||||
var jsonDoc = Parser.parse(value);
|
||||
return completionProvider.doSuggest(document, textDocumentLocation, lines, jsonDoc);
|
||||
return completionProvider.doSuggest(document, textDocumentLocation, jsonDoc);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import SchemaService = require('../jsonSchemaService');
|
|||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import {JSONCompletion} from '../jsonCompletion';
|
||||
import {IXHROptions, IXHRResponse} from '../utils/httpRequest';
|
||||
import {create as createLinesModel} from '../utils/lines';
|
||||
import {JSONDocumentSymbols} from '../jsonDocumentSymbols';
|
||||
|
||||
import {SymbolInformation, SymbolKind, TextDocumentIdentifier, ITextDocument, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver';
|
||||
|
@ -23,9 +22,8 @@ suite('JSON Document Symbols', () => {
|
|||
var symbolProvider = new JSONDocumentSymbols();
|
||||
|
||||
var document = ITextDocument.create(uri, value);
|
||||
var lines = createLinesModel(value);
|
||||
var jsonDoc = Parser.parse(value);
|
||||
return symbolProvider.compute(document, lines, jsonDoc);
|
||||
return symbolProvider.compute(document, jsonDoc);
|
||||
}
|
||||
|
||||
var assertOutline: any = function(actual: SymbolInformation[], expected: any[], message: string) {
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
'use strict';
|
||||
|
||||
import Json = require('../json-toolbox/json');
|
||||
import {
|
||||
ITextDocument, DocumentFormattingParams, Range, Position, FormattingOptions, TextEdit
|
||||
} from 'vscode-languageserver';
|
||||
import {LinesModel, create as createLinesModel} from '../utils/lines';
|
||||
import {ITextDocument, DocumentFormattingParams, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver';
|
||||
import Formatter = require('../jsonFormatter');
|
||||
import assert = require('assert');
|
||||
|
||||
|
@ -18,29 +15,26 @@ suite('JSON Formatter', () => {
|
|||
let range: Range = null;
|
||||
let uri = 'test://test.json';
|
||||
|
||||
let lines = createLinesModel(unformatted);
|
||||
|
||||
let rangeStart = unformatted.indexOf('|');
|
||||
let rangeEnd = unformatted.lastIndexOf('|');
|
||||
if (rangeStart !== -1 && rangeEnd !== -1) {
|
||||
// remove '|'
|
||||
var unformattedDoc = ITextDocument.create(uri, unformatted);
|
||||
unformatted = unformatted.substring(0, rangeStart) + unformatted.substring(rangeStart + 1, rangeEnd) + unformatted.substring(rangeEnd + 1);
|
||||
let startPos = lines.positionAt(rangeStart);
|
||||
let endPos = lines.positionAt(rangeEnd);
|
||||
let startPos = unformattedDoc.positionAt(rangeStart);
|
||||
let endPos = unformattedDoc.positionAt(rangeEnd);
|
||||
range = Range.create(startPos, endPos);
|
||||
|
||||
lines = createLinesModel(unformatted);
|
||||
}
|
||||
|
||||
var document = ITextDocument.create(uri, unformatted);
|
||||
let edits = Formatter.format(document, lines, range, { tabSize: 2, insertSpaces: insertSpaces });
|
||||
let edits = Formatter.format(document, range, { tabSize: 2, insertSpaces: insertSpaces });
|
||||
|
||||
let formatted = unformatted;
|
||||
let sortedEdits = edits.sort((a, b) => lines.offsetAt(b.range.start) - lines.offsetAt(a.range.start));
|
||||
let sortedEdits = edits.sort((a, b) => document.offsetAt(b.range.start) - document.offsetAt(a.range.start));
|
||||
let lastOffset = formatted.length;
|
||||
sortedEdits.forEach(e => {
|
||||
let startOffset = lines.offsetAt(e.range.start);
|
||||
let endOffset = lines.offsetAt(e.range.end);
|
||||
let startOffset = document.offsetAt(e.range.start);
|
||||
let endOffset = document.offsetAt(e.range.end);
|
||||
assert.ok(startOffset <= endOffset);
|
||||
assert.ok(endOffset <= lastOffset);
|
||||
formatted = formatted.substring(0, startOffset) + e.newText + formatted.substring(endOffset, formatted.length);
|
||||
|
|
|
@ -10,7 +10,6 @@ import SchemaService = require('../jsonSchemaService');
|
|||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import {JSONCompletion} from '../jsonCompletion';
|
||||
import {IXHROptions, IXHRResponse} from '../utils/httpRequest';
|
||||
import {create as createLinesModel} from '../utils/lines';
|
||||
import {JSONHover} from '../jsonHover';
|
||||
|
||||
import {Hover, ITextDocument, TextDocumentIdentifier, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver';
|
||||
|
@ -27,9 +26,8 @@ suite('JSON Hover', () => {
|
|||
|
||||
var document = ITextDocument.create(uri, value);
|
||||
var textDocumentLocation = TextDocumentPosition.create(uri, position);
|
||||
var lines = createLinesModel(value);
|
||||
var jsonDoc = Parser.parse(value);
|
||||
return hoverProvider.doHover(document, textDocumentLocation, lines, jsonDoc);
|
||||
return hoverProvider.doHover(document, textDocumentLocation, jsonDoc);
|
||||
}
|
||||
|
||||
var requestService = function(options: IXHROptions): Promise<IXHRResponse> {
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import assert = require('assert');
|
||||
import lines = require('../utils/lines');
|
||||
import {Position} from 'vscode-languageserver';
|
||||
|
||||
suite('Lines Model Validator', () => {
|
||||
|
||||
test('single line', () => {
|
||||
var str = "Hello World";
|
||||
var lm = lines.create(str);
|
||||
assert.equal(lm.lineCount, 1);
|
||||
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
assert.equal(lm.offsetAt(Position.create(0, i)), i);
|
||||
assert.deepEqual(lm.positionAt(i), Position.create(0, i));
|
||||
}
|
||||
});
|
||||
|
||||
test('Mutiple lines', () => {
|
||||
var str = "ABCDE\nFGHIJ\nKLMNO\n";
|
||||
var lm = lines.create(str);
|
||||
assert.equal(lm.lineCount, 4);
|
||||
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var line = Math.floor(i / 6);
|
||||
var column = i % 6;
|
||||
|
||||
assert.equal(lm.offsetAt(Position.create(line, column)), i);
|
||||
assert.deepEqual(lm.positionAt(i), Position.create(line, column));
|
||||
}
|
||||
|
||||
assert.equal(lm.offsetAt(Position.create(3, 0)), 18);
|
||||
assert.equal(lm.offsetAt(Position.create(3, 1)), 18);
|
||||
assert.deepEqual(lm.positionAt(18), Position.create(3, 0));
|
||||
assert.deepEqual(lm.positionAt(19), Position.create(3, 0));
|
||||
});
|
||||
|
||||
test('New line characters', () => {
|
||||
var str = "ABCDE\rFGHIJ";
|
||||
assert.equal(lines.create(str).lineCount, 2);
|
||||
|
||||
var str = "ABCDE\nFGHIJ";
|
||||
assert.equal(lines.create(str).lineCount, 2);
|
||||
|
||||
var str = "ABCDE\r\nFGHIJ";
|
||||
assert.equal(lines.create(str).lineCount, 2);
|
||||
|
||||
str = "ABCDE\n\nFGHIJ";
|
||||
assert.equal(lines.create(str).lineCount, 3);
|
||||
|
||||
str = "ABCDE\r\rFGHIJ";
|
||||
assert.equal(lines.create(str).lineCount, 3);
|
||||
|
||||
str = "ABCDE\n\rFGHIJ";
|
||||
assert.equal(lines.create(str).lineCount, 3);
|
||||
})
|
||||
|
||||
|
||||
test('invalid inputs', () => {
|
||||
var str = "Hello World";
|
||||
var lm = lines.create(str);
|
||||
|
||||
// invalid position
|
||||
assert.equal(lm.offsetAt(Position.create(0, str.length)), str.length);
|
||||
assert.equal(lm.offsetAt(Position.create(0, str.length + 3)), str.length);
|
||||
assert.equal(lm.offsetAt(Position.create(2, 3)), str.length);
|
||||
assert.equal(lm.offsetAt(Position.create(-1, 3)), 0);
|
||||
assert.equal(lm.offsetAt(Position.create(0, -3)), 0);
|
||||
assert.equal(lm.offsetAt(Position.create(1, -3)), str.length);
|
||||
|
||||
// invalid offsets
|
||||
assert.deepEqual(lm.positionAt(-1), Position.create(0, 0));
|
||||
assert.deepEqual(lm.positionAt(str.length), Position.create(0, str.length));
|
||||
assert.deepEqual(lm.positionAt(str.length + 3), Position.create(0, str.length));
|
||||
});
|
||||
});
|
|
@ -1,88 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {
|
||||
Position
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
export interface LinesModel {
|
||||
/**
|
||||
* Converts a zero-based offset to a position.
|
||||
*
|
||||
* @param offset A zero-based offset.
|
||||
* @return A valid [position](#Position).
|
||||
*/
|
||||
positionAt(offset: number): Position;
|
||||
|
||||
/**
|
||||
* Converts the position to a zero-based offset.
|
||||
*
|
||||
* The position will be [adjusted](#TextDocument.validatePosition).
|
||||
*
|
||||
* @param position A position.
|
||||
* @return A valid zero-based offset.
|
||||
*/
|
||||
offsetAt(position: Position): number;
|
||||
|
||||
/**
|
||||
* The number of lines in this document.
|
||||
*
|
||||
* @readonly
|
||||
*/
|
||||
lineCount: number;
|
||||
}
|
||||
|
||||
export function create(text:string) : LinesModel {
|
||||
const lineStarts: number[] = [];
|
||||
var isLineStart = true;
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
if (isLineStart) {
|
||||
lineStarts.push(i);
|
||||
isLineStart = false;
|
||||
}
|
||||
var ch = text.charAt(i);
|
||||
isLineStart = (ch === '\r' || ch === '\n');
|
||||
if (ch === '\r' && i + 1 < text.length && text.charAt(i+1) === '\n') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (isLineStart && text.length > 0) {
|
||||
lineStarts.push(text.length);
|
||||
}
|
||||
return {
|
||||
positionAt: (offset:number) => {
|
||||
offset = Math.max(Math.min(offset, text.length), 0);
|
||||
let low = 0, high = lineStarts.length;
|
||||
if (high === 0) {
|
||||
return Position.create(0, offset);
|
||||
}
|
||||
while (low < high) {
|
||||
let mid = Math.floor((low + high) / 2);
|
||||
if (lineStarts[mid] > offset) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
// low is the least x for which the line offset is larger than the offset
|
||||
// or array.length if no element fullfills the given function.
|
||||
var line = low - 1;
|
||||
return Position.create(line, offset - lineStarts[line]);
|
||||
},
|
||||
offsetAt: (position: Position) => {
|
||||
if (position.line >= lineStarts.length) {
|
||||
return text.length;
|
||||
} else if (position.line < 0) {
|
||||
return 0;
|
||||
}
|
||||
var lineStart = lineStarts[position.line];
|
||||
var nextLineStart = (position.line + 1 < lineStarts.length) ? lineStarts[position.line + 1] : text.length;
|
||||
return Math.max(Math.min(lineStart + position.character, nextLineStart), lineStart);
|
||||
},
|
||||
lineCount: lineStarts.length
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue