提交 121f96c2 编写于 作者: A Alex Dima

Use a StringBuilder for rendering view lines

上级 d5265968
......@@ -7,6 +7,7 @@
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { createStringBuilder, IStringBuilder } from 'vs/editor/common/core/stringBuilder';
/**
* Represents a visible line
......@@ -22,7 +23,7 @@ export interface IVisibleLine {
* Return null if the HTML should not be touched.
* Return the new HTML otherwise.
*/
renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData): string;
renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean;
/**
* Layout the line.
......@@ -503,12 +504,12 @@ class ViewLayerRenderer<T extends IVisibleLine> {
ctx.lines.splice(removeIndex, removeCount);
}
private _finishRenderingNewLines(ctx: IRendererContext<T>, domNodeIsEmpty: boolean, newLinesHTML: string[], wasNew: boolean[]): void {
private _finishRenderingNewLines(ctx: IRendererContext<T>, domNodeIsEmpty: boolean, newLinesHTML: string, wasNew: boolean[]): void {
let lastChild = <HTMLElement>this.domNode.lastChild;
if (domNodeIsEmpty || !lastChild) {
this.domNode.innerHTML = newLinesHTML.join('');
this.domNode.innerHTML = newLinesHTML;
} else {
lastChild.insertAdjacentHTML('afterend', newLinesHTML.join(''));
lastChild.insertAdjacentHTML('afterend', newLinesHTML);
}
let currChild = <HTMLElement>this.domNode.lastChild;
......@@ -521,10 +522,10 @@ class ViewLayerRenderer<T extends IVisibleLine> {
}
}
private _finishRenderingInvalidLines(ctx: IRendererContext<T>, invalidLinesHTML: string[], wasInvalid: boolean[]): void {
private _finishRenderingInvalidLines(ctx: IRendererContext<T>, invalidLinesHTML: string, wasInvalid: boolean[]): void {
let hugeDomNode = document.createElement('div');
hugeDomNode.innerHTML = invalidLinesHTML.join('');
hugeDomNode.innerHTML = invalidLinesHTML;
for (let i = 0; i < ctx.linesLength; i++) {
let line = ctx.lines[i];
......@@ -537,14 +538,21 @@ class ViewLayerRenderer<T extends IVisibleLine> {
}
}
private static _sb1 = createStringBuilder(100000);
private static _sb2 = createStringBuilder(100000);
private _finishRendering(ctx: IRendererContext<T>, domNodeIsEmpty: boolean, deltaTop: number[]): void {
const sb1 = ViewLayerRenderer._sb1;
const sb2 = ViewLayerRenderer._sb2;
sb1.reset();
sb2.reset();
let hadNewLine = false;
let wasNew: boolean[] = [];
let newLinesHTML: string[] = [];
let hadInvalidLine = false;
let wasInvalid: boolean[] = [];
let invalidLinesHTML: string[] = [];
for (let i = 0, len = ctx.linesLength; i < len; i++) {
let line = ctx.lines[i];
......@@ -553,19 +561,19 @@ class ViewLayerRenderer<T extends IVisibleLine> {
wasNew[i] = false;
wasInvalid[i] = false;
let renderResult = line.renderLine(lineNumber, deltaTop[i], this.viewportData);
const lineDomNode = line.getDomNode();
if (renderResult !== null) {
// Line needs rendering
let lineDomNode = line.getDomNode();
if (!lineDomNode) {
if (!lineDomNode) {
let renderResult = line.renderLine(lineNumber, deltaTop[i], this.viewportData, sb1);
if (renderResult) {
// Line is new
newLinesHTML.push(renderResult);
wasNew[i] = true;
hadNewLine = true;
} else {
}
} else {
let renderResult = line.renderLine(lineNumber, deltaTop[i], this.viewportData, sb2);
if (renderResult) {
// Line is invalid
invalidLinesHTML.push(renderResult);
wasInvalid[i] = true;
hadInvalidLine = true;
}
......@@ -573,11 +581,11 @@ class ViewLayerRenderer<T extends IVisibleLine> {
}
if (hadNewLine) {
this._finishRenderingNewLines(ctx, domNodeIsEmpty, newLinesHTML, wasNew);
this._finishRenderingNewLines(ctx, domNodeIsEmpty, sb1.build(), wasNew);
}
if (hadInvalidLine) {
this._finishRenderingInvalidLines(ctx, invalidLinesHTML, wasInvalid);
this._finishRenderingInvalidLines(ctx, sb2.build(), wasInvalid);
}
}
}
......@@ -14,6 +14,7 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
import { ViewPart } from 'vs/editor/browser/view/viewPart';
import { IStringBuilder } from 'vs/editor/common/core/stringBuilder';
export class ViewOverlays extends ViewPart implements IVisibleLinesHost<ViewOverlayLine> {
......@@ -178,7 +179,7 @@ export class ViewOverlayLine implements IVisibleLine {
}
}
public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData): string {
public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean {
let result = '';
for (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {
let dynamicOverlay = this._dynamicOverlays[i];
......@@ -187,12 +188,20 @@ export class ViewOverlayLine implements IVisibleLine {
if (this._renderedContent === result) {
// No rendering needed
return null;
return false;
}
this._renderedContent = result;
return `<div style="position:absolute;top:${deltaTop}px;width:100%;height:${this._lineHeight}px;">${result}</div>`;
sb.appendASCIIString('<div style="position:absolute;top:');
sb.appendASCIIString(String(deltaTop));
sb.appendASCIIString('px;width:100%;height:');
sb.appendASCIIString(String(this._lineHeight));
sb.appendASCIIString('px;">');
sb.appendASCIIString(result);
sb.appendASCIIString('</div>');
return true;
}
public layoutLine(lineNumber: number, deltaTop: number): void {
......
......@@ -142,12 +142,12 @@ export class GlyphMarginOverlay extends DedupOverlay {
protected _getDecorations(ctx: RenderingContext): DecorationToRender[] {
let decorations = ctx.getDecorationsInViewport();
let r: DecorationToRender[] = [];
let r: DecorationToRender[] = [], rLen = 0;
for (let i = 0, len = decorations.length; i < len; i++) {
let d = decorations[i];
let glyphMarginClassName = d.source.options.glyphMarginClassName;
if (glyphMarginClassName) {
r.push(new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName));
r[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, glyphMarginClassName);
}
}
return r;
......
......@@ -16,6 +16,7 @@ import { RangeUtil } from 'vs/editor/browser/viewParts/lines/rangeUtil';
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
import { ThemeType, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService';
import { IStringBuilder } from 'vs/editor/common/core/stringBuilder';
const canUseFastRenderedViewLine = (function () {
if (platform.isNative) {
......@@ -156,10 +157,10 @@ export class ViewLine implements IVisibleLine {
return false;
}
public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData): string {
public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData, sb: IStringBuilder): boolean {
if (this._isMaybeInvalid === false) {
// it appears that nothing relevant has changed
return null;
return false;
}
this._isMaybeInvalid = false;
......@@ -204,10 +205,20 @@ export class ViewLine implements IVisibleLine {
if (this._renderedViewLine && this._renderedViewLine.input.equals(renderLineInput)) {
// no need to do anything, we have the same render input
return null;
return false;
}
const output = renderViewLine(renderLineInput);
sb.appendASCIIString('<div style="top:');
sb.appendASCIIString(String(deltaTop));
sb.appendASCIIString('px;height:');
sb.appendASCIIString(String(this._options.lineHeight));
sb.appendASCIIString('px;" class="');
sb.appendASCIIString(ViewLine.CLASS_NAME);
sb.appendASCIIString('">');
const output = renderViewLine(renderLineInput, sb);
sb.appendASCIIString('</div>');
let renderedViewLine: IRenderedViewLine = null;
if (canUseFastRenderedViewLine && options.useMonospaceOptimizations && !output.containsForeignElements) {
......@@ -239,7 +250,7 @@ export class ViewLine implements IVisibleLine {
this._renderedViewLine = renderedViewLine;
return `<div style="top:${deltaTop}px;height:${this._options.lineHeight}px;" class="${ViewLine.CLASS_NAME}">${output.html}</div>`;
return true;
}
public layoutLine(lineNumber: number, deltaTop: number): void {
......
......@@ -42,6 +42,7 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDeco
import { DiffReview } from 'vs/editor/browser/widget/diffReview';
import URI from 'vs/base/common/uri';
import { IMessageService } from 'vs/platform/message/common/message';
import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';
interface IEditorDiffDecorations {
decorations: editorCommon.IModelDeltaDecoration[];
......@@ -1943,12 +1944,12 @@ class InlineViewZonesComputer extends ViewZonesComputer {
}
}
let html: string[] = [];
let sb = createStringBuilder(10000);
let marginHTML: string[] = [];
let lineDecorationsWidth = this.modifiedEditorConfiguration.layoutInfo.decorationsWidth;
let lineHeight = this.modifiedEditorConfiguration.lineHeight;
for (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) {
html = html.concat(this.renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorConfiguration, this.modifiedEditorTabSize, lineNumber, decorations));
this.renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorConfiguration, this.modifiedEditorTabSize, lineNumber, decorations, sb);
if (this.renderIndicators) {
let index = lineNumber - lineChange.originalStartLineNumber;
......@@ -1960,7 +1961,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
let domNode = document.createElement('div');
domNode.className = 'view-lines line-delete';
domNode.innerHTML = html.join('');
domNode.innerHTML = sb.build();
Configuration.applyFontInfoSlow(domNode, this.modifiedEditorConfiguration.fontInfo);
let marginDomNode = document.createElement('div');
......@@ -1977,7 +1978,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
};
}
private renderOriginalLine(count: number, originalModel: editorCommon.IModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[]): string[] {
private renderOriginalLine(count: number, originalModel: editorCommon.IModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): void {
let lineContent = originalModel.getLineContent(lineNumber);
let actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1);
......@@ -1988,7 +1989,16 @@ class InlineViewZonesComputer extends ViewZonesComputer {
| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
) >>> 0;
let r = renderViewLine(new RenderLineInput(
sb.appendASCIIString('<div class="view-line');
if (decorations.length === 0) {
// No char changes
sb.appendASCIIString(' char-delete');
}
sb.appendASCIIString('" style="top:');
sb.appendASCIIString(String(count * config.lineHeight));
sb.appendASCIIString('px;width:1000000px;">');
renderViewLine(new RenderLineInput(
(config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations),
lineContent,
originalModel.mightContainRTL(),
......@@ -2001,21 +2011,9 @@ class InlineViewZonesComputer extends ViewZonesComputer {
config.viewInfo.renderWhitespace,
config.viewInfo.renderControlCharacters,
config.viewInfo.fontLigatures
));
let myResult: string[] = [];
myResult.push('<div class="view-line');
if (decorations.length === 0) {
// No char changes
myResult.push(' char-delete');
}
myResult.push('" style="top:');
myResult.push(String(count * config.lineHeight));
myResult.push('px;width:1000000px;">');
myResult = myResult.concat(r.html);
myResult.push('</div>');
), sb);
return myResult;
sb.appendASCIIString('</div>');
}
}
......
......@@ -10,7 +10,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import * as dom from 'vs/base/browser/dom';
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { renderViewLine2 as renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { Configuration } from 'vs/editor/browser/config/configuration';
import { Position } from 'vs/editor/common/core/position';
......
/*---------------------------------------------------------------------------------------------
* 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 * as strings from 'vs/base/common/strings';
declare var TextDecoder: any; // TODO@TypeScript
interface TextDecoder {
decode(view: Uint16Array): string;
}
export interface IStringBuilder {
build(): string;
reset(): void;
write1(charCode: number): void;
appendASCII(charCode: number): void;
appendASCIIString(str: string): void;
}
export let createStringBuilder: (capacity: number) => IStringBuilder;
if ((<any>self).TextDecoder) {
createStringBuilder = (capacity) => new StringBuilder(capacity);
} else {
createStringBuilder = (capacity) => new CompatStringBuilder();
}
class StringBuilder implements IStringBuilder {
private readonly _decoder: TextDecoder;
private readonly _capacity: number;
private readonly _buffer: Uint16Array;
private _completedStrings: string[];
private _bufferLength: number;
constructor(capacity: number) {
this._decoder = new TextDecoder('UTF-16LE');
this._capacity = capacity | 0;
this._buffer = new Uint16Array(this._capacity);
this._completedStrings = null;
this._bufferLength = 0;
}
public reset(): void {
this._completedStrings = null;
this._bufferLength = 0;
}
public build(): string {
if (this._completedStrings !== null) {
this._flushBuffer();
return this._completedStrings.join('');
}
return this._buildBuffer();
}
private _buildBuffer(): string {
if (this._bufferLength === 0) {
return '';
}
const view = new Uint16Array(this._buffer.buffer, 0, this._bufferLength);
return this._decoder.decode(view);
}
private _flushBuffer(): void {
const bufferString = this._buildBuffer();
this._bufferLength = 0;
if (this._completedStrings === null) {
this._completedStrings = [bufferString];
} else {
this._completedStrings.push(bufferString);
}
}
public write1(charCode: number): void {
const remainingSpace = this._capacity - this._bufferLength;
if (remainingSpace <= 1) {
if (remainingSpace === 0 || strings.isHighSurrogate(charCode)) {
this._flushBuffer();
}
}
this._buffer[this._bufferLength++] = charCode;
}
public appendASCII(charCode: number): void {
if (this._bufferLength === this._capacity) {
// buffer is full
this._flushBuffer();
}
this._buffer[this._bufferLength++] = charCode;
}
public appendASCIIString(str: string): void {
const strLen = str.length;
if (this._bufferLength + strLen >= this._capacity) {
// This string does not fit in the remaining buffer space
this._flushBuffer();
this._completedStrings.push(str);
return;
}
for (let i = 0; i < strLen; i++) {
this._buffer[this._bufferLength++] = str.charCodeAt(i);
}
}
}
class CompatStringBuilder implements IStringBuilder {
private _pieces: string[];
private _piecesLen: number;
constructor() {
this._pieces = [];
this._piecesLen = 0;
}
public reset(): void {
this._pieces = [];
this._piecesLen = 0;
}
public build(): string {
return this._pieces.join('');
}
public write1(charCode: number): void {
this._pieces[this._piecesLen++] = String.fromCharCode(charCode);
}
public appendASCII(charCode: number): void {
this._pieces[this._piecesLen++] = String.fromCharCode(charCode);
}
public appendASCIIString(str: string): void {
this._pieces[this._piecesLen++] = str;
}
}
......@@ -8,6 +8,7 @@ import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { CharCode } from 'vs/base/common/charCode';
import { LineDecoration, LineDecorationsNormalizer } from 'vs/editor/common/viewLayout/lineDecorations';
import * as strings from 'vs/base/common/strings';
import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';
export const enum RenderWhitespace {
None = 0,
......@@ -223,19 +224,17 @@ export class RenderLineOutput {
_renderLineOutputBrand: void;
readonly characterMapping: CharacterMapping;
readonly html: string;
readonly containsRTL: boolean;
readonly containsForeignElements: boolean;
constructor(characterMapping: CharacterMapping, html: string, containsRTL: boolean, containsForeignElements: boolean) {
constructor(characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: boolean) {
this.characterMapping = characterMapping;
this.html = html;
this.containsRTL = containsRTL;
this.containsForeignElements = containsForeignElements;
}
}
export function renderViewLine(input: RenderLineInput): RenderLineOutput {
export function renderViewLine(input: RenderLineInput, sb: IStringBuilder): RenderLineOutput {
if (input.lineContent.length === 0) {
let containsForeignElements = false;
......@@ -259,15 +258,31 @@ export function renderViewLine(input: RenderLineInput): RenderLineOutput {
}
}
sb.appendASCIIString(content);
return new RenderLineOutput(
new CharacterMapping(0, 0),
content,
false,
containsForeignElements
);
}
return _renderLine(resolveRenderLineInput(input));
return _renderLine(resolveRenderLineInput(input), sb);
}
export class RenderLineOutput2 {
constructor(
public readonly characterMapping: CharacterMapping,
public readonly html: string,
public readonly containsRTL: boolean,
public readonly containsForeignElements: boolean
) {
}
}
export function renderViewLine2(input: RenderLineInput): RenderLineOutput2 {
let sb = createStringBuilder(10000);
let out = renderViewLine(input, sb);
return new RenderLineOutput2(out.characterMapping, sb.build(), out.containsRTL, out.containsForeignElements);
}
class ResolvedRenderLineInput {
......@@ -564,7 +579,7 @@ function _applyInlineDecorations(lineContent: string, len: number, tokens: LineP
* This function is on purpose not split up into multiple functions to allow runtime type inference (i.e. performance reasons).
* Notice how all the needed data is fully resolved and passed in (i.e. no other calls).
*/
function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): RenderLineOutput {
const fontIsMonospace = input.fontIsMonospace;
const containsForeignElements = input.containsForeignElements;
const lineContent = input.lineContent;
......@@ -583,7 +598,8 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
let tabsCharDelta = 0;
let charOffsetInPart = 0;
let out = '<span>';
sb.appendASCIIString('<span>');
for (let partIndex = 0, tokensLen = parts.length; partIndex < tokensLen; partIndex++) {
const part = parts[partIndex];
const partEndIndex = part.endIndex;
......@@ -591,10 +607,42 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
const partRendersWhitespace = (renderWhitespace !== RenderWhitespace.None && (partType.indexOf('vs-whitespace') >= 0));
charOffsetInPart = 0;
sb.appendASCIIString('<span class="');
sb.appendASCIIString(partType);
sb.appendASCII(CharCode.DoubleQuote);
if (partRendersWhitespace) {
let partContentCnt = 0;
let partContent = '';
{
let _charIndex = charIndex;
let _tabsCharDelta = tabsCharDelta;
let _charOffsetInPart = charOffsetInPart;
for (; _charIndex < partEndIndex; _charIndex++) {
const charCode = lineContent.charCodeAt(_charIndex);
if (charCode === CharCode.Tab) {
let insertSpacesCount = tabSize - (_charIndex + _tabsCharDelta) % tabSize;
_tabsCharDelta += insertSpacesCount - 1;
_charOffsetInPart += insertSpacesCount - 1;
partContentCnt += insertSpacesCount;
} else {
partContentCnt++;
}
_charOffsetInPart++;
}
}
if (fontIsMonospace || containsForeignElements) {
} else {
sb.appendASCIIString(' style="width:');
sb.appendASCIIString(String(spaceWidth * partContentCnt));
sb.appendASCIIString('px"');
}
sb.appendASCII(CharCode.GreaterThan);
for (; charIndex < partEndIndex; charIndex++) {
characterMapping.setPartData(charIndex, partIndex, charOffsetInPart);
const charCode = lineContent.charCodeAt(charIndex);
......@@ -604,35 +652,31 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
tabsCharDelta += insertSpacesCount - 1;
charOffsetInPart += insertSpacesCount - 1;
if (insertSpacesCount > 0) {
partContent += '&rarr;';
partContentCnt++;
sb.appendASCIIString('&rarr;');
insertSpacesCount--;
}
while (insertSpacesCount > 0) {
partContent += '&nbsp;';
partContentCnt++;
sb.appendASCIIString('&nbsp;');
insertSpacesCount--;
}
} else {
// must be CharCode.Space
partContent += '&middot;';
partContentCnt++;
sb.appendASCIIString('&middot;');
}
charOffsetInPart++;
}
characterMapping.setPartLength(partIndex, partContentCnt);
if (fontIsMonospace || containsForeignElements) {
out += `<span class="${partType}">${partContent}</span>`;
} else {
out += `<span class="${partType}" style="width:${spaceWidth * partContentCnt}px">${partContent}</span>`;
}
} else {
let partContentCnt = 0;
let partContent = '';
if (containsRTL) {
sb.appendASCIIString(' dir="ltr"');
}
sb.appendASCII(CharCode.GreaterThan);
for (; charIndex < partEndIndex; charIndex++) {
characterMapping.setPartData(charIndex, partIndex, charOffsetInPart);
......@@ -644,55 +688,55 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
tabsCharDelta += insertSpacesCount - 1;
charOffsetInPart += insertSpacesCount - 1;
while (insertSpacesCount > 0) {
partContent += '&nbsp;';
sb.appendASCIIString('&nbsp;');
partContentCnt++;
insertSpacesCount--;
}
break;
case CharCode.Space:
partContent += '&nbsp;';
sb.appendASCIIString('&nbsp;');
partContentCnt++;
break;
case CharCode.LessThan:
partContent += '&lt;';
sb.appendASCIIString('&lt;');
partContentCnt++;
break;
case CharCode.GreaterThan:
partContent += '&gt;';
sb.appendASCIIString('&gt;');
partContentCnt++;
break;
case CharCode.Ampersand:
partContent += '&amp;';
sb.appendASCIIString('&amp;');
partContentCnt++;
break;
case CharCode.Null:
partContent += '&#00;';
sb.appendASCIIString('&#00;');
partContentCnt++;
break;
case CharCode.UTF8_BOM:
case CharCode.LINE_SEPARATOR_2028:
partContent += '\ufffd';
sb.write1(0xfffd);
partContentCnt++;
break;
case CharCode.CarriageReturn:
// zero width space, because carriage return would introduce a line break
partContent += '&#8203';
sb.appendASCIIString('&#8203;');
partContentCnt++;
break;
default:
if (renderControlCharacters && charCode < 32) {
partContent += String.fromCharCode(9216 + charCode);
sb.write1(9216 + charCode);
partContentCnt++;
} else {
partContent += String.fromCharCode(charCode);
sb.write1(charCode);
partContentCnt++;
}
}
......@@ -701,13 +745,10 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
}
characterMapping.setPartLength(partIndex, partContentCnt);
if (containsRTL) {
out += `<span dir="ltr" class="${partType}">${partContent}</span>`;
} else {
out += `<span class="${partType}">${partContent}</span>`;
}
}
sb.appendASCIIString('</span>');
}
// When getting client rects for the last character, we will position the
......@@ -715,10 +756,10 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
characterMapping.setPartData(len, parts.length - 1, charOffsetInPart);
if (isOverflowing) {
out += `<span>&hellip;</span>`;
sb.appendASCIIString('<span>&hellip;</span>');
}
out += '</span>';
sb.appendASCIIString('</span>');
return new RenderLineOutput(characterMapping, out, containsRTL, containsForeignElements);
return new RenderLineOutput(characterMapping, containsRTL, containsForeignElements);
}
......@@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { IModel } from 'vs/editor/common/editorCommon';
import { ColorId, MetadataConsts, FontStyle, TokenizationRegistry, ITokenizationSupport } from 'vs/editor/common/modes';
import { IModeService } from 'vs/editor/common/services/modeService';
import { renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { renderViewLine2 as renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
import * as strings from 'vs/base/common/strings';
......
......@@ -5,7 +5,7 @@
'use strict';
import * as assert from 'assert';
import { renderViewLine, RenderLineInput, CharacterMapping } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { renderViewLine2 as renderViewLine, RenderLineInput, CharacterMapping } from 'vs/editor/common/viewLayout/viewLineRenderer';
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { CharCode } from 'vs/base/common/charCode';
import { MetadataConsts } from 'vs/editor/common/modes';
......@@ -56,7 +56,7 @@ suite('viewLineRenderer.renderLine', () => {
assertCharacterReplacement('a\0b', 4, 'a&#00;b', [[0, 1, 2, 3]], [3]);
assertCharacterReplacement('a' + String.fromCharCode(CharCode.UTF8_BOM) + 'b', 4, 'a\ufffdb', [[0, 1, 2, 3]], [3]);
assertCharacterReplacement('a\u2028b', 4, 'a\ufffdb', [[0, 1, 2, 3]], [3]);
assertCharacterReplacement('a\rb', 4, 'a&#8203b', [[0, 1, 2, 3]], [3]);
assertCharacterReplacement('a\rb', 4, 'a&#8203;b', [[0, 1, 2, 3]], [3]);
});
test('handles tabs', () => {
......@@ -355,10 +355,10 @@ suite('viewLineRenderer.renderLine', () => {
];
let expectedOutput = [
'<span dir="ltr" class="mtk6">var</span>',
'<span dir="ltr" class="mtk1">&nbsp;קודמות&nbsp;=&nbsp;</span>',
'<span dir="ltr" class="mtk20">"מיותר&nbsp;קודמות&nbsp;צ\'ט&nbsp;של,&nbsp;אם&nbsp;לשון&nbsp;העברית&nbsp;שינויים&nbsp;ויש,&nbsp;אם"</span>',
'<span dir="ltr" class="mtk1">;</span>'
'<span class="mtk6" dir="ltr">var</span>',
'<span class="mtk1" dir="ltr">&nbsp;קודמות&nbsp;=&nbsp;</span>',
'<span class="mtk20" dir="ltr">"מיותר&nbsp;קודמות&nbsp;צ\'ט&nbsp;של,&nbsp;אם&nbsp;לשון&nbsp;העברית&nbsp;שינויים&nbsp;ויש,&nbsp;אם"</span>',
'<span class="mtk1" dir="ltr">;</span>'
].join('');
let _actual = renderViewLine(new RenderLineInput(
......@@ -546,7 +546,7 @@ suite('viewLineRenderer.renderLine', () => {
let lineText = 'את גרמנית בהתייחסות שמו, שנתי המשפט אל חפש, אם כתב אחרים ולחבר. של התוכן אודות בויקיפדיה כלל, של עזרה כימיה היא. על עמוד יוצרים מיתולוגיה סדר, אם שכל שתפו לעברית שינויים, אם שאלות אנגלית עזה. שמות בקלות מה סדר.';
let lineParts = [createPart(lineText.length, 1)];
let expectedOutput = [
'<span dir="ltr" class="mtk1">את&nbsp;גרמנית&nbsp;בהתייחסות&nbsp;שמו,&nbsp;שנתי&nbsp;המשפט&nbsp;אל&nbsp;חפש,&nbsp;אם&nbsp;כתב&nbsp;אחרים&nbsp;ולחבר.&nbsp;של&nbsp;התוכן&nbsp;אודות&nbsp;בויקיפדיה&nbsp;כלל,&nbsp;של&nbsp;עזרה&nbsp;כימיה&nbsp;היא.&nbsp;על&nbsp;עמוד&nbsp;יוצרים&nbsp;מיתולוגיה&nbsp;סדר,&nbsp;אם&nbsp;שכל&nbsp;שתפו&nbsp;לעברית&nbsp;שינויים,&nbsp;אם&nbsp;שאלות&nbsp;אנגלית&nbsp;עזה.&nbsp;שמות&nbsp;בקלות&nbsp;מה&nbsp;סדר.</span>'
'<span class="mtk1" dir="ltr">את&nbsp;גרמנית&nbsp;בהתייחסות&nbsp;שמו,&nbsp;שנתי&nbsp;המשפט&nbsp;אל&nbsp;חפש,&nbsp;אם&nbsp;כתב&nbsp;אחרים&nbsp;ולחבר.&nbsp;של&nbsp;התוכן&nbsp;אודות&nbsp;בויקיפדיה&nbsp;כלל,&nbsp;של&nbsp;עזרה&nbsp;כימיה&nbsp;היא.&nbsp;על&nbsp;עמוד&nbsp;יוצרים&nbsp;מיתולוגיה&nbsp;סדר,&nbsp;אם&nbsp;שכל&nbsp;שתפו&nbsp;לעברית&nbsp;שינויים,&nbsp;אם&nbsp;שאלות&nbsp;אנגלית&nbsp;עזה.&nbsp;שמות&nbsp;בקלות&nbsp;מה&nbsp;סדר.</span>'
];
let actual = renderViewLine(new RenderLineInput(
false,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册