diff --git a/src/vs/editor/browser/standalone/colorizer.ts b/src/vs/editor/browser/standalone/colorizer.ts index bd677e26bfb1a4cb41973a8da4050fa03e0bc910..490801a8f4f1815aea53170271cc4fcd65f8ea67 100644 --- a/src/vs/editor/browser/standalone/colorizer.ts +++ b/src/vs/editor/browser/standalone/colorizer.ts @@ -6,10 +6,10 @@ import {TPromise} from 'vs/base/common/winjs.base'; import Schedulers = require('vs/base/common/async'); -import ViewLine = require('vs/editor/browser/viewParts/lines/viewLine'); import EditorCommon = require('vs/editor/common/editorCommon'); import Modes = require('vs/editor/common/modes'); import {IModeService} from 'vs/editor/common/services/modeService'; +import {IRenderLineOutput, renderLine} from 'vs/editor/common/viewLayout/viewLineRenderer'; export interface IColorizerOptions { tabSize?: number; @@ -90,7 +90,7 @@ export function colorize(modeService:IModeService, text:string, mimeType:string, } export function colorizeLine(line:string, tokens:EditorCommon.ILineToken[], tabSize:number = 4): string { - var renderResult = ViewLine.renderLine({ + var renderResult = renderLine({ lineContent: line, parts: tokens, stopRenderingLineAfter: -1, @@ -120,7 +120,7 @@ function actualColorize(lines:string[], mode:Modes.IMode, tabSize:number): IActu length:number, line: string, tokenizeResult: Modes.ILineTokens, - renderResult: ViewLine.IRenderLineOutput, + renderResult: IRenderLineOutput, retokenize: TPromise[] = []; for (i = 0, length = lines.length; i < length; i++) { @@ -131,7 +131,7 @@ function actualColorize(lines:string[], mode:Modes.IMode, tabSize:number): IActu retokenize.push(tokenizeResult.retokenize); } - renderResult = ViewLine.renderLine({ + renderResult = renderLine({ lineContent: line, parts: tokenizeResult.tokens, stopRenderingLineAfter: -1, diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index f3e2a1ddca6df546ae501775111b79775aca9121..01391adb0cf61a4725afed4813c24b23aca0ed48 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -9,7 +9,8 @@ import {StyleMutator} from 'vs/base/browser/dom'; import {IVisibleLineData} from 'vs/editor/browser/view/viewLayer'; import {ILineParts, createLineParts} from 'vs/editor/common/viewLayout/viewLineParts'; import {ClassNames, IViewContext, HorizontalRange} from 'vs/editor/browser/editorBrowser'; -import {IModelDecoration, IConfigurationChangedEvent, ILineToken} from 'vs/editor/common/editorCommon'; +import {IModelDecoration, IConfigurationChangedEvent} from 'vs/editor/common/editorCommon'; +import {renderLine} from 'vs/editor/common/viewLayout/viewLineRenderer'; export class ViewLine implements IVisibleLineData { @@ -516,160 +517,3 @@ function createNormalLine(context: IViewContext): ViewLine { return new ViewLine(context); } -export interface IRenderLineInput { - lineContent: string; - tabSize: number; - stopRenderingLineAfter: number; - renderWhitespace: boolean; - parts: ILineToken[]; -} - -export interface IRenderLineOutput { - charOffsetInPart: number[]; - lastRenderedPartIndex: number; - output: string[]; -} - -let _space = ' '.charCodeAt(0); -let _tab = '\t'.charCodeAt(0); -let _lowerThan = '<'.charCodeAt(0); -let _greaterThan = '>'.charCodeAt(0); -let _ampersand = '&'.charCodeAt(0); -let _carriageReturn = '\r'.charCodeAt(0); -let _lineSeparator = '\u2028'.charCodeAt(0); //http://www.fileformat.info/info/unicode/char/2028/index.htm -let _bom = 65279; -let _replacementCharacter = '\ufffd'; - -export function renderLine(input:IRenderLineInput): IRenderLineOutput { - const lineText = input.lineContent; - let lineTextLength = lineText.length; - const stopRenderingLineAfter = input.stopRenderingLineAfter; - const tabSize = input.tabSize; - - if (lineTextLength === 0) { - return { - charOffsetInPart: [], - lastRenderedPartIndex: 0, - // This is basically for IE's hit test to work - output: [' '] - }; - } - - let result: IRenderLineOutput = { - charOffsetInPart: [], - lastRenderedPartIndex: 0, - output: [] - }; - - result.output.push(''); - let partClassName: string, - partIndex = -1, - nextPartIndex = 0, - tabsCharDelta = 0, - charOffsetInPart = 0, - append = '', - renderWhitespace = false; - - let actualLineParts = input.parts; - if (actualLineParts.length === 0) { - throw new Error('Cannot render non empty line without line parts!'); - } - - if (stopRenderingLineAfter !== -1 && lineTextLength > stopRenderingLineAfter - 1) { - append = lineText.substr(stopRenderingLineAfter - 1, 1); - lineTextLength = stopRenderingLineAfter - 1; - } - - for (let i = 0; i < lineTextLength; i++) { - if (i === nextPartIndex) { - partIndex++; - nextPartIndex = (partIndex + 1 < actualLineParts.length ? actualLineParts[partIndex + 1].startIndex : Number.MAX_VALUE); - if (i > 0) { - result.output.push(''); - } - result.output.push(''); - - charOffsetInPart = 0; - } - - result.charOffsetInPart[i] = charOffsetInPart; - let charCode = lineText.charCodeAt(i); - - switch (charCode) { - case _tab: - let insertSpacesCount = tabSize - (i + tabsCharDelta) % tabSize; - tabsCharDelta += insertSpacesCount - 1; - charOffsetInPart += insertSpacesCount - 1; - if (insertSpacesCount > 0) { - result.output.push(renderWhitespace ? '→' : ' '); - insertSpacesCount--; - } - while (insertSpacesCount > 0) { - result.output.push(' '); - insertSpacesCount--; - } - break; - - case _space: - result.output.push(renderWhitespace ? '·' : ' '); - break; - - case _lowerThan: - result.output.push('<'); - break; - - case _greaterThan: - result.output.push('>'); - break; - - case _ampersand: - result.output.push('&'); - break; - - case 0: - result.output.push('�'); - break; - - case _bom: - case _lineSeparator: - result.output.push(_replacementCharacter); - break; - - case _carriageReturn: - // zero width space, because carriage return would introduce a line break - result.output.push('​'); - break; - - default: - result.output.push(lineText.charAt(i)); - } - - charOffsetInPart ++; - } - result.output.push(''); - - // When getting client rects for the last character, we will position the - // text range at the end of the span, insteaf of at the beginning of next span - result.charOffsetInPart[lineTextLength] = charOffsetInPart; - - // In case we stop rendering, we record here the index of the last span - // that should be used for getting client rects - result.lastRenderedPartIndex = partIndex; - - if (append.length > 0) { - result.output.push(''); - result.output.push(append); - result.output.push('…'); - } - result.output.push(''); - - return result; -} diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index c5a4ccf51ad5f59ed832e5338204cc44a3f48d0e..1a0b51af0505de6530c2a255290d027555f481a5 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -16,11 +16,11 @@ import EditorCommon = require('vs/editor/common/editorCommon'); import EditorBrowser = require('vs/editor/browser/editorBrowser'); import Actions = require('vs/base/common/actions'); import Sash = require('vs/base/browser/ui/sash/sash'); -import ViewLine = require('vs/editor/browser/viewParts/lines/viewLine'); import ViewLineParts = require('vs/editor/common/viewLayout/viewLineParts'); import Schedulers = require('vs/base/common/async'); import {Range} from 'vs/editor/common/core/range'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; +import {renderLine} from 'vs/editor/common/viewLayout/viewLineRenderer'; interface IEditorScrollEvent { scrollLeft: number; @@ -1772,7 +1772,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { parts = ViewLineParts.createLineParts(lineNumber, lineContent, lineTokens, decorations, config.renderWhitespace); - var r = ViewLine.renderLine({ + var r = renderLine({ lineContent: lineContent, tabSize: indentation.tabSize, stopRenderingLineAfter: config.stopRenderingLineAfter, diff --git a/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ed4e5b8da17b8c668fd9f8a85e81858986cc0e4 --- /dev/null +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -0,0 +1,165 @@ +/*--------------------------------------------------------------------------------------------- + * 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 {ILineToken} from 'vs/editor/common/editorCommon'; + +export interface IRenderLineInput { + lineContent: string; + tabSize: number; + stopRenderingLineAfter: number; + renderWhitespace: boolean; + parts: ILineToken[]; +} + +export interface IRenderLineOutput { + charOffsetInPart: number[]; + lastRenderedPartIndex: number; + output: string[]; +} + +let _space = ' '.charCodeAt(0); +let _tab = '\t'.charCodeAt(0); +let _lowerThan = '<'.charCodeAt(0); +let _greaterThan = '>'.charCodeAt(0); +let _ampersand = '&'.charCodeAt(0); +let _carriageReturn = '\r'.charCodeAt(0); +let _lineSeparator = '\u2028'.charCodeAt(0); //http://www.fileformat.info/info/unicode/char/2028/index.htm +let _bom = 65279; +let _replacementCharacter = '\ufffd'; + +export function renderLine(input:IRenderLineInput): IRenderLineOutput { + const lineText = input.lineContent; + let lineTextLength = lineText.length; + const stopRenderingLineAfter = input.stopRenderingLineAfter; + const tabSize = input.tabSize; + + if (lineTextLength === 0) { + return { + charOffsetInPart: [], + lastRenderedPartIndex: 0, + // This is basically for IE's hit test to work + output: [' '] + }; + } + + let result: IRenderLineOutput = { + charOffsetInPart: [], + lastRenderedPartIndex: 0, + output: [] + }; + + result.output.push(''); + let partClassName: string, + partIndex = -1, + nextPartIndex = 0, + tabsCharDelta = 0, + charOffsetInPart = 0, + append = '', + renderWhitespace = false; + + let actualLineParts = input.parts; + if (actualLineParts.length === 0) { + throw new Error('Cannot render non empty line without line parts!'); + } + + if (stopRenderingLineAfter !== -1 && lineTextLength > stopRenderingLineAfter - 1) { + append = lineText.substr(stopRenderingLineAfter - 1, 1); + lineTextLength = stopRenderingLineAfter - 1; + } + + for (let i = 0; i < lineTextLength; i++) { + if (i === nextPartIndex) { + partIndex++; + nextPartIndex = (partIndex + 1 < actualLineParts.length ? actualLineParts[partIndex + 1].startIndex : Number.MAX_VALUE); + if (i > 0) { + result.output.push(''); + } + result.output.push(''); + + charOffsetInPart = 0; + } + + result.charOffsetInPart[i] = charOffsetInPart; + let charCode = lineText.charCodeAt(i); + + switch (charCode) { + case _tab: + let insertSpacesCount = tabSize - (i + tabsCharDelta) % tabSize; + tabsCharDelta += insertSpacesCount - 1; + charOffsetInPart += insertSpacesCount - 1; + if (insertSpacesCount > 0) { + result.output.push(renderWhitespace ? '→' : ' '); + insertSpacesCount--; + } + while (insertSpacesCount > 0) { + result.output.push(' '); + insertSpacesCount--; + } + break; + + case _space: + result.output.push(renderWhitespace ? '·' : ' '); + break; + + case _lowerThan: + result.output.push('<'); + break; + + case _greaterThan: + result.output.push('>'); + break; + + case _ampersand: + result.output.push('&'); + break; + + case 0: + result.output.push('�'); + break; + + case _bom: + case _lineSeparator: + result.output.push(_replacementCharacter); + break; + + case _carriageReturn: + // zero width space, because carriage return would introduce a line break + result.output.push('​'); + break; + + default: + result.output.push(lineText.charAt(i)); + } + + charOffsetInPart ++; + } + result.output.push(''); + + // When getting client rects for the last character, we will position the + // text range at the end of the span, insteaf of at the beginning of next span + result.charOffsetInPart[lineTextLength] = charOffsetInPart; + + // In case we stop rendering, we record here the index of the last span + // that should be used for getting client rects + result.lastRenderedPartIndex = partIndex; + + if (append.length > 0) { + result.output.push(''); + result.output.push(append); + result.output.push('…'); + } + result.output.push(''); + + return result; +}