提交 7ba794d2 编写于 作者: J Joao Moreno

Merge branch 'master' into grid

......@@ -30,6 +30,15 @@ export interface IPanelStyles {
headerHighContrastBorder?: Color;
}
/**
* A Panel is a structured SplitView view.
*
* WARNING: You must call `render()` after you contruct it.
* It can't be done automatically at the end of the ctor
* because of the order of property initialization in TypeScript.
* Subclasses wouldn't be able to set own properties
* before the `render()` call, thus forbiding their use.
*/
export abstract class Panel implements IView {
private static readonly HEADER_SIZE = 22;
......@@ -40,25 +49,21 @@ export abstract class Panel implements IView {
private _minimumBodySize: number;
private _maximumBodySize: number;
private ariaHeaderLabel: string;
private styles: IPanelStyles | undefined = undefined;
private styles: IPanelStyles = {};
private el: HTMLElement;
readonly element: HTMLElement;
private header: HTMLElement;
protected disposables: IDisposable[] = [];
private _onDidChange = new Emitter<number | undefined>();
readonly onDidChange: Event<number | undefined> = this._onDidChange.event;
get element(): HTMLElement {
return this.el;
}
get draggableElement(): HTMLElement {
return this.header;
}
get dropTargetElement(): HTMLElement {
return this.el;
return this.element;
}
private _dropBackground: Color | undefined;
......@@ -109,6 +114,8 @@ export abstract class Panel implements IView {
this.ariaHeaderLabel = options.ariaHeaderLabel || '';
this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120;
this._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY;
this.element = $('.panel');
}
isExpanded(): boolean {
......@@ -139,11 +146,9 @@ export abstract class Panel implements IView {
this._onDidChange.fire();
}
render(container: HTMLElement): void {
this.el = append(container, $('.panel'));
render(): void {
this.header = $('.panel-header');
append(this.el, this.header);
append(this.element, this.header);
this.header.setAttribute('tabindex', '0');
this.header.setAttribute('role', 'toolbar');
this.header.setAttribute('aria-label', this.ariaHeaderLabel);
......@@ -177,7 +182,7 @@ export abstract class Panel implements IView {
// onHeaderKeyDown.filter(e => e.keyCode === KeyCode.DownArrow)
// .event(focusNext, this, this.disposables);
const body = append(this.el, $('.panel-body'));
const body = append(this.element, $('.panel-body'));
this.renderBody(body);
}
......
......@@ -20,10 +20,10 @@ export interface ISplitViewOptions {
}
export interface IView {
readonly element: HTMLElement;
readonly minimumSize: number;
readonly maximumSize: number;
readonly onDidChange: Event<number | undefined>;
render(container: HTMLElement, orientation: Orientation): void;
layout(size: number, orientation: Orientation): void;
}
......@@ -169,7 +169,7 @@ export class SplitView implements IDisposable {
this.sashItems.splice(index - 1, 0, sashItem);
}
view.render(container, this.orientation);
container.appendChild(view.element);
this.relayout(index);
this.state = State.Idle;
}
......
......@@ -19,8 +19,11 @@ class TestView implements IView {
get maximumSize(): number { return this._maximumSize; }
set maximumSize(size: number) { this._maximumSize = size; this._onDidChange.fire(); }
private _onDidRender = new Emitter<{ container: HTMLElement; orientation: Orientation }>();
readonly onDidRender = this._onDidRender.event;
private _element: HTMLElement = document.createElement('div');
get element(): HTMLElement { this._onDidGetElement.fire(); return this._element; }
private _onDidGetElement = new Emitter<void>();
readonly onDidGetElement = this._onDidGetElement.event;
private _size = 0;
get size(): number { return this._size; }
......@@ -37,10 +40,6 @@ class TestView implements IView {
assert(_minimumSize <= _maximumSize, 'splitview view minimum size must be <= maximum size');
}
render(container: HTMLElement, orientation: Orientation): void {
this._onDidRender.fire({ container, orientation });
}
layout(size: number, orientation: Orientation): void {
this._size = size;
this._onDidLayout.fire({ size, orientation });
......@@ -52,7 +51,7 @@ class TestView implements IView {
dispose(): void {
this._onDidChange.dispose();
this._onDidRender.dispose();
this._onDidGetElement.dispose();
this._onDidLayout.dispose();
this._onDidFocus.dispose();
}
......@@ -136,7 +135,7 @@ suite('Splitview', () => {
const layoutDisposable = view.onDidLayout(() => didLayout = true);
let didRender = false;
const renderDisposable = view.onDidRender(() => didRender = true);
const renderDisposable = view.onDidGetElement(() => didRender = true);
splitview.addView(view, 20);
......@@ -322,7 +321,7 @@ suite('Splitview', () => {
splitview.addView(view1, 142, 0);
assert.equal(view1.size, 986, 'first view is stretched');
view2.onDidRender(() => {
view2.onDidGetElement(() => {
assert.throws(() => splitview.resizeView(1, 922));
assert.throws(() => splitview.resizeView(1, 922));
});
......
......@@ -704,10 +704,6 @@ export namespace CoreNavigationCommands {
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly) {
return;
}
let newState: CursorState;
if (args.wholeLine) {
newState = CursorMoveCommands.line(context, cursors.getPrimaryCursor(), false, args.position, args.viewPosition);
......@@ -769,10 +765,6 @@ export namespace CoreNavigationCommands {
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly) {
return;
}
const lastAddedCursorIndex = cursors.getLastAddedCursorIndex();
let newStates = cursors.getAll().slice(0);
......@@ -1251,9 +1243,6 @@ export namespace CoreNavigationCommands {
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly) {
return;
}
const lastAddedCursorIndex = cursors.getLastAddedCursorIndex();
......@@ -1312,12 +1301,6 @@ export namespace CoreNavigationCommands {
}
public runCoreEditorCommand(cursors: ICursors, args: any): void {
const context = cursors.context;
if (context.config.readOnly) {
return;
}
const lastAddedCursorIndex = cursors.getLastAddedCursorIndex();
let newStates = cursors.getAll().slice(0);
......
......@@ -53,6 +53,11 @@ export interface IViewZone {
* If neither `heightInPx` nor `heightInLines` is specified, a default of `heightInLines` = 1 will be chosen.
*/
heightInPx?: number;
/**
* The minimum width in px of the view zone.
* If this is set, the editor will ensure that the scroll width is >= than this value.
*/
minWidthInPx?: number;
/**
* The dom node of the view zone
*/
......
......@@ -271,6 +271,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
return this._visibleLines.onTokensChanged(e);
}
public onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {
this._context.viewLayout.onMaxLineWidthChanged(this._maxLineWidth);
return this._visibleLines.onZonesChanged(e);
}
public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {
......
......@@ -25,6 +25,7 @@ export interface IMyViewZone {
interface IComputedViewZoneProps {
afterViewLineNumber: number;
heightInPx: number;
minWidthInPx: number;
}
export class ViewZones extends ViewPart {
......@@ -138,7 +139,8 @@ export class ViewZones extends ViewPart {
if (zone.afterLineNumber === 0) {
return {
afterViewLineNumber: 0,
heightInPx: this._heightInPixels(zone)
heightInPx: this._heightInPixels(zone),
minWidthInPx: this._minWidthInPixels(zone)
};
}
......@@ -177,13 +179,14 @@ export class ViewZones extends ViewPart {
let isVisible = this._context.model.coordinatesConverter.modelPositionIsVisible(zoneBeforeModelPosition);
return {
afterViewLineNumber: viewPosition.lineNumber,
heightInPx: (isVisible ? this._heightInPixels(zone) : 0)
heightInPx: (isVisible ? this._heightInPixels(zone) : 0),
minWidthInPx: this._minWidthInPixels(zone)
};
}
public addZone(zone: IViewZone): number {
let props = this._computeWhitespaceProps(zone);
let whitespaceId = this._context.viewLayout.addWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx);
let whitespaceId = this._context.viewLayout.addWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx);
let myZone: IMyViewZone = {
whitespaceId: whitespaceId,
......@@ -275,6 +278,13 @@ export class ViewZones extends ViewPart {
return this._lineHeight;
}
private _minWidthInPixels(zone: IViewZone): number {
if (typeof zone.minWidthInPx === 'number') {
return zone.minWidthInPx;
}
return 0;
}
private _safeCallOnComputedHeight(zone: IViewZone, height: number): void {
if (typeof zone.onComputedHeight === 'function') {
try {
......
......@@ -23,13 +23,11 @@ import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
import { renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
import { CodeEditor } from 'vs/editor/browser/codeEditor';
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, 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 * as editorOptions from 'vs/editor/common/config/editorOptions';
import { registerThemingParticipant, IThemeService, ITheme, getThemeTypeSelector } from 'vs/platform/theme/common/themeService';
......@@ -1175,7 +1173,7 @@ interface IDataSource {
getModifiedEditor(): editorBrowser.ICodeEditor;
}
class DiffEditorWidgetStyle extends Disposable {
abstract class DiffEditorWidgetStyle extends Disposable {
_dataSource: IDataSource;
_insertColor: Color;
......@@ -1223,17 +1221,9 @@ class DiffEditorWidgetStyle extends Disposable {
};
}
_getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones {
return null;
}
_getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
return null;
}
_getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
return null;
}
protected abstract _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones;
protected abstract _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations;
protected abstract _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations;
}
interface IMyViewZone extends editorBrowser.IViewZone {
......@@ -1617,12 +1607,12 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
return this._dataSource.getHeight();
}
_getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones {
protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones {
let c = new SideBySideViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ);
return c.getViewZones();
}
_getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
protected _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._removeColor.toString();
let result: IEditorDiffDecorations = {
......@@ -1682,7 +1672,7 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
return result;
}
_getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
protected _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._insertColor.toString();
let result: IEditorDiffDecorations = {
......@@ -1749,7 +1739,7 @@ class SideBySideViewZonesComputer extends ViewZonesComputer {
super(lineChanges, originalForeignVZ, modifiedForeignVZ);
}
_produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
protected _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
if (lineChangeModifiedLength > lineChangeOriginalLength) {
return {
afterLineNumber: Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber),
......@@ -1760,7 +1750,7 @@ class SideBySideViewZonesComputer extends ViewZonesComputer {
return null;
}
_produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
protected _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
if (lineChangeOriginalLength > lineChangeModifiedLength) {
return {
afterLineNumber: Math.max(lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber),
......@@ -1797,12 +1787,12 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
// Nothing to do..
}
_getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones {
protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones {
let computer = new InlineViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor, renderIndicators);
return computer.getViewZones();
}
_getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
protected _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._removeColor.toString();
let result: IEditorDiffDecorations = {
......@@ -1831,7 +1821,7 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
return result;
}
_getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
protected _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
const overviewZoneColor = this._insertColor.toString();
let result: IEditorDiffDecorations = {
......@@ -1913,7 +1903,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
this.renderIndicators = renderIndicators;
}
_produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
protected _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
let marginDomNode = document.createElement('div');
marginDomNode.className = 'inline-added-margin-view-zone';
Configuration.applyFontInfoSlow(marginDomNode, this.modifiedEditorConfiguration.fontInfo);
......@@ -1926,7 +1916,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
};
}
_produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
protected _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone {
let decorations: InlineDecoration[] = [];
if (lineChange.charChanges) {
for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
......@@ -1945,8 +1935,10 @@ class InlineViewZonesComputer extends ViewZonesComputer {
let marginHTML: string[] = [];
let lineDecorationsWidth = this.modifiedEditorConfiguration.layoutInfo.decorationsWidth;
let lineHeight = this.modifiedEditorConfiguration.lineHeight;
const typicalHalfwidthCharacterWidth = this.modifiedEditorConfiguration.fontInfo.typicalHalfwidthCharacterWidth;
let maxCharsPerLine = 0;
for (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) {
this.renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorConfiguration, this.modifiedEditorTabSize, lineNumber, decorations, sb);
maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorConfiguration, this.modifiedEditorTabSize, lineNumber, decorations, sb));
if (this.renderIndicators) {
let index = lineNumber - lineChange.originalStartLineNumber;
......@@ -1955,6 +1947,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
]);
}
}
maxCharsPerLine += this.modifiedEditorConfiguration.viewInfo.scrollBeyondLastColumn;
let domNode = document.createElement('div');
domNode.className = 'view-lines line-delete';
......@@ -1970,27 +1963,17 @@ class InlineViewZonesComputer extends ViewZonesComputer {
shouldNotShrink: true,
afterLineNumber: (lineChange.modifiedEndLineNumber === 0 ? lineChange.modifiedStartLineNumber : lineChange.modifiedStartLineNumber - 1),
heightInLines: lineChangeOriginalLength,
minWidthInPx: (maxCharsPerLine * typicalHalfwidthCharacterWidth),
domNode: domNode,
marginDomNode: marginDomNode
};
}
private renderOriginalLine(count: number, originalModel: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): void {
let lineContent = originalModel.getLineContent(lineNumber);
let actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1);
private _renderOriginalLine(count: number, originalModel: ITextModel, config: editorOptions.InternalEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): number {
const lineTokens = originalModel.getLineTokens(lineNumber);
const lineContent = lineTokens.getLineContent();
const defaultMetadata = (
(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)
| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)
| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)
) >>> 0;
const tokens = new Uint32Array(2);
tokens[0] = lineContent.length;
tokens[1] = defaultMetadata;
const lineTokens = new LineTokens(tokens, lineContent);
const actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1);
sb.appendASCIIString('<div class="view-line');
if (decorations.length === 0) {
......@@ -2003,7 +1986,7 @@ class InlineViewZonesComputer extends ViewZonesComputer {
const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII());
const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL());
renderViewLine(new RenderLineInput(
const output = renderViewLine(new RenderLineInput(
(config.fontInfo.isMonospace && !config.viewInfo.disableMonospaceOptimizations),
lineContent,
isBasicASCII,
......@@ -2020,6 +2003,9 @@ class InlineViewZonesComputer extends ViewZonesComputer {
), sb);
sb.appendASCIIString('</div>');
const absoluteOffsets = output.characterMapping.getAbsoluteOffsets();
return absoluteOffsets.length > 0 ? absoluteOffsets[absoluteOffsets.length - 1] : 0;
}
}
......
......@@ -254,6 +254,11 @@ const editorConfiguration: IConfigurationNode = {
'default': EDITOR_DEFAULTS.viewInfo.scrollBeyondLastLine,
'description': nls.localize('scrollBeyondLastLine', "Controls if the editor will scroll beyond the last line")
},
'editor.scrollBeyondLastColumn': {
'type': 'number',
'default': EDITOR_DEFAULTS.viewInfo.scrollBeyondLastColumn,
'description': nls.localize('scrollBeyondLastColumn', "Controls if the editor will scroll beyond the last column")
},
'editor.smoothScrolling': {
'type': 'boolean',
'default': EDITOR_DEFAULTS.viewInfo.smoothScrolling,
......@@ -700,4 +705,24 @@ const editorConfiguration: IConfigurationNode = {
}
};
let cachedEditorConfigurationKeys: { [key: string]: boolean; } = null;
function getEditorConfigurationKeys(): { [key: string]: boolean; } {
if (cachedEditorConfigurationKeys === null) {
cachedEditorConfigurationKeys = Object.create(null);
Object.keys(editorConfiguration.properties).forEach((prop) => {
cachedEditorConfigurationKeys[prop] = true;
});
}
return cachedEditorConfigurationKeys;
}
export function isEditorConfigurationKey(key: string): boolean {
const editorConfigurationKeys = getEditorConfigurationKeys();
return (editorConfigurationKeys[`editor.${key}`] || false);
}
export function isDiffEditorConfigurationKey(key: string): boolean {
const editorConfigurationKeys = getEditorConfigurationKeys();
return (editorConfigurationKeys[`diffEditor.${key}`] || false);
}
configurationRegistry.registerConfiguration(editorConfiguration);
......@@ -300,6 +300,11 @@ export interface IEditorOptions {
* Defaults to true.
*/
scrollBeyondLastLine?: boolean;
/**
* Enable that scrolling can go beyond the last column by a number of columns.
* Defaults to 5.
*/
scrollBeyondLastColumn?: number;
/**
* Enable that the editor animates scrolling to a position.
* Defaults to false.
......@@ -825,6 +830,7 @@ export interface InternalEditorViewOptions {
readonly cursorWidth: number;
readonly hideCursorInOverviewRuler: boolean;
readonly scrollBeyondLastLine: boolean;
readonly scrollBeyondLastColumn: number;
readonly smoothScrolling: boolean;
readonly stopRenderingLineAfter: number;
readonly renderWhitespace: 'none' | 'boundary' | 'all';
......@@ -1105,6 +1111,7 @@ export class InternalEditorOptions {
&& a.cursorWidth === b.cursorWidth
&& a.hideCursorInOverviewRuler === b.hideCursorInOverviewRuler
&& a.scrollBeyondLastLine === b.scrollBeyondLastLine
&& a.scrollBeyondLastColumn === b.scrollBeyondLastColumn
&& a.smoothScrolling === b.smoothScrolling
&& a.stopRenderingLineAfter === b.stopRenderingLineAfter
&& a.renderWhitespace === b.renderWhitespace
......@@ -1718,6 +1725,7 @@ export class EditorOptionsValidator {
cursorWidth: _clampedInt(opts.cursorWidth, defaults.cursorWidth, 0, Number.MAX_VALUE),
hideCursorInOverviewRuler: _boolean(opts.hideCursorInOverviewRuler, defaults.hideCursorInOverviewRuler),
scrollBeyondLastLine: _boolean(opts.scrollBeyondLastLine, defaults.scrollBeyondLastLine),
scrollBeyondLastColumn: _clampedInt(opts.scrollBeyondLastColumn, defaults.scrollBeyondLastColumn, 0, Constants.MAX_SAFE_SMALL_INTEGER),
smoothScrolling: _boolean(opts.smoothScrolling, defaults.smoothScrolling),
stopRenderingLineAfter: _clampedInt(opts.stopRenderingLineAfter, defaults.stopRenderingLineAfter, -1, Constants.MAX_SAFE_SMALL_INTEGER),
renderWhitespace: renderWhitespace,
......@@ -1830,6 +1838,7 @@ export class InternalEditorOptionsFactory {
cursorWidth: opts.viewInfo.cursorWidth,
hideCursorInOverviewRuler: opts.viewInfo.hideCursorInOverviewRuler,
scrollBeyondLastLine: opts.viewInfo.scrollBeyondLastLine,
scrollBeyondLastColumn: opts.viewInfo.scrollBeyondLastColumn,
smoothScrolling: opts.viewInfo.smoothScrolling,
stopRenderingLineAfter: opts.viewInfo.stopRenderingLineAfter,
renderWhitespace: (accessibilityIsOn ? 'none' : opts.viewInfo.renderWhitespace), // DISABLED WHEN SCREEN READER IS ATTACHED
......@@ -2280,6 +2289,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
cursorWidth: 0,
hideCursorInOverviewRuler: false,
scrollBeyondLastLine: true,
scrollBeyondLastColumn: 5,
smoothScrolling: false,
stopRenderingLineAfter: 10000,
renderWhitespace: 'none',
......
......@@ -24,7 +24,7 @@ export const EditorZoom: IEditorZoom = new class implements IEditorZoom {
}
public setZoomLevel(zoomLevel: number): void {
zoomLevel = Math.min(Math.max(-9, zoomLevel), 9);
zoomLevel = Math.min(Math.max(-5, zoomLevel), 20);
if (this._zoomLevel === zoomLevel) {
return;
}
......
......@@ -579,6 +579,8 @@ export class TypeOperations {
return false;
}
const isTypingAQuoteCharacter = (ch === '\'' || ch === '"');
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
......@@ -603,6 +605,15 @@ export class TypeOperations {
if (selectionContainsOnlyWhitespace) {
return false;
}
if (isTypingAQuoteCharacter && selection.startLineNumber === selection.endLineNumber && selection.startColumn + 1 === selection.endColumn) {
const selectionText = model.getValueInRange(selection);
if ((selectionText === '\'' || selectionText === '"')) {
// Typing a quote character on top of another quote character
// => disable surround selection type
return false;
}
}
}
return true;
......
......@@ -37,7 +37,7 @@ function canSyncModel(modelService: IModelService, resource: URI): boolean {
if (!model) {
return false;
}
if (model.isTooLargeForTokenization()) {
if (model.isTooLargeForSyncing()) {
return false;
}
return true;
......@@ -265,7 +265,7 @@ class EditorModelManager extends Disposable {
if (!model) {
return;
}
if (model.isTooLargeForTokenization()) {
if (model.isTooLargeForSyncing()) {
return;
}
......
......@@ -64,8 +64,8 @@ export class LinesLayout {
* @param heightInPx The height of the whitespace, in pixels.
* @return An id that can be used later to mutate or delete the whitespace
*/
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number): number {
return this._whitespaces.insertWhitespace(afterLineNumber, ordinal, heightInPx);
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): number {
return this._whitespaces.insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth);
}
/**
......@@ -155,6 +155,10 @@ export class LinesLayout {
return this._whitespaces.getCount() > 0;
}
public getWhitespaceMinWidth(): number {
return this._whitespaces.getMinWidth();
}
/**
* Check if `verticalOffset` is below all lines.
*/
......
......@@ -18,8 +18,6 @@ const SMOOTH_SCROLLING_TIME = 125;
export class ViewLayout extends Disposable implements IViewLayout {
static LINES_HORIZONTAL_EXTRA_PX = 30;
private readonly _configuration: editorCommon.IConfiguration;
private readonly _linesLayout: LinesLayout;
......@@ -143,7 +141,9 @@ export class ViewLayout extends Disposable implements IViewLayout {
private _computeScrollWidth(maxLineWidth: number, viewportWidth: number): number {
let isViewportWrapping = this._configuration.editor.wrappingInfo.isViewportWrapping;
if (!isViewportWrapping) {
return Math.max(maxLineWidth + ViewLayout.LINES_HORIZONTAL_EXTRA_PX, viewportWidth);
const extraHorizontalSpace = this._configuration.editor.viewInfo.scrollBeyondLastColumn * this._configuration.editor.fontInfo.typicalHalfwidthCharacterWidth;
const whitespaceMinWidth = this._linesLayout.getWhitespaceMinWidth();
return Math.max(maxLineWidth + extraHorizontalSpace, viewportWidth, whitespaceMinWidth);
}
return Math.max(maxLineWidth, viewportWidth);
}
......@@ -174,8 +174,8 @@ export class ViewLayout extends Disposable implements IViewLayout {
// ---- IVerticalLayoutProvider
public addWhitespace(afterLineNumber: number, ordinal: number, height: number): number {
return this._linesLayout.insertWhitespace(afterLineNumber, ordinal, height);
public addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): number {
return this._linesLayout.insertWhitespace(afterLineNumber, ordinal, height, minWidth);
}
public changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean {
return this._linesLayout.changeWhitespace(id, newAfterLineNumber, newHeight);
......
......@@ -21,6 +21,11 @@ export class WhitespaceComputer {
*/
private _heights: number[];
/**
* minWidths[i] is the min width in pixels for whitespace at index i
*/
private _minWidths: number[];
/**
* afterLineNumbers[i] is the line number whitespace at index i is after
*/
......@@ -58,8 +63,11 @@ export class WhitespaceComputer {
*/
private _lastWhitespaceId: number;
private _minWidth: number;
constructor() {
this._heights = [];
this._minWidths = [];
this._ids = [];
this._afterLineNumbers = [];
this._ordinals = [];
......@@ -67,6 +75,7 @@ export class WhitespaceComputer {
this._prefixSumValidIndex = -1;
this._whitespaceId2Index = {};
this._lastWhitespaceId = 0;
this._minWidth = -1; /* marker for not being computed */
}
/**
......@@ -105,25 +114,29 @@ export class WhitespaceComputer {
* @param heightInPx The height of the whitespace, in pixels.
* @return An id that can be used later to mutate or delete the whitespace
*/
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number): number {
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): number {
afterLineNumber = afterLineNumber | 0;
ordinal = ordinal | 0;
heightInPx = heightInPx | 0;
minWidth = minWidth | 0;
let id = (++this._lastWhitespaceId);
let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal);
this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx);
this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx, minWidth);
this._minWidth = -1; /* marker for not being computed */
return id;
}
private _insertWhitespaceAtIndex(id: number, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number): void {
private _insertWhitespaceAtIndex(id: number, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): void {
id = id | 0;
insertIndex = insertIndex | 0;
afterLineNumber = afterLineNumber | 0;
ordinal = ordinal | 0;
heightInPx = heightInPx | 0;
minWidth = minWidth | 0;
this._heights.splice(insertIndex, 0, heightInPx);
this._minWidths.splice(insertIndex, 0, minWidth);
this._ids.splice(insertIndex, 0, id);
this._afterLineNumbers.splice(insertIndex, 0, afterLineNumber);
this._ordinals.splice(insertIndex, 0, ordinal);
......@@ -202,12 +215,15 @@ export class WhitespaceComputer {
// Record old height
let heightInPx = this._heights[index];
// Record old min width
let minWidth = this._minWidths[index];
// Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace
this.removeWhitespace(id);
// And add it again
let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, newAfterLineNumber, this._ordinals, ordinal);
this._insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx);
this._insertWhitespaceAtIndex(id, insertionIndex, newAfterLineNumber, ordinal, heightInPx, minWidth);
return true;
}
......@@ -230,6 +246,7 @@ export class WhitespaceComputer {
let index = this._whitespaceId2Index[sid];
delete this._whitespaceId2Index[sid];
this._removeWhitespaceAtIndex(index);
this._minWidth = -1; /* marker for not being computed */
return true;
}
......@@ -240,6 +257,7 @@ export class WhitespaceComputer {
removeIndex = removeIndex | 0;
this._heights.splice(removeIndex, 1);
this._minWidths.splice(removeIndex, 1);
this._ids.splice(removeIndex, 1);
this._afterLineNumbers.splice(removeIndex, 1);
this._ordinals.splice(removeIndex, 1);
......@@ -410,6 +428,20 @@ export class WhitespaceComputer {
return this._heights.length;
}
/**
* The maximum min width for all whitespaces.
*/
public getMinWidth(): number {
if (this._minWidth === -1) {
let minWidth = 0;
for (let i = 0, len = this._minWidths.length; i < len; i++) {
minWidth = Math.max(minWidth, this._minWidths[i]);
}
this._minWidth = minWidth;
}
return this._minWidth;
}
/**
* Get the `afterLineNumber` for whitespace at index `index`.
*
......
......@@ -75,7 +75,7 @@ export interface IViewLayout {
* Reserve rendering space.
* @return an identifier that can be later used to remove or change the whitespace.
*/
addWhitespace(afterLineNumber: number, ordinal: number, height: number): number;
addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): number;
/**
* Change the properties of a whitespace.
*/
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import { registerEditorAction, ServicesAccessor, EditorAction } from 'vs/editor/browser/editorExtensions';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorZoom } from 'vs/editor/common/config/editorZoom';
class EditorFontZoomIn extends EditorAction {
constructor() {
super({
id: 'editor.action.fontZoomIn',
label: nls.localize('EditorFontZoomIn.label', "Editor Font Zoom In"),
alias: 'Editor Font Zoom In',
precondition: null
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
EditorZoom.setZoomLevel(EditorZoom.getZoomLevel() + 1);
}
}
class EditorFontZoomOut extends EditorAction {
constructor() {
super({
id: 'editor.action.fontZoomOut',
label: nls.localize('EditorFontZoomOut.label', "Editor Font Zoom Out"),
alias: 'Editor Font Zoom Out',
precondition: null
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
EditorZoom.setZoomLevel(EditorZoom.getZoomLevel() - 1);
}
}
class EditorFontZoomReset extends EditorAction {
constructor() {
super({
id: 'editor.action.fontZoomReset',
label: nls.localize('EditorFontZoomReset.label', "Editor Font Zoom Reset"),
alias: 'Editor Font Zoom Reset',
precondition: null
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
EditorZoom.setZoomLevel(0);
}
}
registerEditorAction(EditorFontZoomIn);
registerEditorAction(EditorFontZoomOut);
registerEditorAction(EditorFontZoomReset);
......@@ -22,6 +22,7 @@ import 'vs/editor/contrib/cursorUndo/cursorUndo';
import 'vs/editor/contrib/dnd/dnd';
import 'vs/editor/contrib/find/findController';
import 'vs/editor/contrib/folding/folding';
import 'vs/editor/contrib/fontZoom/fontZoom';
import 'vs/editor/contrib/format/formatActions';
import 'vs/editor/contrib/goToDeclaration/goToDeclarationCommands';
import 'vs/editor/contrib/goToDeclaration/goToDeclarationMouse';
......
......@@ -41,6 +41,7 @@ import { ITextModel } from 'vs/editor/common/model';
import { INotificationService, INotification, INotificationHandle, NoOpNotification, IPromptChoice } from 'vs/platform/notification/common/notification';
import { IConfirmation, IConfirmationResult, IDialogService, IDialogOptions } from 'vs/platform/dialogs/common/dialogs';
import { IPosition, Position as Pos } from 'vs/editor/common/core/position';
import { isEditorConfigurationKey, isDiffEditorConfigurationKey } from 'vs/editor/common/config/commonEditorConfig';
export class SimpleEditor implements IEditor {
......@@ -358,7 +359,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
this._cachedResolver = null;
this._dynamicKeybindings = [];
this.toDispose.push(dom.addDisposableListener(domNode, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
this._register(dom.addDisposableListener(domNode, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
let keyEvent = new StandardKeyboardEvent(e);
let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target);
if (shouldPreventDefault) {
......@@ -419,6 +420,10 @@ export class StandaloneKeybindingService extends AbstractKeybindingService {
return this._cachedResolver;
}
protected _documentHasFocus(): boolean {
return document.hasFocus();
}
private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] {
let result: ResolvedKeybindingItem[] = [], resultLen = 0;
for (let i = 0, len = items.length; i < len; i++) {
......@@ -495,6 +500,7 @@ export class SimpleConfigurationService implements IConfigurationService {
}
public updateValue(key: string, value: any, arg3?: any, arg4?: any): TPromise<void> {
this.configuration().updateValue(key, value);
return TPromise.as(null);
}
......@@ -620,3 +626,20 @@ export class SimpleWorkspaceContextService implements IWorkspaceContextService {
return true;
}
}
export function applyConfigurationValues(configurationService: IConfigurationService, source: any, isDiffEditor: boolean): void {
if (!source) {
return;
}
if (!(configurationService instanceof SimpleConfigurationService)) {
return;
}
Object.keys(source).forEach((key) => {
if (isEditorConfigurationKey(key)) {
configurationService.updateValue(`editor.${key}`, source[key]);
}
if (isDiffEditor && isDiffEditorConfigurationKey(key)) {
configurationService.updateValue(`diffEditor.${key}`, source[key]);
}
});
}
......@@ -16,7 +16,7 @@ import { IModelChangedEvent } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { StandaloneKeybindingService } from 'vs/editor/standalone/browser/simpleServices';
import { StandaloneKeybindingService, applyConfigurationValues } from 'vs/editor/standalone/browser/simpleServices';
import { IEditorContextViewService } from 'vs/editor/standalone/browser/standaloneServices';
import { CodeEditor } from 'vs/editor/browser/codeEditor';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
......@@ -30,6 +30,7 @@ import * as aria from 'vs/base/browser/ui/aria/aria';
import * as nls from 'vs/nls';
import * as browser from 'vs/base/browser/browser';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
/**
* Description of an action contribution
......@@ -284,6 +285,7 @@ export class StandaloneCodeEditor extends CodeEditor implements IStandaloneCodeE
export class StandaloneEditor extends StandaloneCodeEditor implements IStandaloneCodeEditor {
private _contextViewService: IEditorContextViewService;
private readonly _configurationService: IConfigurationService;
private _ownsModel: boolean;
constructor(
......@@ -298,7 +300,9 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
@IContextViewService contextViewService: IContextViewService,
@IStandaloneThemeService themeService: IStandaloneThemeService,
@INotificationService notificationService: INotificationService,
@IConfigurationService configurationService: IConfigurationService
) {
applyConfigurationValues(configurationService, options, false);
options = options || {};
if (typeof options.theme === 'string') {
themeService.setTheme(options.theme);
......@@ -308,6 +312,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
super(domElement, options, instantiationService, codeEditorService, commandService, contextKeyService, keybindingService, themeService, notificationService);
this._contextViewService = <IEditorContextViewService>contextViewService;
this._configurationService = configurationService;
this._register(toDispose);
if (typeof model === 'undefined') {
......@@ -331,6 +336,11 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
super.dispose();
}
public updateOptions(newOptions: IEditorOptions): void {
applyConfigurationValues(this._configurationService, newOptions, false);
super.updateOptions(newOptions);
}
_attachModel(model: ITextModel): void {
super._attachModel(model);
if (this._view) {
......@@ -350,6 +360,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
export class StandaloneDiffEditor extends DiffEditorWidget implements IStandaloneDiffEditor {
private _contextViewService: IEditorContextViewService;
private readonly _configurationService: IConfigurationService;
constructor(
domElement: HTMLElement,
......@@ -362,8 +373,10 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon
@IEditorWorkerService editorWorkerService: IEditorWorkerService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@IStandaloneThemeService themeService: IStandaloneThemeService,
@INotificationService notificationService: INotificationService
@INotificationService notificationService: INotificationService,
@IConfigurationService configurationService: IConfigurationService
) {
applyConfigurationValues(configurationService, options, true);
options = options || {};
if (typeof options.theme === 'string') {
options.theme = themeService.setTheme(options.theme);
......@@ -372,6 +385,7 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon
super(domElement, options, editorWorkerService, contextKeyService, instantiationService, codeEditorService, themeService, notificationService);
this._contextViewService = <IEditorContextViewService>contextViewService;
this._configurationService = configurationService;
this._register(toDispose);
......@@ -382,6 +396,11 @@ export class StandaloneDiffEditor extends DiffEditorWidget implements IStandalon
super.dispose();
}
public updateOptions(newOptions: IDiffEditorOptions): void {
applyConfigurationValues(this._configurationService, newOptions, true);
super.updateOptions(newOptions);
}
protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: IEditorOptions): CodeEditor {
return instantiationService.createInstance(StandaloneCodeEditor, container, options);
}
......
......@@ -38,6 +38,7 @@ import * as editorOptions from 'vs/editor/common/config/editorOptions';
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
import { ITextModel, OverviewRulerLane, EndOfLinePreference, DefaultEndOfLine, EndOfLineSequence, TrackedRangeStickiness, TextModelResolvedOptions, FindMatch } from 'vs/editor/common/model';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
function withAllStandaloneServices<T extends editorCommon.IEditor>(domElement: HTMLElement, override: IEditorOverrideServices, callback: (services: DynamicStandaloneServices) => T): T {
let services = new DynamicStandaloneServices(domElement, override);
......@@ -90,7 +91,8 @@ export function create(domElement: HTMLElement, options?: IEditorConstructionOpt
services.get(IKeybindingService),
services.get(IContextViewService),
services.get(IStandaloneThemeService),
services.get(INotificationService)
services.get(INotificationService),
services.get(IConfigurationService),
);
});
}
......@@ -124,7 +126,8 @@ export function createDiffEditor(domElement: HTMLElement, options?: IDiffEditorC
services.get(IEditorWorkerService),
services.get(ICodeEditorService),
services.get(IStandaloneThemeService),
services.get(INotificationService)
services.get(INotificationService),
services.get(IConfigurationService),
);
});
}
......
......@@ -1220,7 +1220,7 @@ suite('Editor Controller - Regression tests', () => {
constructor() {
super(languageId);
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
surroundingPairs: [{ open: '"', close: '"' }]
surroundingPairs: [{ open: '%', close: '%' }]
}));
}
}
......@@ -1231,8 +1231,8 @@ suite('Editor Controller - Regression tests', () => {
withTestCodeEditor(null, { model: model }, (editor, cursor) => {
editor.setSelection(new Selection(1, 1, 1, 2));
cursorCommand(cursor, H.Type, { text: '"' }, 'keyboard');
assert.equal(model.getValue(EndOfLinePreference.LF), '"\'"👁\'', 'assert1');
cursorCommand(cursor, H.Type, { text: '%' }, 'keyboard');
assert.equal(model.getValue(EndOfLinePreference.LF), '%\'%👁\'', 'assert1');
cursorCommand(cursor, H.Undo, {});
assert.equal(model.getValue(EndOfLinePreference.LF), '\'👁\'', 'assert2');
......@@ -4159,6 +4159,43 @@ suite('autoClosingPairs', () => {
mode.dispose();
});
test('issue #41825: Special handling of quotes in surrounding pairs', () => {
const languageId = new LanguageIdentifier('myMode', 3);
class MyMode extends MockMode {
constructor() {
super(languageId);
this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {
surroundingPairs: [
{ open: '"', close: '"' },
{ open: '\'', close: '\'' },
]
}));
}
}
const mode = new MyMode();
const model = createTextModel('var x = \'hi\';', undefined, languageId);
withTestCodeEditor(null, { model: model }, (editor, cursor) => {
editor.setSelections([
new Selection(1, 9, 1, 10),
new Selection(1, 12, 1, 13)
]);
cursorCommand(cursor, H.Type, { text: '"' }, 'keyboard');
assert.equal(model.getValue(EndOfLinePreference.LF), 'var x = "hi";', 'assert1');
editor.setSelections([
new Selection(1, 9, 1, 10),
new Selection(1, 12, 1, 13)
]);
cursorCommand(cursor, H.Type, { text: '\'' }, 'keyboard');
assert.equal(model.getValue(EndOfLinePreference.LF), 'var x = \'hi\';', 'assert2');
});
model.dispose();
mode.dispose();
});
test('All cursors should do the same thing when deleting left', () => {
let mode = new AutoClosingMode();
let model = createTextModel(
......
......@@ -32,25 +32,25 @@ suite('Common Editor Config', () => {
assert.equal(zoom.getZoomLevel(), 9);
zoom.setZoomLevel(-9);
assert.equal(zoom.getZoomLevel(), -9);
assert.equal(zoom.getZoomLevel(), -5);
zoom.setZoomLevel(10);
assert.equal(zoom.getZoomLevel(), 9);
zoom.setZoomLevel(20);
assert.equal(zoom.getZoomLevel(), 20);
zoom.setZoomLevel(-10);
assert.equal(zoom.getZoomLevel(), -9);
assert.equal(zoom.getZoomLevel(), -5);
zoom.setZoomLevel(9.1);
assert.equal(zoom.getZoomLevel(), 9);
assert.equal(zoom.getZoomLevel(), 9.1);
zoom.setZoomLevel(-9.1);
assert.equal(zoom.getZoomLevel(), -9);
assert.equal(zoom.getZoomLevel(), -5);
zoom.setZoomLevel(Infinity);
assert.equal(zoom.getZoomLevel(), 9);
assert.equal(zoom.getZoomLevel(), 20);
zoom.setZoomLevel(Number.NEGATIVE_INFINITY);
assert.equal(zoom.getZoomLevel(), -9);
assert.equal(zoom.getZoomLevel(), -5);
});
class TestWrappingConfiguration extends TestConfiguration {
......
......@@ -41,7 +41,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(29), 3);
// Add whitespace of height 5px after 2nd line
linesLayout.insertWhitespace(2, 0, 5);
linesLayout.insertWhitespace(2, 0, 5, 0);
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
// whitespace: a(2,5)
assert.equal(linesLayout.getLinesTotalHeight(), 105);
......@@ -65,8 +65,8 @@ suite('Editor ViewLayout - LinesLayout', () => {
assert.equal(linesLayout.getLineNumberAtOrAfterVerticalOffset(105), 10);
// Add two more whitespaces of height 5px
linesLayout.insertWhitespace(3, 0, 5);
linesLayout.insertWhitespace(4, 0, 5);
linesLayout.insertWhitespace(3, 0, 5, 0);
linesLayout.insertWhitespace(4, 0, 5, 0);
// lines: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
// whitespace: a(2,5), b(3, 5), c(4, 5)
assert.equal(linesLayout.getLinesTotalHeight(), 115);
......@@ -122,7 +122,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
// Start off with 10 lines and one whitespace after line 2, of height 5
var linesLayout = new LinesLayout(10, 1);
var a = linesLayout.insertWhitespace(2, 0, 5);
var a = linesLayout.insertWhitespace(2, 0, 5, 0);
// 10 lines
// whitespace: - a(2,5)
......@@ -218,7 +218,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout getLineNumberAtOrAfterVerticalOffset', () => {
var linesLayout = new LinesLayout(10, 1);
linesLayout.insertWhitespace(6, 0, 10);
linesLayout.insertWhitespace(6, 0, 10, 0);
// 10 lines
// whitespace: - a(6,10)
......@@ -267,7 +267,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout getCenteredLineInViewport', () => {
var linesLayout = new LinesLayout(10, 1);
linesLayout.insertWhitespace(6, 0, 10);
linesLayout.insertWhitespace(6, 0, 10, 0);
// 10 lines
// whitespace: - a(6,10)
......@@ -350,7 +350,7 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout getLinesViewportData 1', () => {
var linesLayout = new LinesLayout(10, 10);
linesLayout.insertWhitespace(6, 0, 100);
linesLayout.insertWhitespace(6, 0, 100, 0);
// 10 lines
// whitespace: - a(6,100)
......@@ -484,8 +484,8 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout getLinesViewportData 2 & getWhitespaceViewportData', () => {
var linesLayout = new LinesLayout(10, 10);
var a = linesLayout.insertWhitespace(6, 0, 100);
var b = linesLayout.insertWhitespace(7, 0, 50);
var a = linesLayout.insertWhitespace(6, 0, 100, 0);
var b = linesLayout.insertWhitespace(7, 0, 50, 0);
// 10 lines
// whitespace: - a(6,100), b(7, 50)
......@@ -555,8 +555,8 @@ suite('Editor ViewLayout - LinesLayout', () => {
test('LinesLayout getWhitespaceAtVerticalOffset', () => {
var linesLayout = new LinesLayout(10, 10);
var a = linesLayout.insertWhitespace(6, 0, 100);
var b = linesLayout.insertWhitespace(7, 0, 50);
var a = linesLayout.insertWhitespace(6, 0, 100, 0);
var b = linesLayout.insertWhitespace(7, 0, 50, 0);
var whitespace = linesLayout.getWhitespaceAtVerticalOffset(0);
assert.equal(whitespace, null);
......
......@@ -14,7 +14,7 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
var whitespaceComputer = new WhitespaceComputer();
// Insert a whitespace after line number 2, of height 10
var a = whitespaceComputer.insertWhitespace(2, 0, 10);
var a = whitespaceComputer.insertWhitespace(2, 0, 10, 0);
// whitespaces: a(2, 10)
assert.equal(whitespaceComputer.getCount(), 1);
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
......@@ -27,7 +27,7 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 10);
// Insert a whitespace again after line number 2, of height 20
var b = whitespaceComputer.insertWhitespace(2, 0, 20);
var b = whitespaceComputer.insertWhitespace(2, 0, 20, 0);
// whitespaces: a(2, 10), b(2, 20)
assert.equal(whitespaceComputer.getCount(), 2);
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 2);
......@@ -72,7 +72,7 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 10);
// Add a whitespace before the first line of height 50
b = whitespaceComputer.insertWhitespace(0, 0, 50);
b = whitespaceComputer.insertWhitespace(0, 0, 50, 0);
// whitespaces: b(0, 50), a(2, 10)
assert.equal(whitespaceComputer.getCount(), 2);
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
......@@ -88,7 +88,7 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(4), 60);
// Add a whitespace after line 4 of height 20
whitespaceComputer.insertWhitespace(4, 0, 20);
whitespaceComputer.insertWhitespace(4, 0, 20, 0);
// whitespaces: b(0, 50), a(2, 10), c(4, 20)
assert.equal(whitespaceComputer.getCount(), 3);
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
......@@ -108,7 +108,7 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
assert.equal(whitespaceComputer.getAccumulatedHeightBeforeLineNumber(5), 80);
// Add a whitespace after line 3 of height 30
whitespaceComputer.insertWhitespace(3, 0, 30);
whitespaceComputer.insertWhitespace(3, 0, 30, 0);
// whitespaces: b(0, 50), a(2, 10), d(3, 30), c(4, 20)
assert.equal(whitespaceComputer.getCount(), 4);
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
......@@ -379,9 +379,9 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
test('WhitespaceComputer changeWhitespaceAfterLineNumber & getFirstWhitespaceIndexAfterLineNumber', () => {
var whitespaceComputer = new WhitespaceComputer();
var a = whitespaceComputer.insertWhitespace(0, 0, 1);
var b = whitespaceComputer.insertWhitespace(7, 0, 1);
var c = whitespaceComputer.insertWhitespace(3, 0, 1);
var a = whitespaceComputer.insertWhitespace(0, 0, 1, 0);
var b = whitespaceComputer.insertWhitespace(7, 0, 1, 0);
var c = whitespaceComputer.insertWhitespace(3, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getAfterLineNumberForWhitespaceIndex(0), 0);
......@@ -504,32 +504,32 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
test('WhitespaceComputer Bug', () => {
var whitespaceComputer = new WhitespaceComputer();
var a = whitespaceComputer.insertWhitespace(0, 0, 1);
var b = whitespaceComputer.insertWhitespace(7, 0, 1);
var a = whitespaceComputer.insertWhitespace(0, 0, 1, 0);
var b = whitespaceComputer.insertWhitespace(7, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), b); // 7
var c = whitespaceComputer.insertWhitespace(3, 0, 1);
var c = whitespaceComputer.insertWhitespace(3, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), c); // 3
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), b); // 7
var d = whitespaceComputer.insertWhitespace(2, 0, 1);
var d = whitespaceComputer.insertWhitespace(2, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7
var e = whitespaceComputer.insertWhitespace(8, 0, 1);
var e = whitespaceComputer.insertWhitespace(8, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(3), b); // 7
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8
var f = whitespaceComputer.insertWhitespace(11, 0, 1);
var f = whitespaceComputer.insertWhitespace(11, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
......@@ -537,7 +537,7 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(4), e); // 8
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), f); // 11
var g = whitespaceComputer.insertWhitespace(10, 0, 1);
var g = whitespaceComputer.insertWhitespace(10, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), d); // 2
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), c); // 3
......@@ -546,7 +546,7 @@ suite('Editor ViewLayout - WhitespaceComputer', () => {
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(5), g); // 10
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(6), f); // 11
var h = whitespaceComputer.insertWhitespace(0, 0, 1);
var h = whitespaceComputer.insertWhitespace(0, 0, 1, 0);
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(0), a); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(1), h); // 0
assert.equal(whitespaceComputer.getIdForWhitespaceIndex(2), d); // 2
......
......@@ -2623,6 +2623,11 @@ declare namespace monaco.editor {
* Defaults to true.
*/
scrollBeyondLastLine?: boolean;
/**
* Enable that scrolling can go beyond the last column by a number of columns.
* Defaults to 5.
*/
scrollBeyondLastColumn?: number;
/**
* Enable that the editor animates scrolling to a position.
* Defaults to false.
......@@ -3088,6 +3093,7 @@ declare namespace monaco.editor {
readonly cursorWidth: number;
readonly hideCursorInOverviewRuler: boolean;
readonly scrollBeyondLastLine: boolean;
readonly scrollBeyondLastColumn: number;
readonly smoothScrolling: boolean;
readonly stopRenderingLineAfter: number;
readonly renderWhitespace: 'none' | 'boundary' | 'all';
......@@ -3334,6 +3340,11 @@ declare namespace monaco.editor {
* If neither `heightInPx` nor `heightInLines` is specified, a default of `heightInLines` = 1 will be chosen.
*/
heightInPx?: number;
/**
* The minimum width in px of the view zone.
* If this is set, the editor will ensure that the scroll width is >= than this value.
*/
minWidthInPx?: number;
/**
* The dom node of the view zone
*/
......
......@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import { ResolvedKeybinding, Keybinding } from 'vs/base/common/keyCodes';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { KeybindingResolver, IResolveResult } from 'vs/platform/keybinding/common/keybindingResolver';
import { IKeybindingEvent, IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
......@@ -16,18 +16,18 @@ import { Event, Emitter } from 'vs/base/common/event';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IntervalTimer } from 'vs/base/common/async';
interface CurrentChord {
keypress: string;
label: string;
}
export abstract class AbstractKeybindingService implements IKeybindingService {
export abstract class AbstractKeybindingService extends Disposable implements IKeybindingService {
public _serviceBrand: any;
protected toDispose: IDisposable[] = [];
private _currentChord: CurrentChord;
private _currentChordChecker: IntervalTimer;
private _currentChordStatusMessage: IDisposable;
protected _onDidUpdateKeybindings: Emitter<IKeybindingEvent>;
......@@ -44,6 +44,7 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
notificationService: INotificationService,
statusService?: IStatusbarService
) {
super();
this._contextKeyService = contextKeyService;
this._commandService = commandService;
this._telemetryService = telemetryService;
......@@ -51,13 +52,13 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
this._notificationService = notificationService;
this._currentChord = null;
this._currentChordChecker = new IntervalTimer();
this._currentChordStatusMessage = null;
this._onDidUpdateKeybindings = new Emitter<IKeybindingEvent>();
this.toDispose.push(this._onDidUpdateKeybindings);
this._onDidUpdateKeybindings = this._register(new Emitter<IKeybindingEvent>());
}
public dispose(): void {
this.toDispose = dispose(this.toDispose);
super.dispose();
}
get onDidUpdateKeybindings(): Event<IKeybindingEvent> {
......@@ -65,6 +66,7 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
}
protected abstract _getResolver(): KeybindingResolver;
protected abstract _documentHasFocus(): boolean;
public abstract resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[];
public abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;
public abstract resolveUserBinding(userBinding: string): ResolvedKeybinding[];
......@@ -114,6 +116,40 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
return this._getResolver().resolve(contextValue, currentChord, firstPart);
}
private _enterChordMode(firstPart: string, keypressLabel: string): void {
this._currentChord = {
keypress: firstPart,
label: keypressLabel
};
if (this._statusService) {
this._currentChordStatusMessage = this._statusService.setStatusMessage(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", keypressLabel));
}
const chordEnterTime = Date.now();
this._currentChordChecker.cancelAndSet(() => {
if (!this._documentHasFocus()) {
// Focus has been lost => leave chord mode
this._leaveChordMode();
return;
}
if (Date.now() - chordEnterTime > 5000) {
// 5 seconds elapsed => leave chord mode
this._leaveChordMode();
}
}, 500);
}
private _leaveChordMode(): void {
if (this._currentChordStatusMessage) {
this._currentChordStatusMessage.dispose();
this._currentChordStatusMessage = null;
}
this._currentChordChecker.cancel();
this._currentChord = null;
}
protected _dispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {
let shouldPreventDefault = false;
......@@ -135,13 +171,7 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
if (resolveResult && resolveResult.enterChord) {
shouldPreventDefault = true;
this._currentChord = {
keypress: firstPart,
label: keypressLabel
};
if (this._statusService) {
this._currentChordStatusMessage = this._statusService.setStatusMessage(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", keypressLabel));
}
this._enterChordMode(firstPart, keypressLabel);
return shouldPreventDefault;
}
......@@ -151,11 +181,8 @@ export abstract class AbstractKeybindingService implements IKeybindingService {
shouldPreventDefault = true;
}
}
if (this._currentChordStatusMessage) {
this._currentChordStatusMessage.dispose();
this._currentChordStatusMessage = null;
}
this._currentChord = null;
this._leaveChordMode();
if (resolveResult && resolveResult.commandId) {
if (!resolveResult.bubble) {
......
......@@ -49,6 +49,10 @@ suite('AbstractKeybindingService', () => {
return this._resolver;
}
protected _documentHasFocus(): boolean {
return true;
}
public resolveKeybinding(kb: Keybinding): ResolvedKeybinding[] {
return [new USLayoutResolvedKeybinding(kb, OS)];
}
......
......@@ -65,10 +65,10 @@ export abstract class ViewletPanel extends Panel {
this.actionRunner = options.actionRunner;
}
render(container: HTMLElement): void {
super.render(container);
render(): void {
super.render();
const focusTracker = trackFocus(container);
const focusTracker = trackFocus(this.element);
this.disposables.push(focusTracker);
this.disposables.push(focusTracker.onDidFocus(() => this._onDidFocus.fire()));
}
......
......@@ -382,7 +382,7 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
for (const viewDescriptor of toAdd) {
let viewState = this.viewsStates.get(viewDescriptor.id);
let index = visible.indexOf(viewDescriptor);
const view = this.createView(viewDescriptor,
const panel = this.createView(viewDescriptor,
{
id: viewDescriptor.id,
name: viewDescriptor.name,
......@@ -390,10 +390,11 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
expanded: !(viewState ? viewState.collapsed : viewDescriptor.collapsed),
viewletSettings: this.viewletSettings
});
toCreate.push(view);
panel.render();
toCreate.push(panel);
const size = (viewState && viewState.size) || 200;
panelsToAdd.push({ panel: view, size, index });
panelsToAdd.push({ panel, size, index });
}
this.addPanels(panelsToAdd);
......@@ -586,7 +587,7 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
}
protected createView(viewDescriptor: IViewDescriptor, options: IViewletViewOptions): ViewsViewletPanel {
return this.instantiationService.createInstance(viewDescriptor.ctor, options);
return this.instantiationService.createInstance(viewDescriptor.ctor, options) as ViewsViewletPanel;
}
protected get views(): ViewsViewletPanel[] {
......
......@@ -5,6 +5,7 @@
import './electron-browser/accessibility';
import './electron-browser/inspectKeybindings';
import './electron-browser/largeFileOptimizations';
import './electron-browser/menuPreventer';
import './electron-browser/selectionClipboard';
import './electron-browser/textMate/inspectTMScopes';
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import * as path from 'path';
import { Disposable } from 'vs/base/common/lifecycle';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
/**
* Shows a message when opening a large file which has been memory optimized (and features disabled).
*/
export class LargeFileOptimizationsWarner extends Disposable implements IEditorContribution {
private static readonly ID = 'editor.contrib.largeFileOptimizationsWarner';
private _isDisabled: boolean;
constructor(
private readonly _editor: ICodeEditor,
@INotificationService private readonly _notificationService: INotificationService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IStorageService private readonly _storageService: IStorageService,
) {
super();
this._isDisabled = this._storageService.getBoolean('editor.neverPromptForLargeFiles', StorageScope.GLOBAL, false);
this._register(this._editor.onDidChangeModel((e) => {
const model = this._editor.getModel();
if (!model) {
return;
}
if (this._isDisabled) {
return;
}
if (model.isTooLargeForTokenization()) {
const message = nls.localize(
{
key: 'largeFile',
comment: [
'Variable 0 will be a file name.'
]
},
"{0}: tokenization, wrapping and folding have been turned off for this large file in order to reduce memory usage and avoid freezing or crashing.",
path.basename(model.uri.path)
);
this._notificationService.prompt(Severity.Info, message, [
{
label: nls.localize('neverShowAgain', "OK. Never show again"),
run: () => {
this._isDisabled = true;
this._storageService.store('editor.neverPromptForLargeFiles', true, StorageScope.GLOBAL);
}
},
{
label: nls.localize('removeOptimizations', "Forcefully enable features"),
run: () => {
this._configurationService.updateValue(`editor.largeFileOptimizations`, false).then(() => {
this._notificationService.info(nls.localize('reopenFilePrompt', "Please reopen file in order for this setting to take effect."));
}, (err) => {
this._notificationService.error(err);
});
}
}
]);
}
}));
}
public getId(): string {
return LargeFileOptimizationsWarner.ID;
}
}
registerEditorContribution(LargeFileOptimizationsWarner);
......@@ -768,8 +768,8 @@ export class RepositoryPanel extends ViewletPanel {
this.menus = instantiationService.createInstance(SCMMenus, repository.provider);
}
render(container: HTMLElement): void {
super.render(container);
render(): void {
super.render();
this.menus.onDidChangeTitle(this.updateActions, this, this.disposables);
}
......@@ -1168,6 +1168,7 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle
if (shouldMainPanelBeVisible) {
this.mainPanel = this.instantiationService.createInstance(MainPanel, this);
this.mainPanel.render();
this.addPanels([{ panel: this.mainPanel, size: this.mainPanel.minimumSize, index: 0 }]);
const selectionChangeDisposable = this.mainPanel.onSelectionChange(this.onSelectionChange, this);
......@@ -1302,7 +1303,11 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle
// Collect new selected panels
const newRepositoryPanels = repositories
.filter(r => this.repositoryPanels.every(p => p.repository !== r))
.map(r => this.instantiationService.createInstance(RepositoryPanel, r, this));
.map(r => {
const panel = this.instantiationService.createInstance(RepositoryPanel, r, this);
panel.render();
return panel;
});
// Add new selected panels
let index = repositoryPanels.length + (this.mainPanel ? 1 : 0);
......@@ -1364,6 +1369,8 @@ export class SCMViewlet extends PanelViewlet implements IViewModel, IViewsViewle
viewletSettings: {} // what is this
}) as ViewsViewletPanel;
panel.render();
this.addPanels([{ panel, size: size || panel.minimumSize, index: start + index }]);
panel.setVisible(true);
......
......@@ -115,9 +115,8 @@ class SplitPaneContainer {
}
private _addChild(size: number, instance: ITerminalInstance, index: number): void {
const child = new SplitPane(this.orientation === Orientation.HORIZONTAL ? this._height : this._width);
const child = new SplitPane(instance, this.orientation === Orientation.HORIZONTAL ? this._height : this._width);
child.orientation = this.orientation;
child.instance = instance;
if (typeof index === 'number') {
this._children.splice(index, 0, child);
} else {
......@@ -197,23 +196,21 @@ class SplitPane implements IView {
public minimumSize: number = SPLIT_PANE_MIN_SIZE;
public maximumSize: number = Number.MAX_VALUE;
public instance: ITerminalInstance;
public orientation: Orientation | undefined;
protected _size: number;
private _onDidChange: Event<number | undefined> = Event.None;
public get onDidChange(): Event<number | undefined> { return this._onDidChange; }
readonly element: HTMLElement;
constructor(
readonly instance: ITerminalInstance,
public orthogonalSize: number
) {
}
public render(container: HTMLElement): void {
if (!container) {
return;
}
this.instance.attachToElement(container);
this.element = document.createElement('div');
this.element.className = 'terminal-split-pane';
this.instance.attachToElement(this.element);
}
public layout(size: number): void {
......
......@@ -291,8 +291,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
this._cachedResolver = null;
this._firstTimeComputingResolver = true;
this.userKeybindings = new ConfigWatcher(environmentService.appKeybindingsPath, { defaultConfig: [], onError: error => onUnexpectedError(error) });
this.toDispose.push(this.userKeybindings);
this.userKeybindings = this._register(new ConfigWatcher(environmentService.appKeybindingsPath, { defaultConfig: [], onError: error => onUnexpectedError(error) }));
keybindingsExtPoint.setHandler((extensions) => {
let commandAdded = false;
......@@ -306,12 +305,12 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
}
});
this.toDispose.push(this.userKeybindings.onDidUpdateConfiguration(event => this.updateResolver({
this._register(this.userKeybindings.onDidUpdateConfiguration(event => this.updateResolver({
source: KeybindingSource.User,
keybindings: event.config
})));
this.toDispose.push(dom.addDisposableListener(windowElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
this._register(dom.addDisposableListener(windowElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
let keyEvent = new StandardKeyboardEvent(e);
let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target);
if (shouldPreventDefault) {
......@@ -367,6 +366,10 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
return this._cachedResolver;
}
protected _documentHasFocus(): boolean {
return document.hasFocus();
}
private _resolveKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] {
let result: ResolvedKeybindingItem[] = [], resultLen = 0;
for (let i = 0, len = items.length; i < len; i++) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册