mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-01 01:25:38 -05:00
Merge VS Code 1.23.1 (#1520)
This commit is contained in:
@@ -12,6 +12,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { EditorAction, EditorExtensionsRegistry, IEditorContributionCtor } from 'vs/editor/browser/editorExtensions';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export class CodeEditor extends CodeEditorWidget {
|
||||
|
||||
@@ -22,9 +23,10 @@ export class CodeEditor extends CodeEditorWidget {
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IThemeService themeService: IThemeService
|
||||
@IThemeService themeService: IThemeService,
|
||||
@INotificationService notificationService: INotificationService
|
||||
) {
|
||||
super(domElement, options, instantiationService, codeEditorService, commandService, contextKeyService, themeService);
|
||||
super(domElement, options, false, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService);
|
||||
}
|
||||
|
||||
protected _getContributions(): IEditorContributionCtor[] {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
@@ -102,7 +102,7 @@ class CSSBasedConfiguration extends Disposable {
|
||||
private _evictUntrustedReadingsTimeout: number;
|
||||
|
||||
private _onDidChange = this._register(new Emitter<void>());
|
||||
public onDidChange: Event<void> = this._onDidChange.event;
|
||||
public readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -276,8 +276,21 @@ class CSSBasedConfiguration extends Disposable {
|
||||
|
||||
export class Configuration extends CommonEditorConfiguration {
|
||||
|
||||
private static _massageFontFamily(fontFamily: string): string {
|
||||
if (/[,"']/.test(fontFamily)) {
|
||||
// Looks like the font family might be already escaped
|
||||
return fontFamily;
|
||||
}
|
||||
if (/[+ ]/.test(fontFamily)) {
|
||||
// Wrap a font family using + or <space> with quotes
|
||||
return `"${fontFamily}"`;
|
||||
}
|
||||
|
||||
return fontFamily;
|
||||
}
|
||||
|
||||
public static applyFontInfoSlow(domNode: HTMLElement, fontInfo: BareFontInfo): void {
|
||||
domNode.style.fontFamily = fontInfo.fontFamily;
|
||||
domNode.style.fontFamily = Configuration._massageFontFamily(fontInfo.fontFamily);
|
||||
domNode.style.fontWeight = fontInfo.fontWeight;
|
||||
domNode.style.fontSize = fontInfo.fontSize + 'px';
|
||||
domNode.style.lineHeight = fontInfo.lineHeight + 'px';
|
||||
@@ -285,7 +298,7 @@ export class Configuration extends CommonEditorConfiguration {
|
||||
}
|
||||
|
||||
public static applyFontInfo(domNode: FastDomNode<HTMLElement>, fontInfo: BareFontInfo): void {
|
||||
domNode.setFontFamily(fontInfo.fontFamily);
|
||||
domNode.setFontFamily(Configuration._massageFontFamily(fontInfo.fontFamily));
|
||||
domNode.setFontWeight(fontInfo.fontWeight);
|
||||
domNode.setFontSize(fontInfo.fontSize);
|
||||
domNode.setLineHeight(fontInfo.lineHeight);
|
||||
@@ -349,7 +362,7 @@ export class Configuration extends CommonEditorConfiguration {
|
||||
extraEditorClassName: this._getExtraEditorClassName(),
|
||||
outerWidth: this._elementSizeObserver.getWidth(),
|
||||
outerHeight: this._elementSizeObserver.getHeight(),
|
||||
emptySelectionClipboard: browser.isWebKit,
|
||||
emptySelectionClipboard: browser.isWebKit || browser.isFirefox,
|
||||
pixelRatio: browser.getPixelRatio(),
|
||||
zoomLevel: browser.getZoomLevel(),
|
||||
accessibilitySupport: browser.getAccessibilitySupport()
|
||||
|
||||
@@ -325,7 +325,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow,
|
||||
linux: { primary: 0 }
|
||||
}
|
||||
@@ -344,7 +344,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow,
|
||||
linux: { primary: 0 }
|
||||
}
|
||||
@@ -376,7 +376,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow,
|
||||
linux: { primary: 0 }
|
||||
}
|
||||
@@ -388,7 +388,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageUp,
|
||||
linux: { primary: 0 }
|
||||
}
|
||||
@@ -414,7 +414,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow,
|
||||
linux: { primary: 0 }
|
||||
}
|
||||
@@ -426,7 +426,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageDown,
|
||||
linux: { primary: 0 }
|
||||
}
|
||||
@@ -502,7 +502,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.LeftArrow,
|
||||
mac: { primary: KeyCode.LeftArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_B] }
|
||||
}
|
||||
@@ -519,7 +519,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.LeftArrow
|
||||
}
|
||||
}));
|
||||
@@ -535,7 +535,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.RightArrow,
|
||||
mac: { primary: KeyCode.RightArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_F] }
|
||||
}
|
||||
@@ -552,7 +552,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.RightArrow
|
||||
}
|
||||
}));
|
||||
@@ -568,7 +568,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.UpArrow,
|
||||
mac: { primary: KeyCode.UpArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_P] }
|
||||
}
|
||||
@@ -585,7 +585,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.UpArrow,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow],
|
||||
mac: { primary: KeyMod.Shift | KeyCode.UpArrow },
|
||||
@@ -604,7 +604,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.PageUp
|
||||
}
|
||||
}));
|
||||
@@ -620,7 +620,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.PageUp
|
||||
}
|
||||
}));
|
||||
@@ -636,7 +636,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.DownArrow,
|
||||
mac: { primary: KeyCode.DownArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_N] }
|
||||
}
|
||||
@@ -653,7 +653,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.DownArrow,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow],
|
||||
mac: { primary: KeyMod.Shift | KeyCode.DownArrow },
|
||||
@@ -672,7 +672,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.PageDown
|
||||
}
|
||||
}));
|
||||
@@ -688,7 +688,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.PageDown
|
||||
}
|
||||
}));
|
||||
@@ -813,7 +813,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.Home,
|
||||
mac: { primary: KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyCode.LeftArrow] }
|
||||
}
|
||||
@@ -825,7 +825,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.Home,
|
||||
mac: { primary: KeyMod.Shift | KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow] }
|
||||
}
|
||||
@@ -838,7 +838,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: 0,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_A }
|
||||
}
|
||||
@@ -892,7 +892,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.End,
|
||||
mac: { primary: KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyCode.RightArrow] }
|
||||
}
|
||||
@@ -904,7 +904,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.Shift | KeyCode.End,
|
||||
mac: { primary: KeyMod.Shift | KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow] }
|
||||
}
|
||||
@@ -917,7 +917,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: 0,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_E }
|
||||
}
|
||||
@@ -972,7 +972,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.Home,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }
|
||||
}
|
||||
@@ -984,7 +984,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Home,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }
|
||||
}
|
||||
@@ -1016,7 +1016,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.End,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }
|
||||
}
|
||||
@@ -1028,7 +1028,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.End,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }
|
||||
}
|
||||
@@ -1112,7 +1112,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.UpArrow,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.PageUp }
|
||||
}
|
||||
@@ -1137,7 +1137,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.PageUp,
|
||||
win: { primary: KeyMod.Alt | KeyCode.PageUp },
|
||||
linux: { primary: KeyMod.Alt | KeyCode.PageUp }
|
||||
@@ -1163,7 +1163,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.DownArrow,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.PageDown }
|
||||
}
|
||||
@@ -1188,7 +1188,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.PageDown,
|
||||
win: { primary: KeyMod.Alt | KeyCode.PageDown },
|
||||
linux: { primary: KeyMod.Alt | KeyCode.PageDown }
|
||||
@@ -1351,7 +1351,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_I
|
||||
}
|
||||
});
|
||||
@@ -1376,7 +1376,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: EditorContextKeys.hasNonEmptySelection,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.Escape,
|
||||
secondary: [KeyMod.Shift | KeyCode.Escape]
|
||||
}
|
||||
@@ -1403,7 +1403,7 @@ export namespace CoreNavigationCommands {
|
||||
precondition: EditorContextKeys.hasMultipleSelections,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT + 1,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.Escape,
|
||||
secondary: [KeyMod.Shift | KeyCode.Escape]
|
||||
}
|
||||
@@ -1521,7 +1521,7 @@ export namespace CoreEditingCommands {
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: null,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_O }
|
||||
}
|
||||
@@ -1542,7 +1542,7 @@ export namespace CoreEditingCommands {
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: ContextKeyExpr.and(
|
||||
EditorContextKeys.textFocus,
|
||||
EditorContextKeys.editorTextFocus,
|
||||
EditorContextKeys.tabDoesNotMoveFocus
|
||||
),
|
||||
primary: KeyMod.Shift | KeyCode.Tab
|
||||
@@ -1565,7 +1565,7 @@ export namespace CoreEditingCommands {
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: ContextKeyExpr.and(
|
||||
EditorContextKeys.textFocus,
|
||||
EditorContextKeys.editorTextFocus,
|
||||
EditorContextKeys.tabDoesNotMoveFocus
|
||||
),
|
||||
primary: KeyCode.Tab
|
||||
@@ -1587,7 +1587,7 @@ export namespace CoreEditingCommands {
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.Backspace,
|
||||
secondary: [KeyMod.Shift | KeyCode.Backspace],
|
||||
mac: { primary: KeyCode.Backspace, secondary: [KeyMod.Shift | KeyCode.Backspace, KeyMod.WinCtrl | KeyCode.KEY_H, KeyMod.WinCtrl | KeyCode.Backspace] }
|
||||
@@ -1613,7 +1613,7 @@ export namespace CoreEditingCommands {
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyCode.Delete,
|
||||
mac: { primary: KeyCode.Delete, secondary: [KeyMod.WinCtrl | KeyCode.KEY_D, KeyMod.WinCtrl | KeyCode.Delete] }
|
||||
}
|
||||
@@ -1743,7 +1743,7 @@ registerCommand(new EditorOrNativeTextInputCommand({
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
|
||||
}
|
||||
}));
|
||||
@@ -1756,7 +1756,7 @@ registerCommand(new EditorOrNativeTextInputCommand({
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
|
||||
|
||||
@@ -11,7 +11,7 @@ import * as dom from 'vs/base/browser/dom';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
import { MouseTarget, MouseTargetFactory, IViewZoneData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { MouseTarget, MouseTargetFactory, IViewZoneData, HitTestContext } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
|
||||
import { TimeoutTimer, RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { ViewContext } from 'vs/editor/common/view/viewContext';
|
||||
@@ -220,8 +220,8 @@ export class MouseHandler extends ViewEventHandler {
|
||||
let targetIsViewZone = (t.type === editorBrowser.MouseTargetType.CONTENT_VIEW_ZONE || t.type === editorBrowser.MouseTargetType.GUTTER_VIEW_ZONE);
|
||||
let targetIsWidget = (t.type === editorBrowser.MouseTargetType.CONTENT_WIDGET);
|
||||
|
||||
let shouldHandle = e.leftButton;
|
||||
if (platform.isMacintosh && e.ctrlKey) {
|
||||
let shouldHandle = e.leftButton || e.middleButton;
|
||||
if (platform.isMacintosh && e.leftButton && e.ctrlKey) {
|
||||
shouldHandle = false;
|
||||
}
|
||||
|
||||
@@ -334,6 +334,7 @@ class MouseDownOperation extends Disposable {
|
||||
this._lastMouseEvent = e;
|
||||
|
||||
this._mouseState.setStartedOnLineNumbers(targetType === editorBrowser.MouseTargetType.GUTTER_LINE_NUMBERS);
|
||||
this._mouseState.setStartButtons(e);
|
||||
this._mouseState.setModifiers(e);
|
||||
let position = this._findMousePosition(e, true);
|
||||
if (!position) {
|
||||
@@ -423,12 +424,30 @@ class MouseDownOperation extends Disposable {
|
||||
const mouseColumn = this._getMouseColumn(e);
|
||||
|
||||
if (e.posy < editorContent.y) {
|
||||
let aboveLineNumber = viewLayout.getLineNumberAtVerticalOffset(Math.max(viewLayout.getCurrentScrollTop() - (editorContent.y - e.posy), 0));
|
||||
const verticalOffset = Math.max(viewLayout.getCurrentScrollTop() - (editorContent.y - e.posy), 0);
|
||||
const viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset);
|
||||
if (viewZoneData) {
|
||||
const newPosition = this._helpPositionJumpOverViewZone(viewZoneData);
|
||||
if (newPosition) {
|
||||
return new MouseTarget(null, editorBrowser.MouseTargetType.OUTSIDE_EDITOR, mouseColumn, newPosition);
|
||||
}
|
||||
}
|
||||
|
||||
let aboveLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset);
|
||||
return new MouseTarget(null, editorBrowser.MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(aboveLineNumber, 1));
|
||||
}
|
||||
|
||||
if (e.posy > editorContent.y + editorContent.height) {
|
||||
let belowLineNumber = viewLayout.getLineNumberAtVerticalOffset(viewLayout.getCurrentScrollTop() + (e.posy - editorContent.y));
|
||||
const verticalOffset = viewLayout.getCurrentScrollTop() + (e.posy - editorContent.y);
|
||||
const viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset);
|
||||
if (viewZoneData) {
|
||||
const newPosition = this._helpPositionJumpOverViewZone(viewZoneData);
|
||||
if (newPosition) {
|
||||
return new MouseTarget(null, editorBrowser.MouseTargetType.OUTSIDE_EDITOR, mouseColumn, newPosition);
|
||||
}
|
||||
}
|
||||
|
||||
let belowLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset);
|
||||
return new MouseTarget(null, editorBrowser.MouseTargetType.OUTSIDE_EDITOR, mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber)));
|
||||
}
|
||||
|
||||
@@ -458,24 +477,31 @@ class MouseDownOperation extends Disposable {
|
||||
}
|
||||
|
||||
if (t.type === editorBrowser.MouseTargetType.CONTENT_VIEW_ZONE || t.type === editorBrowser.MouseTargetType.GUTTER_VIEW_ZONE) {
|
||||
// Force position on view zones to go above or below depending on where selection started from
|
||||
let selectionStart = new Position(this._currentSelection.selectionStartLineNumber, this._currentSelection.selectionStartColumn);
|
||||
let viewZoneData = <IViewZoneData>t.detail;
|
||||
let positionBefore = viewZoneData.positionBefore;
|
||||
let positionAfter = viewZoneData.positionAfter;
|
||||
|
||||
if (positionBefore && positionAfter) {
|
||||
if (positionBefore.isBefore(selectionStart)) {
|
||||
return new MouseTarget(t.element, t.type, t.mouseColumn, positionBefore, null, t.detail);
|
||||
} else {
|
||||
return new MouseTarget(t.element, t.type, t.mouseColumn, positionAfter, null, t.detail);
|
||||
}
|
||||
const newPosition = this._helpPositionJumpOverViewZone(<IViewZoneData>t.detail);
|
||||
if (newPosition) {
|
||||
return new MouseTarget(t.element, t.type, t.mouseColumn, newPosition, null, t.detail);
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
private _helpPositionJumpOverViewZone(viewZoneData: IViewZoneData): Position {
|
||||
// Force position on view zones to go above or below depending on where selection started from
|
||||
let selectionStart = new Position(this._currentSelection.selectionStartLineNumber, this._currentSelection.selectionStartColumn);
|
||||
let positionBefore = viewZoneData.positionBefore;
|
||||
let positionAfter = viewZoneData.positionAfter;
|
||||
|
||||
if (positionBefore && positionAfter) {
|
||||
if (positionBefore.isBefore(selectionStart)) {
|
||||
return positionBefore;
|
||||
} else {
|
||||
return positionAfter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private _dispatchMouse(position: MouseTarget, inSelectionMode: boolean): void {
|
||||
this._viewController.dispatchMouse({
|
||||
position: position.position,
|
||||
@@ -488,6 +514,9 @@ class MouseDownOperation extends Disposable {
|
||||
ctrlKey: this._mouseState.ctrlKey,
|
||||
metaKey: this._mouseState.metaKey,
|
||||
shiftKey: this._mouseState.shiftKey,
|
||||
|
||||
leftButton: this._mouseState.leftButton,
|
||||
middleButton: this._mouseState.middleButton,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -508,6 +537,12 @@ class MouseDownState {
|
||||
private _shiftKey: boolean;
|
||||
public get shiftKey(): boolean { return this._shiftKey; }
|
||||
|
||||
private _leftButton: boolean;
|
||||
public get leftButton(): boolean { return this._leftButton; }
|
||||
|
||||
private _middleButton: boolean;
|
||||
public get middleButton(): boolean { return this._middleButton; }
|
||||
|
||||
private _startedOnLineNumbers: boolean;
|
||||
public get startedOnLineNumbers(): boolean { return this._startedOnLineNumbers; }
|
||||
|
||||
@@ -522,6 +557,8 @@ class MouseDownState {
|
||||
this._ctrlKey = false;
|
||||
this._metaKey = false;
|
||||
this._shiftKey = false;
|
||||
this._leftButton = false;
|
||||
this._middleButton = false;
|
||||
this._startedOnLineNumbers = false;
|
||||
this._lastMouseDownPosition = null;
|
||||
this._lastMouseDownPositionEqualCount = 0;
|
||||
@@ -541,6 +578,11 @@ class MouseDownState {
|
||||
this._shiftKey = source.shiftKey;
|
||||
}
|
||||
|
||||
public setStartButtons(source: EditorMouseEvent) {
|
||||
this._leftButton = source.leftButton;
|
||||
this._middleButton = source.middleButton;
|
||||
}
|
||||
|
||||
public setStartedOnLineNumbers(startedOnLineNumbers: boolean): void {
|
||||
this._startedOnLineNumbers = startedOnLineNumbers;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPa
|
||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions';
|
||||
import { ViewLine } from 'vs/editor/browser/viewParts/lines/viewLine';
|
||||
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
|
||||
|
||||
export interface IViewZoneData {
|
||||
viewZoneId: number;
|
||||
@@ -34,6 +35,7 @@ export interface IMarginData {
|
||||
|
||||
export interface IEmptyContentData {
|
||||
isAfterLines: boolean;
|
||||
horizontalDistanceToText?: number;
|
||||
}
|
||||
|
||||
interface IETextRange {
|
||||
@@ -174,6 +176,14 @@ class ElementPath {
|
||||
);
|
||||
}
|
||||
|
||||
public static isStrictChildOfViewLines(path: Uint8Array): boolean {
|
||||
return (
|
||||
path.length > 4
|
||||
&& path[0] === PartFingerprint.OverflowGuard
|
||||
&& path[3] === PartFingerprint.ViewLines
|
||||
);
|
||||
}
|
||||
|
||||
public static isChildOfScrollableElement(path: Uint8Array): boolean {
|
||||
return (
|
||||
path.length >= 2
|
||||
@@ -214,7 +224,7 @@ class ElementPath {
|
||||
}
|
||||
}
|
||||
|
||||
class HitTestContext {
|
||||
export class HitTestContext {
|
||||
|
||||
public readonly model: IViewModel;
|
||||
public readonly layoutInfo: EditorLayoutInfo;
|
||||
@@ -238,12 +248,16 @@ class HitTestContext {
|
||||
}
|
||||
|
||||
public getZoneAtCoord(mouseVerticalOffset: number): IViewZoneData {
|
||||
return HitTestContext.getZoneAtCoord(this._context, mouseVerticalOffset);
|
||||
}
|
||||
|
||||
public static getZoneAtCoord(context: ViewContext, mouseVerticalOffset: number): IViewZoneData {
|
||||
// The target is either a view zone or the empty space after the last view-line
|
||||
let viewZoneWhitespace = this._context.viewLayout.getWhitespaceAtVerticalOffset(mouseVerticalOffset);
|
||||
let viewZoneWhitespace = context.viewLayout.getWhitespaceAtVerticalOffset(mouseVerticalOffset);
|
||||
|
||||
if (viewZoneWhitespace) {
|
||||
let viewZoneMiddle = viewZoneWhitespace.verticalOffset + viewZoneWhitespace.height / 2,
|
||||
lineCount = this._context.model.getLineCount(),
|
||||
lineCount = context.model.getLineCount(),
|
||||
positionBefore: Position = null,
|
||||
position: Position,
|
||||
positionAfter: Position = null;
|
||||
@@ -254,7 +268,7 @@ class HitTestContext {
|
||||
}
|
||||
if (viewZoneWhitespace.afterLineNumber > 0) {
|
||||
// There are more lines above this view zone
|
||||
positionBefore = new Position(viewZoneWhitespace.afterLineNumber, this._context.model.getLineMaxColumn(viewZoneWhitespace.afterLineNumber));
|
||||
positionBefore = new Position(viewZoneWhitespace.afterLineNumber, context.model.getLineMaxColumn(viewZoneWhitespace.afterLineNumber));
|
||||
}
|
||||
|
||||
if (positionAfter === null) {
|
||||
@@ -330,7 +344,7 @@ class HitTestContext {
|
||||
return this._viewHelper.getLineWidth(lineNumber);
|
||||
}
|
||||
|
||||
public visibleRangeForPosition2(lineNumber: number, column: number) {
|
||||
public visibleRangeForPosition2(lineNumber: number, column: number): HorizontalRange {
|
||||
return this._viewHelper.visibleRangeForPosition2(lineNumber, column);
|
||||
}
|
||||
|
||||
@@ -402,7 +416,13 @@ class HitTestRequest extends BareHitTestRequest {
|
||||
}
|
||||
|
||||
const EMPTY_CONTENT_AFTER_LINES: IEmptyContentData = { isAfterLines: true };
|
||||
const EMPTY_CONTENT_IN_LINES: IEmptyContentData = { isAfterLines: false };
|
||||
|
||||
function createEmptyContentDataInLines(horizontalDistanceToText: number): IEmptyContentData {
|
||||
return {
|
||||
isAfterLines: false,
|
||||
horizontalDistanceToText: horizontalDistanceToText
|
||||
};
|
||||
}
|
||||
|
||||
export class MouseTargetFactory {
|
||||
|
||||
@@ -621,6 +641,17 @@ export class MouseTargetFactory {
|
||||
}
|
||||
|
||||
if (domHitTestExecuted) {
|
||||
// Check if we are hitting a view-line (can happen in the case of inline decorations on empty lines)
|
||||
// See https://github.com/Microsoft/vscode/issues/46942
|
||||
if (ElementPath.isStrictChildOfViewLines(request.targetPath)) {
|
||||
const lineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);
|
||||
if (ctx.model.getLineLength(lineNumber) === 0) {
|
||||
const lineWidth = ctx.getLineWidth(lineNumber);
|
||||
const detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);
|
||||
return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, 1), void 0, detail);
|
||||
}
|
||||
}
|
||||
|
||||
// We have already executed hit test...
|
||||
return request.fulfill(MouseTargetType.UNKNOWN);
|
||||
}
|
||||
@@ -691,9 +722,11 @@ export class MouseTargetFactory {
|
||||
if (request.mouseContentHorizontalOffset > lineWidth) {
|
||||
if (browser.isEdge && pos.column === 1) {
|
||||
// See https://github.com/Microsoft/vscode/issues/10875
|
||||
return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, ctx.model.getLineMaxColumn(lineNumber)), void 0, EMPTY_CONTENT_IN_LINES);
|
||||
const detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);
|
||||
return request.fulfill(MouseTargetType.CONTENT_EMPTY, new Position(lineNumber, ctx.model.getLineMaxColumn(lineNumber)), void 0, detail);
|
||||
}
|
||||
return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, void 0, EMPTY_CONTENT_IN_LINES);
|
||||
const detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);
|
||||
return request.fulfill(MouseTargetType.CONTENT_EMPTY, pos, void 0, detail);
|
||||
}
|
||||
|
||||
const visibleRange = ctx.visibleRangeForPosition2(lineNumber, column);
|
||||
|
||||
@@ -228,7 +228,7 @@ export class PointerHandler implements IDisposable {
|
||||
this.handler = new MsPointerHandler(context, viewController, viewHelper);
|
||||
} else if ((<any>window).TouchEvent) {
|
||||
this.handler = new TouchHandler(context, viewController, viewHelper);
|
||||
} else if (window.navigator.pointerEnabled) {
|
||||
} else if (window.navigator.pointerEnabled || (<any>window).PointerEvent) {
|
||||
this.handler = new StandardPointerHandler(context, viewController, viewHelper);
|
||||
} else {
|
||||
this.handler = new MouseHandler(context, viewController, viewHelper);
|
||||
|
||||
@@ -27,6 +27,7 @@ import { LineNumbersOverlay } from 'vs/editor/browser/viewParts/lineNumbers/line
|
||||
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { getMapForWordSeparators, WordCharacterClass } from 'vs/editor/common/controller/wordCharacterClassifier';
|
||||
|
||||
export interface ITextAreaHandlerHelper {
|
||||
visibleRangeForPositionRelativeToEditor(lineNumber: number, column: number): HorizontalRange;
|
||||
@@ -163,7 +164,7 @@ export class TextAreaHandler extends ViewPart {
|
||||
|
||||
const textAreaInputHost: ITextAreaInputHost = {
|
||||
getPlainTextToCopy: (): string => {
|
||||
const rawWhatToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard);
|
||||
const rawWhatToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard, platform.isWindows);
|
||||
const newLineCharacter = this._context.model.getEOL();
|
||||
|
||||
const isFromEmptySelection = (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty());
|
||||
@@ -203,16 +204,19 @@ export class TextAreaHandler extends ViewPart {
|
||||
if (this._accessibilitySupport === platform.AccessibilitySupport.Disabled) {
|
||||
// We know for a fact that a screen reader is not attached
|
||||
// On OSX, we write the character before the cursor to allow for "long-press" composition
|
||||
// Also on OSX, we write the word before the cursor to allow for the Accessibility Keyboard to give good hints
|
||||
if (platform.isMacintosh) {
|
||||
const selection = this._selections[0];
|
||||
if (selection.isEmpty()) {
|
||||
const position = selection.getStartPosition();
|
||||
if (position.column > 1) {
|
||||
const lineContent = this._context.model.getLineContent(position.lineNumber);
|
||||
const charBefore = lineContent.charAt(position.column - 2);
|
||||
if (!strings.isHighSurrogate(charBefore.charCodeAt(0))) {
|
||||
return new TextAreaState(charBefore, 1, 1, position, position);
|
||||
}
|
||||
|
||||
let textBefore = this._getWordBeforePosition(position);
|
||||
if (textBefore.length === 0) {
|
||||
textBefore = this._getCharacterBeforePosition(position);
|
||||
}
|
||||
|
||||
if (textBefore.length > 0) {
|
||||
return new TextAreaState(textBefore, textBefore.length, textBefore.length, position, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,6 +332,35 @@ export class TextAreaHandler extends ViewPart {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private _getWordBeforePosition(position: Position): string {
|
||||
const lineContent = this._context.model.getLineContent(position.lineNumber);
|
||||
const wordSeparators = getMapForWordSeparators(this._context.configuration.editor.wordSeparators);
|
||||
|
||||
let column = position.column;
|
||||
let distance = 0;
|
||||
while (column > 1) {
|
||||
const charCode = lineContent.charCodeAt(column - 2);
|
||||
const charClass = wordSeparators.get(charCode);
|
||||
if (charClass !== WordCharacterClass.Regular || distance > 50) {
|
||||
return lineContent.substring(column - 1, position.column - 1);
|
||||
}
|
||||
distance++;
|
||||
column--;
|
||||
}
|
||||
return lineContent.substring(0, position.column - 1);
|
||||
}
|
||||
|
||||
private _getCharacterBeforePosition(position: Position): string {
|
||||
if (position.column > 1) {
|
||||
const lineContent = this._context.model.getLineContent(position.lineNumber);
|
||||
const charBefore = lineContent.charAt(position.column - 2);
|
||||
if (!strings.isHighSurrogate(charBefore.charCodeAt(0))) {
|
||||
return charBefore;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// --- begin event handlers
|
||||
|
||||
public onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {
|
||||
@@ -509,7 +542,7 @@ export class TextAreaHandler extends ViewPart {
|
||||
tac.setHeight(1);
|
||||
|
||||
if (this._context.configuration.editor.viewInfo.glyphMargin) {
|
||||
tac.setClassName('monaco-editor-background textAreaCover ' + Margin.CLASS_NAME);
|
||||
tac.setClassName('monaco-editor-background textAreaCover ' + Margin.OUTER_CLASS_NAME);
|
||||
} else {
|
||||
if (this._context.configuration.editor.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off) {
|
||||
tac.setClassName('monaco-editor-background textAreaCover ' + LineNumbersOverlay.CLASS_NAME);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ITypeData, TextAreaState, ITextAreaWrapper } from 'vs/editor/browser/controller/textAreaState';
|
||||
@@ -42,6 +42,19 @@ export interface ITextAreaInputHost {
|
||||
deduceModelPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position;
|
||||
}
|
||||
|
||||
const enum TextAreaInputEventType {
|
||||
none,
|
||||
compositionstart,
|
||||
compositionupdate,
|
||||
compositionend,
|
||||
input,
|
||||
cut,
|
||||
copy,
|
||||
paste,
|
||||
focus,
|
||||
blur
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes screen reader content to the textarea and is able to analyze its input events to generate:
|
||||
* - onCut
|
||||
@@ -53,42 +66,43 @@ export interface ITextAreaInputHost {
|
||||
export class TextAreaInput extends Disposable {
|
||||
|
||||
private _onFocus = this._register(new Emitter<void>());
|
||||
public onFocus: Event<void> = this._onFocus.event;
|
||||
public readonly onFocus: Event<void> = this._onFocus.event;
|
||||
|
||||
private _onBlur = this._register(new Emitter<void>());
|
||||
public onBlur: Event<void> = this._onBlur.event;
|
||||
public readonly onBlur: Event<void> = this._onBlur.event;
|
||||
|
||||
private _onKeyDown = this._register(new Emitter<IKeyboardEvent>());
|
||||
public onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;
|
||||
public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;
|
||||
|
||||
private _onKeyUp = this._register(new Emitter<IKeyboardEvent>());
|
||||
public onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
|
||||
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
|
||||
|
||||
private _onCut = this._register(new Emitter<void>());
|
||||
public onCut: Event<void> = this._onCut.event;
|
||||
public readonly onCut: Event<void> = this._onCut.event;
|
||||
|
||||
private _onPaste = this._register(new Emitter<IPasteData>());
|
||||
public onPaste: Event<IPasteData> = this._onPaste.event;
|
||||
public readonly onPaste: Event<IPasteData> = this._onPaste.event;
|
||||
|
||||
private _onType = this._register(new Emitter<ITypeData>());
|
||||
public onType: Event<ITypeData> = this._onType.event;
|
||||
public readonly onType: Event<ITypeData> = this._onType.event;
|
||||
|
||||
private _onCompositionStart = this._register(new Emitter<void>());
|
||||
public onCompositionStart: Event<void> = this._onCompositionStart.event;
|
||||
public readonly onCompositionStart: Event<void> = this._onCompositionStart.event;
|
||||
|
||||
private _onCompositionUpdate = this._register(new Emitter<ICompositionData>());
|
||||
public onCompositionUpdate: Event<ICompositionData> = this._onCompositionUpdate.event;
|
||||
public readonly onCompositionUpdate: Event<ICompositionData> = this._onCompositionUpdate.event;
|
||||
|
||||
private _onCompositionEnd = this._register(new Emitter<void>());
|
||||
public onCompositionEnd: Event<void> = this._onCompositionEnd.event;
|
||||
public readonly onCompositionEnd: Event<void> = this._onCompositionEnd.event;
|
||||
|
||||
private _onSelectionChangeRequest = this._register(new Emitter<Selection>());
|
||||
public onSelectionChangeRequest: Event<Selection> = this._onSelectionChangeRequest.event;
|
||||
public readonly onSelectionChangeRequest: Event<Selection> = this._onSelectionChangeRequest.event;
|
||||
|
||||
// ---
|
||||
|
||||
private readonly _host: ITextAreaInputHost;
|
||||
private readonly _textArea: TextAreaWrapper;
|
||||
private _lastTextAreaEvent: TextAreaInputEventType;
|
||||
private readonly _asyncTriggerCut: RunOnceScheduler;
|
||||
|
||||
private _textAreaState: TextAreaState;
|
||||
@@ -101,6 +115,7 @@ export class TextAreaInput extends Disposable {
|
||||
super();
|
||||
this._host = host;
|
||||
this._textArea = this._register(new TextAreaWrapper(textArea));
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.none;
|
||||
this._asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0));
|
||||
|
||||
this._textAreaState = TextAreaState.EMPTY;
|
||||
@@ -129,6 +144,8 @@ export class TextAreaInput extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'compositionstart', (e: CompositionEvent) => {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.compositionstart;
|
||||
|
||||
if (this._isDoingComposition) {
|
||||
return;
|
||||
}
|
||||
@@ -145,10 +162,10 @@ export class TextAreaInput extends Disposable {
|
||||
/**
|
||||
* Deduce the typed input from a text area's value and the last observed state.
|
||||
*/
|
||||
const deduceInputFromTextAreaValue = (couldBeEmojiInput: boolean): [TextAreaState, ITypeData] => {
|
||||
const deduceInputFromTextAreaValue = (couldBeEmojiInput: boolean, couldBeTypingAtOffset0: boolean): [TextAreaState, ITypeData] => {
|
||||
const oldState = this._textAreaState;
|
||||
const newState = this._textAreaState.readFromTextArea(this._textArea);
|
||||
return [newState, TextAreaState.deduceInput(oldState, newState, couldBeEmojiInput)];
|
||||
const newState = TextAreaState.readFromTextArea(this._textArea);
|
||||
return [newState, TextAreaState.deduceInput(oldState, newState, couldBeEmojiInput, couldBeTypingAtOffset0)];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -164,7 +181,29 @@ export class TextAreaInput extends Disposable {
|
||||
return [newState, typeInput];
|
||||
};
|
||||
|
||||
const compositionDataInValid = (locale: string): boolean => {
|
||||
// https://github.com/Microsoft/monaco-editor/issues/339
|
||||
// Multi-part Japanese compositions reset cursor in Edge/IE, Chinese and Korean IME don't have this issue.
|
||||
// The reason that we can't use this path for all CJK IME is IE and Edge behave differently when handling Korean IME,
|
||||
// which breaks this path of code.
|
||||
if (browser.isEdgeOrIE && locale === 'ja') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://github.com/Microsoft/monaco-editor/issues/545
|
||||
// On IE11, we can't trust composition data when typing Chinese as IE11 doesn't emit correct
|
||||
// events when users type numbers in IME.
|
||||
// Chinese: zh-Hans-CN, zh-Hans-SG, zh-Hant-TW, zh-Hant-HK
|
||||
if (browser.isIE && locale.indexOf('zh-Han') === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'compositionupdate', (e: CompositionEvent) => {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.compositionupdate;
|
||||
|
||||
if (browser.isChromev56) {
|
||||
// See https://github.com/Microsoft/monaco-editor/issues/320
|
||||
// where compositionupdate .data is broken in Chrome v55 and v56
|
||||
@@ -174,12 +213,8 @@ export class TextAreaInput extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
if (browser.isEdgeOrIE && e.locale === 'ja') {
|
||||
// https://github.com/Microsoft/monaco-editor/issues/339
|
||||
// Multi-part Japanese compositions reset cursor in Edge/IE, Chinese and Korean IME don't have this issue.
|
||||
// The reason that we can't use this path for all CJK IME is IE and Edge behave differently when handling Korean IME,
|
||||
// which breaks this path of code.
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false);
|
||||
if (compositionDataInValid(e.locale)) {
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false, /*couldBeTypingAtOffset0*/false);
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
this._onCompositionUpdate.fire(e);
|
||||
@@ -193,13 +228,14 @@ export class TextAreaInput extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'compositionend', (e: CompositionEvent) => {
|
||||
if (browser.isEdgeOrIE && e.locale === 'ja') {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.compositionend;
|
||||
|
||||
if (compositionDataInValid(e.locale)) {
|
||||
// https://github.com/Microsoft/monaco-editor/issues/339
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false);
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/false, /*couldBeTypingAtOffset0*/false);
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
const [newState, typeInput] = deduceComposition(e.data);
|
||||
this._textAreaState = newState;
|
||||
this._onType.fire(typeInput);
|
||||
@@ -208,7 +244,7 @@ export class TextAreaInput extends Disposable {
|
||||
// Due to isEdgeOrIE (where the textarea was not cleared initially) and isChrome (the textarea is not updated correctly when composition ends)
|
||||
// we cannot assume the text at the end consists only of the composited text
|
||||
if (browser.isEdgeOrIE || browser.isChrome) {
|
||||
this._textAreaState = this._textAreaState.readFromTextArea(this._textArea);
|
||||
this._textAreaState = TextAreaState.readFromTextArea(this._textArea);
|
||||
}
|
||||
|
||||
if (!this._isDoingComposition) {
|
||||
@@ -220,6 +256,10 @@ export class TextAreaInput extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'input', () => {
|
||||
// We want to find out if this is the first `input` after a `focus`.
|
||||
const previousEventWasFocus = (this._lastTextAreaEvent === TextAreaInputEventType.focus);
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.input;
|
||||
|
||||
// Pretend here we touched the text area, as the `input` event will most likely
|
||||
// result in a `selectionchange` event which we want to ignore
|
||||
this._textArea.setIgnoreSelectionChangeTime('received input event');
|
||||
@@ -239,7 +279,7 @@ export class TextAreaInput extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/platform.isMacintosh);
|
||||
const [newState, typeInput] = deduceInputFromTextAreaValue(/*couldBeEmojiInput*/platform.isMacintosh, /*couldBeTypingAtOffset0*/previousEventWasFocus && platform.isMacintosh);
|
||||
if (typeInput.replaceCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) {
|
||||
// Ignore invalid input but keep it around for next time
|
||||
return;
|
||||
@@ -264,6 +304,8 @@ export class TextAreaInput extends Disposable {
|
||||
// --- Clipboard operations
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'cut', (e: ClipboardEvent) => {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.cut;
|
||||
|
||||
// Pretend here we touched the text area, as the `cut` event will most likely
|
||||
// result in a `selectionchange` event which we want to ignore
|
||||
this._textArea.setIgnoreSelectionChangeTime('received cut event');
|
||||
@@ -273,10 +315,14 @@ export class TextAreaInput extends Disposable {
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'copy', (e: ClipboardEvent) => {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.copy;
|
||||
|
||||
this._ensureClipboardGetsEditorSelection(e);
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'paste', (e: ClipboardEvent) => {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.paste;
|
||||
|
||||
// Pretend here we touched the text area, as the `paste` event will most likely
|
||||
// result in a `selectionchange` event which we want to ignore
|
||||
this._textArea.setIgnoreSelectionChangeTime('received paste event');
|
||||
@@ -297,8 +343,14 @@ export class TextAreaInput extends Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'focus', () => this._setHasFocus(true)));
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'blur', () => this._setHasFocus(false)));
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'focus', () => {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.focus;
|
||||
this._setHasFocus(true);
|
||||
}));
|
||||
this._register(dom.addDisposableListener(textArea.domNode, 'blur', () => {
|
||||
this._lastTextAreaEvent = TextAreaInputEventType.blur;
|
||||
this._setHasFocus(false);
|
||||
}));
|
||||
|
||||
|
||||
// See https://github.com/Microsoft/vscode/issues/27216
|
||||
|
||||
@@ -51,7 +51,7 @@ export class TextAreaState {
|
||||
return '[ <' + this.value + '>, selectionStart: ' + this.selectionStart + ', selectionEnd: ' + this.selectionEnd + ']';
|
||||
}
|
||||
|
||||
public readFromTextArea(textArea: ITextAreaWrapper): TextAreaState {
|
||||
public static readFromTextArea(textArea: ITextAreaWrapper): TextAreaState {
|
||||
return new TextAreaState(textArea.getValue(), textArea.getSelectionStart(), textArea.getSelectionEnd(), null, null);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export class TextAreaState {
|
||||
}
|
||||
|
||||
public writeToTextArea(reason: string, textArea: ITextAreaWrapper, select: boolean): void {
|
||||
// console.log(Date.now() + ': applyToTextArea ' + reason + ': ' + this.toString());
|
||||
// console.log(Date.now() + ': writeToTextArea ' + reason + ': ' + this.toString());
|
||||
textArea.setValue(reason, this.value);
|
||||
if (select) {
|
||||
textArea.setSelectionRange(reason, this.selectionStart, this.selectionEnd);
|
||||
@@ -97,7 +97,7 @@ export class TextAreaState {
|
||||
return new TextAreaState(text, 0, text.length, null, null);
|
||||
}
|
||||
|
||||
public static deduceInput(previousState: TextAreaState, currentState: TextAreaState, couldBeEmojiInput: boolean): ITypeData {
|
||||
public static deduceInput(previousState: TextAreaState, currentState: TextAreaState, couldBeEmojiInput: boolean, couldBeTypingAtOffset0: boolean): ITypeData {
|
||||
if (!previousState) {
|
||||
// This is the EMPTY state
|
||||
return {
|
||||
@@ -117,6 +117,18 @@ export class TextAreaState {
|
||||
let currentSelectionStart = currentState.selectionStart;
|
||||
let currentSelectionEnd = currentState.selectionEnd;
|
||||
|
||||
if (couldBeTypingAtOffset0 && previousValue.length > 0 && previousSelectionStart === previousSelectionEnd && currentSelectionStart === currentSelectionEnd) {
|
||||
// See https://github.com/Microsoft/vscode/issues/42251
|
||||
// where typing always happens at offset 0 in the textarea
|
||||
// when using a custom title area in OSX and moving the window
|
||||
if (strings.endsWith(currentValue, previousValue)) {
|
||||
// Looks like something was typed at offset 0
|
||||
// ==> pretend we placed the cursor at offset 0 to begin with...
|
||||
previousSelectionStart = 0;
|
||||
previousSelectionEnd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip the previous suffix from the value (without interfering with the current selection)
|
||||
const previousSuffix = previousValue.substring(previousSelectionEnd);
|
||||
const currentSuffix = currentValue.substring(currentSelectionEnd);
|
||||
|
||||
@@ -71,3 +71,33 @@ export class EditorState {
|
||||
return this._equals(new EditorState(editor, this.flags));
|
||||
}
|
||||
}
|
||||
|
||||
export class StableEditorScrollState {
|
||||
|
||||
public static capture(editor: ICodeEditor): StableEditorScrollState {
|
||||
let visiblePosition: Position = null;
|
||||
let visiblePositionScrollDelta = 0;
|
||||
if (editor.getScrollTop() !== 0) {
|
||||
const visibleRanges = editor.getVisibleRanges();
|
||||
if (visibleRanges.length > 0) {
|
||||
visiblePosition = visibleRanges[0].getStartPosition();
|
||||
const visiblePositionScrollTop = editor.getTopForPosition(visiblePosition.lineNumber, visiblePosition.column);
|
||||
visiblePositionScrollDelta = editor.getScrollTop() - visiblePositionScrollTop;
|
||||
}
|
||||
}
|
||||
return new StableEditorScrollState(visiblePosition, visiblePositionScrollDelta);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _visiblePosition: Position,
|
||||
private readonly _visiblePositionScrollDelta: number
|
||||
) {
|
||||
}
|
||||
|
||||
public restore(editor: ICodeEditor): void {
|
||||
if (this._visiblePosition) {
|
||||
const visiblePositionScrollTop = editor.getTopForPosition(this._visiblePosition.lineNumber, this._visiblePosition.column);
|
||||
editor.setScrollTop(visiblePositionScrollTop + this._visiblePositionScrollDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +309,11 @@ export interface IOverviewRuler {
|
||||
* A rich code editor.
|
||||
*/
|
||||
export interface ICodeEditor extends editorCommon.IEditor {
|
||||
/**
|
||||
* This editor is used as an alternative to an <input> box, i.e. as a simple widget.
|
||||
* @internal
|
||||
*/
|
||||
readonly isSimpleWidget: boolean;
|
||||
/**
|
||||
* An event emitted when the content of the current model has changed.
|
||||
* @event
|
||||
@@ -386,6 +391,12 @@ export interface ICodeEditor extends editorCommon.IEditor {
|
||||
* @internal
|
||||
*/
|
||||
onDidType(listener: (text: string) => void): IDisposable;
|
||||
/**
|
||||
* An event emitted when editing failed because the editor is read-only.
|
||||
* @event
|
||||
* @internal
|
||||
*/
|
||||
onDidAttemptReadOnlyEdit(listener: () => void): IDisposable;
|
||||
/**
|
||||
* An event emitted when users paste text in the editor.
|
||||
* @event
|
||||
@@ -614,11 +625,6 @@ export interface ICodeEditor extends editorCommon.IEditor {
|
||||
*/
|
||||
getLayoutInfo(): editorOptions.EditorLayoutInfo;
|
||||
|
||||
/**
|
||||
* Returns the range that is currently centered in the view port.
|
||||
*/
|
||||
getCenteredRangeInViewport(): Range;
|
||||
|
||||
/**
|
||||
* Returns the ranges that are currently visible.
|
||||
* Does not account for horizontal scrolling.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
@@ -14,12 +14,12 @@ export abstract class AbstractCodeEditorService implements ICodeEditorService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private _onCodeEditorAdd: Emitter<ICodeEditor>;
|
||||
private _onCodeEditorRemove: Emitter<ICodeEditor>;
|
||||
private readonly _onCodeEditorAdd: Emitter<ICodeEditor>;
|
||||
private readonly _onCodeEditorRemove: Emitter<ICodeEditor>;
|
||||
private _codeEditors: { [editorId: string]: ICodeEditor; };
|
||||
|
||||
private _onDiffEditorAdd: Emitter<IDiffEditor>;
|
||||
private _onDiffEditorRemove: Emitter<IDiffEditor>;
|
||||
private readonly _onDiffEditorAdd: Emitter<IDiffEditor>;
|
||||
private readonly _onDiffEditorRemove: Emitter<IDiffEditor>;
|
||||
private _diffEditors: { [editorId: string]: IDiffEditor; };
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import Event from 'vs/base/common/event';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDecorationOptions, ITextModel } from 'vs/editor/common/model';
|
||||
|
||||
@@ -19,7 +19,7 @@ export class CodeEditorServiceImpl extends AbstractCodeEditorService {
|
||||
private _decorationOptionProviders: { [key: string]: IModelDecorationOptionsProvider };
|
||||
private _themeService: IThemeService;
|
||||
|
||||
constructor( @IThemeService themeService: IThemeService, styleSheet = dom.createStyleSheet()) {
|
||||
constructor(@IThemeService themeService: IThemeService, styleSheet = dom.createStyleSheet()) {
|
||||
super();
|
||||
this._styleSheet = styleSheet;
|
||||
this._decorationOptionProviders = Object.create(null);
|
||||
@@ -126,6 +126,7 @@ class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider {
|
||||
|
||||
public className: string;
|
||||
public inlineClassName: string;
|
||||
public inlineClassNameAffectsLetterSpacing: boolean;
|
||||
public beforeContentClassName: string;
|
||||
public afterContentClassName: string;
|
||||
public glyphMarginClassName: string;
|
||||
@@ -145,9 +146,21 @@ class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider {
|
||||
}
|
||||
return void 0;
|
||||
};
|
||||
let createInlineCSSRules = (type: ModelDecorationCSSRuleType) => {
|
||||
let rules = new DecorationCSSRules(type, providerArgs, themeService);
|
||||
if (rules.hasContent) {
|
||||
this._disposables.push(rules);
|
||||
return { className: rules.className, hasLetterSpacing: rules.hasLetterSpacing };
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.className = createCSSRules(ModelDecorationCSSRuleType.ClassName);
|
||||
this.inlineClassName = createCSSRules(ModelDecorationCSSRuleType.InlineClassName);
|
||||
const inlineData = createInlineCSSRules(ModelDecorationCSSRuleType.InlineClassName);
|
||||
if (inlineData) {
|
||||
this.inlineClassName = inlineData.className;
|
||||
this.inlineClassNameAffectsLetterSpacing = inlineData.hasLetterSpacing;
|
||||
}
|
||||
this.beforeContentClassName = createCSSRules(ModelDecorationCSSRuleType.BeforeContentClassName);
|
||||
this.afterContentClassName = createCSSRules(ModelDecorationCSSRuleType.AfterContentClassName);
|
||||
this.glyphMarginClassName = createCSSRules(ModelDecorationCSSRuleType.GlyphMarginClassName);
|
||||
@@ -194,6 +207,7 @@ class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider {
|
||||
|
||||
const _CSS_MAP = {
|
||||
color: 'color:{0} !important;',
|
||||
opacity: 'opacity:{0};',
|
||||
backgroundColor: 'background-color:{0};',
|
||||
|
||||
outline: 'outline:{0};',
|
||||
@@ -231,6 +245,7 @@ class DecorationCSSRules {
|
||||
private _className: string;
|
||||
private _unThemedSelector: string;
|
||||
private _hasContent: boolean;
|
||||
private _hasLetterSpacing: boolean;
|
||||
private _ruleType: ModelDecorationCSSRuleType;
|
||||
private _themeListener: IDisposable;
|
||||
private _providerArgs: ProviderArguments;
|
||||
@@ -242,6 +257,7 @@ class DecorationCSSRules {
|
||||
this._providerArgs = providerArgs;
|
||||
this._usesThemeColors = false;
|
||||
this._hasContent = false;
|
||||
this._hasLetterSpacing = false;
|
||||
|
||||
let className = CSSNameHelper.getClassName(this._providerArgs.key, ruleType);
|
||||
if (this._providerArgs.parentTypeKey) {
|
||||
@@ -277,6 +293,10 @@ class DecorationCSSRules {
|
||||
return this._hasContent;
|
||||
}
|
||||
|
||||
public get hasLetterSpacing(): boolean {
|
||||
return this._hasLetterSpacing;
|
||||
}
|
||||
|
||||
public get className(): string {
|
||||
return this._className;
|
||||
}
|
||||
@@ -357,7 +377,10 @@ class DecorationCSSRules {
|
||||
return '';
|
||||
}
|
||||
let cssTextArr: string[] = [];
|
||||
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'cursor', 'color', 'letterSpacing'], cssTextArr);
|
||||
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'cursor', 'color', 'opacity', 'letterSpacing'], cssTextArr);
|
||||
if (opts.letterSpacing) {
|
||||
this._hasLetterSpacing = true;
|
||||
}
|
||||
return cssTextArr.join('');
|
||||
}
|
||||
|
||||
@@ -385,7 +408,7 @@ class DecorationCSSRules {
|
||||
|
||||
cssTextArr.push(strings.format(_CSS_MAP.contentText, escaped));
|
||||
}
|
||||
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'color', 'backgroundColor', 'margin'], cssTextArr);
|
||||
this.collectCSSText(opts, ['fontStyle', 'fontWeight', 'textDecoration', 'color', 'opacity', 'backgroundColor', 'margin'], cssTextArr);
|
||||
if (this.collectCSSText(opts, ['width', 'height'], cssTextArr)) {
|
||||
cssTextArr.push('display:inline-block;');
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { ViewOutgoingEvents } from 'vs/editor/browser/view/viewOutgoingEvents';
|
||||
import { CoreNavigationCommands, CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands';
|
||||
@@ -33,6 +31,18 @@ export interface IMouseDispatchData {
|
||||
ctrlKey: boolean;
|
||||
metaKey: boolean;
|
||||
shiftKey: boolean;
|
||||
|
||||
leftButton: boolean;
|
||||
middleButton: boolean;
|
||||
}
|
||||
|
||||
export interface ICommandDelegate {
|
||||
paste(source: string, text: string, pasteOnNewLine: boolean, multicursorText: string[]): void;
|
||||
type(source: string, text: string): void;
|
||||
replacePreviousChar(source: string, text: string, replaceCharCnt: number): void;
|
||||
compositionStart(source: string): void;
|
||||
compositionEnd(source: string): void;
|
||||
cut(source: string): void;
|
||||
}
|
||||
|
||||
export class ViewController {
|
||||
@@ -41,20 +51,20 @@ export class ViewController {
|
||||
private readonly viewModel: IViewModel;
|
||||
private readonly _execCoreEditorCommandFunc: ExecCoreEditorCommandFunc;
|
||||
private readonly outgoingEvents: ViewOutgoingEvents;
|
||||
private readonly commandService: ICommandService;
|
||||
private readonly commandDelegate: ICommandDelegate;
|
||||
|
||||
constructor(
|
||||
configuration: Configuration,
|
||||
viewModel: IViewModel,
|
||||
execCommandFunc: ExecCoreEditorCommandFunc,
|
||||
outgoingEvents: ViewOutgoingEvents,
|
||||
commandService: ICommandService
|
||||
commandDelegate: ICommandDelegate
|
||||
) {
|
||||
this.configuration = configuration;
|
||||
this.viewModel = viewModel;
|
||||
this._execCoreEditorCommandFunc = execCommandFunc;
|
||||
this.outgoingEvents = outgoingEvents;
|
||||
this.commandService = commandService;
|
||||
this.commandDelegate = commandDelegate;
|
||||
}
|
||||
|
||||
private _execMouseCommand(editorCommand: CoreEditorCommand, args: any): void {
|
||||
@@ -63,36 +73,27 @@ export class ViewController {
|
||||
}
|
||||
|
||||
public paste(source: string, text: string, pasteOnNewLine: boolean, multicursorText: string[]): void {
|
||||
this.commandService.executeCommand(editorCommon.Handler.Paste, {
|
||||
text: text,
|
||||
pasteOnNewLine: pasteOnNewLine,
|
||||
multicursorText: multicursorText
|
||||
});
|
||||
this.commandDelegate.paste(source, text, pasteOnNewLine, multicursorText);
|
||||
}
|
||||
|
||||
public type(source: string, text: string): void {
|
||||
this.commandService.executeCommand(editorCommon.Handler.Type, {
|
||||
text: text
|
||||
});
|
||||
this.commandDelegate.type(source, text);
|
||||
}
|
||||
|
||||
public replacePreviousChar(source: string, text: string, replaceCharCnt: number): void {
|
||||
this.commandService.executeCommand(editorCommon.Handler.ReplacePreviousChar, {
|
||||
text: text,
|
||||
replaceCharCnt: replaceCharCnt
|
||||
});
|
||||
this.commandDelegate.replacePreviousChar(source, text, replaceCharCnt);
|
||||
}
|
||||
|
||||
public compositionStart(source: string): void {
|
||||
this.commandService.executeCommand(editorCommon.Handler.CompositionStart, {});
|
||||
this.commandDelegate.compositionStart(source);
|
||||
}
|
||||
|
||||
public compositionEnd(source: string): void {
|
||||
this.commandService.executeCommand(editorCommon.Handler.CompositionEnd, {});
|
||||
this.commandDelegate.compositionEnd(source);
|
||||
}
|
||||
|
||||
public cut(source: string): void {
|
||||
this.commandService.executeCommand(editorCommon.Handler.Cut, {});
|
||||
this.commandDelegate.cut(source);
|
||||
}
|
||||
|
||||
public setSelection(source: string, modelSelection: Selection): void {
|
||||
@@ -135,7 +136,13 @@ export class ViewController {
|
||||
}
|
||||
|
||||
public dispatchMouse(data: IMouseDispatchData): void {
|
||||
if (data.startedOnLineNumbers) {
|
||||
if (data.middleButton) {
|
||||
if (data.inSelectionMode) {
|
||||
this.columnSelect(data.position, data.mouseColumn);
|
||||
} else {
|
||||
this.moveTo(data.position);
|
||||
}
|
||||
} else if (data.startedOnLineNumbers) {
|
||||
// If the dragging started on the gutter, then have operations work on the entire line
|
||||
if (this._hasMulticursorModifier(data)) {
|
||||
if (data.inSelectionMode) {
|
||||
|
||||
@@ -8,14 +8,13 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler';
|
||||
import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import { TextAreaHandler, ITextAreaHandlerHelper } from 'vs/editor/browser/controller/textAreaHandler';
|
||||
import { PointerHandler } from 'vs/editor/browser/controller/pointerHandler';
|
||||
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
|
||||
import { ViewController, ExecCoreEditorCommandFunc } from 'vs/editor/browser/view/viewController';
|
||||
import { ViewController, ExecCoreEditorCommandFunc, ICommandDelegate } from 'vs/editor/browser/view/viewController';
|
||||
import { ViewEventDispatcher } from 'vs/editor/common/view/viewEventDispatcher';
|
||||
import { ContentViewOverlays, MarginViewOverlays } from 'vs/editor/browser/view/viewOverlays';
|
||||
import { ViewContentWidgets } from 'vs/editor/browser/viewParts/contentWidgets/contentWidgets';
|
||||
@@ -93,7 +92,7 @@ export class View extends ViewEventHandler {
|
||||
private _renderAnimationFrame: IDisposable;
|
||||
|
||||
constructor(
|
||||
commandService: ICommandService,
|
||||
commandDelegate: ICommandDelegate,
|
||||
configuration: Configuration,
|
||||
themeService: IThemeService,
|
||||
model: IViewModel,
|
||||
@@ -105,7 +104,7 @@ export class View extends ViewEventHandler {
|
||||
this._renderAnimationFrame = null;
|
||||
this.outgoingEvents = new ViewOutgoingEvents(model);
|
||||
|
||||
let viewController = new ViewController(configuration, model, execCoreEditorCommandFunc, this.outgoingEvents, commandService);
|
||||
let viewController = new ViewController(configuration, model, execCoreEditorCommandFunc, this.outgoingEvents, commandDelegate);
|
||||
|
||||
// The event dispatcher will always go through _renderOnce before dispatching any events
|
||||
this.eventDispatcher = new ViewEventDispatcher((callback: () => void) => this._renderOnce(callback));
|
||||
@@ -178,8 +177,8 @@ export class View extends ViewEventHandler {
|
||||
this.viewParts.push(contentViewOverlays);
|
||||
contentViewOverlays.addDynamicOverlay(new CurrentLineHighlightOverlay(this._context));
|
||||
contentViewOverlays.addDynamicOverlay(new SelectionsOverlay(this._context));
|
||||
contentViewOverlays.addDynamicOverlay(new DecorationsOverlay(this._context));
|
||||
contentViewOverlays.addDynamicOverlay(new IndentGuidesOverlay(this._context));
|
||||
contentViewOverlays.addDynamicOverlay(new DecorationsOverlay(this._context));
|
||||
|
||||
let marginViewOverlays = new MarginViewOverlays(this._context);
|
||||
this.viewParts.push(marginViewOverlays);
|
||||
@@ -322,6 +321,7 @@ export class View extends ViewEventHandler {
|
||||
}
|
||||
public onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {
|
||||
this.domNode.setClassName(this.getEditorClassName());
|
||||
this._context.model.setHasFocus(e.isFocused);
|
||||
if (e.isFocused) {
|
||||
this.outgoingEvents.emitViewFocusGained();
|
||||
} else {
|
||||
|
||||
@@ -308,7 +308,8 @@ class Widget {
|
||||
private _layoutBoxInPage(topLeft: Coordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult {
|
||||
let left0 = topLeft.left - ctx.scrollLeft;
|
||||
|
||||
if (left0 + width < 0 || left0 > this._contentWidth) {
|
||||
if (left0 < 0 || left0 > this._contentWidth) {
|
||||
// Don't render if position is scrolled outside viewport
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,8 +85,14 @@ export class DecorationsOverlay extends DynamicViewOverlay {
|
||||
|
||||
// Sort decorations for consistent render output
|
||||
decorations = decorations.sort((a, b) => {
|
||||
let aClassName = a.options.className;
|
||||
let bClassName = b.options.className;
|
||||
if (a.options.zIndex < b.options.zIndex) {
|
||||
return -1;
|
||||
}
|
||||
if (a.options.zIndex > b.options.zIndex) {
|
||||
return 1;
|
||||
}
|
||||
const aClassName = a.options.className;
|
||||
const bClassName = b.options.className;
|
||||
|
||||
if (aClassName < bClassName) {
|
||||
return -1;
|
||||
@@ -142,8 +148,12 @@ export class DecorationsOverlay extends DynamicViewOverlay {
|
||||
}
|
||||
|
||||
private _renderNormalDecorations(ctx: RenderingContext, decorations: ViewModelDecoration[], output: string[]): void {
|
||||
let lineHeight = String(this._lineHeight);
|
||||
let visibleStartLineNumber = ctx.visibleRange.startLineNumber;
|
||||
const lineHeight = String(this._lineHeight);
|
||||
const visibleStartLineNumber = ctx.visibleRange.startLineNumber;
|
||||
|
||||
let prevClassName: string = null;
|
||||
let prevShowIfCollapsed: boolean = false;
|
||||
let prevRange: Range = null;
|
||||
|
||||
for (let i = 0, lenI = decorations.length; i < lenI; i++) {
|
||||
const d = decorations[i];
|
||||
@@ -160,39 +170,60 @@ export class DecorationsOverlay extends DynamicViewOverlay {
|
||||
range = new Range(range.startLineNumber, range.startColumn, range.endLineNumber - 1, this._context.model.getLineMaxColumn(range.endLineNumber - 1));
|
||||
}
|
||||
|
||||
let linesVisibleRanges = ctx.linesVisibleRangesForRange(range, /*TODO@Alex*/className === 'findMatch');
|
||||
if (!linesVisibleRanges) {
|
||||
if (prevClassName === className && prevShowIfCollapsed === showIfCollapsed && Range.areIntersectingOrTouching(prevRange, range)) {
|
||||
// merge into previous decoration
|
||||
prevRange = Range.plusRange(prevRange, range);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0, lenJ = linesVisibleRanges.length; j < lenJ; j++) {
|
||||
let lineVisibleRanges = linesVisibleRanges[j];
|
||||
const lineIndex = lineVisibleRanges.lineNumber - visibleStartLineNumber;
|
||||
// flush previous decoration
|
||||
if (prevClassName !== null) {
|
||||
this._renderNormalDecoration(ctx, prevRange, prevClassName, prevShowIfCollapsed, lineHeight, visibleStartLineNumber, output);
|
||||
}
|
||||
|
||||
if (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {
|
||||
const singleVisibleRange = lineVisibleRanges.ranges[0];
|
||||
if (singleVisibleRange.width === 0) {
|
||||
// collapsed range case => make the decoration visible by faking its width
|
||||
lineVisibleRanges.ranges[0] = new HorizontalRange(singleVisibleRange.left, this._typicalHalfwidthCharacterWidth);
|
||||
}
|
||||
}
|
||||
prevClassName = className;
|
||||
prevShowIfCollapsed = showIfCollapsed;
|
||||
prevRange = range;
|
||||
}
|
||||
|
||||
for (let k = 0, lenK = lineVisibleRanges.ranges.length; k < lenK; k++) {
|
||||
const visibleRange = lineVisibleRanges.ranges[k];
|
||||
const decorationOutput = (
|
||||
'<div class="cdr '
|
||||
+ className
|
||||
+ '" style="left:'
|
||||
+ String(visibleRange.left)
|
||||
+ 'px;width:'
|
||||
+ String(visibleRange.width)
|
||||
+ 'px;height:'
|
||||
+ lineHeight
|
||||
+ 'px;"></div>'
|
||||
);
|
||||
output[lineIndex] += decorationOutput;
|
||||
if (prevClassName !== null) {
|
||||
this._renderNormalDecoration(ctx, prevRange, prevClassName, prevShowIfCollapsed, lineHeight, visibleStartLineNumber, output);
|
||||
}
|
||||
}
|
||||
|
||||
private _renderNormalDecoration(ctx: RenderingContext, range: Range, className: string, showIfCollapsed: boolean, lineHeight: string, visibleStartLineNumber: number, output: string[]): void {
|
||||
let linesVisibleRanges = ctx.linesVisibleRangesForRange(range, /*TODO@Alex*/className === 'findMatch');
|
||||
if (!linesVisibleRanges) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let j = 0, lenJ = linesVisibleRanges.length; j < lenJ; j++) {
|
||||
let lineVisibleRanges = linesVisibleRanges[j];
|
||||
const lineIndex = lineVisibleRanges.lineNumber - visibleStartLineNumber;
|
||||
|
||||
if (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {
|
||||
const singleVisibleRange = lineVisibleRanges.ranges[0];
|
||||
if (singleVisibleRange.width === 0) {
|
||||
// collapsed range case => make the decoration visible by faking its width
|
||||
lineVisibleRanges.ranges[0] = new HorizontalRange(singleVisibleRange.left, this._typicalHalfwidthCharacterWidth);
|
||||
}
|
||||
}
|
||||
|
||||
for (let k = 0, lenK = lineVisibleRanges.ranges.length; k < lenK; k++) {
|
||||
const visibleRange = lineVisibleRanges.ranges[k];
|
||||
const decorationOutput = (
|
||||
'<div class="cdr '
|
||||
+ className
|
||||
+ '" style="left:'
|
||||
+ String(visibleRange.left)
|
||||
+ 'px;width:'
|
||||
+ String(visibleRange.width)
|
||||
+ 'px;height:'
|
||||
+ lineHeight
|
||||
+ 'px;"></div>'
|
||||
);
|
||||
output[lineIndex] += decorationOutput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,3 +10,6 @@
|
||||
.monaco-editor .lines-content .cigr {
|
||||
position: absolute;
|
||||
}
|
||||
.monaco-editor .lines-content .cigra {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@ import { ViewContext } from 'vs/editor/common/view/viewContext';
|
||||
import { RenderingContext } from 'vs/editor/common/view/renderingContext';
|
||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { editorIndentGuides } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { editorIndentGuides, editorActiveIndentGuides } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
|
||||
export class IndentGuidesOverlay extends DynamicViewOverlay {
|
||||
|
||||
private _context: ViewContext;
|
||||
private _primaryLineNumber: number;
|
||||
private _lineHeight: number;
|
||||
private _spaceWidth: number;
|
||||
private _renderResult: string[];
|
||||
@@ -26,6 +26,7 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
|
||||
constructor(context: ViewContext) {
|
||||
super();
|
||||
this._context = context;
|
||||
this._primaryLineNumber = 0;
|
||||
this._lineHeight = this._context.configuration.editor.lineHeight;
|
||||
this._spaceWidth = this._context.configuration.editor.fontInfo.spaceWidth;
|
||||
this._enabled = this._context.configuration.editor.viewInfo.renderIndentGuides;
|
||||
@@ -55,6 +56,17 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
|
||||
const selection = e.selections[0];
|
||||
const newPrimaryLineNumber = selection.isEmpty() ? selection.positionLineNumber : 0;
|
||||
|
||||
if (this._primaryLineNumber !== newPrimaryLineNumber) {
|
||||
this._primaryLineNumber = newPrimaryLineNumber;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {
|
||||
// true for inline decorations
|
||||
return true;
|
||||
@@ -94,20 +106,32 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
|
||||
const tabSize = this._context.model.getTabSize();
|
||||
const tabWidth = tabSize * this._spaceWidth;
|
||||
const lineHeight = this._lineHeight;
|
||||
const indentGuideWidth = dom.computeScreenAwareSize(1);
|
||||
const indentGuideWidth = tabWidth;
|
||||
|
||||
const indents = this._context.model.getLinesIndentGuides(visibleStartLineNumber, visibleEndLineNumber);
|
||||
|
||||
let activeIndentStartLineNumber = 0;
|
||||
let activeIndentEndLineNumber = 0;
|
||||
let activeIndentLevel = 0;
|
||||
if (this._primaryLineNumber) {
|
||||
const activeIndentInfo = this._context.model.getActiveIndentGuide(this._primaryLineNumber, visibleStartLineNumber, visibleEndLineNumber);
|
||||
activeIndentStartLineNumber = activeIndentInfo.startLineNumber;
|
||||
activeIndentEndLineNumber = activeIndentInfo.endLineNumber;
|
||||
activeIndentLevel = activeIndentInfo.indent;
|
||||
}
|
||||
|
||||
let output: string[] = [];
|
||||
for (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {
|
||||
const containsActiveIndentGuide = (activeIndentStartLineNumber <= lineNumber && lineNumber <= activeIndentEndLineNumber);
|
||||
const lineIndex = lineNumber - visibleStartLineNumber;
|
||||
const indent = indents[lineIndex];
|
||||
|
||||
let result = '';
|
||||
let leftMostVisiblePosition = ctx.visibleRangeForPosition(new Position(lineNumber, 1));
|
||||
let left = leftMostVisiblePosition ? leftMostVisiblePosition.left : 0;
|
||||
for (let i = 0; i < indent; i++) {
|
||||
result += `<div class="cigr" style="left:${left}px;height:${lineHeight}px;width:${indentGuideWidth}px"></div>`;
|
||||
for (let i = 1; i <= indent; i++) {
|
||||
let className = (containsActiveIndentGuide && i === activeIndentLevel ? 'cigra' : 'cigr');
|
||||
result += `<div class="${className}" style="left:${left}px;height:${lineHeight}px;width:${indentGuideWidth}px"></div>`;
|
||||
left += tabWidth;
|
||||
}
|
||||
|
||||
@@ -129,8 +153,12 @@ export class IndentGuidesOverlay extends DynamicViewOverlay {
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
let editorGuideColor = theme.getColor(editorIndentGuides);
|
||||
if (editorGuideColor) {
|
||||
collector.addRule(`.monaco-editor .lines-content .cigr { background-color: ${editorGuideColor}; }`);
|
||||
let editorIndentGuidesColor = theme.getColor(editorIndentGuides);
|
||||
if (editorIndentGuidesColor) {
|
||||
collector.addRule(`.monaco-editor .lines-content .cigr { box-shadow: 1px 0 0 0 ${editorIndentGuidesColor} inset; }`);
|
||||
}
|
||||
let editorActiveIndentGuidesColor = theme.getColor(editorActiveIndentGuides) || editorIndentGuidesColor;
|
||||
if (editorActiveIndentGuidesColor) {
|
||||
collector.addRule(`.monaco-editor .lines-content .cigra { box-shadow: 1px 0 0 0 ${editorActiveIndentGuidesColor} inset; }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||
import { IConfiguration } from 'vs/editor/common/editorCommon';
|
||||
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
|
||||
import { renderViewLine, RenderLineInput, CharacterMapping } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||
import { renderViewLine, RenderLineInput, CharacterMapping, ForeignElementType } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||
import { IVisibleLine } from 'vs/editor/browser/view/viewLayer';
|
||||
import { RangeUtil } from 'vs/editor/browser/viewParts/lines/rangeUtil';
|
||||
import { HorizontalRange } from 'vs/editor/common/view/renderingContext';
|
||||
@@ -192,7 +191,8 @@ export class ViewLine implements IVisibleLine {
|
||||
let renderLineInput = new RenderLineInput(
|
||||
options.useMonospaceOptimizations,
|
||||
lineData.content,
|
||||
lineData.mightContainRTL,
|
||||
lineData.isBasicASCII,
|
||||
lineData.containsRTL,
|
||||
lineData.minColumn - 1,
|
||||
lineData.tokens,
|
||||
actualInlineDecorations,
|
||||
@@ -222,18 +222,16 @@ export class ViewLine implements IVisibleLine {
|
||||
sb.appendASCIIString('</div>');
|
||||
|
||||
let renderedViewLine: IRenderedViewLine = null;
|
||||
if (canUseFastRenderedViewLine && options.useMonospaceOptimizations && !output.containsForeignElements) {
|
||||
let isRegularASCII = true;
|
||||
if (lineData.mightContainNonBasicASCII) {
|
||||
isRegularASCII = strings.isBasicASCII(lineData.content);
|
||||
}
|
||||
|
||||
if (isRegularASCII && lineData.content.length < 1000 && renderLineInput.lineTokens.getCount() < 100) {
|
||||
if (canUseFastRenderedViewLine && lineData.isBasicASCII && options.useMonospaceOptimizations && output.containsForeignElements === ForeignElementType.None) {
|
||||
if (lineData.content.length < 300 && renderLineInput.lineTokens.getCount() < 100) {
|
||||
// Browser rounding errors have been observed in Chrome and IE, so using the fast
|
||||
// view line only for short lines. Please test before removing the length check...
|
||||
// ---
|
||||
// Another rounding error has been observed on Linux in VSCode, where <span> width
|
||||
// rounding errors add up to an observable large number...
|
||||
// ---
|
||||
// Also see another example of rounding errors on Windows in
|
||||
// https://github.com/Microsoft/vscode/issues/33178
|
||||
renderedViewLine = new FastRenderedViewLine(
|
||||
this._renderedViewLine ? this._renderedViewLine.domNode : null,
|
||||
renderLineInput,
|
||||
@@ -385,7 +383,7 @@ class RenderedViewLine implements IRenderedViewLine {
|
||||
|
||||
protected readonly _characterMapping: CharacterMapping;
|
||||
private readonly _isWhitespaceOnly: boolean;
|
||||
private readonly _containsForeignElements: boolean;
|
||||
private readonly _containsForeignElements: ForeignElementType;
|
||||
private _cachedWidth: number;
|
||||
|
||||
/**
|
||||
@@ -393,7 +391,7 @@ class RenderedViewLine implements IRenderedViewLine {
|
||||
*/
|
||||
private _pixelOffsetCache: Int32Array;
|
||||
|
||||
constructor(domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: boolean) {
|
||||
constructor(domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) {
|
||||
this.domNode = domNode;
|
||||
this.input = renderLineInput;
|
||||
this._characterMapping = characterMapping;
|
||||
@@ -471,10 +469,18 @@ class RenderedViewLine implements IRenderedViewLine {
|
||||
protected _readPixelOffset(column: number, context: DomReadingContext): number {
|
||||
if (this._characterMapping.length === 0) {
|
||||
// This line has no content
|
||||
if (!this._containsForeignElements) {
|
||||
if (this._containsForeignElements === ForeignElementType.None) {
|
||||
// We can assume the line is really empty
|
||||
return 0;
|
||||
}
|
||||
if (this._containsForeignElements === ForeignElementType.After) {
|
||||
// We have foreign elements after the (empty) line
|
||||
return 0;
|
||||
}
|
||||
if (this._containsForeignElements === ForeignElementType.Before) {
|
||||
// We have foreign element before the (empty) line
|
||||
return this.getWidth();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._pixelOffsetCache !== null) {
|
||||
@@ -503,7 +509,7 @@ class RenderedViewLine implements IRenderedViewLine {
|
||||
return r[0].left;
|
||||
}
|
||||
|
||||
if (column === this._characterMapping.length && this._isWhitespaceOnly && !this._containsForeignElements) {
|
||||
if (column === this._characterMapping.length && this._isWhitespaceOnly && this._containsForeignElements === ForeignElementType.None) {
|
||||
// This branch helps in the case of whitespace only lines which have a width set
|
||||
return this.getWidth();
|
||||
}
|
||||
@@ -586,17 +592,17 @@ class WebKitRenderedViewLine extends RenderedViewLine {
|
||||
}
|
||||
}
|
||||
|
||||
const createRenderedLine: (domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: boolean) => RenderedViewLine = (function () {
|
||||
const createRenderedLine: (domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) => RenderedViewLine = (function () {
|
||||
if (browser.isWebKit) {
|
||||
return createWebKitRenderedLine;
|
||||
}
|
||||
return createNormalRenderedLine;
|
||||
})();
|
||||
|
||||
function createWebKitRenderedLine(domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: boolean): RenderedViewLine {
|
||||
function createWebKitRenderedLine(domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine {
|
||||
return new WebKitRenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements);
|
||||
}
|
||||
|
||||
function createNormalRenderedLine(domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: boolean): RenderedViewLine {
|
||||
function createNormalRenderedLine(domNode: FastDomNode<HTMLElement>, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine {
|
||||
return new RenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
export class Margin extends ViewPart {
|
||||
|
||||
public static readonly CLASS_NAME = 'glyph-margin';
|
||||
public static readonly OUTER_CLASS_NAME = 'margin';
|
||||
|
||||
private _domNode: FastDomNode<HTMLElement>;
|
||||
private _canUseLayerHinting: boolean;
|
||||
@@ -42,7 +43,7 @@ export class Margin extends ViewPart {
|
||||
|
||||
private _createDomNode(): FastDomNode<HTMLElement> {
|
||||
let domNode = createFastDomNode(document.createElement('div'));
|
||||
domNode.setClassName('margin');
|
||||
domNode.setClassName(Margin.OUTER_CLASS_NAME);
|
||||
domNode.setPosition('absolute');
|
||||
domNode.setAttribute('role', 'presentation');
|
||||
domNode.setAttribute('aria-hidden', 'true');
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import 'vs/css!./minimap';
|
||||
import { ViewPart, PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ViewContext } from 'vs/editor/common/view/viewContext';
|
||||
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
|
||||
import { getOrCreateMinimapCharRenderer } from 'vs/editor/common/view/runtimeMinimapCharRenderer';
|
||||
@@ -897,17 +898,22 @@ export class Minimap extends ViewPart {
|
||||
// No need to render anything since space is invisible
|
||||
dx += charWidth;
|
||||
} else {
|
||||
if (renderMinimap === RenderMinimap.Large) {
|
||||
minimapCharRenderer.x2RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont);
|
||||
} else if (renderMinimap === RenderMinimap.Small) {
|
||||
minimapCharRenderer.x1RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont);
|
||||
} else if (renderMinimap === RenderMinimap.LargeBlocks) {
|
||||
minimapCharRenderer.x2BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont);
|
||||
} else {
|
||||
// RenderMinimap.SmallBlocks
|
||||
minimapCharRenderer.x1BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont);
|
||||
// Render twice for a full width character
|
||||
let count = strings.isFullWidthCharacter(charCode) ? 2 : 1;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
if (renderMinimap === RenderMinimap.Large) {
|
||||
minimapCharRenderer.x2RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont);
|
||||
} else if (renderMinimap === RenderMinimap.Small) {
|
||||
minimapCharRenderer.x1RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor, useLighterFont);
|
||||
} else if (renderMinimap === RenderMinimap.LargeBlocks) {
|
||||
minimapCharRenderer.x2BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont);
|
||||
} else {
|
||||
// RenderMinimap.SmallBlocks
|
||||
minimapCharRenderer.x1BlockRenderChar(target, dx, dy, tokenColor, backgroundColor, useLighterFont);
|
||||
}
|
||||
dx += charWidth;
|
||||
}
|
||||
dx += charWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,8 +58,13 @@ class Settings {
|
||||
this.themeType = theme.type;
|
||||
|
||||
const minimapEnabled = config.editor.viewInfo.minimap.enabled;
|
||||
const minimapSide = config.editor.viewInfo.minimap.side;
|
||||
const backgroundColor = (minimapEnabled ? TokenizationRegistry.getDefaultBackground() : null);
|
||||
this.backgroundColor = (backgroundColor ? Color.Format.CSS.formatHex(backgroundColor) : null);
|
||||
if (backgroundColor === null || minimapSide === 'left') {
|
||||
this.backgroundColor = null;
|
||||
} else {
|
||||
this.backgroundColor = Color.Format.CSS.formatHex(backgroundColor);
|
||||
}
|
||||
|
||||
const position = config.editor.layoutInfo.overviewRuler;
|
||||
this.top = position.top;
|
||||
|
||||
@@ -13,7 +13,6 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v
|
||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { editorRuler } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
|
||||
export class Rulers extends ViewPart {
|
||||
|
||||
@@ -67,7 +66,7 @@ export class Rulers extends ViewPart {
|
||||
}
|
||||
|
||||
if (currentCount < desiredCount) {
|
||||
const rulerWidth = dom.computeScreenAwareSize(1);
|
||||
const rulerWidth = this._context.model.getTabSize();
|
||||
let addCount = desiredCount - currentCount;
|
||||
while (addCount > 0) {
|
||||
let node = createFastDomNode(document.createElement('div'));
|
||||
@@ -104,6 +103,6 @@ export class Rulers extends ViewPart {
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
let rulerColor = theme.getColor(editorRuler);
|
||||
if (rulerColor) {
|
||||
collector.addRule(`.monaco-editor .view-ruler { background-color: ${rulerColor}; }`);
|
||||
collector.addRule(`.monaco-editor .view-ruler { box-shadow: 1px 0 0 0 ${rulerColor} inset; }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -54,7 +54,12 @@ export class ScrollDecorationViewPart extends ViewPart {
|
||||
|
||||
private _updateWidth(): boolean {
|
||||
const layoutInfo = this._context.configuration.editor.layoutInfo;
|
||||
let newWidth = layoutInfo.width - layoutInfo.minimapWidth;
|
||||
let newWidth = 0;
|
||||
if (layoutInfo.renderMinimap === 0 || (layoutInfo.minimapWidth > 0 && layoutInfo.minimapLeft === 0)) {
|
||||
newWidth = layoutInfo.width;
|
||||
} else {
|
||||
newWidth = layoutInfo.width - layoutInfo.minimapWidth - layoutInfo.verticalScrollbarWidth;
|
||||
}
|
||||
if (this._width !== newWidth) {
|
||||
this._width = newWidth;
|
||||
return true;
|
||||
|
||||
@@ -78,6 +78,7 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
private _context: ViewContext;
|
||||
private _lineHeight: number;
|
||||
private _roundedSelection: boolean;
|
||||
private _typicalHalfwidthCharacterWidth: number;
|
||||
private _selections: Range[];
|
||||
private _renderResult: string[];
|
||||
|
||||
@@ -86,6 +87,7 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
this._context = context;
|
||||
this._lineHeight = this._context.configuration.editor.lineHeight;
|
||||
this._roundedSelection = this._context.configuration.editor.viewInfo.roundedSelection;
|
||||
this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth;
|
||||
this._selections = [];
|
||||
this._renderResult = null;
|
||||
this._context.addEventHandler(this);
|
||||
@@ -108,6 +110,9 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
if (e.viewInfo) {
|
||||
this._roundedSelection = this._context.configuration.editor.viewInfo.roundedSelection;
|
||||
}
|
||||
if (e.fontInfo) {
|
||||
this._typicalHalfwidthCharacterWidth = this._context.configuration.editor.fontInfo.typicalHalfwidthCharacterWidth;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
|
||||
@@ -153,23 +158,28 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
return false;
|
||||
}
|
||||
|
||||
private _enrichVisibleRangesWithStyle(linesVisibleRanges: LineVisibleRangesWithStyle[], previousFrame: LineVisibleRangesWithStyle[]): void {
|
||||
private _enrichVisibleRangesWithStyle(viewport: Range, linesVisibleRanges: LineVisibleRangesWithStyle[], previousFrame: LineVisibleRangesWithStyle[]): void {
|
||||
const epsilon = this._typicalHalfwidthCharacterWidth / 4;
|
||||
let previousFrameTop: HorizontalRangeWithStyle = null;
|
||||
let previousFrameBottom: HorizontalRangeWithStyle = null;
|
||||
|
||||
if (previousFrame && previousFrame.length > 0 && linesVisibleRanges.length > 0) {
|
||||
|
||||
let topLineNumber = linesVisibleRanges[0].lineNumber;
|
||||
for (let i = 0; !previousFrameTop && i < previousFrame.length; i++) {
|
||||
if (previousFrame[i].lineNumber === topLineNumber) {
|
||||
previousFrameTop = previousFrame[i].ranges[0];
|
||||
if (topLineNumber === viewport.startLineNumber) {
|
||||
for (let i = 0; !previousFrameTop && i < previousFrame.length; i++) {
|
||||
if (previousFrame[i].lineNumber === topLineNumber) {
|
||||
previousFrameTop = previousFrame[i].ranges[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bottomLineNumber = linesVisibleRanges[linesVisibleRanges.length - 1].lineNumber;
|
||||
for (let i = previousFrame.length - 1; !previousFrameBottom && i >= 0; i--) {
|
||||
if (previousFrame[i].lineNumber === bottomLineNumber) {
|
||||
previousFrameBottom = previousFrame[i].ranges[0];
|
||||
if (bottomLineNumber === viewport.endLineNumber) {
|
||||
for (let i = previousFrame.length - 1; !previousFrameBottom && i >= 0; i--) {
|
||||
if (previousFrame[i].lineNumber === bottomLineNumber) {
|
||||
previousFrameBottom = previousFrame[i].ranges[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,13 +212,13 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
let prevLeft = linesVisibleRanges[i - 1].ranges[0].left;
|
||||
let prevRight = linesVisibleRanges[i - 1].ranges[0].left + linesVisibleRanges[i - 1].ranges[0].width;
|
||||
|
||||
if (curLeft === prevLeft) {
|
||||
if (abs(curLeft - prevLeft) < epsilon) {
|
||||
startStyle.top = CornerStyle.FLAT;
|
||||
} else if (curLeft > prevLeft) {
|
||||
startStyle.top = CornerStyle.INTERN;
|
||||
}
|
||||
|
||||
if (curRight === prevRight) {
|
||||
if (abs(curRight - prevRight) < epsilon) {
|
||||
endStyle.top = CornerStyle.FLAT;
|
||||
} else if (prevLeft < curRight && curRight < prevRight) {
|
||||
endStyle.top = CornerStyle.INTERN;
|
||||
@@ -224,13 +234,13 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
let nextLeft = linesVisibleRanges[i + 1].ranges[0].left;
|
||||
let nextRight = linesVisibleRanges[i + 1].ranges[0].left + linesVisibleRanges[i + 1].ranges[0].width;
|
||||
|
||||
if (curLeft === nextLeft) {
|
||||
if (abs(curLeft - nextLeft) < epsilon) {
|
||||
startStyle.bottom = CornerStyle.FLAT;
|
||||
} else if (nextLeft < curLeft && curLeft < nextRight) {
|
||||
startStyle.bottom = CornerStyle.INTERN;
|
||||
}
|
||||
|
||||
if (curRight === nextRight) {
|
||||
if (abs(curRight - nextRight) < epsilon) {
|
||||
endStyle.bottom = CornerStyle.FLAT;
|
||||
} else if (curRight < nextRight) {
|
||||
endStyle.bottom = CornerStyle.INTERN;
|
||||
@@ -252,7 +262,7 @@ export class SelectionsOverlay extends DynamicViewOverlay {
|
||||
let visibleRangesHaveGaps = this._visibleRangesHaveGaps(linesVisibleRanges);
|
||||
|
||||
if (!isIEWithZoomingIssuesNearRoundedBorders && !visibleRangesHaveGaps && this._roundedSelection) {
|
||||
this._enrichVisibleRangesWithStyle(linesVisibleRanges, previousFrame);
|
||||
this._enrichVisibleRangesWithStyle(ctx.visibleRange, linesVisibleRanges, previousFrame);
|
||||
}
|
||||
|
||||
// The visible ranges are sorted TOP-BOTTOM and LEFT-RIGHT
|
||||
@@ -407,3 +417,7 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.monaco-editor .view-line span.inline-selected-text { color: ${editorSelectionForegroundColor}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
function abs(n: number): number {
|
||||
return n < 0 ? -n : n;
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { ViewContext } from 'vs/editor/common/view/viewContext';
|
||||
import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
|
||||
import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
|
||||
export interface IViewCursorRenderData {
|
||||
domNode: HTMLElement;
|
||||
@@ -28,7 +29,8 @@ class ViewCursorRenderData {
|
||||
public readonly left: number,
|
||||
public readonly width: number,
|
||||
public readonly height: number,
|
||||
public readonly textContent: string
|
||||
public readonly textContent: string,
|
||||
public readonly textContentClassName: string
|
||||
) { }
|
||||
}
|
||||
|
||||
@@ -118,6 +120,7 @@ export class ViewCursor {
|
||||
|
||||
private _prepareRender(ctx: RenderingContext): ViewCursorRenderData {
|
||||
let textContent = '';
|
||||
let textContentClassName = '';
|
||||
|
||||
if (this._cursorStyle === TextEditorCursorStyle.Line || this._cursorStyle === TextEditorCursorStyle.LineThin) {
|
||||
const visibleRange = ctx.visibleRangeForPosition(this._position);
|
||||
@@ -136,7 +139,7 @@ export class ViewCursor {
|
||||
width = dom.computeScreenAwareSize(1);
|
||||
}
|
||||
const top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta;
|
||||
return new ViewCursorRenderData(top, visibleRange.left, width, this._lineHeight, textContent);
|
||||
return new ViewCursorRenderData(top, visibleRange.left, width, this._lineHeight, textContent, textContentClassName);
|
||||
}
|
||||
|
||||
const visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + 1), false);
|
||||
@@ -150,8 +153,13 @@ export class ViewCursor {
|
||||
const width = range.width < 1 ? this._typicalHalfwidthCharacterWidth : range.width;
|
||||
|
||||
if (this._cursorStyle === TextEditorCursorStyle.Block) {
|
||||
const lineContent = this._context.model.getLineContent(this._position.lineNumber);
|
||||
textContent = lineContent.charAt(this._position.column - 1);
|
||||
const lineData = this._context.model.getViewLineData(this._position.lineNumber);
|
||||
textContent = lineData.content.charAt(this._position.column - 1);
|
||||
if (strings.isHighSurrogate(lineData.content.charCodeAt(this._position.column - 1))) {
|
||||
textContent += lineData.content.charAt(this._position.column);
|
||||
}
|
||||
const tokenIndex = lineData.tokens.findTokenIndexAtOffset(this._position.column - 1);
|
||||
textContentClassName = lineData.tokens.getClassName(tokenIndex);
|
||||
}
|
||||
|
||||
let top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta;
|
||||
@@ -163,7 +171,7 @@ export class ViewCursor {
|
||||
height = 2;
|
||||
}
|
||||
|
||||
return new ViewCursorRenderData(top, range.left, width, height, textContent);
|
||||
return new ViewCursorRenderData(top, range.left, width, height, textContent, textContentClassName);
|
||||
}
|
||||
|
||||
public prepareRender(ctx: RenderingContext): void {
|
||||
@@ -181,6 +189,8 @@ export class ViewCursor {
|
||||
this._domNode.domNode.textContent = this._lastRenderedContent;
|
||||
}
|
||||
|
||||
this._domNode.setClassName('cursor ' + this._renderData.textContentClassName);
|
||||
|
||||
this._domNode.setDisplay('block');
|
||||
this._domNode.setTop(this._renderData.top);
|
||||
this._domNode.setLeft(this._renderData.left);
|
||||
|
||||
@@ -99,7 +99,11 @@ export class ViewZones extends ViewPart {
|
||||
}
|
||||
|
||||
public onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {
|
||||
return this._recomputeWhitespacesProps();
|
||||
const hadAChange = this._recomputeWhitespacesProps();
|
||||
if (hadAChange) {
|
||||
this._context.viewLayout.onHeightMaybeChanged();
|
||||
}
|
||||
return hadAChange;
|
||||
}
|
||||
|
||||
public onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {
|
||||
|
||||
@@ -21,18 +21,20 @@ import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
|
||||
import { View, IOverlayWidgetData, IContentWidgetData } from 'vs/editor/browser/view/viewImpl';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { InternalEditorAction } from 'vs/editor/common/editorAction';
|
||||
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoBorder, editorInfoForeground } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoBorder, editorInfoForeground, editorHintForeground, editorHintBorder } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { ClassName } from 'vs/editor/common/model/intervalTree';
|
||||
import { ITextModel, IModelDecorationOptions } from 'vs/editor/common/model';
|
||||
import { ICommandDelegate } from 'vs/editor/browser/view/viewController';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export abstract class CodeEditorWidget extends CommonCodeEditor implements editorBrowser.ICodeEditor {
|
||||
|
||||
@@ -86,26 +88,22 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
|
||||
constructor(
|
||||
domElement: HTMLElement,
|
||||
options: IEditorOptions,
|
||||
isSimpleWidget: boolean,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IThemeService themeService: IThemeService
|
||||
@IThemeService themeService: IThemeService,
|
||||
@INotificationService notificationService: INotificationService
|
||||
) {
|
||||
super(domElement, options, instantiationService, contextKeyService);
|
||||
super(domElement, options, isSimpleWidget, instantiationService, contextKeyService, notificationService);
|
||||
this._codeEditorService = codeEditorService;
|
||||
this._commandService = commandService;
|
||||
this._themeService = themeService;
|
||||
|
||||
this._focusTracker = new CodeEditorWidgetFocusTracker(domElement);
|
||||
this._focusTracker.onChange(() => {
|
||||
let hasFocus = this._focusTracker.hasFocus();
|
||||
|
||||
if (hasFocus) {
|
||||
this._onDidFocusEditor.fire();
|
||||
} else {
|
||||
this._onDidBlurEditor.fire();
|
||||
}
|
||||
this._editorFocus.setValue(this._focusTracker.hasFocus());
|
||||
});
|
||||
|
||||
this.contentWidgets = {};
|
||||
@@ -358,8 +356,62 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
|
||||
}
|
||||
|
||||
protected _createView(): void {
|
||||
let commandDelegate: ICommandDelegate;
|
||||
if (this.isSimpleWidget) {
|
||||
commandDelegate = {
|
||||
paste: (source: string, text: string, pasteOnNewLine: boolean, multicursorText: string[]) => {
|
||||
this.cursor.trigger(source, editorCommon.Handler.Paste, { text, pasteOnNewLine, multicursorText });
|
||||
},
|
||||
type: (source: string, text: string) => {
|
||||
this.cursor.trigger(source, editorCommon.Handler.Type, { text });
|
||||
},
|
||||
replacePreviousChar: (source: string, text: string, replaceCharCnt: number) => {
|
||||
this.cursor.trigger(source, editorCommon.Handler.ReplacePreviousChar, { text, replaceCharCnt });
|
||||
},
|
||||
compositionStart: (source: string) => {
|
||||
this.cursor.trigger(source, editorCommon.Handler.CompositionStart, undefined);
|
||||
},
|
||||
compositionEnd: (source: string) => {
|
||||
this.cursor.trigger(source, editorCommon.Handler.CompositionEnd, undefined);
|
||||
},
|
||||
cut: (source: string) => {
|
||||
this.cursor.trigger(source, editorCommon.Handler.Cut, undefined);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
commandDelegate = {
|
||||
paste: (source: string, text: string, pasteOnNewLine: boolean, multicursorText: string[]) => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.Paste, {
|
||||
text: text,
|
||||
pasteOnNewLine: pasteOnNewLine,
|
||||
multicursorText: multicursorText
|
||||
});
|
||||
},
|
||||
type: (source: string, text: string) => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.Type, {
|
||||
text: text
|
||||
});
|
||||
},
|
||||
replacePreviousChar: (source: string, text: string, replaceCharCnt: number) => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.ReplacePreviousChar, {
|
||||
text: text,
|
||||
replaceCharCnt: replaceCharCnt
|
||||
});
|
||||
},
|
||||
compositionStart: (source: string) => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.CompositionStart, {});
|
||||
},
|
||||
compositionEnd: (source: string) => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.CompositionEnd, {});
|
||||
},
|
||||
cut: (source: string) => {
|
||||
this._commandService.executeCommand(editorCommon.Handler.Cut, {});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
this._view = new View(
|
||||
this._commandService,
|
||||
commandDelegate,
|
||||
this._configuration,
|
||||
this._themeService,
|
||||
this.viewModel,
|
||||
@@ -375,13 +427,13 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
|
||||
const viewEventBus = this._view.getInternalEventBus();
|
||||
|
||||
viewEventBus.onDidGainFocus = () => {
|
||||
this._onDidFocusEditorText.fire();
|
||||
this._editorTextFocus.setValue(true);
|
||||
// In IE, the focus is not synchronous, so we give it a little help
|
||||
this._onDidFocusEditor.fire();
|
||||
this._editorFocus.setValue(true);
|
||||
};
|
||||
|
||||
viewEventBus.onDidScroll = (e) => this._onDidScrollChange.fire(e);
|
||||
viewEventBus.onDidLoseFocus = () => this._onDidBlurEditorText.fire();
|
||||
viewEventBus.onDidLoseFocus = () => this._editorTextFocus.setValue(false);
|
||||
viewEventBus.onContextMenu = (e) => this._onContextMenu.fire(e);
|
||||
viewEventBus.onMouseDown = (e) => this._onMouseDown.fire(e);
|
||||
viewEventBus.onMouseUp = (e) => this._onMouseUp.fire(e);
|
||||
@@ -399,7 +451,12 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito
|
||||
return;
|
||||
}
|
||||
if (s && s.cursorState && s.viewState) {
|
||||
this._view.restoreState(this.viewModel.viewLayout.reduceRestoreState(s.viewState));
|
||||
const reducedState = this.viewModel.reduceRestoreState(s.viewState);
|
||||
const linesViewportData = this.viewModel.viewLayout.getLinesViewportDataAtScrollTop(reducedState.scrollTop);
|
||||
const startPosition = this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.startLineNumber, 1));
|
||||
const endPosition = this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(linesViewportData.endLineNumber, 1));
|
||||
this.model.tokenizeViewport(startPosition.lineNumber, endPosition.lineNumber);
|
||||
this._view.restoreState(reducedState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,8 +512,8 @@ class CodeEditorWidgetFocusTracker extends Disposable {
|
||||
private _hasFocus: boolean;
|
||||
private _domFocusTracker: dom.IFocusTracker;
|
||||
|
||||
private _onChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
public onChange: Event<void> = this._onChange.event;
|
||||
private readonly _onChange: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onChange: Event<void> = this._onChange.event;
|
||||
|
||||
constructor(domElement: HTMLElement) {
|
||||
super();
|
||||
@@ -486,6 +543,13 @@ function getSquigglySVGData(color: Color) {
|
||||
return squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;
|
||||
}
|
||||
|
||||
const dotdotdotStart = encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" height="3" width="12"><g fill="`);
|
||||
const dotdotdotEnd = encodeURIComponent(`"><circle cx="1" cy="1" r="1"/><circle cx="5" cy="1" r="1"/><circle cx="9" cy="1" r="1"/></g></svg>`);
|
||||
|
||||
function getDotDotDotSVGData(color: Color) {
|
||||
return dotdotdotStart + encodeURIComponent(color.toString()) + dotdotdotEnd;
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
let errorBorderColor = theme.getColor(editorErrorBorder);
|
||||
if (errorBorderColor) {
|
||||
@@ -513,4 +577,13 @@ registerThemingParticipant((theme, collector) => {
|
||||
if (infoForeground) {
|
||||
collector.addRule(`.monaco-editor .${ClassName.EditorInfoDecoration} { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(infoForeground)}") repeat-x bottom left; }`);
|
||||
}
|
||||
|
||||
let hintBorderColor = theme.getColor(editorHintBorder);
|
||||
if (hintBorderColor) {
|
||||
collector.addRule(`.monaco-editor .${ClassName.EditorHintDecoration} { border-bottom: 2px dotted ${hintBorderColor}; }`);
|
||||
}
|
||||
let hintForeground = theme.getColor(editorHintForeground);
|
||||
if (hintForeground) {
|
||||
collector.addRule(`.monaco-editor .${ClassName.EditorHintDecoration} { background: url("data:image/svg+xml;utf8,${getDotDotDotSVGData(hintForeground)}") no-repeat bottom left; }`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -27,10 +27,10 @@ import { LineTokens } from 'vs/editor/common/core/lineTokens';
|
||||
import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import { Position, IPosition } from 'vs/editor/common/core/position';
|
||||
import { Selection, ISelection } from 'vs/editor/common/core/selection';
|
||||
import { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { InlineDecoration, InlineDecorationType, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ColorId, MetadataConsts, FontStyle } from 'vs/editor/common/modes';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import * as editorOptions from 'vs/editor/common/config/editorOptions';
|
||||
import { registerThemingParticipant, IThemeService, ITheme, getThemeTypeSelector } from 'vs/platform/theme/common/themeService';
|
||||
import { scrollbarShadow, diffInserted, diffRemoved, defaultInsertColor, defaultRemoveColor, diffInsertedOutline, diffRemovedOutline } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -43,6 +43,7 @@ import URI from 'vs/base/common/uri';
|
||||
import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';
|
||||
import { IModelDeltaDecoration, IModelDecorationsChangeAccessor, ITextModel } from 'vs/editor/common/model';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { StableEditorScrollState } from 'vs/editor/browser/core/editorState';
|
||||
|
||||
interface IEditorDiffDecorations {
|
||||
decorations: IModelDeltaDecoration[];
|
||||
@@ -99,15 +100,13 @@ class VisualEditorState {
|
||||
this._zonesMap = {};
|
||||
|
||||
// (2) Model decorations
|
||||
if (this._decorations.length > 0) {
|
||||
editor.changeDecorations((changeAccessor: IModelDecorationsChangeAccessor) => {
|
||||
changeAccessor.deltaDecorations(this._decorations, []);
|
||||
});
|
||||
}
|
||||
this._decorations = [];
|
||||
this._decorations = editor.deltaDecorations(this._decorations, []);
|
||||
}
|
||||
|
||||
public apply(editor: CodeEditor, overviewRuler: editorBrowser.IOverviewRuler, newDecorations: IEditorDiffDecorationsWithZones): void {
|
||||
public apply(editor: CodeEditor, overviewRuler: editorBrowser.IOverviewRuler, newDecorations: IEditorDiffDecorationsWithZones, restoreScrollState: boolean): void {
|
||||
|
||||
const scrollState = restoreScrollState ? StableEditorScrollState.capture(editor) : null;
|
||||
|
||||
// view zones
|
||||
editor.changeViewZones((viewChangeAccessor: editorBrowser.IViewZoneChangeAccessor) => {
|
||||
for (let i = 0, length = this._zones.length; i < length; i++) {
|
||||
@@ -123,6 +122,10 @@ class VisualEditorState {
|
||||
}
|
||||
});
|
||||
|
||||
if (scrollState) {
|
||||
scrollState.restore(editor);
|
||||
}
|
||||
|
||||
// decorations
|
||||
this._decorations = editor.deltaDecorations(this._decorations, newDecorations.decorations);
|
||||
|
||||
@@ -284,13 +287,22 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
|
||||
this._lineChanges = null;
|
||||
|
||||
const services = new ServiceCollection();
|
||||
services.set(IContextKeyService, this._contextKeyService);
|
||||
const leftContextKeyService = this._contextKeyService.createScoped();
|
||||
leftContextKeyService.createKey('isInDiffLeftEditor', true);
|
||||
|
||||
const scopedInstantiationService = instantiationService.createChild(services);
|
||||
const leftServices = new ServiceCollection();
|
||||
leftServices.set(IContextKeyService, leftContextKeyService);
|
||||
const leftScopedInstantiationService = instantiationService.createChild(leftServices);
|
||||
|
||||
this._createLeftHandSideEditor(options, scopedInstantiationService);
|
||||
this._createRightHandSideEditor(options, scopedInstantiationService);
|
||||
const rightContextKeyService = this._contextKeyService.createScoped();
|
||||
rightContextKeyService.createKey('isInDiffRightEditor', true);
|
||||
|
||||
const rightServices = new ServiceCollection();
|
||||
rightServices.set(IContextKeyService, rightContextKeyService);
|
||||
const rightScopedInstantiationService = instantiationService.createChild(rightServices);
|
||||
|
||||
this._createLeftHandSideEditor(options, leftScopedInstantiationService);
|
||||
this._createRightHandSideEditor(options, rightScopedInstantiationService);
|
||||
|
||||
this._reviewPane = new DiffReview(this);
|
||||
this._containerDomElement.appendChild(this._reviewPane.domNode.domNode);
|
||||
@@ -912,8 +924,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
|
||||
try {
|
||||
this._currentlyChangingViewZones = true;
|
||||
this._originalEditorState.apply(this.originalEditor, this._originalOverviewRuler, diffDecorations.original);
|
||||
this._modifiedEditorState.apply(this.modifiedEditor, this._modifiedOverviewRuler, diffDecorations.modified);
|
||||
this._originalEditorState.apply(this.originalEditor, this._originalOverviewRuler, diffDecorations.original, false);
|
||||
this._modifiedEditorState.apply(this.modifiedEditor, this._modifiedOverviewRuler, diffDecorations.modified, true);
|
||||
} finally {
|
||||
this._currentlyChangingViewZones = false;
|
||||
}
|
||||
@@ -1989,10 +2001,13 @@ class InlineViewZonesComputer extends ViewZonesComputer {
|
||||
sb.appendASCIIString(String(count * config.lineHeight));
|
||||
sb.appendASCIIString('px;width:1000000px;">');
|
||||
|
||||
const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII());
|
||||
const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL());
|
||||
renderViewLine(new RenderLineInput(
|
||||
(config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations),
|
||||
lineContent,
|
||||
originalModel.mightContainRTL(),
|
||||
isBasicASCII,
|
||||
containsRTL,
|
||||
0,
|
||||
lineTokens,
|
||||
actualDecorations,
|
||||
@@ -2023,27 +2038,31 @@ function createFakeLinesDiv(): HTMLElement {
|
||||
}
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
let added = theme.getColor(diffInserted);
|
||||
const added = theme.getColor(diffInserted);
|
||||
if (added) {
|
||||
collector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { background-color: ${added}; }`);
|
||||
collector.addRule(`.monaco-diff-editor .line-insert, .monaco-diff-editor .char-insert { background-color: ${added}; }`);
|
||||
collector.addRule(`.monaco-editor .inline-added-margin-view-zone { background-color: ${added}; }`);
|
||||
}
|
||||
let removed = theme.getColor(diffRemoved);
|
||||
|
||||
const removed = theme.getColor(diffRemoved);
|
||||
if (removed) {
|
||||
collector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { background-color: ${removed}; }`);
|
||||
collector.addRule(`.monaco-diff-editor .line-delete, .monaco-diff-editor .char-delete { background-color: ${removed}; }`);
|
||||
collector.addRule(`.monaco-editor .inline-deleted-margin-view-zone { background-color: ${removed}; }`);
|
||||
}
|
||||
let addedOutline = theme.getColor(diffInsertedOutline);
|
||||
|
||||
const addedOutline = theme.getColor(diffInsertedOutline);
|
||||
if (addedOutline) {
|
||||
collector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { border: 1px dashed ${addedOutline}; }`);
|
||||
collector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${addedOutline}; }`);
|
||||
}
|
||||
let removedOutline = theme.getColor(diffRemovedOutline);
|
||||
|
||||
const removedOutline = theme.getColor(diffRemovedOutline);
|
||||
if (removedOutline) {
|
||||
collector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { border: 1px dashed ${removedOutline}; }`);
|
||||
collector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${removedOutline}; }`);
|
||||
}
|
||||
let shadow = theme.getColor(scrollbarShadow);
|
||||
|
||||
const shadow = theme.getColor(scrollbarShadow);
|
||||
if (shadow) {
|
||||
collector.addRule(`.monaco-diff-editor.side-by-side .editor.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ILineChange, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { IDiffEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
|
||||
|
||||
interface IDiffRange {
|
||||
|
||||
@@ -29,6 +29,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
import { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
|
||||
|
||||
const DIFF_LINES_PADDING = 3;
|
||||
|
||||
@@ -583,9 +584,34 @@ export class DiffReview extends Disposable {
|
||||
|
||||
let cell = document.createElement('div');
|
||||
cell.className = 'diff-review-cell diff-review-summary';
|
||||
cell.appendChild(document.createTextNode(`${diffIndex + 1}/${this._diffs.length}: @@ -${minOriginalLine},${maxOriginalLine - minOriginalLine + 1} +${minModifiedLine},${maxModifiedLine - minModifiedLine + 1} @@`));
|
||||
const originalChangedLinesCnt = maxOriginalLine - minOriginalLine + 1;
|
||||
const modifiedChangedLinesCnt = maxModifiedLine - minModifiedLine + 1;
|
||||
cell.appendChild(document.createTextNode(`${diffIndex + 1}/${this._diffs.length}: @@ -${minOriginalLine},${originalChangedLinesCnt} +${minModifiedLine},${modifiedChangedLinesCnt} @@`));
|
||||
header.setAttribute('data-line', String(minModifiedLine));
|
||||
header.setAttribute('aria-label', nls.localize('header', "Difference {0} of {1}: original {2}, {3} lines, modified {4}, {5} lines", (diffIndex + 1), this._diffs.length, minOriginalLine, maxOriginalLine - minOriginalLine + 1, minModifiedLine, maxModifiedLine - minModifiedLine + 1));
|
||||
|
||||
const getAriaLines = (lines: number) => {
|
||||
if (lines === 0) {
|
||||
return nls.localize('no_lines', "no lines");
|
||||
} else if (lines === 1) {
|
||||
return nls.localize('one_line', "1 line");
|
||||
} else {
|
||||
return nls.localize('more_lines', "{0} lines", lines);
|
||||
}
|
||||
};
|
||||
|
||||
const originalChangedLinesCntAria = getAriaLines(originalChangedLinesCnt);
|
||||
const modifiedChangedLinesCntAria = getAriaLines(modifiedChangedLinesCnt);
|
||||
header.setAttribute('aria-label', nls.localize({
|
||||
key: 'header',
|
||||
comment: [
|
||||
'This is the ARIA label for a git diff header.',
|
||||
'A git diff header looks like this: @@ -154,12 +159,39 @@.',
|
||||
'That encodes that at original line 154 (which is now line 159), 12 lines were removed/changed with 39 lines.',
|
||||
'Variables 0 and 1 refer to the diff index out of total number of diffs.',
|
||||
'Variables 2 and 4 will be numbers (a line number).',
|
||||
'Variables 3 and 5 will be "no lines", "1 line" or "X lines", localized separately.'
|
||||
]
|
||||
}, "Difference {0} of {1}: original {2}, {3}, modified {4}, {5}", (diffIndex + 1), this._diffs.length, minOriginalLine, originalChangedLinesCntAria, minModifiedLine, modifiedChangedLinesCntAria));
|
||||
header.appendChild(cell);
|
||||
|
||||
// @@ -504,7 +517,7 @@
|
||||
@@ -738,10 +764,13 @@ export class DiffReview extends Disposable {
|
||||
|
||||
const lineTokens = new LineTokens(tokens, lineContent);
|
||||
|
||||
const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII());
|
||||
const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL());
|
||||
const r = renderViewLine(new RenderLineInput(
|
||||
(config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations),
|
||||
lineContent,
|
||||
model.mightContainRTL(),
|
||||
isBasicASCII,
|
||||
containsRTL,
|
||||
0,
|
||||
lineTokens,
|
||||
[],
|
||||
|
||||
@@ -30,9 +30,10 @@ export class EmbeddedCodeEditorWidget extends CodeEditor {
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IThemeService themeService: IThemeService
|
||||
@IThemeService themeService: IThemeService,
|
||||
@INotificationService notificationService: INotificationService
|
||||
) {
|
||||
super(domElement, parentEditor.getRawConfiguration(), instantiationService, codeEditorService, commandService, contextKeyService, themeService);
|
||||
super(domElement, parentEditor.getRawConfiguration(), instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService);
|
||||
|
||||
this._parentEditor = parentEditor;
|
||||
this._overwriteOptions = options;
|
||||
|
||||
Reference in New Issue
Block a user