mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
Merge branch 'main' into joh/vscode-dts
This commit is contained in:
commit
f7ef73720f
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -86,6 +86,7 @@
|
||||||
"splitview",
|
"splitview",
|
||||||
"table",
|
"table",
|
||||||
"list",
|
"list",
|
||||||
"git"
|
"git",
|
||||||
|
"sash"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"html.format.wrapAttributes.preservealigned": "Preserve wrapping of attributes but align.",
|
"html.format.wrapAttributes.preservealigned": "Preserve wrapping of attributes but align.",
|
||||||
"html.format.templating.desc": "Honor django, erb, handlebars and php templating language tags.",
|
"html.format.templating.desc": "Honor django, erb, handlebars and php templating language tags.",
|
||||||
"html.format.unformattedContentDelimiter.desc": "Keep text content together between this string.",
|
"html.format.unformattedContentDelimiter.desc": "Keep text content together between this string.",
|
||||||
"html.format.wrapAttributesIndentSize.desc": "Alignment size when using 'force aligned' and 'aligned multiple' in `#html.format.wrapAttributes#` or `null` to use the default indent size.",
|
"html.format.wrapAttributesIndentSize.desc": "Indent wrapped attributes to after N characters. Use `null` to use the default indent size. Ignored if `#html.format.wrapAttributes#` is set to 'aligned'.",
|
||||||
"html.suggest.html5.desc": "Controls whether the built-in HTML language support suggests HTML5 tags, properties and values.",
|
"html.suggest.html5.desc": "Controls whether the built-in HTML language support suggests HTML5 tags, properties and values.",
|
||||||
"html.trace.server.desc": "Traces the communication between VS Code and the HTML language server.",
|
"html.trace.server.desc": "Traces the communication between VS Code and the HTML language server.",
|
||||||
"html.validate.scripts": "Controls whether the built-in HTML language support validates embedded scripts.",
|
"html.validate.scripts": "Controls whether the built-in HTML language support validates embedded scripts.",
|
||||||
|
|
2
src/bootstrap.js
vendored
2
src/bootstrap.js
vendored
|
@ -100,7 +100,7 @@
|
||||||
}
|
}
|
||||||
if (!asarPathAdded && appRoot) {
|
if (!asarPathAdded && appRoot) {
|
||||||
// Assuming that adding just `NODE_MODULES_ASAR_PATH` is sufficient
|
// Assuming that adding just `NODE_MODULES_ASAR_PATH` is sufficient
|
||||||
// because nodejs should find it even if it has a different driver letter case
|
// because nodejs should find it even if it has a different drive letter case
|
||||||
paths.push(NODE_MODULES_ASAR_PATH);
|
paths.push(NODE_MODULES_ASAR_PATH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1382,5 +1382,3 @@ define(function () { return purify; });
|
||||||
// export const removeHooks = purify.removeHooks;
|
// export const removeHooks = purify.removeHooks;
|
||||||
// export const removeAllHooks = purify.removeAllHooks;
|
// export const removeAllHooks = purify.removeAllHooks;
|
||||||
// ESM-uncomment-end
|
// ESM-uncomment-end
|
||||||
|
|
||||||
//# sourceMappingURL=purify.es.js.map
|
|
||||||
|
|
|
@ -293,7 +293,7 @@ export class Grid<T extends IView = IView> extends Disposable {
|
||||||
this._addView(newView, viewSize, location);
|
this._addView(newView, viewSize, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
addViewAt(newView: T, size: number | DistributeSizing | InvisibleSizing, location: number[]): void {
|
private addViewAt(newView: T, size: number | DistributeSizing | InvisibleSizing, location: number[]): void {
|
||||||
if (this.views.has(newView)) {
|
if (this.views.has(newView)) {
|
||||||
throw new Error('Can\'t add same view twice');
|
throw new Error('Can\'t add same view twice');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1028,7 +1028,7 @@ export class GridView implements IDisposable {
|
||||||
this.trySet2x2();
|
this.trySet2x2();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeView(location: number[], sizing?: Sizing): IView {
|
removeView(location: number[], sizing?: DistributeSizing): IView {
|
||||||
this.disposable2x2.dispose();
|
this.disposable2x2.dispose();
|
||||||
this.disposable2x2 = Disposable.None;
|
this.disposable2x2 = Disposable.None;
|
||||||
|
|
||||||
|
|
|
@ -13,29 +13,39 @@ import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecy
|
||||||
import { isMacintosh } from 'vs/base/common/platform';
|
import { isMacintosh } from 'vs/base/common/platform';
|
||||||
import 'vs/css!./sash';
|
import 'vs/css!./sash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow the sashes to be visible at runtime.
|
||||||
|
* @remark Use for development purposes only.
|
||||||
|
*/
|
||||||
let DEBUG = false;
|
let DEBUG = false;
|
||||||
// DEBUG = Boolean("true"); // done "weirdly" so that a lint warning prevents you from pushing this
|
// DEBUG = Boolean("true"); // done "weirdly" so that a lint warning prevents you from pushing this
|
||||||
|
|
||||||
export interface ISashLayoutProvider { }
|
/**
|
||||||
|
* A vertical sash layout provider provides position and height for a sash.
|
||||||
export interface IVerticalSashLayoutProvider extends ISashLayoutProvider {
|
*/
|
||||||
|
export interface IVerticalSashLayoutProvider {
|
||||||
getVerticalSashLeft(sash: Sash): number;
|
getVerticalSashLeft(sash: Sash): number;
|
||||||
getVerticalSashTop?(sash: Sash): number;
|
getVerticalSashTop?(sash: Sash): number;
|
||||||
getVerticalSashHeight?(sash: Sash): number;
|
getVerticalSashHeight?(sash: Sash): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IHorizontalSashLayoutProvider extends ISashLayoutProvider {
|
/**
|
||||||
|
* A vertical sash layout provider provides position and width for a sash.
|
||||||
|
*/
|
||||||
|
export interface IHorizontalSashLayoutProvider {
|
||||||
getHorizontalSashTop(sash: Sash): number;
|
getHorizontalSashTop(sash: Sash): number;
|
||||||
getHorizontalSashLeft?(sash: Sash): number;
|
getHorizontalSashLeft?(sash: Sash): number;
|
||||||
getHorizontalSashWidth?(sash: Sash): number;
|
getHorizontalSashWidth?(sash: Sash): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ISashLayoutProvider = IVerticalSashLayoutProvider | IHorizontalSashLayoutProvider;
|
||||||
|
|
||||||
export interface ISashEvent {
|
export interface ISashEvent {
|
||||||
startX: number;
|
readonly startX: number;
|
||||||
currentX: number;
|
readonly currentX: number;
|
||||||
startY: number;
|
readonly startY: number;
|
||||||
currentY: number;
|
readonly currentY: number;
|
||||||
altKey: boolean;
|
readonly altKey: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum OrthogonalEdge {
|
export enum OrthogonalEdge {
|
||||||
|
@ -46,10 +56,41 @@ export enum OrthogonalEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISashOptions {
|
export interface ISashOptions {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a sash is horizontal or vertical.
|
||||||
|
*/
|
||||||
readonly orientation: Orientation;
|
readonly orientation: Orientation;
|
||||||
readonly orthogonalStartSash?: Sash;
|
|
||||||
readonly orthogonalEndSash?: Sash;
|
/**
|
||||||
|
* The width or height of a vertical or horizontal sash, respectively.
|
||||||
|
*/
|
||||||
readonly size?: number;
|
readonly size?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to another sash, perpendicular to this one, which
|
||||||
|
* aligns at the start of this one. A corner sash will be created
|
||||||
|
* automatically at that location.
|
||||||
|
*
|
||||||
|
* The start of a horizontal sash is its left-most position.
|
||||||
|
* The start of a vertical sash is its top-most position.
|
||||||
|
*/
|
||||||
|
readonly orthogonalStartSash?: Sash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to another sash, perpendicular to this one, which
|
||||||
|
* aligns at the end of this one. A corner sash will be created
|
||||||
|
* automatically at that location.
|
||||||
|
*
|
||||||
|
* The end of a horizontal sash is its right-most position.
|
||||||
|
* The end of a vertical sash is its bottom-most position.
|
||||||
|
*/
|
||||||
|
readonly orthogonalEndSash?: Sash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a hint as to what mouse cursor to use whenever the user
|
||||||
|
* hovers over a corner sash provided by this and an orthogonal sash.
|
||||||
|
*/
|
||||||
readonly orthogonalEdge?: OrthogonalEdge;
|
readonly orthogonalEdge?: OrthogonalEdge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +108,31 @@ export const enum Orientation {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum SashState {
|
export const enum SashState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable any UI interaction.
|
||||||
|
*/
|
||||||
Disabled,
|
Disabled,
|
||||||
Minimum,
|
|
||||||
Maximum,
|
/**
|
||||||
|
* Allow dragging down or to the right, depending on the sash orientation.
|
||||||
|
*
|
||||||
|
* Some OSs allow customizing the mouse cursor differently whenever
|
||||||
|
* some resizable component can't be any smaller, but can be larger.
|
||||||
|
*/
|
||||||
|
AtMinimum,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow dragging up or to the left, depending on the sash orientation.
|
||||||
|
*
|
||||||
|
* Some OSs allow customizing the mouse cursor differently whenever
|
||||||
|
* some resizable component can't be any larger, but can be smaller.
|
||||||
|
*/
|
||||||
|
AtMaximum,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable dragging.
|
||||||
|
*/
|
||||||
Enabled
|
Enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,52 +222,101 @@ class OrthogonalPointerEventFactory implements IPointerEventFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Sash} is the UI component which allows the user to resize other
|
||||||
|
* components. It's usually an invisible horizontal or vertical line which, when
|
||||||
|
* hovered, becomes highlighted and can be dragged along the perpendicular dimension
|
||||||
|
* to its direction.
|
||||||
|
*
|
||||||
|
* Features:
|
||||||
|
* - Touch event handling
|
||||||
|
* - Corner sash support
|
||||||
|
* - Hover with different mouse cursor support
|
||||||
|
* - Configurable hover size
|
||||||
|
* - Linked sash support, for 2x2 corner sashes
|
||||||
|
*/
|
||||||
export class Sash extends Disposable {
|
export class Sash extends Disposable {
|
||||||
|
|
||||||
private el: HTMLElement;
|
private el: HTMLElement;
|
||||||
private layoutProvider: ISashLayoutProvider;
|
private layoutProvider: ISashLayoutProvider;
|
||||||
private orientation!: Orientation;
|
private orientation: Orientation;
|
||||||
private size: number;
|
private size: number;
|
||||||
private hoverDelay = globalHoverDelay;
|
private hoverDelay = globalHoverDelay;
|
||||||
private hoverDelayer = this._register(new Delayer(this.hoverDelay));
|
private hoverDelayer = this._register(new Delayer(this.hoverDelay));
|
||||||
|
|
||||||
private _state: SashState = SashState.Enabled;
|
private _state: SashState = SashState.Enabled;
|
||||||
|
private readonly onDidEnablementChange = this._register(new Emitter<SashState>());
|
||||||
|
private readonly _onDidStart = this._register(new Emitter<ISashEvent>());
|
||||||
|
private readonly _onDidChange = this._register(new Emitter<ISashEvent>());
|
||||||
|
private readonly _onDidReset = this._register(new Emitter<void>());
|
||||||
|
private readonly _onDidEnd = this._register(new Emitter<void>());
|
||||||
|
private readonly orthogonalStartSashDisposables = this._register(new DisposableStore());
|
||||||
|
private _orthogonalStartSash: Sash | undefined;
|
||||||
|
private readonly orthogonalStartDragHandleDisposables = this._register(new DisposableStore());
|
||||||
|
private _orthogonalStartDragHandle: HTMLElement | undefined;
|
||||||
|
private readonly orthogonalEndSashDisposables = this._register(new DisposableStore());
|
||||||
|
private _orthogonalEndSash: Sash | undefined;
|
||||||
|
private readonly orthogonalEndDragHandleDisposables = this._register(new DisposableStore());
|
||||||
|
private _orthogonalEndDragHandle: HTMLElement | undefined;
|
||||||
|
|
||||||
get state(): SashState { return this._state; }
|
get state(): SashState { return this._state; }
|
||||||
|
get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }
|
||||||
|
get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The state of a sash defines whether it can be interacted with by the user
|
||||||
|
* as well as what mouse cursor to use, when hovered.
|
||||||
|
*/
|
||||||
set state(state: SashState) {
|
set state(state: SashState) {
|
||||||
if (this._state === state) {
|
if (this._state === state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.el.classList.toggle('disabled', state === SashState.Disabled);
|
this.el.classList.toggle('disabled', state === SashState.Disabled);
|
||||||
this.el.classList.toggle('minimum', state === SashState.Minimum);
|
this.el.classList.toggle('minimum', state === SashState.AtMinimum);
|
||||||
this.el.classList.toggle('maximum', state === SashState.Maximum);
|
this.el.classList.toggle('maximum', state === SashState.AtMaximum);
|
||||||
|
|
||||||
this._state = state;
|
this._state = state;
|
||||||
this._onDidEnablementChange.fire(state);
|
this.onDidEnablementChange.fire(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly _onDidEnablementChange = this._register(new Emitter<SashState>());
|
/**
|
||||||
readonly onDidEnablementChange: Event<SashState> = this._onDidEnablementChange.event;
|
* An event which fires whenever the user starts dragging this sash.
|
||||||
|
*/
|
||||||
private readonly _onDidStart = this._register(new Emitter<ISashEvent>());
|
|
||||||
readonly onDidStart: Event<ISashEvent> = this._onDidStart.event;
|
readonly onDidStart: Event<ISashEvent> = this._onDidStart.event;
|
||||||
|
|
||||||
private readonly _onDidChange = this._register(new Emitter<ISashEvent>());
|
/**
|
||||||
|
* An event which fires whenever the user moves the mouse while
|
||||||
|
* dragging this sash.
|
||||||
|
*/
|
||||||
readonly onDidChange: Event<ISashEvent> = this._onDidChange.event;
|
readonly onDidChange: Event<ISashEvent> = this._onDidChange.event;
|
||||||
|
|
||||||
private readonly _onDidReset = this._register(new Emitter<void>());
|
/**
|
||||||
|
* An event which fires whenever the user double clicks this sash.
|
||||||
|
*/
|
||||||
readonly onDidReset: Event<void> = this._onDidReset.event;
|
readonly onDidReset: Event<void> = this._onDidReset.event;
|
||||||
|
|
||||||
private readonly _onDidEnd = this._register(new Emitter<void>());
|
/**
|
||||||
|
* An event which fires whenever the user stops dragging this sash.
|
||||||
|
*/
|
||||||
readonly onDidEnd: Event<void> = this._onDidEnd.event;
|
readonly onDidEnd: Event<void> = this._onDidEnd.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A linked sash will be forwarded the same user interactions and events
|
||||||
|
* so it moves exactly the same way as this sash.
|
||||||
|
*
|
||||||
|
* Useful in 2x2 grids. Not meant for widespread usage.
|
||||||
|
*/
|
||||||
linkedSash: Sash | undefined = undefined;
|
linkedSash: Sash | undefined = undefined;
|
||||||
|
|
||||||
private readonly orthogonalStartSashDisposables = this._register(new DisposableStore());
|
/**
|
||||||
private _orthogonalStartSash: Sash | undefined;
|
* A reference to another sash, perpendicular to this one, which
|
||||||
private readonly orthogonalStartDragHandleDisposables = this._register(new DisposableStore());
|
* aligns at the start of this one. A corner sash will be created
|
||||||
private _orthogonalStartDragHandle: HTMLElement | undefined;
|
* automatically at that location.
|
||||||
get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }
|
*
|
||||||
|
* The start of a horizontal sash is its left-most position.
|
||||||
|
* The start of a vertical sash is its top-most position.
|
||||||
|
*/
|
||||||
set orthogonalStartSash(sash: Sash | undefined) {
|
set orthogonalStartSash(sash: Sash | undefined) {
|
||||||
this.orthogonalStartDragHandleDisposables.clear();
|
this.orthogonalStartDragHandleDisposables.clear();
|
||||||
this.orthogonalStartSashDisposables.clear();
|
this.orthogonalStartSashDisposables.clear();
|
||||||
|
@ -223,18 +335,22 @@ export class Sash extends Disposable {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.orthogonalStartSashDisposables.add(sash.onDidEnablementChange(onChange, this));
|
this.orthogonalStartSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));
|
||||||
onChange(sash.state);
|
onChange(sash.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._orthogonalStartSash = sash;
|
this._orthogonalStartSash = sash;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly orthogonalEndSashDisposables = this._register(new DisposableStore());
|
/**
|
||||||
private _orthogonalEndSash: Sash | undefined;
|
* A reference to another sash, perpendicular to this one, which
|
||||||
private readonly orthogonalEndDragHandleDisposables = this._register(new DisposableStore());
|
* aligns at the end of this one. A corner sash will be created
|
||||||
private _orthogonalEndDragHandle: HTMLElement | undefined;
|
* automatically at that location.
|
||||||
get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }
|
*
|
||||||
|
* The end of a horizontal sash is its right-most position.
|
||||||
|
* The end of a vertical sash is its bottom-most position.
|
||||||
|
*/
|
||||||
|
|
||||||
set orthogonalEndSash(sash: Sash | undefined) {
|
set orthogonalEndSash(sash: Sash | undefined) {
|
||||||
this.orthogonalEndDragHandleDisposables.clear();
|
this.orthogonalEndDragHandleDisposables.clear();
|
||||||
this.orthogonalEndSashDisposables.clear();
|
this.orthogonalEndSashDisposables.clear();
|
||||||
|
@ -253,15 +369,30 @@ export class Sash extends Disposable {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.orthogonalEndSashDisposables.add(sash.onDidEnablementChange(onChange, this));
|
this.orthogonalEndSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));
|
||||||
onChange(sash.state);
|
onChange(sash.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._orthogonalEndSash = sash;
|
this._orthogonalEndSash = sash;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(container: HTMLElement, layoutProvider: IVerticalSashLayoutProvider, options: ISashOptions);
|
/**
|
||||||
constructor(container: HTMLElement, layoutProvider: IHorizontalSashLayoutProvider, options: ISashOptions);
|
* Create a new vertical sash.
|
||||||
|
*
|
||||||
|
* @param container A DOM node to append the sash to.
|
||||||
|
* @param verticalLayoutProvider A vertical layout provider.
|
||||||
|
* @param options The options.
|
||||||
|
*/
|
||||||
|
constructor(container: HTMLElement, verticalLayoutProvider: IVerticalSashLayoutProvider, options: IVerticalSashOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new horizontal sash.
|
||||||
|
*
|
||||||
|
* @param container A DOM node to append the sash to.
|
||||||
|
* @param horizontalLayoutProvider A horizontal layout provider.
|
||||||
|
* @param options The options.
|
||||||
|
*/
|
||||||
|
constructor(container: HTMLElement, horizontalLayoutProvider: IHorizontalSashLayoutProvider, options: IHorizontalSashOptions);
|
||||||
constructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions) {
|
constructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -381,17 +512,17 @@ export class Sash extends Disposable {
|
||||||
if (isMultisashResize) {
|
if (isMultisashResize) {
|
||||||
cursor = 'all-scroll';
|
cursor = 'all-scroll';
|
||||||
} else if (this.orientation === Orientation.HORIZONTAL) {
|
} else if (this.orientation === Orientation.HORIZONTAL) {
|
||||||
if (this.state === SashState.Minimum) {
|
if (this.state === SashState.AtMinimum) {
|
||||||
cursor = 's-resize';
|
cursor = 's-resize';
|
||||||
} else if (this.state === SashState.Maximum) {
|
} else if (this.state === SashState.AtMaximum) {
|
||||||
cursor = 'n-resize';
|
cursor = 'n-resize';
|
||||||
} else {
|
} else {
|
||||||
cursor = isMacintosh ? 'row-resize' : 'ns-resize';
|
cursor = isMacintosh ? 'row-resize' : 'ns-resize';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.state === SashState.Minimum) {
|
if (this.state === SashState.AtMinimum) {
|
||||||
cursor = 'e-resize';
|
cursor = 'e-resize';
|
||||||
} else if (this.state === SashState.Maximum) {
|
} else if (this.state === SashState.AtMaximum) {
|
||||||
cursor = 'w-resize';
|
cursor = 'w-resize';
|
||||||
} else {
|
} else {
|
||||||
cursor = isMacintosh ? 'col-resize' : 'ew-resize';
|
cursor = isMacintosh ? 'col-resize' : 'ew-resize';
|
||||||
|
@ -406,7 +537,7 @@ export class Sash extends Disposable {
|
||||||
updateStyle();
|
updateStyle();
|
||||||
|
|
||||||
if (!isMultisashResize) {
|
if (!isMultisashResize) {
|
||||||
this.onDidEnablementChange(updateStyle, null, disposables);
|
this.onDidEnablementChange.event(updateStyle, null, disposables);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onPointerMove = (e: PointerEvent) => {
|
const onPointerMove = (e: PointerEvent) => {
|
||||||
|
@ -472,10 +603,19 @@ export class Sash extends Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forcefully stop any user interactions with this sash.
|
||||||
|
* Useful when hiding a parent component, while the user is still
|
||||||
|
* interacting with the sash.
|
||||||
|
*/
|
||||||
clearSashHoverState(): void {
|
clearSashHoverState(): void {
|
||||||
Sash.onMouseLeave(this);
|
Sash.onMouseLeave(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout the sash. The sash will size and position itself
|
||||||
|
* based on its provided {@link ISashLayoutProvider layout provider}.
|
||||||
|
*/
|
||||||
layout(): void {
|
layout(): void {
|
||||||
if (this.orientation === Orientation.VERTICAL) {
|
if (this.orientation === Orientation.VERTICAL) {
|
||||||
const verticalProvider = (<IVerticalSashLayoutProvider>this.layoutProvider);
|
const verticalProvider = (<IVerticalSashLayoutProvider>this.layoutProvider);
|
||||||
|
|
|
@ -17,45 +17,178 @@ import 'vs/css!./splitview';
|
||||||
export { Orientation } from 'vs/base/browser/ui/sash/sash';
|
export { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||||
|
|
||||||
export interface ISplitViewStyles {
|
export interface ISplitViewStyles {
|
||||||
separatorBorder: Color;
|
readonly separatorBorder: Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultStyles: ISplitViewStyles = {
|
const defaultStyles: ISplitViewStyles = {
|
||||||
separatorBorder: Color.transparent
|
separatorBorder: Color.transparent
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ISplitViewOptions<TLayoutContext = undefined> {
|
|
||||||
readonly orientation?: Orientation; // default Orientation.VERTICAL
|
|
||||||
readonly styles?: ISplitViewStyles;
|
|
||||||
readonly orthogonalStartSash?: Sash;
|
|
||||||
readonly orthogonalEndSash?: Sash;
|
|
||||||
readonly inverseAltBehavior?: boolean;
|
|
||||||
readonly proportionalLayout?: boolean; // default true,
|
|
||||||
readonly descriptor?: ISplitViewDescriptor<TLayoutContext>;
|
|
||||||
readonly scrollbarVisibility?: ScrollbarVisibility;
|
|
||||||
readonly getSashOrthogonalSize?: () => number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only used when `proportionalLayout` is false.
|
|
||||||
*/
|
|
||||||
export const enum LayoutPriority {
|
export const enum LayoutPriority {
|
||||||
Normal,
|
Normal,
|
||||||
Low,
|
Low,
|
||||||
High
|
High
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface to implement for views within a {@link SplitView}.
|
||||||
|
*
|
||||||
|
* An optional {@link TLayoutContext layout context type} may be used in order to
|
||||||
|
* pass along layout contextual data from the {@link SplitView.layout} method down
|
||||||
|
* to each view's {@link IView.layout} calls.
|
||||||
|
*/
|
||||||
export interface IView<TLayoutContext = undefined> {
|
export interface IView<TLayoutContext = undefined> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DOM element for this view.
|
||||||
|
*/
|
||||||
readonly element: HTMLElement;
|
readonly element: HTMLElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A minimum size for this view.
|
||||||
|
*
|
||||||
|
* @remarks If none, set it to `0`.
|
||||||
|
*/
|
||||||
readonly minimumSize: number;
|
readonly minimumSize: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A minimum size for this view.
|
||||||
|
*
|
||||||
|
* @remarks If none, set it to `Number.POSITIVE_INFINITY`.
|
||||||
|
*/
|
||||||
readonly maximumSize: number;
|
readonly maximumSize: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View instances are supposed to fire the {@link IView.onDidChange} event whenever
|
||||||
|
* any of the constraint properties have changed:
|
||||||
|
*
|
||||||
|
* - {@link IView.minimumSize}
|
||||||
|
* - {@link IView.maximumSize}
|
||||||
|
* - {@link IView.priority}
|
||||||
|
* - {@link IView.snap}
|
||||||
|
*
|
||||||
|
* The SplitView will relayout whenever that happens. The event can optionally emit
|
||||||
|
* the view's preferred size for that relayout.
|
||||||
|
*/
|
||||||
readonly onDidChange: Event<number | undefined>;
|
readonly onDidChange: Event<number | undefined>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The priority of the view when the {@link SplitView.resize layout} algorithm
|
||||||
|
* runs. Views with higher priority will be resized first.
|
||||||
|
*
|
||||||
|
* @remarks Only used when `proportionalLayout` is false.
|
||||||
|
*/
|
||||||
readonly priority?: LayoutPriority;
|
readonly priority?: LayoutPriority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the view will snap whenever the user reaches its minimum size or
|
||||||
|
* attempts to grow it beyond the minimum size.
|
||||||
|
*
|
||||||
|
* @defaultValue `false`
|
||||||
|
*/
|
||||||
readonly snap?: boolean;
|
readonly snap?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will be called by the {@link SplitView} during layout. A view meant to
|
||||||
|
* pass along the layout information down to its descendants.
|
||||||
|
*
|
||||||
|
* @param size The size of this view, in pixels.
|
||||||
|
* @param offset The offset of this view, relative to the start of the {@link SplitView}.
|
||||||
|
* @param context The optional {@link IView layout context} passed to {@link SplitView.layout}.
|
||||||
|
*/
|
||||||
layout(size: number, offset: number, context: TLayoutContext | undefined): void;
|
layout(size: number, offset: number, context: TLayoutContext | undefined): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will be called by the {@link SplitView} whenever this view is made
|
||||||
|
* visible or hidden.
|
||||||
|
*
|
||||||
|
* @param visible Whether the view becomes visible.
|
||||||
|
*/
|
||||||
setVisible?(visible: boolean): void;
|
setVisible?(visible: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A descriptor for a {@link SplitView} instance.
|
||||||
|
*/
|
||||||
|
export interface ISplitViewDescriptor<TLayoutContext = undefined> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The layout size of the {@link SplitView}.
|
||||||
|
*/
|
||||||
|
readonly size: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descriptors for each {@link IView view}.
|
||||||
|
*/
|
||||||
|
readonly views: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the {@link IView view} is visible.
|
||||||
|
*
|
||||||
|
* @defaultValue `true`
|
||||||
|
*/
|
||||||
|
readonly visible?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the {@link IView view}.
|
||||||
|
*
|
||||||
|
* @defaultValue `true`
|
||||||
|
*/
|
||||||
|
readonly size: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the {@link IView view}.
|
||||||
|
*
|
||||||
|
* @defaultValue `true`
|
||||||
|
*/
|
||||||
|
readonly view: IView<TLayoutContext>;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISplitViewOptions<TLayoutContext = undefined> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which axis the views align on.
|
||||||
|
*
|
||||||
|
* @defaultValue `Orientation.VERTICAL`
|
||||||
|
*/
|
||||||
|
readonly orientation?: Orientation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles overriding the {@link defaultStyles default ones}.
|
||||||
|
*/
|
||||||
|
readonly styles?: ISplitViewStyles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make Alt-drag the default drag operation.
|
||||||
|
*/
|
||||||
|
readonly inverseAltBehavior?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize each view proportionally when resizing the SplitView.
|
||||||
|
*
|
||||||
|
* @defaultValue `true`
|
||||||
|
*/
|
||||||
|
readonly proportionalLayout?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An initial description of this {@link SplitView} instance, allowing
|
||||||
|
* to initialze all views within the ctor.
|
||||||
|
*/
|
||||||
|
readonly descriptor?: ISplitViewDescriptor<TLayoutContext>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scrollbar visibility setting for whenever the views within
|
||||||
|
* the {@link SplitView} overflow.
|
||||||
|
*/
|
||||||
|
readonly scrollbarVisibility?: ScrollbarVisibility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the orthogonal size of sashes.
|
||||||
|
*/
|
||||||
|
readonly getSashOrthogonalSize?: () => number;
|
||||||
|
}
|
||||||
|
|
||||||
interface ISashEvent {
|
interface ISashEvent {
|
||||||
readonly sash: Sash;
|
readonly sash: Sash;
|
||||||
readonly start: number;
|
readonly start: number;
|
||||||
|
@ -190,30 +323,89 @@ enum State {
|
||||||
Busy
|
Busy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When adding or removing views, distribute the delta space among
|
||||||
|
* all other views.
|
||||||
|
*/
|
||||||
export type DistributeSizing = { type: 'distribute' };
|
export type DistributeSizing = { type: 'distribute' };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When adding or removing views, split the delta space with another
|
||||||
|
* specific view, indexed by the provided `index`.
|
||||||
|
*/
|
||||||
export type SplitSizing = { type: 'split', index: number };
|
export type SplitSizing = { type: 'split', index: number };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When adding or removing views, assume the view is invisible.
|
||||||
|
*/
|
||||||
export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number };
|
export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When adding or removing views, the sizing provides fine grained
|
||||||
|
* control over how other views get resized.
|
||||||
|
*/
|
||||||
export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing;
|
export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing;
|
||||||
|
|
||||||
export namespace Sizing {
|
export namespace Sizing {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When adding or removing views, distribute the delta space among
|
||||||
|
* all other views.
|
||||||
|
*/
|
||||||
export const Distribute: DistributeSizing = { type: 'distribute' };
|
export const Distribute: DistributeSizing = { type: 'distribute' };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When adding or removing views, split the delta space with another
|
||||||
|
* specific view, indexed by the provided `index`.
|
||||||
|
*/
|
||||||
export function Split(index: number): SplitSizing { return { type: 'split', index }; }
|
export function Split(index: number): SplitSizing { return { type: 'split', index }; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When adding or removing views, assume the view is invisible.
|
||||||
|
*/
|
||||||
export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; }
|
export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISplitViewDescriptor<TLayoutContext = undefined> {
|
/**
|
||||||
size: number;
|
* The {@link SplitView} is the UI component which implements a one dimensional
|
||||||
views: {
|
* flex-like layout algorithm for a collection of {@link IView} instances, which
|
||||||
visible?: boolean;
|
* are essentially HTMLElement instances with the following size constraints:
|
||||||
size: number;
|
*
|
||||||
view: IView<TLayoutContext>;
|
* - {@link IView.minimumSize}
|
||||||
}[];
|
* - {@link IView.maximumSize}
|
||||||
}
|
* - {@link IView.priority}
|
||||||
|
* - {@link IView.snap}
|
||||||
|
*
|
||||||
|
* In case the SplitView doesn't have enough size to fit all views, it will overflow
|
||||||
|
* its content with a scrollbar.
|
||||||
|
*
|
||||||
|
* In between each pair of views there will be a {@link Sash} allowing the user
|
||||||
|
* to resize the views, making sure the constraints are respected.
|
||||||
|
*
|
||||||
|
* An optional {@link TLayoutContext layout context type} may be used in order to
|
||||||
|
* pass along layout contextual data from the {@link SplitView.layout} method down
|
||||||
|
* to each view's {@link IView.layout} calls.
|
||||||
|
*
|
||||||
|
* Features:
|
||||||
|
* - Flex-like layout algorithm
|
||||||
|
* - Snap support
|
||||||
|
* - Orthogonal sash support, for corner sashes
|
||||||
|
* - View hide/show support
|
||||||
|
* - View swap/move support
|
||||||
|
* - Alt key modifier behavior, macOS style
|
||||||
|
*/
|
||||||
export class SplitView<TLayoutContext = undefined> extends Disposable {
|
export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This {@link SplitView}'s orientation.
|
||||||
|
*/
|
||||||
readonly orientation: Orientation;
|
readonly orientation: Orientation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DOM element representing this {@link SplitView}.
|
||||||
|
*/
|
||||||
readonly el: HTMLElement;
|
readonly el: HTMLElement;
|
||||||
|
|
||||||
private sashContainer: HTMLElement;
|
private sashContainer: HTMLElement;
|
||||||
private viewContainer: HTMLElement;
|
private viewContainer: HTMLElement;
|
||||||
private scrollable: Scrollable;
|
private scrollable: Scrollable;
|
||||||
|
@ -231,27 +423,58 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
private readonly getSashOrthogonalSize: { (): number } | undefined;
|
private readonly getSashOrthogonalSize: { (): number } | undefined;
|
||||||
|
|
||||||
private _onDidSashChange = this._register(new Emitter<number>());
|
private _onDidSashChange = this._register(new Emitter<number>());
|
||||||
|
private _onDidSashReset = this._register(new Emitter<number>());
|
||||||
|
private _orthogonalStartSash: Sash | undefined;
|
||||||
|
private _orthogonalEndSash: Sash | undefined;
|
||||||
|
private _startSnappingEnabled = true;
|
||||||
|
private _endSnappingEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires whenever the user resizes a {@link Sash sash}.
|
||||||
|
*/
|
||||||
readonly onDidSashChange = this._onDidSashChange.event;
|
readonly onDidSashChange = this._onDidSashChange.event;
|
||||||
|
|
||||||
private _onDidSashReset = this._register(new Emitter<number>());
|
/**
|
||||||
|
* Fires whenever the user double clicks a {@link Sash sash}.
|
||||||
|
*/
|
||||||
readonly onDidSashReset = this._onDidSashReset.event;
|
readonly onDidSashReset = this._onDidSashReset.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires whenever the split view is scrolled.
|
||||||
|
*/
|
||||||
readonly onDidScroll: Event<ScrollEvent>;
|
readonly onDidScroll: Event<ScrollEvent>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of views in this {@link SplitView}.
|
||||||
|
*/
|
||||||
get length(): number {
|
get length(): number {
|
||||||
return this.viewItems.length;
|
return this.viewItems.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum size of this {@link SplitView}.
|
||||||
|
*/
|
||||||
get minimumSize(): number {
|
get minimumSize(): number {
|
||||||
return this.viewItems.reduce((r, item) => r + item.minimumSize, 0);
|
return this.viewItems.reduce((r, item) => r + item.minimumSize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum size of this {@link SplitView}.
|
||||||
|
*/
|
||||||
get maximumSize(): number {
|
get maximumSize(): number {
|
||||||
return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.maximumSize, 0);
|
return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.maximumSize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _orthogonalStartSash: Sash | undefined;
|
|
||||||
get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }
|
get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }
|
||||||
|
get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }
|
||||||
|
get startSnappingEnabled(): boolean { return this._startSnappingEnabled; }
|
||||||
|
get endSnappingEnabled(): boolean { return this._endSnappingEnabled; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a sash, perpendicular to all sashes in this {@link SplitView},
|
||||||
|
* located at the left- or top-most side of the SplitView.
|
||||||
|
* Corner sashes will be created automatically at the intersections.
|
||||||
|
*/
|
||||||
set orthogonalStartSash(sash: Sash | undefined) {
|
set orthogonalStartSash(sash: Sash | undefined) {
|
||||||
for (const sashItem of this.sashItems) {
|
for (const sashItem of this.sashItems) {
|
||||||
sashItem.sash.orthogonalStartSash = sash;
|
sashItem.sash.orthogonalStartSash = sash;
|
||||||
|
@ -260,8 +483,11 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this._orthogonalStartSash = sash;
|
this._orthogonalStartSash = sash;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _orthogonalEndSash: Sash | undefined;
|
/**
|
||||||
get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }
|
* A reference to a sash, perpendicular to all sashes in this {@link SplitView},
|
||||||
|
* located at the right- or bottom-most side of the SplitView.
|
||||||
|
* Corner sashes will be created automatically at the intersections.
|
||||||
|
*/
|
||||||
set orthogonalEndSash(sash: Sash | undefined) {
|
set orthogonalEndSash(sash: Sash | undefined) {
|
||||||
for (const sashItem of this.sashItems) {
|
for (const sashItem of this.sashItems) {
|
||||||
sashItem.sash.orthogonalEndSash = sash;
|
sashItem.sash.orthogonalEndSash = sash;
|
||||||
|
@ -270,12 +496,16 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this._orthogonalEndSash = sash;
|
this._orthogonalEndSash = sash;
|
||||||
}
|
}
|
||||||
|
|
||||||
get sashes(): Sash[] {
|
/**
|
||||||
|
* The internal sashes within this {@link SplitView}.
|
||||||
|
*/
|
||||||
|
get sashes(): readonly Sash[] {
|
||||||
return this.sashItems.map(s => s.sash);
|
return this.sashItems.map(s => s.sash);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _startSnappingEnabled = true;
|
/**
|
||||||
get startSnappingEnabled(): boolean { return this._startSnappingEnabled; }
|
* Enable/disable snapping at the beginning of this {@link SplitView}.
|
||||||
|
*/
|
||||||
set startSnappingEnabled(startSnappingEnabled: boolean) {
|
set startSnappingEnabled(startSnappingEnabled: boolean) {
|
||||||
if (this._startSnappingEnabled === startSnappingEnabled) {
|
if (this._startSnappingEnabled === startSnappingEnabled) {
|
||||||
return;
|
return;
|
||||||
|
@ -285,8 +515,9 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.updateSashEnablement();
|
this.updateSashEnablement();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _endSnappingEnabled = true;
|
/**
|
||||||
get endSnappingEnabled(): boolean { return this._endSnappingEnabled; }
|
* Enable/disable snapping at the end of this {@link SplitView}.
|
||||||
|
*/
|
||||||
set endSnappingEnabled(endSnappingEnabled: boolean) {
|
set endSnappingEnabled(endSnappingEnabled: boolean) {
|
||||||
if (this._endSnappingEnabled === endSnappingEnabled) {
|
if (this._endSnappingEnabled === endSnappingEnabled) {
|
||||||
return;
|
return;
|
||||||
|
@ -296,12 +527,18 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.updateSashEnablement();
|
this.updateSashEnablement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link SplitView} instance.
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
constructor(container: HTMLElement, options: ISplitViewOptions<TLayoutContext> = {}) {
|
constructor(container: HTMLElement, options: ISplitViewOptions<TLayoutContext> = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.orientation = types.isUndefined(options.orientation) ? Orientation.VERTICAL : options.orientation;
|
this.orientation = options.orientation ?? Orientation.VERTICAL;
|
||||||
this.inverseAltBehavior = !!options.inverseAltBehavior;
|
this.inverseAltBehavior = options.inverseAltBehavior ?? false;
|
||||||
this.proportionalLayout = types.isUndefined(options.proportionalLayout) ? true : !!options.proportionalLayout;
|
this.proportionalLayout = options.proportionalLayout ?? true;
|
||||||
this.getSashOrthogonalSize = options.getSashOrthogonalSize;
|
this.getSashOrthogonalSize = options.getSashOrthogonalSize;
|
||||||
|
|
||||||
this.el = document.createElement('div');
|
this.el = document.createElement('div');
|
||||||
|
@ -354,10 +591,24 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link IView view} to this {@link SplitView}.
|
||||||
|
*
|
||||||
|
* @param view The view to add.
|
||||||
|
* @param size Either a fixed size, or a dynamic {@link Sizing} strategy.
|
||||||
|
* @param index The index to insert the view on.
|
||||||
|
* @param skipLayout Whether layout should be skipped.
|
||||||
|
*/
|
||||||
addView(view: IView<TLayoutContext>, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {
|
addView(view: IView<TLayoutContext>, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {
|
||||||
this.doAddView(view, size, index, skipLayout);
|
this.doAddView(view, size, index, skipLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a {@link IView view} from this {@link SplitView}.
|
||||||
|
*
|
||||||
|
* @param index The index where the {@link IView view} is located.
|
||||||
|
* @param sizing Whether to distribute other {@link IView view}'s sizes.
|
||||||
|
*/
|
||||||
removeView(index: number, sizing?: Sizing): IView<TLayoutContext> {
|
removeView(index: number, sizing?: Sizing): IView<TLayoutContext> {
|
||||||
if (this.state !== State.Idle) {
|
if (this.state !== State.Idle) {
|
||||||
throw new Error('Cant modify splitview');
|
throw new Error('Cant modify splitview');
|
||||||
|
@ -383,13 +634,19 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.relayout();
|
this.relayout();
|
||||||
this.state = State.Idle;
|
this.state = State.Idle;
|
||||||
|
|
||||||
if (sizing && sizing.type === 'distribute') {
|
if (sizing?.type === 'distribute') {
|
||||||
this.distributeViewSizes();
|
this.distributeViewSizes();
|
||||||
}
|
}
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a {@link IView view} to a different index.
|
||||||
|
*
|
||||||
|
* @param from The source index.
|
||||||
|
* @param to The target index.
|
||||||
|
*/
|
||||||
moveView(from: number, to: number): void {
|
moveView(from: number, to: number): void {
|
||||||
if (this.state !== State.Idle) {
|
if (this.state !== State.Idle) {
|
||||||
throw new Error('Cant modify splitview');
|
throw new Error('Cant modify splitview');
|
||||||
|
@ -401,6 +658,13 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.addView(view, sizing, to);
|
this.addView(view, sizing, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap two {@link IView views}.
|
||||||
|
*
|
||||||
|
* @param from The source index.
|
||||||
|
* @param to The target index.
|
||||||
|
*/
|
||||||
swapViews(from: number, to: number): void {
|
swapViews(from: number, to: number): void {
|
||||||
if (this.state !== State.Idle) {
|
if (this.state !== State.Idle) {
|
||||||
throw new Error('Cant modify splitview');
|
throw new Error('Cant modify splitview');
|
||||||
|
@ -419,6 +683,11 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.addView(fromView, toSize, to);
|
this.addView(fromView, toSize, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the {@link IView view} is visible.
|
||||||
|
*
|
||||||
|
* @param index The {@link IView view} index.
|
||||||
|
*/
|
||||||
isViewVisible(index: number): boolean {
|
isViewVisible(index: number): boolean {
|
||||||
if (index < 0 || index >= this.viewItems.length) {
|
if (index < 0 || index >= this.viewItems.length) {
|
||||||
throw new Error('Index out of bounds');
|
throw new Error('Index out of bounds');
|
||||||
|
@ -428,6 +697,12 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
return viewItem.visible;
|
return viewItem.visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a {@link IView view}'s visibility.
|
||||||
|
*
|
||||||
|
* @param index The {@link IView view} index.
|
||||||
|
* @param visible Whether the {@link IView view} should be visible.
|
||||||
|
*/
|
||||||
setViewVisible(index: number, visible: boolean): void {
|
setViewVisible(index: number, visible: boolean): void {
|
||||||
if (index < 0 || index >= this.viewItems.length) {
|
if (index < 0 || index >= this.viewItems.length) {
|
||||||
throw new Error('Index out of bounds');
|
throw new Error('Index out of bounds');
|
||||||
|
@ -441,6 +716,11 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.saveProportions();
|
this.saveProportions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link IView view}'s size previously to being hidden.
|
||||||
|
*
|
||||||
|
* @param index The {@link IView view} index.
|
||||||
|
*/
|
||||||
getViewCachedVisibleSize(index: number): number | undefined {
|
getViewCachedVisibleSize(index: number): number | undefined {
|
||||||
if (index < 0 || index >= this.viewItems.length) {
|
if (index < 0 || index >= this.viewItems.length) {
|
||||||
throw new Error('Index out of bounds');
|
throw new Error('Index out of bounds');
|
||||||
|
@ -450,6 +730,12 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
return viewItem.cachedVisibleSize;
|
return viewItem.cachedVisibleSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layout the {@link SplitView}.
|
||||||
|
*
|
||||||
|
* @param size The entire size of the {@link SplitView}.
|
||||||
|
* @param layoutContext An optional layout context to pass along to {@link IView views}.
|
||||||
|
*/
|
||||||
layout(size: number, layoutContext?: TLayoutContext): void {
|
layout(size: number, layoutContext?: TLayoutContext): void {
|
||||||
const previousSize = Math.max(this.size, this.contentSize);
|
const previousSize = Math.max(this.size, this.contentSize);
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
@ -616,6 +902,12 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize a {@link IView view} within the {@link SplitView}.
|
||||||
|
*
|
||||||
|
* @param index The {@link IView view} index.
|
||||||
|
* @param size The {@link IView view} size.
|
||||||
|
*/
|
||||||
resizeView(index: number, size: number): void {
|
resizeView(index: number, size: number): void {
|
||||||
if (this.state !== State.Idle) {
|
if (this.state !== State.Idle) {
|
||||||
throw new Error('Cant modify splitview');
|
throw new Error('Cant modify splitview');
|
||||||
|
@ -640,6 +932,9 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.state = State.Idle;
|
this.state = State.Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distribute the entire {@link SplitView} size among all {@link IView views}.
|
||||||
|
*/
|
||||||
distributeViewSizes(): void {
|
distributeViewSizes(): void {
|
||||||
const flexibleViewItems: ViewItem<TLayoutContext>[] = [];
|
const flexibleViewItems: ViewItem<TLayoutContext>[] = [];
|
||||||
let flexibleSize = 0;
|
let flexibleSize = 0;
|
||||||
|
@ -664,6 +959,9 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
this.relayout(lowPriorityIndexes, highPriorityIndexes);
|
this.relayout(lowPriorityIndexes, highPriorityIndexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of a {@link IView view}.
|
||||||
|
*/
|
||||||
getViewSize(index: number): number {
|
getViewSize(index: number): number {
|
||||||
if (index < 0 || index >= this.viewItems.length) {
|
if (index < 0 || index >= this.viewItems.length) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -964,16 +1262,16 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
||||||
const snappedAfter = typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible;
|
const snappedAfter = typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible;
|
||||||
|
|
||||||
if (snappedBefore && collapsesUp[index] && (position > 0 || this.startSnappingEnabled)) {
|
if (snappedBefore && collapsesUp[index] && (position > 0 || this.startSnappingEnabled)) {
|
||||||
sash.state = SashState.Minimum;
|
sash.state = SashState.AtMinimum;
|
||||||
} else if (snappedAfter && collapsesDown[index] && (position < this.contentSize || this.endSnappingEnabled)) {
|
} else if (snappedAfter && collapsesDown[index] && (position < this.contentSize || this.endSnappingEnabled)) {
|
||||||
sash.state = SashState.Maximum;
|
sash.state = SashState.AtMaximum;
|
||||||
} else {
|
} else {
|
||||||
sash.state = SashState.Disabled;
|
sash.state = SashState.Disabled;
|
||||||
}
|
}
|
||||||
} else if (min && !max) {
|
} else if (min && !max) {
|
||||||
sash.state = SashState.Minimum;
|
sash.state = SashState.AtMinimum;
|
||||||
} else if (!min && max) {
|
} else if (!min && max) {
|
||||||
sash.state = SashState.Maximum;
|
sash.state = SashState.AtMaximum;
|
||||||
} else {
|
} else {
|
||||||
sash.state = SashState.Enabled;
|
sash.state = SashState.Enabled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,12 +297,12 @@ suite('Splitview', () => {
|
||||||
assert.strictEqual(sashes[1].state, SashState.Disabled, 'second sash is disabled');
|
assert.strictEqual(sashes[1].state, SashState.Disabled, 'second sash is disabled');
|
||||||
|
|
||||||
view1.maximumSize = 300;
|
view1.maximumSize = 300;
|
||||||
assert.strictEqual(sashes[0].state, SashState.Minimum, 'first sash is enabled');
|
assert.strictEqual(sashes[0].state, SashState.AtMinimum, 'first sash is enabled');
|
||||||
assert.strictEqual(sashes[1].state, SashState.Minimum, 'second sash is enabled');
|
assert.strictEqual(sashes[1].state, SashState.AtMinimum, 'second sash is enabled');
|
||||||
|
|
||||||
view2.maximumSize = 200;
|
view2.maximumSize = 200;
|
||||||
assert.strictEqual(sashes[0].state, SashState.Minimum, 'first sash is enabled');
|
assert.strictEqual(sashes[0].state, SashState.AtMinimum, 'first sash is enabled');
|
||||||
assert.strictEqual(sashes[1].state, SashState.Minimum, 'second sash is enabled');
|
assert.strictEqual(sashes[1].state, SashState.AtMinimum, 'second sash is enabled');
|
||||||
|
|
||||||
splitview.resizeView(0, 40);
|
splitview.resizeView(0, 40);
|
||||||
assert.strictEqual(sashes[0].state, SashState.Enabled, 'first sash is enabled');
|
assert.strictEqual(sashes[0].state, SashState.Enabled, 'first sash is enabled');
|
||||||
|
|
|
@ -118,7 +118,7 @@ class CodeMain {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906)
|
// Delay creation of spdlog for perf reasons (https://github.com/microsoft/vscode/issues/72906)
|
||||||
bufferLogService.logger = new SpdLogLogger('main', join(environmentMainService.logsPath, 'main.log'), true, bufferLogService.getLevel());
|
bufferLogService.logger = new SpdLogLogger('main', join(environmentMainService.logsPath, 'main.log'), true, false, bufferLogService.getLevel());
|
||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
once(lifecycleMainService.onWillShutdown)(evt => {
|
once(lifecycleMainService.onWillShutdown)(evt => {
|
||||||
|
|
|
@ -110,7 +110,7 @@ class CliMain extends Disposable {
|
||||||
// Log
|
// Log
|
||||||
const logLevel = getLogLevel(environmentService);
|
const logLevel = getLogLevel(environmentService);
|
||||||
const loggers: ILogger[] = [];
|
const loggers: ILogger[] = [];
|
||||||
loggers.push(new SpdLogLogger('cli', join(environmentService.logsPath, 'cli.log'), true, logLevel));
|
loggers.push(new SpdLogLogger('cli', join(environmentService.logsPath, 'cli.log'), true, false, logLevel));
|
||||||
if (logLevel === LogLevel.Trace) {
|
if (logLevel === LogLevel.Trace) {
|
||||||
loggers.push(new ConsoleLogger(logLevel));
|
loggers.push(new ConsoleLogger(logLevel));
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,9 +202,12 @@ export class DecorationsOverlay extends DynamicViewOverlay {
|
||||||
|
|
||||||
if (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {
|
if (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {
|
||||||
const singleVisibleRange = lineVisibleRanges.ranges[0];
|
const singleVisibleRange = lineVisibleRanges.ranges[0];
|
||||||
if (singleVisibleRange.width === 0) {
|
if (singleVisibleRange.width < this._typicalHalfwidthCharacterWidth) {
|
||||||
// collapsed range case => make the decoration visible by faking its width
|
// collapsed/very small range case => make the decoration visible by expanding its width
|
||||||
lineVisibleRanges.ranges[0] = new HorizontalRange(singleVisibleRange.left, this._typicalHalfwidthCharacterWidth);
|
// expand its size on both sides (both to the left and to the right, keeping it centered)
|
||||||
|
const center = Math.round(singleVisibleRange.left + singleVisibleRange.width / 2);
|
||||||
|
const left = Math.max(0, Math.round(center - this._typicalHalfwidthCharacterWidth / 2));
|
||||||
|
lineVisibleRanges.ranges[0] = new HorizontalRange(left, this._typicalHalfwidthCharacterWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { IRange } from 'vs/editor/common/core/range';
|
||||||
import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
|
import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';
|
||||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||||
import { ITextModel } from 'vs/editor/common/model';
|
import { ITextModel } from 'vs/editor/common/model';
|
||||||
|
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||||
import { FoldingRangeKind, FoldingRangeProviderRegistry } from 'vs/editor/common/modes';
|
import { FoldingRangeKind, FoldingRangeProviderRegistry } from 'vs/editor/common/modes';
|
||||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||||
import { CollapseMemento, FoldingModel, getNextFoldLine, getParentFoldLine as getParentFoldLine, getPreviousFoldLine, setCollapseStateAtLevel, setCollapseStateForMatchingLines, setCollapseStateForRest, setCollapseStateForType, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateUp, toggleCollapseState } from 'vs/editor/contrib/folding/foldingModel';
|
import { CollapseMemento, FoldingModel, getNextFoldLine, getParentFoldLine as getParentFoldLine, getPreviousFoldLine, setCollapseStateAtLevel, setCollapseStateForMatchingLines, setCollapseStateForRest, setCollapseStateForType, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateUp, toggleCollapseState } from 'vs/editor/contrib/folding/foldingModel';
|
||||||
|
@ -130,7 +131,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
||||||
const options = this.editor.getOptions();
|
const options = this.editor.getOptions();
|
||||||
this.foldingDecorationProvider.autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover';
|
this.foldingDecorationProvider.autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover';
|
||||||
this.foldingDecorationProvider.showFoldingHighlights = options.get(EditorOption.foldingHighlight);
|
this.foldingDecorationProvider.showFoldingHighlights = options.get(EditorOption.foldingHighlight);
|
||||||
this.onModelContentChanged();
|
this.triggerFoldingModelChanged();
|
||||||
}
|
}
|
||||||
if (e.hasChanged(EditorOption.foldingStrategy)) {
|
if (e.hasChanged(EditorOption.foldingStrategy)) {
|
||||||
this._useFoldingProviders = this.editor.getOptions().get(EditorOption.foldingStrategy) !== 'indentation';
|
this._useFoldingProviders = this.editor.getOptions().get(EditorOption.foldingStrategy) !== 'indentation';
|
||||||
|
@ -225,7 +226,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
||||||
this.localToDispose.add(this.cursorChangedScheduler);
|
this.localToDispose.add(this.cursorChangedScheduler);
|
||||||
this.localToDispose.add(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged()));
|
this.localToDispose.add(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged()));
|
||||||
this.localToDispose.add(this.editor.onDidChangeModelLanguageConfiguration(() => this.onFoldingStrategyChanged())); // covers model language changes as well
|
this.localToDispose.add(this.editor.onDidChangeModelLanguageConfiguration(() => this.onFoldingStrategyChanged())); // covers model language changes as well
|
||||||
this.localToDispose.add(this.editor.onDidChangeModelContent(() => this.onModelContentChanged()));
|
this.localToDispose.add(this.editor.onDidChangeModelContent(e => this.onDidChangeModelContent(e)));
|
||||||
this.localToDispose.add(this.editor.onDidChangeCursorPosition(() => this.onCursorPositionChanged()));
|
this.localToDispose.add(this.editor.onDidChangeCursorPosition(() => this.onCursorPositionChanged()));
|
||||||
this.localToDispose.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
|
this.localToDispose.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
|
||||||
this.localToDispose.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));
|
this.localToDispose.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));
|
||||||
|
@ -250,7 +251,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
||||||
this.rangeProvider = null;
|
this.rangeProvider = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.onModelContentChanged();
|
this.triggerFoldingModelChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private onFoldingStrategyChanged() {
|
private onFoldingStrategyChanged() {
|
||||||
|
@ -258,7 +259,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
||||||
this.rangeProvider.dispose();
|
this.rangeProvider.dispose();
|
||||||
}
|
}
|
||||||
this.rangeProvider = null;
|
this.rangeProvider = null;
|
||||||
this.onModelContentChanged();
|
this.triggerFoldingModelChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRangeProvider(editorModel: ITextModel): RangeProvider {
|
private getRangeProvider(editorModel: ITextModel): RangeProvider {
|
||||||
|
@ -278,7 +279,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
||||||
}, 30000);
|
}, 30000);
|
||||||
return rangeProvider; // keep memento in case there are still no foldingProviders on the next request.
|
return rangeProvider; // keep memento in case there are still no foldingProviders on the next request.
|
||||||
} else if (foldingProviders.length > 0) {
|
} else if (foldingProviders.length > 0) {
|
||||||
this.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders, () => this.onModelContentChanged());
|
this.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders, () => this.triggerFoldingModelChanged());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.foldingStateMemento = null;
|
this.foldingStateMemento = null;
|
||||||
|
@ -289,7 +290,12 @@ export class FoldingController extends Disposable implements IEditorContribution
|
||||||
return this.foldingModelPromise;
|
return this.foldingModelPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onModelContentChanged() {
|
private onDidChangeModelContent(e: IModelContentChangedEvent) {
|
||||||
|
this.hiddenRangeModel?.notifyChangeModelContent(e);
|
||||||
|
this.triggerFoldingModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private triggerFoldingModelChanged() {
|
||||||
if (this.updateScheduler) {
|
if (this.updateScheduler) {
|
||||||
if (this.foldingRegionPromise) {
|
if (this.foldingRegionPromise) {
|
||||||
this.foldingRegionPromise.cancel();
|
this.foldingRegionPromise.cancel();
|
||||||
|
|
|
@ -4,17 +4,22 @@
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { findFirstInSorted } from 'vs/base/common/arrays';
|
import { findFirstInSorted } from 'vs/base/common/arrays';
|
||||||
|
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||||
import { Selection } from 'vs/editor/common/core/selection';
|
import { Selection } from 'vs/editor/common/core/selection';
|
||||||
|
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||||
|
import { countEOL } from 'vs/editor/common/model/tokensStore';
|
||||||
import { CollapseMemento, FoldingModel } from 'vs/editor/contrib/folding/foldingModel';
|
import { CollapseMemento, FoldingModel } from 'vs/editor/contrib/folding/foldingModel';
|
||||||
|
|
||||||
export class HiddenRangeModel {
|
export class HiddenRangeModel {
|
||||||
|
|
||||||
private readonly _foldingModel: FoldingModel;
|
private readonly _foldingModel: FoldingModel;
|
||||||
private _hiddenRanges: IRange[];
|
private _hiddenRanges: IRange[];
|
||||||
private _foldingModelListener: IDisposable | null;
|
private _foldingModelListener: IDisposable | null;
|
||||||
private readonly _updateEventEmitter = new Emitter<IRange[]>();
|
private readonly _updateEventEmitter = new Emitter<IRange[]>();
|
||||||
|
private _hasLineChanges: boolean = false;
|
||||||
|
|
||||||
public get onDidChange(): Event<IRange[]> { return this._updateEventEmitter.event; }
|
public get onDidChange(): Event<IRange[]> { return this._updateEventEmitter.event; }
|
||||||
public get hiddenRanges() { return this._hiddenRanges; }
|
public get hiddenRanges() { return this._hiddenRanges; }
|
||||||
|
@ -28,6 +33,14 @@ export class HiddenRangeModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public notifyChangeModelContent(e: IModelContentChangedEvent) {
|
||||||
|
if (this._hiddenRanges.length && !this._hasLineChanges) {
|
||||||
|
this._hasLineChanges = e.changes.some(change => {
|
||||||
|
return change.range.endLineNumber !== change.range.startLineNumber || countEOL(change.text)[0] !== 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private updateHiddenRanges(): void {
|
private updateHiddenRanges(): void {
|
||||||
let updateHiddenAreas = false;
|
let updateHiddenAreas = false;
|
||||||
let newHiddenAreas: IRange[] = [];
|
let newHiddenAreas: IRange[] = [];
|
||||||
|
@ -61,7 +74,7 @@ export class HiddenRangeModel {
|
||||||
lastCollapsedStart = startLineNumber;
|
lastCollapsedStart = startLineNumber;
|
||||||
lastCollapsedEnd = endLineNumber;
|
lastCollapsedEnd = endLineNumber;
|
||||||
}
|
}
|
||||||
if (updateHiddenAreas || k < this._hiddenRanges.length) {
|
if (this._hasLineChanges || updateHiddenAreas || k < this._hiddenRanges.length) {
|
||||||
this.applyHiddenRanges(newHiddenAreas);
|
this.applyHiddenRanges(newHiddenAreas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +103,7 @@ export class HiddenRangeModel {
|
||||||
|
|
||||||
private applyHiddenRanges(newHiddenAreas: IRange[]) {
|
private applyHiddenRanges(newHiddenAreas: IRange[]) {
|
||||||
this._hiddenRanges = newHiddenAreas;
|
this._hiddenRanges = newHiddenAreas;
|
||||||
|
this._hasLineChanges = false;
|
||||||
this._updateEventEmitter.fire(newHiddenAreas);
|
this._updateEventEmitter.fire(newHiddenAreas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,9 +105,17 @@ class ModesContentComputer implements IHoverComputer<IHoverPart[]> {
|
||||||
|
|
||||||
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
||||||
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
||||||
|
if (d.options.showIfCollapsed) {
|
||||||
|
// Relax check around `showIfCollapsed` decorations to also include +/- 1 character
|
||||||
|
if (startColumn > anchor.range.startColumn + 1 || anchor.range.endColumn - 1 > endColumn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) {
|
if (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,40 +9,6 @@ import { language, locale } from 'vs/base/common/platform';
|
||||||
import { IElement, ILocaleInfo, ILocalizedStrings, IWindowDriver } from 'vs/platform/driver/common/driver';
|
import { IElement, ILocaleInfo, ILocalizedStrings, IWindowDriver } from 'vs/platform/driver/common/driver';
|
||||||
import localizedStrings from 'vs/platform/localizations/common/localizedStrings';
|
import localizedStrings from 'vs/platform/localizations/common/localizedStrings';
|
||||||
|
|
||||||
function serializeElement(element: Element, recursive: boolean): IElement {
|
|
||||||
const attributes = Object.create(null);
|
|
||||||
|
|
||||||
for (let j = 0; j < element.attributes.length; j++) {
|
|
||||||
const attr = element.attributes.item(j);
|
|
||||||
if (attr) {
|
|
||||||
attributes[attr.name] = attr.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const children: IElement[] = [];
|
|
||||||
|
|
||||||
if (recursive) {
|
|
||||||
for (let i = 0; i < element.children.length; i++) {
|
|
||||||
const child = element.children.item(i);
|
|
||||||
if (child) {
|
|
||||||
children.push(serializeElement(child, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { left, top } = getTopLeftOffset(element as HTMLElement);
|
|
||||||
|
|
||||||
return {
|
|
||||||
tagName: element.tagName,
|
|
||||||
className: element.className,
|
|
||||||
textContent: element.textContent || '',
|
|
||||||
attributes,
|
|
||||||
children,
|
|
||||||
left,
|
|
||||||
top
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class BaseWindowDriver implements IWindowDriver {
|
export abstract class BaseWindowDriver implements IWindowDriver {
|
||||||
|
|
||||||
abstract click(selector: string, xoffset?: number, yoffset?: number): Promise<void>;
|
abstract click(selector: string, xoffset?: number, yoffset?: number): Promise<void>;
|
||||||
|
@ -94,12 +60,46 @@ export abstract class BaseWindowDriver implements IWindowDriver {
|
||||||
|
|
||||||
for (let i = 0; i < query.length; i++) {
|
for (let i = 0; i < query.length; i++) {
|
||||||
const element = query.item(i);
|
const element = query.item(i);
|
||||||
result.push(serializeElement(element, recursive));
|
result.push(this.serializeElement(element, recursive));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private serializeElement(element: Element, recursive: boolean): IElement {
|
||||||
|
const attributes = Object.create(null);
|
||||||
|
|
||||||
|
for (let j = 0; j < element.attributes.length; j++) {
|
||||||
|
const attr = element.attributes.item(j);
|
||||||
|
if (attr) {
|
||||||
|
attributes[attr.name] = attr.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const children: IElement[] = [];
|
||||||
|
|
||||||
|
if (recursive) {
|
||||||
|
for (let i = 0; i < element.children.length; i++) {
|
||||||
|
const child = element.children.item(i);
|
||||||
|
if (child) {
|
||||||
|
children.push(this.serializeElement(child, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { left, top } = getTopLeftOffset(element as HTMLElement);
|
||||||
|
|
||||||
|
return {
|
||||||
|
tagName: element.tagName,
|
||||||
|
className: element.className,
|
||||||
|
textContent: element.textContent || '',
|
||||||
|
attributes,
|
||||||
|
children,
|
||||||
|
left,
|
||||||
|
top
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }> {
|
async getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }> {
|
||||||
const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined;
|
const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined;
|
||||||
return this._getElementXY(selector, offset);
|
return this._getElementXY(selector, offset);
|
||||||
|
|
|
@ -154,7 +154,7 @@ export class FileLoggerService extends AbstractLoggerService implements ILoggerS
|
||||||
|
|
||||||
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
|
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
|
||||||
const logger = new BufferLogService(logLevel);
|
const logger = new BufferLogService(logLevel);
|
||||||
whenProviderRegistered(resource, this.fileService).then(() => (<BufferLogService>logger).logger = this.instantiationService.createInstance(FileLogger, basename(resource), resource, logger.getLevel(), !!options?.donotUseFormatters));
|
whenProviderRegistered(resource, this.fileService).then(() => (<BufferLogService>logger).logger = this.instantiationService.createInstance(FileLogger, options?.name || basename(resource), resource, logger.getLevel(), !!options?.donotUseFormatters));
|
||||||
return logger;
|
return logger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,7 @@ export class LoggerService extends AbstractLoggerService implements ILoggerServi
|
||||||
|
|
||||||
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
|
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
|
||||||
if (resource.scheme === Schemas.file) {
|
if (resource.scheme === Schemas.file) {
|
||||||
const logger = new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, logLevel);
|
return new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, !!options?.donotUseFormatters, logLevel);
|
||||||
if (options?.donotUseFormatters) {
|
|
||||||
(<SpdLogLogger>logger).clearFormatters();
|
|
||||||
}
|
|
||||||
return logger;
|
|
||||||
} else {
|
} else {
|
||||||
return new FileLogger(options?.name ?? basename(resource), resource, logLevel, !!options?.donotUseFormatters, this.fileService);
|
return new FileLogger(options?.name ?? basename(resource), resource, logLevel, !!options?.donotUseFormatters, this.fileService);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,16 @@ import * as spdlog from 'spdlog';
|
||||||
import { ByteSize } from 'vs/platform/files/common/files';
|
import { ByteSize } from 'vs/platform/files/common/files';
|
||||||
import { AbstractMessageLogger, ILogger, LogLevel } from 'vs/platform/log/common/log';
|
import { AbstractMessageLogger, ILogger, LogLevel } from 'vs/platform/log/common/log';
|
||||||
|
|
||||||
async function createSpdLogLogger(name: string, logfilePath: string, filesize: number, filecount: number): Promise<spdlog.Logger | null> {
|
async function createSpdLogLogger(name: string, logfilePath: string, filesize: number, filecount: number, donotUseFormatters: boolean): Promise<spdlog.Logger | null> {
|
||||||
// Do not crash if spdlog cannot be loaded
|
// Do not crash if spdlog cannot be loaded
|
||||||
try {
|
try {
|
||||||
const _spdlog = await import('spdlog');
|
const _spdlog = await import('spdlog');
|
||||||
_spdlog.setFlushOn(LogLevel.Trace);
|
_spdlog.setFlushOn(LogLevel.Trace);
|
||||||
return _spdlog.createAsyncRotatingLogger(name, logfilePath, filesize, filecount);
|
const logger = await _spdlog.createAsyncRotatingLogger(name, logfilePath, filesize, filecount);
|
||||||
|
if (donotUseFormatters) {
|
||||||
|
logger.clearFormatters();
|
||||||
|
}
|
||||||
|
return logger;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
@ -49,14 +53,15 @@ export class SpdLogLogger extends AbstractMessageLogger implements ILogger {
|
||||||
private _logger: spdlog.Logger | undefined;
|
private _logger: spdlog.Logger | undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly name: string,
|
name: string,
|
||||||
private readonly filepath: string,
|
filepath: string,
|
||||||
private readonly rotating: boolean,
|
rotating: boolean,
|
||||||
level: LogLevel
|
donotUseFormatters: boolean,
|
||||||
|
level: LogLevel,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.setLevel(level);
|
this.setLevel(level);
|
||||||
this._loggerCreationPromise = this._createSpdLogLogger();
|
this._loggerCreationPromise = this._createSpdLogLogger(name, filepath, rotating, donotUseFormatters);
|
||||||
this._register(this.onDidChangeLogLevel(level => {
|
this._register(this.onDidChangeLogLevel(level => {
|
||||||
if (this._logger) {
|
if (this._logger) {
|
||||||
this._logger.setLevel(level);
|
this._logger.setLevel(level);
|
||||||
|
@ -64,11 +69,10 @@ export class SpdLogLogger extends AbstractMessageLogger implements ILogger {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _createSpdLogLogger(): Promise<void> {
|
private async _createSpdLogLogger(name: string, filepath: string, rotating: boolean, donotUseFormatters: boolean): Promise<void> {
|
||||||
const filecount = this.rotating ? 6 : 1;
|
const filecount = rotating ? 6 : 1;
|
||||||
const filesize = (30 / filecount) * ByteSize.MB;
|
const filesize = (30 / filecount) * ByteSize.MB;
|
||||||
return createSpdLogLogger(this.name, this.filepath, filesize, filecount)
|
const logger = await createSpdLogLogger(name, filepath, filesize, filecount, donotUseFormatters);
|
||||||
.then(logger => {
|
|
||||||
if (logger) {
|
if (logger) {
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
this._logger.setLevel(this.getLevel());
|
this._logger.setLevel(this.getLevel());
|
||||||
|
@ -77,7 +81,6 @@ export class SpdLogLogger extends AbstractMessageLogger implements ILogger {
|
||||||
}
|
}
|
||||||
this.buffer = [];
|
this.buffer = [];
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected log(level: LogLevel, message: string): void {
|
protected log(level: LogLevel, message: string): void {
|
||||||
|
@ -88,14 +91,6 @@ export class SpdLogLogger extends AbstractMessageLogger implements ILogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearFormatters(): void {
|
|
||||||
if (this._logger) {
|
|
||||||
this._logger.clearFormatters();
|
|
||||||
} else {
|
|
||||||
this._loggerCreationPromise.then(() => this.clearFormatters());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override flush(): void {
|
override flush(): void {
|
||||||
if (this._logger) {
|
if (this._logger) {
|
||||||
this._logger.flush();
|
this._logger.flush();
|
||||||
|
|
|
@ -75,7 +75,7 @@ class CliMain extends Disposable {
|
||||||
|
|
||||||
const environmentService = new ServerEnvironmentService(this.args, productService);
|
const environmentService = new ServerEnvironmentService(this.args, productService);
|
||||||
services.set(IServerEnvironmentService, environmentService);
|
services.set(IServerEnvironmentService, environmentService);
|
||||||
const logService: ILogService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, getLogLevel(environmentService)));
|
const logService: ILogService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, false, getLogLevel(environmentService)));
|
||||||
services.set(ILogService, logService);
|
services.set(ILogService, logService);
|
||||||
logService.trace(`Remote configuration data at ${this.remoteDataFolder}`);
|
logService.trace(`Remote configuration data at ${this.remoteDataFolder}`);
|
||||||
logService.trace('process arguments:', this.args);
|
logService.trace('process arguments:', this.args);
|
||||||
|
|
|
@ -1043,7 +1043,7 @@ const getOrCreateSpdLogService: (environmentService: IServerEnvironmentService)
|
||||||
let _logService: ILogService | null;
|
let _logService: ILogService | null;
|
||||||
return function getLogService(environmentService: IServerEnvironmentService): ILogService {
|
return function getLogService(environmentService: IServerEnvironmentService): ILogService {
|
||||||
if (!_logService) {
|
if (!_logService) {
|
||||||
_logService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, getLogLevel(environmentService)));
|
_logService = new LogService(new SpdLogLogger(RemoteExtensionLogFileName, join(environmentService.logsPath, `${RemoteExtensionLogFileName}.log`), true, false, getLogLevel(environmentService)));
|
||||||
}
|
}
|
||||||
return _logService;
|
return _logService;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import { ILoggerService, LogService } from 'vs/platform/log/common/log';
|
import { ILoggerService, LogService } from 'vs/platform/log/common/log';
|
||||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||||
|
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
|
||||||
export class ExtHostLogService extends LogService {
|
export class ExtHostLogService extends LogService {
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ export class ExtHostLogService extends LogService {
|
||||||
@ILoggerService loggerService: ILoggerService,
|
@ILoggerService loggerService: ILoggerService,
|
||||||
@IExtHostInitDataService initData: IExtHostInitDataService,
|
@IExtHostInitDataService initData: IExtHostInitDataService,
|
||||||
) {
|
) {
|
||||||
super(loggerService.createLogger(initData.logFile));
|
super(loggerService.createLogger(initData.logFile, { name: ExtensionHostLogFileName }));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1776,7 +1776,7 @@ export enum TaskPanelKind {
|
||||||
@es5ClassCompat
|
@es5ClassCompat
|
||||||
export class TaskGroup implements vscode.TaskGroup {
|
export class TaskGroup implements vscode.TaskGroup {
|
||||||
|
|
||||||
isDefault?: boolean;
|
isDefault: boolean | undefined;
|
||||||
private _id: string;
|
private _id: string;
|
||||||
|
|
||||||
public static Clean: TaskGroup = new TaskGroup('clean', 'Clean');
|
public static Clean: TaskGroup = new TaskGroup('clean', 'Clean');
|
||||||
|
|
|
@ -14,11 +14,7 @@ export class ExtHostLoggerService extends BaseExtHostLoggerService {
|
||||||
|
|
||||||
protected override doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
|
protected override doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
|
||||||
if (resource.scheme === Schemas.file) {
|
if (resource.scheme === Schemas.file) {
|
||||||
const logger = new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, logLevel);
|
return new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, !!options?.donotUseFormatters, logLevel);
|
||||||
if (options?.donotUseFormatters) {
|
|
||||||
(<SpdLogLogger>logger).clearFormatters();
|
|
||||||
}
|
|
||||||
return logger;
|
|
||||||
}
|
}
|
||||||
return super.doCreateLogger(resource, logLevel, options);
|
return super.doCreateLogger(resource, logLevel, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -727,7 +727,7 @@ registerThemingParticipant((theme, collector) => {
|
||||||
if (debugIconBreakpointCurrentStackframeForegroundColor) {
|
if (debugIconBreakpointCurrentStackframeForegroundColor) {
|
||||||
collector.addRule(`
|
collector.addRule(`
|
||||||
.monaco-workbench ${ThemeIcon.asCSSSelector(icons.debugStackframe)},
|
.monaco-workbench ${ThemeIcon.asCSSSelector(icons.debugStackframe)},
|
||||||
.monaco-editor .debug-top-stack-frame-column::before {
|
.monaco-editor .debug-top-stack-frame-column {
|
||||||
color: ${debugIconBreakpointCurrentStackframeForegroundColor} !important;
|
color: ${debugIconBreakpointCurrentStackframeForegroundColor} !important;
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
|
|
|
@ -17,7 +17,6 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
import { distinct } from 'vs/base/common/arrays';
|
import { distinct } from 'vs/base/common/arrays';
|
||||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||||
import { debugStackframe, debugStackframeFocused } from 'vs/workbench/contrib/debug/browser/debugIcons';
|
import { debugStackframe, debugStackframeFocused } from 'vs/workbench/contrib/debug/browser/debugIcons';
|
||||||
import { noBreakWhitespace } from 'vs/base/common/strings';
|
|
||||||
|
|
||||||
export const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#ffff0033' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.'));
|
export const topStackFrameColor = registerColor('editor.stackFrameHighlightBackground', { dark: '#ffff0033', light: '#ffff6673', hc: '#ffff0033' }, localize('topStackFrameLineHighlight', 'Background color for the highlight of line at the top stack frame position.'));
|
||||||
export const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#7abd7a4d' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.'));
|
export const focusedStackFrameColor = registerColor('editor.focusedStackFrameHighlightBackground', { dark: '#7abd7a4d', light: '#cee7ce73', hc: '#7abd7a4d' }, localize('focusedStackFrameLineHighlight', 'Background color for the highlight of line at focused stack frame position.'));
|
||||||
|
@ -82,7 +81,7 @@ export function createDecorationsForStackFrame(stackFrame: IStackFrame, isFocuse
|
||||||
options: {
|
options: {
|
||||||
description: 'top-stack-frame-inline-decoration',
|
description: 'top-stack-frame-inline-decoration',
|
||||||
before: {
|
before: {
|
||||||
content: noBreakWhitespace,
|
content: '\uEB8B',
|
||||||
inlineClassName: noCharactersBefore ? 'debug-top-stack-frame-column start-of-line' : 'debug-top-stack-frame-column',
|
inlineClassName: noCharactersBefore ? 'debug-top-stack-frame-column start-of-line' : 'debug-top-stack-frame-column',
|
||||||
inlineClassNameAffectsLetterSpacing: true
|
inlineClassNameAffectsLetterSpacing: true
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,12 +20,6 @@
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.codicon-debug-breakpoint.codicon-debug-stackframe-focused::after,
|
|
||||||
.codicon-debug-breakpoint.codicon-debug-stackframe::after {
|
|
||||||
content: '\eb8a';
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monaco-editor .inline-breakpoint-widget.line-start {
|
.monaco-editor .inline-breakpoint-widget.line-start {
|
||||||
left: -8px !important;
|
left: -8px !important;
|
||||||
}
|
}
|
||||||
|
@ -38,10 +32,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .debug-top-stack-frame-column {
|
.monaco-editor .debug-top-stack-frame-column {
|
||||||
|
font: normal normal normal 16px/1 codicon;
|
||||||
|
text-rendering: auto;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-top: -1px; /* TODO @misolori: figure out a way to not use negative margin for alignment */
|
||||||
|
align-items: center;
|
||||||
width: 0.9em;
|
width: 0.9em;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-top: -1px; /* TODO @misolori: figure out a way to not use negative margin for alignment */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do not push text with inline decoration when decoration on start of line */
|
/* Do not push text with inline decoration when decoration on start of line */
|
||||||
|
@ -49,21 +50,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-17px, -50%);
|
transform: translate(-17px, -50%);
|
||||||
}
|
margin-top: 0px; /* TODO @misolori: figure out a way to not use negative margin for alignment */
|
||||||
|
|
||||||
.monaco-editor .debug-top-stack-frame-column {
|
|
||||||
display: inline-flex;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monaco-editor .debug-top-stack-frame-column::before {
|
|
||||||
content: '\eb8b';
|
|
||||||
font: normal normal normal 16px/1 codicon;
|
|
||||||
text-rendering: auto;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .inline-breakpoint-widget {
|
.monaco-editor .inline-breakpoint-widget {
|
||||||
|
|
|
@ -196,6 +196,36 @@ suite('EditorService', () => {
|
||||||
visibleEditorChangeListener.dispose();
|
visibleEditorChangeListener.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('openEditor() - same input does not cancel previous one - https://github.com/microsoft/vscode/issues/136684', async () => {
|
||||||
|
const [, service] = await createEditorService();
|
||||||
|
|
||||||
|
let input = new TestFileEditorInput(URI.parse('my://resource-basics'), TEST_EDITOR_INPUT_ID);
|
||||||
|
|
||||||
|
let editorP1 = service.openEditor(input, { pinned: true });
|
||||||
|
let editorP2 = service.openEditor(input, { pinned: true });
|
||||||
|
|
||||||
|
let editor1 = await editorP1;
|
||||||
|
assert.strictEqual(editor1?.input, input);
|
||||||
|
|
||||||
|
let editor2 = await editorP2;
|
||||||
|
assert.strictEqual(editor2?.input, input);
|
||||||
|
|
||||||
|
assert.ok(editor2.group);
|
||||||
|
await editor2.group.closeAllEditors();
|
||||||
|
|
||||||
|
input = new TestFileEditorInput(URI.parse('my://resource-basics'), TEST_EDITOR_INPUT_ID);
|
||||||
|
let inputSame = new TestFileEditorInput(URI.parse('my://resource-basics'), TEST_EDITOR_INPUT_ID);
|
||||||
|
|
||||||
|
editorP1 = service.openEditor(input, { pinned: true });
|
||||||
|
editorP2 = service.openEditor(inputSame, { pinned: true });
|
||||||
|
|
||||||
|
editor1 = await editorP1;
|
||||||
|
assert.strictEqual(editor1?.input, input);
|
||||||
|
|
||||||
|
editor2 = await editorP2;
|
||||||
|
assert.strictEqual(editor2?.input, input);
|
||||||
|
});
|
||||||
|
|
||||||
test('openEditor() - locked groups', async () => {
|
test('openEditor() - locked groups', async () => {
|
||||||
disposables.add(registerTestFileEditor());
|
disposables.add(registerTestFileEditor());
|
||||||
|
|
||||||
|
|
4
src/vscode-dts/vscode.d.ts
vendored
4
src/vscode-dts/vscode.d.ts
vendored
|
@ -6577,7 +6577,7 @@ declare module 'vscode' {
|
||||||
* Whether the task that is part of this group is the default for the group.
|
* Whether the task that is part of this group is the default for the group.
|
||||||
* This property cannot be set through API, and is controlled by a user's task configurations.
|
* This property cannot be set through API, and is controlled by a user's task configurations.
|
||||||
*/
|
*/
|
||||||
readonly isDefault?: boolean;
|
readonly isDefault: boolean | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID of the task group. Is one of TaskGroup.Clean.id, TaskGroup.Build.id, TaskGroup.Rebuild.id, or TaskGroup.Test.id.
|
* The ID of the task group. Is one of TaskGroup.Clean.id, TaskGroup.Build.id, TaskGroup.Rebuild.id, or TaskGroup.Test.id.
|
||||||
|
@ -6913,7 +6913,7 @@ declare module 'vscode' {
|
||||||
/**
|
/**
|
||||||
* The task's scope.
|
* The task's scope.
|
||||||
*/
|
*/
|
||||||
readonly scope?: TaskScope.Global | TaskScope.Workspace | WorkspaceFolder;
|
readonly scope: TaskScope.Global | TaskScope.Workspace | WorkspaceFolder | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The task's name
|
* The task's name
|
||||||
|
|
Loading…
Reference in a new issue