diff --git a/src/vs/editor/browser/standalone/colorizer.ts b/src/vs/editor/browser/standalone/colorizer.ts
index cc370e16139..f0c82ae7c1e 100644
--- a/src/vs/editor/browser/standalone/colorizer.ts
+++ b/src/vs/editor/browser/standalone/colorizer.ts
@@ -94,9 +94,10 @@ export class Colorizer {
});
}
- public static colorizeLine(line: string, tokens: ViewLineToken[], tabSize: number = 4): string {
+ public static colorizeLine(line: string, mightContainRTL: boolean, tokens: ViewLineToken[], tabSize: number = 4): string {
let renderResult = renderViewLine(new RenderLineInput(
line,
+ mightContainRTL,
0,
tokens,
[],
@@ -113,7 +114,7 @@ export class Colorizer {
let content = model.getLineContent(lineNumber);
let tokens = model.getLineTokens(lineNumber, false);
let inflatedTokens = tokens.inflate();
- return this.colorizeLine(content, inflatedTokens, tabSize);
+ return this.colorizeLine(content, model.mightContainRTL(), inflatedTokens, tabSize);
}
}
@@ -129,6 +130,7 @@ function _fakeColorize(lines: string[], tabSize: number): string {
let renderResult = renderViewLine(new RenderLineInput(
line,
+ false,
0,
[new ViewLineToken(line.length, '')],
[],
@@ -157,6 +159,7 @@ function _actualColorize(lines: string[], tabSize: number, tokenizationSupport:
let lineTokens = new LineTokens(colorMap, tokenizeResult.tokens, line);
let renderResult = renderViewLine(new RenderLineInput(
line,
+ true/* check for RTL */,
0,
lineTokens.inflate(),
[],
diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts
index 14bebc00d2a..01230e61f79 100644
--- a/src/vs/editor/browser/viewParts/lines/viewLine.ts
+++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts
@@ -102,6 +102,7 @@ export class ViewLine implements IVisibleLineData {
let renderLineInput = new RenderLineInput(
model.getLineContent(lineNumber),
+ model.mightContainRTL(),
model.getLineMinColumn(lineNumber) - 1,
model.getLineTokens(lineNumber),
actualInlineDecorations,
diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts
index e02011125a7..6bd46d9b65e 100644
--- a/src/vs/editor/browser/widget/codeEditorWidget.ts
+++ b/src/vs/editor/browser/widget/codeEditorWidget.ts
@@ -134,7 +134,7 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
let tokens = model.getLineTokens(lineNumber, false);
let inflatedTokens = tokens.inflate();
let tabSize = model.getOptions().tabSize;
- return Colorizer.colorizeLine(content, inflatedTokens, tabSize);
+ return Colorizer.colorizeLine(content, model.mightContainRTL(), inflatedTokens, tabSize);
}
public getView(): editorBrowser.IView {
return this._view;
diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts
index 8a423b577ab..56f3ed899bc 100644
--- a/src/vs/editor/browser/widget/diffEditorWidget.ts
+++ b/src/vs/editor/browser/widget/diffEditorWidget.ts
@@ -1889,6 +1889,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
let r = renderViewLine(new RenderLineInput(
lineContent,
+ originalModel.mightContainRTL(),
0,
[new ViewLineToken(lineContent.length, '')],
actualDecorations,
diff --git a/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts
index 6f27d84803f..19aaf73bc45 100644
--- a/src/vs/editor/common/viewLayout/viewLineRenderer.ts
+++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts
@@ -18,6 +18,7 @@ export const enum RenderWhitespace {
export class RenderLineInput {
public readonly lineContent: string;
+ public readonly mightContainRTL: boolean;
public readonly fauxIndentLength: number;
public readonly lineTokens: ViewLineToken[];
public readonly lineDecorations: Decoration[];
@@ -29,6 +30,7 @@ export class RenderLineInput {
constructor(
lineContent: string,
+ mightContainRTL: boolean,
fauxIndentLength: number,
lineTokens: ViewLineToken[],
lineDecorations: Decoration[],
@@ -39,6 +41,7 @@ export class RenderLineInput {
renderControlCharacters: boolean,
) {
this.lineContent = lineContent;
+ this.mightContainRTL = mightContainRTL;
this.fauxIndentLength = fauxIndentLength;
this.lineTokens = lineTokens;
this.lineDecorations = lineDecorations;
@@ -58,6 +61,7 @@ export class RenderLineInput {
public equals(other: RenderLineInput): boolean {
return (
this.lineContent === other.lineContent
+ && this.mightContainRTL === other.mightContainRTL
&& this.fauxIndentLength === other.fauxIndentLength
&& this.tabSize === other.tabSize
&& this.spaceWidth === other.spaceWidth
@@ -213,6 +217,7 @@ class ResolvedRenderLineInput {
public readonly tokens: ViewLineToken[],
public readonly lineDecorations: Decoration[],
public readonly tabSize: number,
+ public readonly emitLTRDir: boolean,
public readonly spaceWidth: number,
public readonly renderWhitespace: RenderWhitespace,
public readonly renderControlCharacters: boolean,
@@ -243,6 +248,11 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
tokens = _applyInlineDecorations(lineContent, len, tokens, input.lineDecorations);
}
+ let emitLTRDir = false;
+ if (input.mightContainRTL) {
+ emitLTRDir = strings.containsRTL(lineContent);
+ }
+
return new ResolvedRenderLineInput(
lineContent,
len,
@@ -250,6 +260,7 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
tokens,
input.lineDecorations,
input.tabSize,
+ emitLTRDir,
input.spaceWidth,
input.renderWhitespace,
input.renderControlCharacters
@@ -424,6 +435,7 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
const isOverflowing = input.isOverflowing;
const tokens = input.tokens;
const tabSize = input.tabSize;
+ const emitLTRDir = input.emitLTRDir;
const spaceWidth = input.spaceWidth;
const renderWhitespace = input.renderWhitespace;
const renderControlCharacters = input.renderControlCharacters;
@@ -534,7 +546,11 @@ function _renderLine(input: ResolvedRenderLineInput): RenderLineOutput {
charOffsetInPart++;
}
- out += `${partContent}`;
+ if (emitLTRDir) {
+ out += `${partContent}`;
+ } else {
+ out += `${partContent}`;
+ }
}
}
diff --git a/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts b/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts
index 8057407ddeb..eb4cd882114 100644
--- a/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts
+++ b/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts
@@ -58,6 +58,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
function testCreateLineParts(lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'all', expected: string): void {
let actual = renderViewLine(new RenderLineInput(
lineContent,
+ false,
fauxIndentLength,
tokens,
[],
@@ -267,6 +268,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
test('createLineParts can handle unsorted inline decorations', () => {
let actual = renderViewLine(new RenderLineInput(
'Hello world',
+ false,
0,
[new ViewLineToken(11, '')],
[
@@ -371,6 +373,7 @@ suite('Editor ViewLayout - ViewLineParts', () => {
function createTestGetColumnOfLinePartOffset(lineContent: string, tabSize: number, parts: ViewLineToken[]): (partIndex: number, partLength: number, offset: number, expected: number) => void {
let renderLineOutput = renderViewLine(new RenderLineInput(
lineContent,
+ false,
0,
parts,
[],
diff --git a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts
index fa0c12db006..d238e9c4b50 100644
--- a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts
+++ b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts
@@ -18,6 +18,7 @@ suite('viewLineRenderer.renderLine', () => {
function assertCharacterReplacement(lineContent: string, tabSize: number, expected: string, expectedCharOffsetInPart: number[][]): void {
let _actual = renderViewLine(new RenderLineInput(
lineContent,
+ false,
0,
[new ViewLineToken(lineContent.length, '')],
[],
@@ -62,6 +63,7 @@ suite('viewLineRenderer.renderLine', () => {
function assertParts(lineContent: string, tabSize: number, parts: ViewLineToken[], expected: string, expectedCharOffsetInPart: number[][]): void {
let _actual = renderViewLine(new RenderLineInput(
lineContent,
+ false,
0,
parts,
[],
@@ -95,6 +97,7 @@ suite('viewLineRenderer.renderLine', () => {
test('overflow', () => {
let _actual = renderViewLine(new RenderLineInput(
'Hello world!',
+ false,
0,
[
createPart(1, '0'),
@@ -190,6 +193,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
lineText,
+ false,
0,
lineParts,
[],
@@ -246,6 +250,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
lineText,
+ false,
0,
lineParts,
[],
@@ -302,6 +307,7 @@ suite('viewLineRenderer.renderLine', () => {
let _actual = renderViewLine(new RenderLineInput(
lineText,
+ false,
0,
lineParts,
[],
@@ -316,6 +322,39 @@ suite('viewLineRenderer.renderLine', () => {
assertCharacterMapping(_actual.characterMapping, expectedOffsetsArr);
});
+ test('issue Microsoft/monaco-editor#280: Improved source code rendering for RTL languages', () => {
+ let lineText = 'var קודמות = \"מיותר קודמות צ\'ט של, אם לשון העברית שינויים ויש, אם\";';
+
+ let lineParts = [
+ createPart(3, 'mtk6'),
+ createPart(13, 'mtk1'),
+ createPart(66, 'mtk20'),
+ createPart(67, 'mtk1'),
+ ];
+
+ let expectedOutput = [
+ 'var',
+ ' קודמות = ',
+ '"מיותר קודמות צ\'ט של, אם לשון העברית שינויים ויש, אם"',
+ ';'
+ ].join('');
+
+ let _actual = renderViewLine(new RenderLineInput(
+ lineText,
+ true,
+ 0,
+ lineParts,
+ [],
+ 4,
+ 10,
+ -1,
+ 'none',
+ false
+ ));
+
+ assert.equal(_actual.output, '' + expectedOutput + '');
+ });
+
function assertCharacterMapping(actual: CharacterMapping, expected: number[][]): void {
let charOffset = 0;
for (let partIndex = 0; partIndex < expected.length; partIndex++) {