Merge branch 'main' into joh/vscode-dts

This commit is contained in:
Johannes Rieken 2021-11-10 15:36:05 +01:00
commit f7ef73720f
No known key found for this signature in database
GPG key ID: 96634B5AF12F8798
29 changed files with 687 additions and 215 deletions

View file

@ -86,6 +86,7 @@
"splitview",
"table",
"list",
"git"
"git",
"sash"
]
}

View file

@ -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
View file

@ -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);
}
}

View file

@ -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

View file

@ -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');
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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');

View file

@ -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 => {

View file

@ -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));
}

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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;
});
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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);

View file

@ -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;
};

View file

@ -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 }));
}
}

View file

@ -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');

View file

@ -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);
}

View file

@ -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;
}
`);

View file

@ -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
},

View file

@ -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 {

View file

@ -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());

View file

@ -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