mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 13:29:44 +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",
|
||||
"table",
|
||||
"list",
|
||||
"git"
|
||||
"git",
|
||||
"sash"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"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.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.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.",
|
||||
|
|
2
src/bootstrap.js
vendored
2
src/bootstrap.js
vendored
|
@ -100,7 +100,7 @@
|
|||
}
|
||||
if (!asarPathAdded && appRoot) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1382,5 +1382,3 @@ define(function () { return purify; });
|
|||
// export const removeHooks = purify.removeHooks;
|
||||
// export const removeAllHooks = purify.removeAllHooks;
|
||||
// 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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
throw new Error('Can\'t add same view twice');
|
||||
}
|
||||
|
|
|
@ -1028,7 +1028,7 @@ export class GridView implements IDisposable {
|
|||
this.trySet2x2();
|
||||
}
|
||||
|
||||
removeView(location: number[], sizing?: Sizing): IView {
|
||||
removeView(location: number[], sizing?: DistributeSizing): IView {
|
||||
this.disposable2x2.dispose();
|
||||
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 'vs/css!./sash';
|
||||
|
||||
/**
|
||||
* Allow the sashes to be visible at runtime.
|
||||
* @remark Use for development purposes only.
|
||||
*/
|
||||
let DEBUG = false;
|
||||
// DEBUG = Boolean("true"); // done "weirdly" so that a lint warning prevents you from pushing this
|
||||
|
||||
export interface ISashLayoutProvider { }
|
||||
|
||||
export interface IVerticalSashLayoutProvider extends ISashLayoutProvider {
|
||||
/**
|
||||
* A vertical sash layout provider provides position and height for a sash.
|
||||
*/
|
||||
export interface IVerticalSashLayoutProvider {
|
||||
getVerticalSashLeft(sash: Sash): number;
|
||||
getVerticalSashTop?(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;
|
||||
getHorizontalSashLeft?(sash: Sash): number;
|
||||
getHorizontalSashWidth?(sash: Sash): number;
|
||||
}
|
||||
|
||||
type ISashLayoutProvider = IVerticalSashLayoutProvider | IHorizontalSashLayoutProvider;
|
||||
|
||||
export interface ISashEvent {
|
||||
startX: number;
|
||||
currentX: number;
|
||||
startY: number;
|
||||
currentY: number;
|
||||
altKey: boolean;
|
||||
readonly startX: number;
|
||||
readonly currentX: number;
|
||||
readonly startY: number;
|
||||
readonly currentY: number;
|
||||
readonly altKey: boolean;
|
||||
}
|
||||
|
||||
export enum OrthogonalEdge {
|
||||
|
@ -46,10 +56,41 @@ export enum OrthogonalEdge {
|
|||
}
|
||||
|
||||
export interface ISashOptions {
|
||||
|
||||
/**
|
||||
* Whether a sash is horizontal or vertical.
|
||||
*/
|
||||
readonly orientation: Orientation;
|
||||
readonly orthogonalStartSash?: Sash;
|
||||
readonly orthogonalEndSash?: Sash;
|
||||
|
||||
/**
|
||||
* The width or height of a vertical or horizontal sash, respectively.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -67,9 +108,31 @@ export const enum Orientation {
|
|||
}
|
||||
|
||||
export const enum SashState {
|
||||
|
||||
/**
|
||||
* Disable any UI interaction.
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
private el: HTMLElement;
|
||||
private layoutProvider: ISashLayoutProvider;
|
||||
private orientation!: Orientation;
|
||||
private orientation: Orientation;
|
||||
private size: number;
|
||||
private hoverDelay = globalHoverDelay;
|
||||
private hoverDelayer = this._register(new Delayer(this.hoverDelay));
|
||||
|
||||
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 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) {
|
||||
if (this._state === state) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.el.classList.toggle('disabled', state === SashState.Disabled);
|
||||
this.el.classList.toggle('minimum', state === SashState.Minimum);
|
||||
this.el.classList.toggle('maximum', state === SashState.Maximum);
|
||||
this.el.classList.toggle('minimum', state === SashState.AtMinimum);
|
||||
this.el.classList.toggle('maximum', state === SashState.AtMaximum);
|
||||
|
||||
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;
|
||||
|
||||
private readonly _onDidStart = this._register(new Emitter<ISashEvent>());
|
||||
/**
|
||||
* An event which fires whenever the user starts dragging this sash.
|
||||
*/
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private readonly orthogonalStartSashDisposables = this._register(new DisposableStore());
|
||||
private _orthogonalStartSash: Sash | undefined;
|
||||
private readonly orthogonalStartDragHandleDisposables = this._register(new DisposableStore());
|
||||
private _orthogonalStartDragHandle: HTMLElement | undefined;
|
||||
get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
set orthogonalStartSash(sash: Sash | undefined) {
|
||||
this.orthogonalStartDragHandleDisposables.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);
|
||||
}
|
||||
|
||||
this._orthogonalStartSash = sash;
|
||||
}
|
||||
|
||||
private readonly orthogonalEndSashDisposables = this._register(new DisposableStore());
|
||||
private _orthogonalEndSash: Sash | undefined;
|
||||
private readonly orthogonalEndDragHandleDisposables = this._register(new DisposableStore());
|
||||
private _orthogonalEndDragHandle: HTMLElement | undefined;
|
||||
get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
set orthogonalEndSash(sash: Sash | undefined) {
|
||||
this.orthogonalEndDragHandleDisposables.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);
|
||||
}
|
||||
|
||||
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) {
|
||||
super();
|
||||
|
||||
|
@ -381,17 +512,17 @@ export class Sash extends Disposable {
|
|||
if (isMultisashResize) {
|
||||
cursor = 'all-scroll';
|
||||
} else if (this.orientation === Orientation.HORIZONTAL) {
|
||||
if (this.state === SashState.Minimum) {
|
||||
if (this.state === SashState.AtMinimum) {
|
||||
cursor = 's-resize';
|
||||
} else if (this.state === SashState.Maximum) {
|
||||
} else if (this.state === SashState.AtMaximum) {
|
||||
cursor = 'n-resize';
|
||||
} else {
|
||||
cursor = isMacintosh ? 'row-resize' : 'ns-resize';
|
||||
}
|
||||
} else {
|
||||
if (this.state === SashState.Minimum) {
|
||||
if (this.state === SashState.AtMinimum) {
|
||||
cursor = 'e-resize';
|
||||
} else if (this.state === SashState.Maximum) {
|
||||
} else if (this.state === SashState.AtMaximum) {
|
||||
cursor = 'w-resize';
|
||||
} else {
|
||||
cursor = isMacintosh ? 'col-resize' : 'ew-resize';
|
||||
|
@ -406,7 +537,7 @@ export class Sash extends Disposable {
|
|||
updateStyle();
|
||||
|
||||
if (!isMultisashResize) {
|
||||
this.onDidEnablementChange(updateStyle, null, disposables);
|
||||
this.onDidEnablementChange.event(updateStyle, null, disposables);
|
||||
}
|
||||
|
||||
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 {
|
||||
Sash.onMouseLeave(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Layout the sash. The sash will size and position itself
|
||||
* based on its provided {@link ISashLayoutProvider layout provider}.
|
||||
*/
|
||||
layout(): void {
|
||||
if (this.orientation === Orientation.VERTICAL) {
|
||||
const verticalProvider = (<IVerticalSashLayoutProvider>this.layoutProvider);
|
||||
|
|
|
@ -17,45 +17,178 @@ import 'vs/css!./splitview';
|
|||
export { Orientation } from 'vs/base/browser/ui/sash/sash';
|
||||
|
||||
export interface ISplitViewStyles {
|
||||
separatorBorder: Color;
|
||||
readonly separatorBorder: Color;
|
||||
}
|
||||
|
||||
const defaultStyles: ISplitViewStyles = {
|
||||
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 {
|
||||
Normal,
|
||||
Low,
|
||||
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> {
|
||||
|
||||
/**
|
||||
* The DOM element for this view.
|
||||
*/
|
||||
readonly element: HTMLElement;
|
||||
|
||||
/**
|
||||
* A minimum size for this view.
|
||||
*
|
||||
* @remarks If none, set it to `0`.
|
||||
*/
|
||||
readonly minimumSize: number;
|
||||
|
||||
/**
|
||||
* A minimum size for this view.
|
||||
*
|
||||
* @remarks If none, set it to `Number.POSITIVE_INFINITY`.
|
||||
*/
|
||||
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>;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
readonly sash: Sash;
|
||||
readonly start: number;
|
||||
|
@ -190,30 +323,89 @@ enum State {
|
|||
Busy
|
||||
}
|
||||
|
||||
/**
|
||||
* When adding or removing views, distribute the delta space among
|
||||
* all other views.
|
||||
*/
|
||||
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 };
|
||||
|
||||
/**
|
||||
* When adding or removing views, assume the view is invisible.
|
||||
*/
|
||||
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 namespace Sizing {
|
||||
|
||||
/**
|
||||
* When adding or removing views, distribute the delta space among
|
||||
* all other views.
|
||||
*/
|
||||
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 }; }
|
||||
|
||||
/**
|
||||
* When adding or removing views, assume the view is invisible.
|
||||
*/
|
||||
export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; }
|
||||
}
|
||||
|
||||
export interface ISplitViewDescriptor<TLayoutContext = undefined> {
|
||||
size: number;
|
||||
views: {
|
||||
visible?: boolean;
|
||||
size: number;
|
||||
view: IView<TLayoutContext>;
|
||||
}[];
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SplitView} is the UI component which implements a one dimensional
|
||||
* flex-like layout algorithm for a collection of {@link IView} instances, which
|
||||
* are essentially HTMLElement instances with the following size constraints:
|
||||
*
|
||||
* - {@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 {
|
||||
|
||||
/**
|
||||
* This {@link SplitView}'s orientation.
|
||||
*/
|
||||
readonly orientation: Orientation;
|
||||
|
||||
/**
|
||||
* The DOM element representing this {@link SplitView}.
|
||||
*/
|
||||
readonly el: HTMLElement;
|
||||
|
||||
private sashContainer: HTMLElement;
|
||||
private viewContainer: HTMLElement;
|
||||
private scrollable: Scrollable;
|
||||
|
@ -231,27 +423,58 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
private readonly getSashOrthogonalSize: { (): number } | undefined;
|
||||
|
||||
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;
|
||||
|
||||
private _onDidSashReset = this._register(new Emitter<number>());
|
||||
/**
|
||||
* Fires whenever the user double clicks a {@link Sash sash}.
|
||||
*/
|
||||
readonly onDidSashReset = this._onDidSashReset.event;
|
||||
|
||||
/**
|
||||
* Fires whenever the split view is scrolled.
|
||||
*/
|
||||
readonly onDidScroll: Event<ScrollEvent>;
|
||||
|
||||
/**
|
||||
* The amount of views in this {@link SplitView}.
|
||||
*/
|
||||
get length(): number {
|
||||
return this.viewItems.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum size of this {@link SplitView}.
|
||||
*/
|
||||
get minimumSize(): number {
|
||||
return this.viewItems.reduce((r, item) => r + item.minimumSize, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum size of this {@link SplitView}.
|
||||
*/
|
||||
get maximumSize(): number {
|
||||
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 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) {
|
||||
for (const sashItem of this.sashItems) {
|
||||
sashItem.sash.orthogonalStartSash = sash;
|
||||
|
@ -260,8 +483,11 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
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) {
|
||||
for (const sashItem of this.sashItems) {
|
||||
sashItem.sash.orthogonalEndSash = sash;
|
||||
|
@ -270,12 +496,16 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
this._orthogonalEndSash = sash;
|
||||
}
|
||||
|
||||
get sashes(): Sash[] {
|
||||
/**
|
||||
* The internal sashes within this {@link SplitView}.
|
||||
*/
|
||||
get sashes(): readonly 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) {
|
||||
if (this._startSnappingEnabled === startSnappingEnabled) {
|
||||
return;
|
||||
|
@ -285,8 +515,9 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
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) {
|
||||
if (this._endSnappingEnabled === endSnappingEnabled) {
|
||||
return;
|
||||
|
@ -296,12 +527,18 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
this.updateSashEnablement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link SplitView} instance.
|
||||
*
|
||||
* @param container
|
||||
* @param options
|
||||
*/
|
||||
constructor(container: HTMLElement, options: ISplitViewOptions<TLayoutContext> = {}) {
|
||||
super();
|
||||
|
||||
this.orientation = types.isUndefined(options.orientation) ? Orientation.VERTICAL : options.orientation;
|
||||
this.inverseAltBehavior = !!options.inverseAltBehavior;
|
||||
this.proportionalLayout = types.isUndefined(options.proportionalLayout) ? true : !!options.proportionalLayout;
|
||||
this.orientation = options.orientation ?? Orientation.VERTICAL;
|
||||
this.inverseAltBehavior = options.inverseAltBehavior ?? false;
|
||||
this.proportionalLayout = options.proportionalLayout ?? true;
|
||||
this.getSashOrthogonalSize = options.getSashOrthogonalSize;
|
||||
|
||||
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 {
|
||||
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> {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
|
@ -383,13 +634,19 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
this.relayout();
|
||||
this.state = State.Idle;
|
||||
|
||||
if (sizing && sizing.type === 'distribute') {
|
||||
if (sizing?.type === 'distribute') {
|
||||
this.distributeViewSizes();
|
||||
}
|
||||
|
||||
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 {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
|
@ -401,6 +658,13 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
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 {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
|
@ -419,6 +683,11 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
this.addView(fromView, toSize, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link IView view} is visible.
|
||||
*
|
||||
* @param index The {@link IView view} index.
|
||||
*/
|
||||
isViewVisible(index: number): boolean {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
throw new Error('Index out of bounds');
|
||||
|
@ -428,6 +697,12 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
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 {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
throw new Error('Index out of bounds');
|
||||
|
@ -441,6 +716,11 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
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 {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
throw new Error('Index out of bounds');
|
||||
|
@ -450,6 +730,12 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
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 {
|
||||
const previousSize = Math.max(this.size, this.contentSize);
|
||||
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 {
|
||||
if (this.state !== State.Idle) {
|
||||
throw new Error('Cant modify splitview');
|
||||
|
@ -640,6 +932,9 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
this.state = State.Idle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Distribute the entire {@link SplitView} size among all {@link IView views}.
|
||||
*/
|
||||
distributeViewSizes(): void {
|
||||
const flexibleViewItems: ViewItem<TLayoutContext>[] = [];
|
||||
let flexibleSize = 0;
|
||||
|
@ -664,6 +959,9 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
this.relayout(lowPriorityIndexes, highPriorityIndexes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of a {@link IView view}.
|
||||
*/
|
||||
getViewSize(index: number): number {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return -1;
|
||||
|
@ -964,16 +1262,16 @@ export class SplitView<TLayoutContext = undefined> extends Disposable {
|
|||
const snappedAfter = typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible;
|
||||
|
||||
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)) {
|
||||
sash.state = SashState.Maximum;
|
||||
sash.state = SashState.AtMaximum;
|
||||
} else {
|
||||
sash.state = SashState.Disabled;
|
||||
}
|
||||
} else if (min && !max) {
|
||||
sash.state = SashState.Minimum;
|
||||
sash.state = SashState.AtMinimum;
|
||||
} else if (!min && max) {
|
||||
sash.state = SashState.Maximum;
|
||||
sash.state = SashState.AtMaximum;
|
||||
} else {
|
||||
sash.state = SashState.Enabled;
|
||||
}
|
||||
|
|
|
@ -297,12 +297,12 @@ suite('Splitview', () => {
|
|||
assert.strictEqual(sashes[1].state, SashState.Disabled, 'second sash is disabled');
|
||||
|
||||
view1.maximumSize = 300;
|
||||
assert.strictEqual(sashes[0].state, SashState.Minimum, 'first sash is enabled');
|
||||
assert.strictEqual(sashes[1].state, SashState.Minimum, 'second sash is enabled');
|
||||
assert.strictEqual(sashes[0].state, SashState.AtMinimum, 'first sash is enabled');
|
||||
assert.strictEqual(sashes[1].state, SashState.AtMinimum, 'second sash is enabled');
|
||||
|
||||
view2.maximumSize = 200;
|
||||
assert.strictEqual(sashes[0].state, SashState.Minimum, 'first sash is enabled');
|
||||
assert.strictEqual(sashes[1].state, SashState.Minimum, 'second sash is enabled');
|
||||
assert.strictEqual(sashes[0].state, SashState.AtMinimum, 'first sash is enabled');
|
||||
assert.strictEqual(sashes[1].state, SashState.AtMinimum, 'second sash is enabled');
|
||||
|
||||
splitview.resizeView(0, 40);
|
||||
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)
|
||||
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
|
||||
once(lifecycleMainService.onWillShutdown)(evt => {
|
||||
|
|
|
@ -110,7 +110,7 @@ class CliMain extends Disposable {
|
|||
// Log
|
||||
const logLevel = getLogLevel(environmentService);
|
||||
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) {
|
||||
loggers.push(new ConsoleLogger(logLevel));
|
||||
}
|
||||
|
|
|
@ -202,9 +202,12 @@ export class DecorationsOverlay extends DynamicViewOverlay {
|
|||
|
||||
if (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {
|
||||
const singleVisibleRange = lineVisibleRanges.ranges[0];
|
||||
if (singleVisibleRange.width === 0) {
|
||||
// collapsed range case => make the decoration visible by faking its width
|
||||
lineVisibleRanges.ranges[0] = new HorizontalRange(singleVisibleRange.left, this._typicalHalfwidthCharacterWidth);
|
||||
if (singleVisibleRange.width < this._typicalHalfwidthCharacterWidth) {
|
||||
// collapsed/very small range case => make the decoration visible by expanding its width
|
||||
// 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 { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
import { FoldingRangeKind, FoldingRangeProviderRegistry } from 'vs/editor/common/modes';
|
||||
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';
|
||||
|
@ -130,7 +131,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
|||
const options = this.editor.getOptions();
|
||||
this.foldingDecorationProvider.autoHideFoldingControls = options.get(EditorOption.showFoldingControls) === 'mouseover';
|
||||
this.foldingDecorationProvider.showFoldingHighlights = options.get(EditorOption.foldingHighlight);
|
||||
this.onModelContentChanged();
|
||||
this.triggerFoldingModelChanged();
|
||||
}
|
||||
if (e.hasChanged(EditorOption.foldingStrategy)) {
|
||||
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(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged()));
|
||||
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.onMouseDown(e => this.onEditorMouseDown(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.onModelContentChanged();
|
||||
this.triggerFoldingModelChanged();
|
||||
}
|
||||
|
||||
private onFoldingStrategyChanged() {
|
||||
|
@ -258,7 +259,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
|||
this.rangeProvider.dispose();
|
||||
}
|
||||
this.rangeProvider = null;
|
||||
this.onModelContentChanged();
|
||||
this.triggerFoldingModelChanged();
|
||||
}
|
||||
|
||||
private getRangeProvider(editorModel: ITextModel): RangeProvider {
|
||||
|
@ -278,7 +279,7 @@ export class FoldingController extends Disposable implements IEditorContribution
|
|||
}, 30000);
|
||||
return rangeProvider; // keep memento in case there are still no foldingProviders on the next request.
|
||||
} else if (foldingProviders.length > 0) {
|
||||
this.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders, () => this.onModelContentChanged());
|
||||
this.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders, () => this.triggerFoldingModelChanged());
|
||||
}
|
||||
}
|
||||
this.foldingStateMemento = null;
|
||||
|
@ -289,7 +290,12 @@ export class FoldingController extends Disposable implements IEditorContribution
|
|||
return this.foldingModelPromise;
|
||||
}
|
||||
|
||||
private onModelContentChanged() {
|
||||
private onDidChangeModelContent(e: IModelContentChangedEvent) {
|
||||
this.hiddenRangeModel?.notifyChangeModelContent(e);
|
||||
this.triggerFoldingModelChanged();
|
||||
}
|
||||
|
||||
private triggerFoldingModelChanged() {
|
||||
if (this.updateScheduler) {
|
||||
if (this.foldingRegionPromise) {
|
||||
this.foldingRegionPromise.cancel();
|
||||
|
|
|
@ -4,17 +4,22 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { findFirstInSorted } from 'vs/base/common/arrays';
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
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';
|
||||
|
||||
export class HiddenRangeModel {
|
||||
|
||||
private readonly _foldingModel: FoldingModel;
|
||||
private _hiddenRanges: IRange[];
|
||||
private _foldingModelListener: IDisposable | null;
|
||||
private readonly _updateEventEmitter = new Emitter<IRange[]>();
|
||||
private _hasLineChanges: boolean = false;
|
||||
|
||||
public get onDidChange(): Event<IRange[]> { return this._updateEventEmitter.event; }
|
||||
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 {
|
||||
let updateHiddenAreas = false;
|
||||
let newHiddenAreas: IRange[] = [];
|
||||
|
@ -61,7 +74,7 @@ export class HiddenRangeModel {
|
|||
lastCollapsedStart = startLineNumber;
|
||||
lastCollapsedEnd = endLineNumber;
|
||||
}
|
||||
if (updateHiddenAreas || k < this._hiddenRanges.length) {
|
||||
if (this._hasLineChanges || updateHiddenAreas || k < this._hiddenRanges.length) {
|
||||
this.applyHiddenRanges(newHiddenAreas);
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +103,7 @@ export class HiddenRangeModel {
|
|||
|
||||
private applyHiddenRanges(newHiddenAreas: IRange[]) {
|
||||
this._hiddenRanges = newHiddenAreas;
|
||||
this._hasLineChanges = false;
|
||||
this._updateEventEmitter.fire(newHiddenAreas);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,9 +105,17 @@ class ModesContentComputer implements IHoverComputer<IHoverPart[]> {
|
|||
|
||||
const startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;
|
||||
const endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;
|
||||
if (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) {
|
||||
return false;
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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 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 {
|
||||
|
||||
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++) {
|
||||
const element = query.item(i);
|
||||
result.push(serializeElement(element, recursive));
|
||||
result.push(this.serializeElement(element, recursive));
|
||||
}
|
||||
|
||||
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; }> {
|
||||
const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined;
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,7 @@ export class LoggerService extends AbstractLoggerService implements ILoggerServi
|
|||
|
||||
protected doCreateLogger(resource: URI, logLevel: LogLevel, options?: ILoggerOptions): ILogger {
|
||||
if (resource.scheme === Schemas.file) {
|
||||
const logger = new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, logLevel);
|
||||
if (options?.donotUseFormatters) {
|
||||
(<SpdLogLogger>logger).clearFormatters();
|
||||
}
|
||||
return logger;
|
||||
return new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, !!options?.donotUseFormatters, logLevel);
|
||||
} else {
|
||||
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 { 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
|
||||
try {
|
||||
const _spdlog = await import('spdlog');
|
||||
_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) {
|
||||
console.error(e);
|
||||
}
|
||||
|
@ -49,14 +53,15 @@ export class SpdLogLogger extends AbstractMessageLogger implements ILogger {
|
|||
private _logger: spdlog.Logger | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly name: string,
|
||||
private readonly filepath: string,
|
||||
private readonly rotating: boolean,
|
||||
level: LogLevel
|
||||
name: string,
|
||||
filepath: string,
|
||||
rotating: boolean,
|
||||
donotUseFormatters: boolean,
|
||||
level: LogLevel,
|
||||
) {
|
||||
super();
|
||||
this.setLevel(level);
|
||||
this._loggerCreationPromise = this._createSpdLogLogger();
|
||||
this._loggerCreationPromise = this._createSpdLogLogger(name, filepath, rotating, donotUseFormatters);
|
||||
this._register(this.onDidChangeLogLevel(level => {
|
||||
if (this._logger) {
|
||||
this._logger.setLevel(level);
|
||||
|
@ -64,20 +69,18 @@ export class SpdLogLogger extends AbstractMessageLogger implements ILogger {
|
|||
}));
|
||||
}
|
||||
|
||||
private _createSpdLogLogger(): Promise<void> {
|
||||
const filecount = this.rotating ? 6 : 1;
|
||||
private async _createSpdLogLogger(name: string, filepath: string, rotating: boolean, donotUseFormatters: boolean): Promise<void> {
|
||||
const filecount = rotating ? 6 : 1;
|
||||
const filesize = (30 / filecount) * ByteSize.MB;
|
||||
return createSpdLogLogger(this.name, this.filepath, filesize, filecount)
|
||||
.then(logger => {
|
||||
if (logger) {
|
||||
this._logger = logger;
|
||||
this._logger.setLevel(this.getLevel());
|
||||
for (const { level, message } of this.buffer) {
|
||||
log(this._logger, level, message);
|
||||
}
|
||||
this.buffer = [];
|
||||
}
|
||||
});
|
||||
const logger = await createSpdLogLogger(name, filepath, filesize, filecount, donotUseFormatters);
|
||||
if (logger) {
|
||||
this._logger = logger;
|
||||
this._logger.setLevel(this.getLevel());
|
||||
for (const { level, message } of this.buffer) {
|
||||
log(this._logger, level, message);
|
||||
}
|
||||
this.buffer = [];
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if (this._logger) {
|
||||
this._logger.flush();
|
||||
|
|
|
@ -75,7 +75,7 @@ class CliMain extends Disposable {
|
|||
|
||||
const environmentService = new ServerEnvironmentService(this.args, productService);
|
||||
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);
|
||||
logService.trace(`Remote configuration data at ${this.remoteDataFolder}`);
|
||||
logService.trace('process arguments:', this.args);
|
||||
|
|
|
@ -1043,7 +1043,7 @@ const getOrCreateSpdLogService: (environmentService: IServerEnvironmentService)
|
|||
let _logService: ILogService | null;
|
||||
return function getLogService(environmentService: IServerEnvironmentService): ILogService {
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { ILoggerService, LogService } from 'vs/platform/log/common/log';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
export class ExtHostLogService extends LogService {
|
||||
|
||||
|
@ -14,7 +15,7 @@ export class ExtHostLogService extends LogService {
|
|||
@ILoggerService loggerService: ILoggerService,
|
||||
@IExtHostInitDataService initData: IExtHostInitDataService,
|
||||
) {
|
||||
super(loggerService.createLogger(initData.logFile));
|
||||
super(loggerService.createLogger(initData.logFile, { name: ExtensionHostLogFileName }));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1776,7 +1776,7 @@ export enum TaskPanelKind {
|
|||
@es5ClassCompat
|
||||
export class TaskGroup implements vscode.TaskGroup {
|
||||
|
||||
isDefault?: boolean;
|
||||
isDefault: boolean | undefined;
|
||||
private _id: string;
|
||||
|
||||
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 {
|
||||
if (resource.scheme === Schemas.file) {
|
||||
const logger = new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, logLevel);
|
||||
if (options?.donotUseFormatters) {
|
||||
(<SpdLogLogger>logger).clearFormatters();
|
||||
}
|
||||
return logger;
|
||||
return new SpdLogLogger(options?.name || generateUuid(), resource.fsPath, !options?.donotRotate, !!options?.donotUseFormatters, logLevel);
|
||||
}
|
||||
return super.doCreateLogger(resource, logLevel, options);
|
||||
}
|
||||
|
|
|
@ -727,7 +727,7 @@ registerThemingParticipant((theme, collector) => {
|
|||
if (debugIconBreakpointCurrentStackframeForegroundColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench ${ThemeIcon.asCSSSelector(icons.debugStackframe)},
|
||||
.monaco-editor .debug-top-stack-frame-column::before {
|
||||
.monaco-editor .debug-top-stack-frame-column {
|
||||
color: ${debugIconBreakpointCurrentStackframeForegroundColor} !important;
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -17,7 +17,6 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
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 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: {
|
||||
description: 'top-stack-frame-inline-decoration',
|
||||
before: {
|
||||
content: noBreakWhitespace,
|
||||
content: '\uEB8B',
|
||||
inlineClassName: noCharactersBefore ? 'debug-top-stack-frame-column start-of-line' : 'debug-top-stack-frame-column',
|
||||
inlineClassNameAffectsLetterSpacing: true
|
||||
},
|
||||
|
|
|
@ -20,12 +20,6 @@
|
|||
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 {
|
||||
left: -8px !important;
|
||||
}
|
||||
|
@ -38,10 +32,17 @@
|
|||
}
|
||||
|
||||
.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;
|
||||
display: inline-flex;
|
||||
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 */
|
||||
|
@ -49,21 +50,7 @@
|
|||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-17px, -50%);
|
||||
}
|
||||
|
||||
.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;
|
||||
margin-top: 0px; /* TODO @misolori: figure out a way to not use negative margin for alignment */
|
||||
}
|
||||
|
||||
.monaco-editor .inline-breakpoint-widget {
|
||||
|
|
|
@ -196,6 +196,36 @@ suite('EditorService', () => {
|
|||
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 () => {
|
||||
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.
|
||||
* 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.
|
||||
|
@ -6913,7 +6913,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* The task's scope.
|
||||
*/
|
||||
readonly scope?: TaskScope.Global | TaskScope.Workspace | WorkspaceFolder;
|
||||
readonly scope: TaskScope.Global | TaskScope.Workspace | WorkspaceFolder | undefined;
|
||||
|
||||
/**
|
||||
* The task's name
|
||||
|
|
Loading…
Reference in a new issue