Skip to content

Commit ab0eb6d

Browse files
committed
Fixes microsoft#82153: Allow editor.fontLigatures to contain font-feature-settings
1 parent e1f09b5 commit ab0eb6d

11 files changed

Lines changed: 110 additions & 38 deletions

File tree

src/vs/base/browser/fastDomNode.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class FastDomNode<T extends HTMLElement> {
1818
private _fontFamily: string;
1919
private _fontWeight: string;
2020
private _fontSize: number;
21+
private _fontFeatureSettings: string;
2122
private _lineHeight: number;
2223
private _letterSpacing: number;
2324
private _className: string;
@@ -38,6 +39,7 @@ export class FastDomNode<T extends HTMLElement> {
3839
this._fontFamily = '';
3940
this._fontWeight = '';
4041
this._fontSize = -1;
42+
this._fontFeatureSettings = '';
4143
this._lineHeight = -1;
4244
this._letterSpacing = -100;
4345
this._className = '';
@@ -135,6 +137,14 @@ export class FastDomNode<T extends HTMLElement> {
135137
this.domNode.style.fontSize = this._fontSize + 'px';
136138
}
137139

140+
public setFontFeatureSettings(fontFeatureSettings: string): void {
141+
if (this._fontFeatureSettings === fontFeatureSettings) {
142+
return;
143+
}
144+
this._fontFeatureSettings = fontFeatureSettings;
145+
this.domNode.style.fontFeatureSettings = this._fontFeatureSettings;
146+
}
147+
138148
public setLineHeight(lineHeight: number): void {
139149
if (this._lineHeight === lineHeight) {
140150
return;

src/vs/editor/browser/config/charWidthReader.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class DomCharWidthReader {
7171
regularDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily();
7272
regularDomNode.style.fontWeight = this._bareFontInfo.fontWeight;
7373
regularDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px';
74+
regularDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings;
7475
regularDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px';
7576
regularDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px';
7677
container.appendChild(regularDomNode);
@@ -79,6 +80,7 @@ class DomCharWidthReader {
7980
boldDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily();
8081
boldDomNode.style.fontWeight = 'bold';
8182
boldDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px';
83+
boldDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings;
8284
boldDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px';
8385
boldDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px';
8486
container.appendChild(boldDomNode);
@@ -87,6 +89,7 @@ class DomCharWidthReader {
8789
italicDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily();
8890
italicDomNode.style.fontWeight = this._bareFontInfo.fontWeight;
8991
italicDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px';
92+
italicDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings;
9093
italicDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px';
9194
italicDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px';
9295
italicDomNode.style.fontStyle = 'italic';

src/vs/editor/browser/config/configuration.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform';
1111
import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader';
1212
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
1313
import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig';
14-
import { EditorOption, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions';
14+
import { EditorOption, IEditorConstructionOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
1515
import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';
1616
import { IDimension } from 'vs/editor/common/editorCommon';
1717
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
@@ -79,6 +79,7 @@ export interface ISerializedFontInfo {
7979
readonly fontFamily: string;
8080
readonly fontWeight: string;
8181
readonly fontSize: number;
82+
fontFeatureSettings: string;
8283
readonly lineHeight: number;
8384
readonly letterSpacing: number;
8485
readonly isMonospace: boolean;
@@ -151,11 +152,14 @@ class CSSBasedConfiguration extends Disposable {
151152
return this._cache.getValues().filter(item => item.isTrusted);
152153
}
153154

154-
public restoreFontInfo(savedFontInfo: ISerializedFontInfo[]): void {
155+
public restoreFontInfo(savedFontInfos: ISerializedFontInfo[]): void {
155156
// Take all the saved font info and insert them in the cache without the trusted flag.
156157
// The reason for this is that a font might have been installed on the OS in the meantime.
157-
for (let i = 0, len = savedFontInfo.length; i < len; i++) {
158-
const fontInfo = new FontInfo(savedFontInfo[i], false);
158+
for (let i = 0, len = savedFontInfos.length; i < len; i++) {
159+
const savedFontInfo = savedFontInfos[i];
160+
// compatibility with older versions of VS Code which did not store this...
161+
savedFontInfo.fontFeatureSettings = savedFontInfo.fontFeatureSettings || EditorFontLigatures.OFF;
162+
const fontInfo = new FontInfo(savedFontInfo, false);
159163
this._writeToCache(fontInfo, fontInfo);
160164
}
161165
}
@@ -171,6 +175,7 @@ class CSSBasedConfiguration extends Disposable {
171175
fontFamily: readConfig.fontFamily,
172176
fontWeight: readConfig.fontWeight,
173177
fontSize: readConfig.fontSize,
178+
fontFeatureSettings: readConfig.fontFeatureSettings,
174179
lineHeight: readConfig.lineHeight,
175180
letterSpacing: readConfig.letterSpacing,
176181
isMonospace: readConfig.isMonospace,
@@ -249,9 +254,9 @@ class CSSBasedConfiguration extends Disposable {
249254

250255
const maxDigitWidth = Math.max(digit0.width, digit1.width, digit2.width, digit3.width, digit4.width, digit5.width, digit6.width, digit7.width, digit8.width, digit9.width);
251256

252-
let isMonospace = true;
257+
let isMonospace = (bareFontInfo.fontFeatureSettings === EditorFontLigatures.OFF);
253258
const referenceWidth = monospace[0].width;
254-
for (let i = 1, len = monospace.length; i < len; i++) {
259+
for (let i = 1, len = monospace.length; isMonospace && i < len; i++) {
255260
const diff = referenceWidth - monospace[i].width;
256261
if (diff < -0.001 || diff > 0.001) {
257262
isMonospace = false;
@@ -276,6 +281,7 @@ class CSSBasedConfiguration extends Disposable {
276281
fontFamily: bareFontInfo.fontFamily,
277282
fontWeight: bareFontInfo.fontWeight,
278283
fontSize: bareFontInfo.fontSize,
284+
fontFeatureSettings: bareFontInfo.fontFeatureSettings,
279285
lineHeight: bareFontInfo.lineHeight,
280286
letterSpacing: bareFontInfo.letterSpacing,
281287
isMonospace: isMonospace,
@@ -294,6 +300,7 @@ export class Configuration extends CommonEditorConfiguration {
294300
domNode.style.fontFamily = fontInfo.getMassagedFontFamily();
295301
domNode.style.fontWeight = fontInfo.fontWeight;
296302
domNode.style.fontSize = fontInfo.fontSize + 'px';
303+
domNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings;
297304
domNode.style.lineHeight = fontInfo.lineHeight + 'px';
298305
domNode.style.letterSpacing = fontInfo.letterSpacing + 'px';
299306
}
@@ -302,6 +309,7 @@ export class Configuration extends CommonEditorConfiguration {
302309
domNode.setFontFamily(fontInfo.getMassagedFontFamily());
303310
domNode.setFontWeight(fontInfo.fontWeight);
304311
domNode.setFontSize(fontInfo.fontSize);
312+
domNode.setFontFeatureSettings(fontInfo.fontFeatureSettings);
305313
domNode.setLineHeight(fontInfo.lineHeight);
306314
domNode.setLetterSpacing(fontInfo.letterSpacing);
307315
}

src/vs/editor/browser/viewParts/lines/viewLine.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine,
1616
import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';
1717
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
1818
import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService';
19-
import { EditorOption } from 'vs/editor/common/config/editorOptions';
19+
import { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
2020

2121
const canUseFastRenderedViewLine = (function () {
2222
if (platform.isNative) {
@@ -77,7 +77,7 @@ export class ViewLineOptions {
7777
public readonly canUseHalfwidthRightwardsArrow: boolean;
7878
public readonly lineHeight: number;
7979
public readonly stopRenderingLineAfter: number;
80-
public readonly fontLigatures: boolean;
80+
public readonly fontLigatures: string;
8181

8282
constructor(config: IConfiguration, themeType: ThemeType) {
8383
this.themeType = themeType;
@@ -89,7 +89,6 @@ export class ViewLineOptions {
8989
this.useMonospaceOptimizations = (
9090
fontInfo.isMonospace
9191
&& !options.get(EditorOption.disableMonospaceOptimizations)
92-
&& !options.get(EditorOption.fontLigatures)
9392
);
9493
this.canUseHalfwidthRightwardsArrow = fontInfo.canUseHalfwidthRightwardsArrow;
9594
this.lineHeight = options.get(EditorOption.lineHeight);
@@ -218,7 +217,7 @@ export class ViewLine implements IVisibleLine {
218217
options.stopRenderingLineAfter,
219218
options.renderWhitespace,
220219
options.renderControlCharacters,
221-
options.fontLigatures,
220+
options.fontLigatures !== EditorFontLigatures.OFF,
222221
selectionsOnLine
223222
);
224223

src/vs/editor/browser/widget/diffEditorWidget.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser';
2020
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
2121
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
2222
import { DiffReview } from 'vs/editor/browser/widget/diffReview';
23-
import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions';
23+
import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
2424
import { IPosition, Position } from 'vs/editor/common/core/position';
2525
import { IRange, Range } from 'vs/editor/common/core/range';
2626
import { ISelection, Selection } from 'vs/editor/common/core/selection';
@@ -2060,7 +2060,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
20602060
const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII());
20612061
const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL());
20622062
const output = renderViewLine(new RenderLineInput(
2063-
(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)),
2063+
(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)),
20642064
fontInfo.canUseHalfwidthRightwardsArrow,
20652065
lineContent,
20662066
false,
@@ -2074,7 +2074,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
20742074
options.get(EditorOption.stopRenderingLineAfter),
20752075
options.get(EditorOption.renderWhitespace),
20762076
options.get(EditorOption.renderControlCharacters),
2077-
options.get(EditorOption.fontLigatures),
2077+
options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF,
20782078
null // Send no selections, original line cannot be selected
20792079
), sb);
20802080

src/vs/editor/browser/widget/diffReview.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1717
import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';
1818
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
1919
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
20-
import { IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';
20+
import { IComputedEditorOptions, EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
2121
import { LineTokens } from 'vs/editor/common/core/lineTokens';
2222
import { Position } from 'vs/editor/common/core/position';
2323
import { ILineChange, ScrollType } from 'vs/editor/common/editorCommon';
@@ -770,7 +770,7 @@ export class DiffReview extends Disposable {
770770
const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII());
771771
const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL());
772772
const r = renderViewLine(new RenderLineInput(
773-
(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)),
773+
(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)),
774774
fontInfo.canUseHalfwidthRightwardsArrow,
775775
lineContent,
776776
false,
@@ -784,7 +784,7 @@ export class DiffReview extends Disposable {
784784
options.get(EditorOption.stopRenderingLineAfter),
785785
options.get(EditorOption.renderWhitespace),
786786
options.get(EditorOption.renderControlCharacters),
787-
options.get(EditorOption.fontLigatures),
787+
options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF,
788788
null
789789
));
790790

src/vs/editor/browser/widget/media/editor.css

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@
2121
position: relative;
2222
overflow: visible;
2323
-webkit-text-size-adjust: 100%;
24-
-webkit-font-feature-settings: "liga" off, "calt" off;
25-
font-feature-settings: "liga" off, "calt" off;
26-
}
27-
.monaco-editor.enable-ligatures {
28-
-webkit-font-feature-settings: "liga" on, "calt" on;
29-
font-feature-settings: "liga" on, "calt" on;
3024
}
3125

3226
/* -------------------- Misc -------------------- */

src/vs/editor/common/config/editorOptions.ts

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export interface IEditorOptions {
178178
* Enable font ligatures.
179179
* Defaults to false.
180180
*/
181-
fontLigatures?: boolean;
181+
fontLigatures?: boolean | string;
182182
/**
183183
* Disable the use of `will-change` for the editor margin and lines layers.
184184
* The usage of `will-change` acts as a hint for browsers to create an extra layer.
@@ -641,6 +641,9 @@ export interface IEditorOption<K1 extends EditorOption, V> {
641641
type PossibleKeyName0<V> = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions];
642642
type PossibleKeyName<V> = NonNullable<PossibleKeyName0<V>>;
643643

644+
/**
645+
* @internal
646+
*/
644647
abstract class BaseEditorOption<K1 extends EditorOption, V> implements IEditorOption<K1, V> {
645648

646649
public readonly id: K1;
@@ -1044,7 +1047,7 @@ function _cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'l
10441047
class EditorClassName extends ComputedEditorOption<EditorOption.editorClassName, string> {
10451048

10461049
constructor() {
1047-
super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.fontLigatures, EditorOption.extraEditorClassName]);
1050+
super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.extraEditorClassName]);
10481051
}
10491052

10501053
public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string {
@@ -1055,9 +1058,6 @@ class EditorClassName extends ComputedEditorOption<EditorOption.editorClassName,
10551058
if (env.extraEditorClassName) {
10561059
className += ' ' + env.extraEditorClassName;
10571060
}
1058-
if (options.get(EditorOption.fontLigatures)) {
1059-
className += ' enable-ligatures';
1060-
}
10611061
if (options.get(EditorOption.mouseStyle) === 'default') {
10621062
className += ' mouse-default';
10631063
} else if (options.get(EditorOption.mouseStyle) === 'copy') {
@@ -1167,6 +1167,57 @@ class EditorFind extends BaseEditorOption<EditorOption.find, EditorFindOptions>
11671167

11681168
//#endregion
11691169

1170+
//#region fontLigatures
1171+
1172+
/**
1173+
* @internal
1174+
*/
1175+
export class EditorFontLigatures extends BaseEditorOption<EditorOption.fontLigatures, string> {
1176+
1177+
public static OFF = '"liga" off, "calt" off';
1178+
public static ON = '"liga" on, "calt" on';
1179+
1180+
constructor() {
1181+
super(
1182+
EditorOption.fontLigatures, 'fontLigatures', EditorFontLigatures.OFF,
1183+
{
1184+
anyOf: [
1185+
{
1186+
type: 'boolean',
1187+
description: nls.localize('fontLigatures', "Enables/Disables font ligatures."),
1188+
},
1189+
{
1190+
type: 'string',
1191+
description: nls.localize('fontFeatureSettings', "Explicit font-feature-settings.")
1192+
}
1193+
],
1194+
default: false
1195+
}
1196+
);
1197+
}
1198+
1199+
public validate(input: any): string {
1200+
if (typeof input === 'undefined') {
1201+
return this.defaultValue;
1202+
}
1203+
if (typeof input === 'string') {
1204+
if (input === 'false') {
1205+
return EditorFontLigatures.OFF;
1206+
}
1207+
if (input === 'true') {
1208+
return EditorFontLigatures.ON;
1209+
}
1210+
return input;
1211+
}
1212+
if (Boolean(input)) {
1213+
return EditorFontLigatures.ON;
1214+
}
1215+
return EditorFontLigatures.OFF;
1216+
}
1217+
}
1218+
1219+
//#endregion
1220+
11701221
//#region fontInfo
11711222

11721223
class EditorFontInfo extends ComputedEditorOption<EditorOption.fontInfo, FontInfo> {
@@ -2910,10 +2961,7 @@ export const EditorOptions = {
29102961
{ description: nls.localize('fontFamily', "Controls the font family.") }
29112962
)),
29122963
fontInfo: register(new EditorFontInfo()),
2913-
fontLigatures: register(new EditorBooleanOption(
2914-
EditorOption.fontLigatures, 'fontLigatures', false,
2915-
{ description: nls.localize('fontLigatures', "Enables/Disables font ligatures.") }
2916-
)),
2964+
fontLigatures2: register(new EditorFontLigatures()),
29172965
fontSize: register(new EditorFontSize()),
29182966
fontWeight: register(new EditorStringOption(
29192967
EditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight,

0 commit comments

Comments
 (0)