mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-19 18:14:50 +01:00
Introduce minimap section headers, a la Xcode (#190759)
* WIP for adding minimap section headers for #74843 * Get section headers rendering * Fix default value of section header font size * Fix tests * Improve section header position * Fix separator display, update after config change * Split too-long headers with an ellipsis * Render section headers on the decorations canvas * Support MARK with just a separator line * Calculate minimap section headers asynchronously * Simplify change * Avoid font variable duplication * Fix issue introduced earlier * Recompute section headers when the language configuration changes * Fix problem in constructing region header range * Parse mark headers in the entire file and then filter out the ones not appearing in comments on the UI side, where tokens info is available --------- Co-authored-by: Alexandru Dima <alexdima@microsoft.com>
This commit is contained in:
co-authored by
Alexandru Dima
parent
cda53a0627
commit
c800bf9216
@@ -0,0 +1,16 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
|
||||
/**
|
||||
* The best font-family to be used in CSS based on the platform:
|
||||
* - Windows: Segoe preferred, fallback to sans-serif
|
||||
* - macOS: standard system font, fallback to sans-serif
|
||||
* - Linux: standard system font preferred, fallback to Ubuntu fonts
|
||||
*
|
||||
* Note: this currently does not adjust for different locales.
|
||||
*/
|
||||
export const DEFAULT_FONT_FAMILY = isWindows ? '"Segoe WPC", "Segoe UI", sans-serif' : isMacintosh ? '-apple-system, BlinkMacSystemFont, sans-serif' : 'system-ui, "Ubuntu", "Droid Sans", sans-serif';
|
||||
@@ -29,6 +29,7 @@ import { IDocumentDiff, IDocumentDiffProviderOptions } from 'vs/editor/common/di
|
||||
import { ILinesDiffComputerOptions, MovedText } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
import { DetailedLineRangeMapping, RangeMapping, LineRangeMapping } from 'vs/editor/common/diff/rangeMapping';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { SectionHeader, FindSectionHeaderOptions } from 'vs/editor/common/services/findSectionHeaders';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
import { WindowIntervalTimer } from 'vs/base/browser/dom';
|
||||
|
||||
@@ -190,6 +191,10 @@ export class EditorWorkerService extends Disposable implements IEditorWorkerServ
|
||||
computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> {
|
||||
return this._workerManager.withWorker().then(client => client.computeWordRanges(resource, range));
|
||||
}
|
||||
|
||||
public findSectionHeaders(uri: URI, options: FindSectionHeaderOptions): Promise<SectionHeader[]> {
|
||||
return this._workerManager.withWorker().then(client => client.findSectionHeaders(uri, options));
|
||||
}
|
||||
}
|
||||
|
||||
class WordBasedCompletionItemProvider implements languages.CompletionItemProvider {
|
||||
@@ -613,6 +618,12 @@ export class EditorWorkerClient extends Disposable implements IEditorWorkerClien
|
||||
});
|
||||
}
|
||||
|
||||
public findSectionHeaders(uri: URI, options: FindSectionHeaderOptions): Promise<SectionHeader[]> {
|
||||
return this._withSyncedResources([uri]).then(proxy => {
|
||||
return proxy.findSectionHeaders(uri.toString(), options);
|
||||
});
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
this._disposed = true;
|
||||
|
||||
@@ -27,14 +27,16 @@ import { ViewContext } from 'vs/editor/common/viewModel/viewContext';
|
||||
import { EditorTheme } from 'vs/editor/common/editorTheme';
|
||||
import * as viewEvents from 'vs/editor/common/viewEvents';
|
||||
import { ViewLineData, ViewModelDecoration } from 'vs/editor/common/viewModel';
|
||||
import { minimapSelection, minimapBackground, minimapForegroundOpacity } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { minimapSelection, minimapBackground, minimapForegroundOpacity, editorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch';
|
||||
import { MinimapCharRendererFactory } from 'vs/editor/browser/viewParts/minimap/minimapCharRendererFactory';
|
||||
import { MinimapPosition, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
import { MinimapPosition, MinimapSectionHeaderStyle, TextModelResolvedOptions } from 'vs/editor/common/model';
|
||||
import { createSingleCallFunction } from 'vs/base/common/functional';
|
||||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/base/browser/fonts';
|
||||
|
||||
/**
|
||||
* The orthogonal distance to the slider at which dragging "resets". This implements "snapping"
|
||||
@@ -90,6 +92,9 @@ class MinimapOptions {
|
||||
public readonly fontScale: number;
|
||||
public readonly minimapLineHeight: number;
|
||||
public readonly minimapCharWidth: number;
|
||||
public readonly sectionHeaderFontFamily: string;
|
||||
public readonly sectionHeaderFontSize: number;
|
||||
public readonly sectionHeaderFontColor: RGBA8;
|
||||
|
||||
public readonly charRenderer: () => MinimapCharRenderer;
|
||||
public readonly defaultBackgroundColor: RGBA8;
|
||||
@@ -132,6 +137,9 @@ class MinimapOptions {
|
||||
this.fontScale = minimapLayout.minimapScale;
|
||||
this.minimapLineHeight = minimapLayout.minimapLineHeight;
|
||||
this.minimapCharWidth = Constants.BASE_CHAR_WIDTH * this.fontScale;
|
||||
this.sectionHeaderFontFamily = DEFAULT_FONT_FAMILY;
|
||||
this.sectionHeaderFontSize = minimapOpts.sectionHeaderFontSize * pixelRatio;
|
||||
this.sectionHeaderFontColor = MinimapOptions._getSectionHeaderColor(theme, tokensColorTracker.getColor(ColorId.DefaultForeground));
|
||||
|
||||
this.charRenderer = createSingleCallFunction(() => MinimapCharRendererFactory.create(this.fontScale, fontInfo.fontFamily));
|
||||
this.defaultBackgroundColor = tokensColorTracker.getColor(ColorId.DefaultBackground);
|
||||
@@ -155,6 +163,14 @@ class MinimapOptions {
|
||||
return 255;
|
||||
}
|
||||
|
||||
private static _getSectionHeaderColor(theme: EditorTheme, defaultForegroundColor: RGBA8): RGBA8 {
|
||||
const themeColor = theme.getColor(editorForeground);
|
||||
if (themeColor) {
|
||||
return new RGBA8(themeColor.rgba.r, themeColor.rgba.g, themeColor.rgba.b, Math.round(255 * themeColor.rgba.a));
|
||||
}
|
||||
return defaultForegroundColor;
|
||||
}
|
||||
|
||||
public equals(other: MinimapOptions): boolean {
|
||||
return (this.renderMinimap === other.renderMinimap
|
||||
&& this.size === other.size
|
||||
@@ -179,6 +195,7 @@ class MinimapOptions {
|
||||
&& this.fontScale === other.fontScale
|
||||
&& this.minimapLineHeight === other.minimapLineHeight
|
||||
&& this.minimapCharWidth === other.minimapCharWidth
|
||||
&& this.sectionHeaderFontSize === other.sectionHeaderFontSize
|
||||
&& this.defaultBackgroundColor && this.defaultBackgroundColor.equals(other.defaultBackgroundColor)
|
||||
&& this.backgroundColor && this.backgroundColor.equals(other.backgroundColor)
|
||||
&& this.foregroundAlpha === other.foregroundAlpha
|
||||
@@ -544,6 +561,8 @@ export interface IMinimapModel {
|
||||
getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): (ViewLineData | null)[];
|
||||
getSelections(): Selection[];
|
||||
getMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[];
|
||||
getSectionHeaderDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[];
|
||||
getSectionHeaderText(decoration: ViewModelDecoration, fitWidth: (s: string) => string): string | null;
|
||||
getOptions(): TextModelResolvedOptions;
|
||||
revealLineNumber(lineNumber: number): void;
|
||||
setScrollTop(scrollTop: number): void;
|
||||
@@ -697,7 +716,7 @@ class MinimapSamplingState {
|
||||
|
||||
constructor(
|
||||
public readonly samplingRatio: number,
|
||||
public readonly minimapLines: number[]
|
||||
public readonly minimapLines: number[] // a map of 0-based minimap line indexes to 1-based view line numbers
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -790,6 +809,8 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
||||
private _samplingState: MinimapSamplingState | null;
|
||||
private _shouldCheckSampling: boolean;
|
||||
|
||||
private _sectionHeaderCache = new LRUCache<string, string>(10, 1.5);
|
||||
|
||||
private _actual: InnerMinimap;
|
||||
|
||||
constructor(context: ViewContext) {
|
||||
@@ -1037,15 +1058,8 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
||||
}
|
||||
|
||||
public getMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[] {
|
||||
let visibleRange: Range;
|
||||
if (this._samplingState) {
|
||||
const modelStartLineNumber = this._samplingState.minimapLines[startLineNumber - 1];
|
||||
const modelEndLineNumber = this._samplingState.minimapLines[endLineNumber - 1];
|
||||
visibleRange = new Range(modelStartLineNumber, 1, modelEndLineNumber, this._context.viewModel.getLineMaxColumn(modelEndLineNumber));
|
||||
} else {
|
||||
visibleRange = new Range(startLineNumber, 1, endLineNumber, this._context.viewModel.getLineMaxColumn(endLineNumber));
|
||||
}
|
||||
const decorations = this._context.viewModel.getMinimapDecorationsInRange(visibleRange);
|
||||
const decorations = this._getMinimapDecorationsInViewport(startLineNumber, endLineNumber)
|
||||
.filter(decoration => !decoration.options.minimap?.sectionHeaderStyle);
|
||||
|
||||
if (this._samplingState) {
|
||||
const result: ViewModelDecoration[] = [];
|
||||
@@ -1063,6 +1077,41 @@ export class Minimap extends ViewPart implements IMinimapModel {
|
||||
return decorations;
|
||||
}
|
||||
|
||||
public getSectionHeaderDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[] {
|
||||
const minimapLineHeight = this.options.minimapLineHeight;
|
||||
const sectionHeaderFontSize = this.options.sectionHeaderFontSize;
|
||||
const headerHeightInMinimapLines = sectionHeaderFontSize / minimapLineHeight;
|
||||
startLineNumber = Math.floor(Math.max(1, startLineNumber - headerHeightInMinimapLines));
|
||||
return this._getMinimapDecorationsInViewport(startLineNumber, endLineNumber)
|
||||
.filter(decoration => !!decoration.options.minimap?.sectionHeaderStyle);
|
||||
}
|
||||
|
||||
private _getMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number) {
|
||||
let visibleRange: Range;
|
||||
if (this._samplingState) {
|
||||
const modelStartLineNumber = this._samplingState.minimapLines[startLineNumber - 1];
|
||||
const modelEndLineNumber = this._samplingState.minimapLines[endLineNumber - 1];
|
||||
visibleRange = new Range(modelStartLineNumber, 1, modelEndLineNumber, this._context.viewModel.getLineMaxColumn(modelEndLineNumber));
|
||||
} else {
|
||||
visibleRange = new Range(startLineNumber, 1, endLineNumber, this._context.viewModel.getLineMaxColumn(endLineNumber));
|
||||
}
|
||||
return this._context.viewModel.getMinimapDecorationsInRange(visibleRange);
|
||||
}
|
||||
|
||||
public getSectionHeaderText(decoration: ViewModelDecoration, fitWidth: (s: string) => string): string | null {
|
||||
const headerText = decoration.options.minimap?.sectionHeaderText;
|
||||
if (!headerText) {
|
||||
return null;
|
||||
}
|
||||
const cachedText = this._sectionHeaderCache.get(headerText);
|
||||
if (cachedText) {
|
||||
return cachedText;
|
||||
}
|
||||
const fittedText = fitWidth(headerText);
|
||||
this._sectionHeaderCache.set(headerText, fittedText);
|
||||
return fittedText;
|
||||
}
|
||||
|
||||
public getOptions(): TextModelResolvedOptions {
|
||||
return this._context.viewModel.model.getOptions();
|
||||
}
|
||||
@@ -1469,6 +1518,7 @@ class InnerMinimap extends Disposable {
|
||||
const lineOffsetMap = new ContiguousLineMap<number[] | null>(layout.startLineNumber, layout.endLineNumber, null);
|
||||
this._renderSelectionsHighlights(canvasContext, selections, lineOffsetMap, layout, minimapLineHeight, tabSize, minimapCharWidth, canvasInnerWidth);
|
||||
this._renderDecorationsHighlights(canvasContext, decorations, lineOffsetMap, layout, minimapLineHeight, tabSize, minimapCharWidth, canvasInnerWidth);
|
||||
this._renderSectionHeaders(layout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1735,6 +1785,110 @@ class InnerMinimap extends Disposable {
|
||||
canvasContext.fillRect(x, y, width, height);
|
||||
}
|
||||
|
||||
private _renderSectionHeaders(layout: MinimapLayout) {
|
||||
const minimapLineHeight = this._model.options.minimapLineHeight;
|
||||
const sectionHeaderFontSize = this._model.options.sectionHeaderFontSize;
|
||||
const backgroundFillHeight = sectionHeaderFontSize * 1.5;
|
||||
const { canvasInnerWidth } = this._model.options;
|
||||
|
||||
const backgroundColor = this._model.options.backgroundColor;
|
||||
const backgroundFill = `rgb(${backgroundColor.r} ${backgroundColor.g} ${backgroundColor.b} / .7)`;
|
||||
const foregroundColor = this._model.options.sectionHeaderFontColor;
|
||||
const foregroundFill = `rgb(${foregroundColor.r} ${foregroundColor.g} ${foregroundColor.b})`;
|
||||
const separatorStroke = foregroundFill;
|
||||
|
||||
const canvasContext = this._decorationsCanvas.domNode.getContext('2d')!;
|
||||
canvasContext.font = sectionHeaderFontSize + 'px ' + this._model.options.sectionHeaderFontFamily;
|
||||
canvasContext.strokeStyle = separatorStroke;
|
||||
canvasContext.lineWidth = 0.2;
|
||||
|
||||
const decorations = this._model.getSectionHeaderDecorationsInViewport(layout.startLineNumber, layout.endLineNumber);
|
||||
decorations.sort((a, b) => a.range.startLineNumber - b.range.startLineNumber);
|
||||
|
||||
const fitWidth = InnerMinimap._fitSectionHeader.bind(null, canvasContext,
|
||||
canvasInnerWidth - MINIMAP_GUTTER_WIDTH);
|
||||
|
||||
for (const decoration of decorations) {
|
||||
const y = layout.getYForLineNumber(decoration.range.startLineNumber, minimapLineHeight) + sectionHeaderFontSize;
|
||||
const backgroundFillY = y - sectionHeaderFontSize;
|
||||
const separatorY = backgroundFillY + 2;
|
||||
const headerText = this._model.getSectionHeaderText(decoration, fitWidth);
|
||||
|
||||
InnerMinimap._renderSectionLabel(
|
||||
canvasContext,
|
||||
headerText,
|
||||
decoration.options.minimap?.sectionHeaderStyle === MinimapSectionHeaderStyle.Underlined,
|
||||
backgroundFill,
|
||||
foregroundFill,
|
||||
canvasInnerWidth,
|
||||
backgroundFillY,
|
||||
backgroundFillHeight,
|
||||
y,
|
||||
separatorY);
|
||||
}
|
||||
}
|
||||
|
||||
private static _fitSectionHeader(
|
||||
target: CanvasRenderingContext2D,
|
||||
maxWidth: number,
|
||||
headerText: string,
|
||||
): string {
|
||||
if (!headerText) {
|
||||
return headerText;
|
||||
}
|
||||
|
||||
const ellipsis = '…';
|
||||
const width = target.measureText(headerText).width;
|
||||
const ellipsisWidth = target.measureText(ellipsis).width;
|
||||
|
||||
if (width <= maxWidth || width <= ellipsisWidth) {
|
||||
return headerText;
|
||||
}
|
||||
|
||||
const len = headerText.length;
|
||||
const averageCharWidth = width / headerText.length;
|
||||
const maxCharCount = Math.floor((maxWidth - ellipsisWidth) / averageCharWidth) - 1;
|
||||
|
||||
// Find a halfway point that isn't after whitespace
|
||||
let halfCharCount = Math.ceil(maxCharCount / 2);
|
||||
while (halfCharCount > 0 && /\s/.test(headerText[halfCharCount - 1])) {
|
||||
--halfCharCount;
|
||||
}
|
||||
|
||||
// Split with ellipsis
|
||||
return headerText.substring(0, halfCharCount)
|
||||
+ ellipsis + headerText.substring(len - (maxCharCount - halfCharCount));
|
||||
}
|
||||
|
||||
private static _renderSectionLabel(
|
||||
target: CanvasRenderingContext2D,
|
||||
headerText: string | null,
|
||||
hasSeparatorLine: boolean,
|
||||
backgroundFill: string,
|
||||
foregroundFill: string,
|
||||
minimapWidth: number,
|
||||
backgroundFillY: number,
|
||||
backgroundFillHeight: number,
|
||||
textY: number,
|
||||
separatorY: number
|
||||
): void {
|
||||
if (headerText) {
|
||||
target.fillStyle = backgroundFill;
|
||||
target.fillRect(0, backgroundFillY, minimapWidth, backgroundFillHeight);
|
||||
|
||||
target.fillStyle = foregroundFill;
|
||||
target.fillText(headerText, MINIMAP_GUTTER_WIDTH, textY);
|
||||
}
|
||||
|
||||
if (hasSeparatorLine) {
|
||||
target.beginPath();
|
||||
target.moveTo(0, separatorY);
|
||||
target.lineTo(minimapWidth, separatorY);
|
||||
target.closePath();
|
||||
target.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
private renderLines(layout: MinimapLayout): RenderData | null {
|
||||
const startLineNumber = layout.startLineNumber;
|
||||
const endLineNumber = layout.endLineNumber;
|
||||
|
||||
@@ -3059,6 +3059,18 @@ export interface IEditorMinimapOptions {
|
||||
* Relative size of the font in the minimap. Defaults to 1.
|
||||
*/
|
||||
scale?: number;
|
||||
/**
|
||||
* Whether to show named regions as section headers. Defaults to true.
|
||||
*/
|
||||
showRegionSectionHeaders?: boolean;
|
||||
/**
|
||||
* Whether to show MARK: comments as section headers. Defaults to true.
|
||||
*/
|
||||
showMarkSectionHeaders?: boolean;
|
||||
/**
|
||||
* Font size of section headers. Defaults to 9.
|
||||
*/
|
||||
sectionHeaderFontSize?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3078,6 +3090,9 @@ class EditorMinimap extends BaseEditorOption<EditorOption.minimap, IEditorMinima
|
||||
renderCharacters: true,
|
||||
maxColumn: 120,
|
||||
scale: 1,
|
||||
showRegionSectionHeaders: true,
|
||||
showMarkSectionHeaders: true,
|
||||
sectionHeaderFontSize: 9,
|
||||
};
|
||||
super(
|
||||
EditorOption.minimap, 'minimap', defaults,
|
||||
@@ -3132,6 +3147,21 @@ class EditorMinimap extends BaseEditorOption<EditorOption.minimap, IEditorMinima
|
||||
type: 'number',
|
||||
default: defaults.maxColumn,
|
||||
description: nls.localize('minimap.maxColumn', "Limit the width of the minimap to render at most a certain number of columns.")
|
||||
},
|
||||
'editor.minimap.showRegionSectionHeaders': {
|
||||
type: 'boolean',
|
||||
default: defaults.showRegionSectionHeaders,
|
||||
description: nls.localize('minimap.showRegionSectionHeaders', "Controls whether named regions are shown as section headers in the minimap.")
|
||||
},
|
||||
'editor.minimap.showMarkSectionHeaders': {
|
||||
type: 'boolean',
|
||||
default: defaults.showMarkSectionHeaders,
|
||||
description: nls.localize('minimap.showMarkSectionHeaders', "Controls whether MARK: comments are shown as section headers in the minimap.")
|
||||
},
|
||||
'editor.minimap.sectionHeaderFontSize': {
|
||||
type: 'number',
|
||||
default: defaults.sectionHeaderFontSize,
|
||||
description: nls.localize('minimap.sectionHeaderFontSize', "Controls the font size of section headers in the minimap.")
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -3151,6 +3181,9 @@ class EditorMinimap extends BaseEditorOption<EditorOption.minimap, IEditorMinima
|
||||
renderCharacters: boolean(input.renderCharacters, this.defaultValue.renderCharacters),
|
||||
scale: EditorIntOption.clampedInt(input.scale, 1, 1, 3),
|
||||
maxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000),
|
||||
showRegionSectionHeaders: boolean(input.showRegionSectionHeaders, this.defaultValue.showRegionSectionHeaders),
|
||||
showMarkSectionHeaders: boolean(input.showMarkSectionHeaders, this.defaultValue.showMarkSectionHeaders),
|
||||
sectionHeaderFontSize: EditorFloatOption.clamp(input.sectionHeaderFontSize ?? this.defaultValue.sectionHeaderFontSize, 4, 32),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +70,19 @@ export interface IGlyphMarginLanesModel {
|
||||
/**
|
||||
* Position in the minimap to render the decoration.
|
||||
*/
|
||||
export enum MinimapPosition {
|
||||
export const enum MinimapPosition {
|
||||
Inline = 1,
|
||||
Gutter = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Section header style.
|
||||
*/
|
||||
export const enum MinimapSectionHeaderStyle {
|
||||
Normal = 1,
|
||||
Underlined = 2
|
||||
}
|
||||
|
||||
export interface IDecorationOptions {
|
||||
/**
|
||||
* CSS color to render.
|
||||
@@ -119,6 +127,14 @@ export interface IModelDecorationMinimapOptions extends IDecorationOptions {
|
||||
* The position in the minimap.
|
||||
*/
|
||||
position: MinimapPosition;
|
||||
/**
|
||||
* If the decoration is for a section header, which header style.
|
||||
*/
|
||||
sectionHeaderStyle?: MinimapSectionHeaderStyle | null;
|
||||
/**
|
||||
* If the decoration is for a section header, the header text.
|
||||
*/
|
||||
sectionHeaderText?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2219,12 +2219,15 @@ export class ModelDecorationGlyphMarginOptions {
|
||||
|
||||
export class ModelDecorationMinimapOptions extends DecorationOptions {
|
||||
readonly position: model.MinimapPosition;
|
||||
readonly sectionHeaderStyle: model.MinimapSectionHeaderStyle | null;
|
||||
readonly sectionHeaderText: string | null;
|
||||
private _resolvedColor: Color | undefined;
|
||||
|
||||
|
||||
constructor(options: model.IModelDecorationMinimapOptions) {
|
||||
super(options);
|
||||
this.position = options.position;
|
||||
this.sectionHeaderStyle = options.sectionHeaderStyle ?? null;
|
||||
this.sectionHeaderText = options.sectionHeaderText ?? null;
|
||||
}
|
||||
|
||||
public getColor(theme: IColorTheme): Color | undefined {
|
||||
|
||||
@@ -28,6 +28,7 @@ import { createProxyObject, getAllMethodNames } from 'vs/base/common/objects';
|
||||
import { IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';
|
||||
import { BugIndicatingError } from 'vs/base/common/errors';
|
||||
import { IDocumentColorComputerTarget, computeDefaultDocumentColors } from 'vs/editor/common/languages/defaultDocumentColorsComputer';
|
||||
import { FindSectionHeaderOptions, SectionHeader, findSectionHeaders } from 'vs/editor/common/services/findSectionHeaders';
|
||||
|
||||
export interface IMirrorModel extends IMirrorTextModel {
|
||||
readonly uri: URI;
|
||||
@@ -401,6 +402,14 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable {
|
||||
return UnicodeTextModelHighlighter.computeUnicodeHighlights(model, options, range);
|
||||
}
|
||||
|
||||
public async findSectionHeaders(url: string, options: FindSectionHeaderOptions): Promise<SectionHeader[]> {
|
||||
const model = this._getModel(url);
|
||||
if (!model) {
|
||||
return [];
|
||||
}
|
||||
return findSectionHeaders(model, options);
|
||||
}
|
||||
|
||||
// ---- BEGIN diff --------------------------------------------------------------------------
|
||||
|
||||
public async computeDiff(originalUrl: string, modifiedUrl: string, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise<IDiffComputationResult | null> {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { IInplaceReplaceSupportResult, TextEdit } from 'vs/editor/common/languag
|
||||
import { UnicodeHighlighterOptions } from 'vs/editor/common/services/unicodeTextModelHighlighter';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import type { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';
|
||||
import { SectionHeader, FindSectionHeaderOptions } from 'vs/editor/common/services/findSectionHeaders';
|
||||
|
||||
export const IEditorWorkerService = createDecorator<IEditorWorkerService>('editorWorkerService');
|
||||
|
||||
@@ -36,6 +37,8 @@ export interface IEditorWorkerService {
|
||||
|
||||
canNavigateValueSet(resource: URI): boolean;
|
||||
navigateValueSet(resource: URI, range: IRange, up: boolean): Promise<IInplaceReplaceSupportResult | null>;
|
||||
|
||||
findSectionHeaders(uri: URI, options: FindSectionHeaderOptions): Promise<SectionHeader[]>;
|
||||
}
|
||||
|
||||
export interface IDiffComputationResult {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { FoldingRules } from 'vs/editor/common/languages/languageConfiguration';
|
||||
|
||||
export interface ISectionHeaderFinderTarget {
|
||||
getLineCount(): number;
|
||||
getLineContent(lineNumber: number): string;
|
||||
}
|
||||
|
||||
export interface FindSectionHeaderOptions {
|
||||
foldingRules?: FoldingRules;
|
||||
findRegionSectionHeaders: boolean;
|
||||
findMarkSectionHeaders: boolean;
|
||||
}
|
||||
|
||||
export interface SectionHeader {
|
||||
/**
|
||||
* The location of the header text in the text model.
|
||||
*/
|
||||
range: IRange;
|
||||
/**
|
||||
* The section header text.
|
||||
*/
|
||||
text: string;
|
||||
/**
|
||||
* Whether the section header includes a separator line.
|
||||
*/
|
||||
hasSeparatorLine: boolean;
|
||||
/**
|
||||
* This section should be omitted before rendering if it's not in a comment.
|
||||
*/
|
||||
shouldBeInComments: boolean;
|
||||
}
|
||||
|
||||
const markRegex = /\bMARK:\s*(.*)$/d;
|
||||
const trimDashesRegex = /^-+|-+$/g;
|
||||
|
||||
/**
|
||||
* Find section headers in the model.
|
||||
*
|
||||
* @param model the text model to search in
|
||||
* @param options options to search with
|
||||
* @returns an array of section headers
|
||||
*/
|
||||
export function findSectionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {
|
||||
let headers: SectionHeader[] = [];
|
||||
if (options.findRegionSectionHeaders && options.foldingRules?.markers) {
|
||||
const regionHeaders = collectRegionHeaders(model, options);
|
||||
headers = headers.concat(regionHeaders);
|
||||
}
|
||||
if (options.findMarkSectionHeaders) {
|
||||
const markHeaders = collectMarkHeaders(model);
|
||||
headers = headers.concat(markHeaders);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
function collectRegionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {
|
||||
const regionHeaders: SectionHeader[] = [];
|
||||
const endLineNumber = model.getLineCount();
|
||||
for (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
const match = lineContent.match(options.foldingRules!.markers!.start);
|
||||
if (match) {
|
||||
const range = { startLineNumber: lineNumber, startColumn: match[0].length + 1, endLineNumber: lineNumber, endColumn: lineContent.length + 1 };
|
||||
if (range.endColumn > range.startColumn) {
|
||||
const sectionHeader = {
|
||||
range,
|
||||
...getHeaderText(lineContent.substring(match[0].length)),
|
||||
shouldBeInComments: false
|
||||
};
|
||||
if (sectionHeader.text || sectionHeader.hasSeparatorLine) {
|
||||
regionHeaders.push(sectionHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return regionHeaders;
|
||||
}
|
||||
|
||||
function collectMarkHeaders(model: ISectionHeaderFinderTarget): SectionHeader[] {
|
||||
const markHeaders: SectionHeader[] = [];
|
||||
const endLineNumber = model.getLineCount();
|
||||
for (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) {
|
||||
const lineContent = model.getLineContent(lineNumber);
|
||||
addMarkHeaderIfFound(lineContent, lineNumber, markHeaders);
|
||||
}
|
||||
return markHeaders;
|
||||
}
|
||||
|
||||
function addMarkHeaderIfFound(lineContent: string, lineNumber: number, sectionHeaders: SectionHeader[]) {
|
||||
markRegex.lastIndex = 0;
|
||||
const match = markRegex.exec(lineContent);
|
||||
if (match) {
|
||||
const column = match.indices![1][0] + 1;
|
||||
const endColumn = match.indices![1][1] + 1;
|
||||
const range = { startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: endColumn };
|
||||
if (range.endColumn > range.startColumn) {
|
||||
const sectionHeader = {
|
||||
range,
|
||||
...getHeaderText(match[1]),
|
||||
shouldBeInComments: true
|
||||
};
|
||||
if (sectionHeader.text || sectionHeader.hasSeparatorLine) {
|
||||
sectionHeaders.push(sectionHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getHeaderText(text: string): { text: string; hasSeparatorLine: boolean } {
|
||||
text = text.trim();
|
||||
const hasSeparatorLine = text.startsWith('-');
|
||||
text = text.replace(trimDashesRegex, '');
|
||||
return { text, hasSeparatorLine };
|
||||
}
|
||||
@@ -647,6 +647,14 @@ export enum MinimapPosition {
|
||||
Gutter = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Section header style.
|
||||
*/
|
||||
export enum MinimapSectionHeaderStyle {
|
||||
Normal = 1,
|
||||
Underlined = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of hit element with the mouse in the editor.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancelablePromise, RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorOption, IEditorMinimapOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
|
||||
import { IModelDeltaDecoration, MinimapPosition, MinimapSectionHeaderStyle, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
|
||||
import { FindSectionHeaderOptions, SectionHeader } from 'vs/editor/common/services/findSectionHeaders';
|
||||
|
||||
export class SectionHeaderDetector extends Disposable implements IEditorContribution {
|
||||
|
||||
public static readonly ID: string = 'editor.sectionHeaderDetector';
|
||||
|
||||
private options: FindSectionHeaderOptions | undefined;
|
||||
private decorations = this.editor.createDecorationsCollection();
|
||||
private computeSectionHeaders: RunOnceScheduler;
|
||||
private computePromise: CancelablePromise<SectionHeader[]> | null;
|
||||
private currentOccurrences: { [decorationId: string]: SectionHeaderOccurrence };
|
||||
|
||||
constructor(
|
||||
private readonly editor: ICodeEditor,
|
||||
@ILanguageConfigurationService private readonly languageConfigurationService: ILanguageConfigurationService,
|
||||
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.options = this.createOptions(editor.getOption(EditorOption.minimap));
|
||||
this.computePromise = null;
|
||||
this.currentOccurrences = {};
|
||||
|
||||
this._register(editor.onDidChangeModel((e) => {
|
||||
this.currentOccurrences = {};
|
||||
this.options = this.createOptions(editor.getOption(EditorOption.minimap));
|
||||
this.stop();
|
||||
this.computeSectionHeaders.schedule(0);
|
||||
}));
|
||||
|
||||
this._register(editor.onDidChangeModelLanguage((e) => {
|
||||
this.currentOccurrences = {};
|
||||
this.options = this.createOptions(editor.getOption(EditorOption.minimap));
|
||||
this.stop();
|
||||
this.computeSectionHeaders.schedule(0);
|
||||
}));
|
||||
|
||||
this._register(languageConfigurationService.onDidChange((e) => {
|
||||
const editorLanguageId = this.editor.getModel()?.getLanguageId();
|
||||
if (editorLanguageId && e.affects(editorLanguageId)) {
|
||||
this.currentOccurrences = {};
|
||||
this.options = this.createOptions(editor.getOption(EditorOption.minimap));
|
||||
this.stop();
|
||||
this.computeSectionHeaders.schedule(0);
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(editor.onDidChangeConfiguration(e => {
|
||||
if (this.options && !e.hasChanged(EditorOption.minimap)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.options = this.createOptions(editor.getOption(EditorOption.minimap));
|
||||
|
||||
// Remove any links (for the getting disabled case)
|
||||
this.updateDecorations([]);
|
||||
|
||||
// Stop any computation (for the getting disabled case)
|
||||
this.stop();
|
||||
|
||||
// Start computing (for the getting enabled case)
|
||||
this.computeSectionHeaders.schedule(0);
|
||||
}));
|
||||
|
||||
this._register(this.editor.onDidChangeModelContent(e => {
|
||||
this.computeSectionHeaders.schedule();
|
||||
}));
|
||||
|
||||
this.computeSectionHeaders = this._register(new RunOnceScheduler(() => {
|
||||
this.findSectionHeaders();
|
||||
}, 250));
|
||||
|
||||
this.computeSectionHeaders.schedule(0);
|
||||
}
|
||||
|
||||
private createOptions(minimap: Readonly<Required<IEditorMinimapOptions>>): FindSectionHeaderOptions | undefined {
|
||||
if (!minimap || !this.editor.hasModel()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const languageId = this.editor.getModel().getLanguageId();
|
||||
if (!languageId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const commentsConfiguration = this.languageConfigurationService.getLanguageConfiguration(languageId).comments;
|
||||
const foldingRules = this.languageConfigurationService.getLanguageConfiguration(languageId).foldingRules;
|
||||
|
||||
if (!commentsConfiguration && !foldingRules?.markers) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
foldingRules,
|
||||
findMarkSectionHeaders: minimap.showMarkSectionHeaders,
|
||||
findRegionSectionHeaders: minimap.showRegionSectionHeaders,
|
||||
};
|
||||
}
|
||||
|
||||
private findSectionHeaders() {
|
||||
if (!this.editor.hasModel()
|
||||
|| (!this.options?.findMarkSectionHeaders && !this.options?.findRegionSectionHeaders)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const model = this.editor.getModel();
|
||||
if (model.isDisposed() || model.isTooLargeForSyncing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modelVersionId = model.getVersionId();
|
||||
this.editorWorkerService.findSectionHeaders(model.uri, this.options)
|
||||
.then((sectionHeaders) => {
|
||||
if (model.isDisposed() || model.getVersionId() !== modelVersionId) {
|
||||
// model changed in the meantime
|
||||
return;
|
||||
}
|
||||
this.updateDecorations(sectionHeaders);
|
||||
});
|
||||
}
|
||||
|
||||
private updateDecorations(sectionHeaders: SectionHeader[]): void {
|
||||
|
||||
const model = this.editor.getModel();
|
||||
if (model) {
|
||||
// Remove all section headers that should be in comments and are not in comments
|
||||
sectionHeaders = sectionHeaders.filter((sectionHeader) => {
|
||||
if (!sectionHeader.shouldBeInComments) {
|
||||
return true;
|
||||
}
|
||||
const validRange = model.validateRange(sectionHeader.range);
|
||||
const tokens = model.tokenization.getLineTokens(validRange.startLineNumber);
|
||||
const idx = tokens.findTokenIndexAtOffset(validRange.startColumn - 1);
|
||||
const tokenType = tokens.getStandardTokenType(idx);
|
||||
const languageId = tokens.getLanguageId(idx);
|
||||
return (languageId === model.getLanguageId() && tokenType === StandardTokenType.Comment);
|
||||
});
|
||||
}
|
||||
|
||||
const oldDecorations = Object.values(this.currentOccurrences).map(occurrence => occurrence.decorationId);
|
||||
const newDecorations = sectionHeaders.map(sectionHeader => decoration(sectionHeader));
|
||||
|
||||
this.editor.changeDecorations((changeAccessor) => {
|
||||
const decorations = changeAccessor.deltaDecorations(oldDecorations, newDecorations);
|
||||
|
||||
this.currentOccurrences = {};
|
||||
for (let i = 0, len = decorations.length; i < len; i++) {
|
||||
const occurrence = { sectionHeader: sectionHeaders[i], decorationId: decorations[i] };
|
||||
this.currentOccurrences[occurrence.decorationId] = occurrence;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private stop(): void {
|
||||
this.computeSectionHeaders.cancel();
|
||||
if (this.computePromise) {
|
||||
this.computePromise.cancel();
|
||||
this.computePromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override dispose(): void {
|
||||
super.dispose();
|
||||
this.stop();
|
||||
this.decorations.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface SectionHeaderOccurrence {
|
||||
readonly sectionHeader: SectionHeader;
|
||||
readonly decorationId: string;
|
||||
}
|
||||
|
||||
function decoration(sectionHeader: SectionHeader): IModelDeltaDecoration {
|
||||
return {
|
||||
range: sectionHeader.range,
|
||||
options: ModelDecorationOptions.createDynamic({
|
||||
description: 'section-header',
|
||||
stickiness: TrackedRangeStickiness.GrowsOnlyWhenTypingAfter,
|
||||
collapseOnReplaceEdit: true,
|
||||
minimap: {
|
||||
color: undefined,
|
||||
position: MinimapPosition.Inline,
|
||||
sectionHeaderStyle: sectionHeader.hasSeparatorLine ? MinimapSectionHeaderStyle.Underlined : MinimapSectionHeaderStyle.Normal,
|
||||
sectionHeaderText: sectionHeader.text,
|
||||
},
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
registerEditorContribution(SectionHeaderDetector.ID, SectionHeaderDetector, EditorContributionInstantiation.AfterFirstRender);
|
||||
@@ -44,6 +44,7 @@ import 'vs/editor/contrib/multicursor/browser/multicursor';
|
||||
import 'vs/editor/contrib/inlineEdit/browser/inlineEdit.contribution';
|
||||
import 'vs/editor/contrib/parameterHints/browser/parameterHints';
|
||||
import 'vs/editor/contrib/rename/browser/rename';
|
||||
import 'vs/editor/contrib/sectionHeaders/browser/sectionHeaders';
|
||||
import 'vs/editor/contrib/semanticTokens/browser/documentSemanticTokens';
|
||||
import 'vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens';
|
||||
import 'vs/editor/contrib/smartSelect/browser/smartSelect';
|
||||
|
||||
@@ -550,6 +550,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor {
|
||||
EndOfLinePreference: standaloneEnums.EndOfLinePreference,
|
||||
EndOfLineSequence: standaloneEnums.EndOfLineSequence,
|
||||
MinimapPosition: standaloneEnums.MinimapPosition,
|
||||
MinimapSectionHeaderStyle: standaloneEnums.MinimapSectionHeaderStyle,
|
||||
MouseTargetType: standaloneEnums.MouseTargetType,
|
||||
OverlayWidgetPositionPreference: standaloneEnums.OverlayWidgetPositionPreference,
|
||||
OverviewRulerLane: standaloneEnums.OverviewRulerLane,
|
||||
|
||||
@@ -58,6 +58,9 @@ suite('Editor ViewLayout - EditorLayoutProvider', () => {
|
||||
maxColumn: input.minimapMaxColumn,
|
||||
showSlider: 'mouseover',
|
||||
scale: 1,
|
||||
showRegionSectionHeaders: true,
|
||||
showMarkSectionHeaders: true,
|
||||
sectionHeaderFontSize: 9
|
||||
};
|
||||
options._write(EditorOption.minimap, minimapOptions);
|
||||
const scrollbarOptions: InternalEditorScrollbarOptions = {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { DiffAlgorithmName, IEditorWorkerService, IUnicodeHighlightsResult } fro
|
||||
import { TextEdit, IInplaceReplaceSupportResult } from 'vs/editor/common/languages';
|
||||
import { IDocumentDiff, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';
|
||||
import { IChange } from 'vs/editor/common/diff/legacyLinesDiffComputer';
|
||||
import { SectionHeader } from 'vs/editor/common/services/findSectionHeaders';
|
||||
|
||||
export class TestEditorWorkerService implements IEditorWorkerService {
|
||||
|
||||
@@ -25,4 +26,5 @@ export class TestEditorWorkerService implements IEditorWorkerService {
|
||||
async computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> { return null; }
|
||||
canNavigateValueSet(resource: URI): boolean { return false; }
|
||||
async navigateValueSet(resource: URI, range: IRange, up: boolean): Promise<IInplaceReplaceSupportResult | null> { return null; }
|
||||
async findSectionHeaders(uri: URI): Promise<SectionHeader[]> { return []; }
|
||||
}
|
||||
|
||||
Vendored
+28
@@ -1613,6 +1613,14 @@ declare namespace monaco.editor {
|
||||
Gutter = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Section header style.
|
||||
*/
|
||||
export enum MinimapSectionHeaderStyle {
|
||||
Normal = 1,
|
||||
Underlined = 2
|
||||
}
|
||||
|
||||
export interface IDecorationOptions {
|
||||
/**
|
||||
* CSS color to render.
|
||||
@@ -1656,6 +1664,14 @@ declare namespace monaco.editor {
|
||||
* The position in the minimap.
|
||||
*/
|
||||
position: MinimapPosition;
|
||||
/**
|
||||
* If the decoration is for a section header, which header style.
|
||||
*/
|
||||
sectionHeaderStyle?: MinimapSectionHeaderStyle | null;
|
||||
/**
|
||||
* If the decoration is for a section header, the header text.
|
||||
*/
|
||||
sectionHeaderText?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4290,6 +4306,18 @@ declare namespace monaco.editor {
|
||||
* Relative size of the font in the minimap. Defaults to 1.
|
||||
*/
|
||||
scale?: number;
|
||||
/**
|
||||
* Whether to show named regions as section headers. Defaults to true.
|
||||
*/
|
||||
showRegionSectionHeaders?: boolean;
|
||||
/**
|
||||
* Whether to show MARK: comments as section headers. Defaults to true.
|
||||
*/
|
||||
showMarkSectionHeaders?: boolean;
|
||||
/**
|
||||
* Font size of section headers. Defaults to 9.
|
||||
*/
|
||||
sectionHeaderFontSize?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import 'vs/css!./media/style';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { WORKBENCH_BACKGROUND, TITLE_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { isWeb, isIOS, isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { isWeb, isIOS } from 'vs/base/common/platform';
|
||||
import { createMetaElement } from 'vs/base/browser/dom';
|
||||
import { isSafari, isStandalone } from 'vs/base/browser/browser';
|
||||
import { selectionBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
@@ -60,13 +60,3 @@ registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`body { background-color: ${workbenchBackground}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The best font-family to be used in CSS based on the platform:
|
||||
* - Windows: Segoe preferred, fallback to sans-serif
|
||||
* - macOS: standard system font, fallback to sans-serif
|
||||
* - Linux: standard system font preferred, fallback to Ubuntu fonts
|
||||
*
|
||||
* Note: this currently does not adjust for different locales.
|
||||
*/
|
||||
export const DEFAULT_FONT_FAMILY = isWindows ? '"Segoe WPC", "Segoe UI", sans-serif' : isMacintosh ? '-apple-system, BlinkMacSystemFont, sans-serif' : 'system-ui, "Ubuntu", "Droid Sans", sans-serif';
|
||||
|
||||
@@ -33,7 +33,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { defaultCheckboxStyles } from 'vs/platform/theme/browser/defaultStyles';
|
||||
import { asCssVariableWithDefault, checkboxBorder, inputBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/base/browser/fonts';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
|
||||
import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands';
|
||||
import { ChatSubmitEditorAction, ChatSubmitSecondaryAgentEditorAction } from 'vs/workbench/contrib/chat/browser/actions/chatActions';
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreve
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
|
||||
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
|
||||
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/base/browser/fonts';
|
||||
import { HistoryNavigator } from 'vs/base/common/history';
|
||||
import { registerAndCreateHistoryNavigationContext, IHistoryNavigationContext } from 'vs/platform/history/browser/contextScopedHistoryWidget';
|
||||
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
|
||||
|
||||
@@ -15,7 +15,7 @@ import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/wi
|
||||
import { IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/base/browser/fonts';
|
||||
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
|
||||
import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestController';
|
||||
|
||||
@@ -67,7 +67,7 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/base/browser/fonts';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/base/browser/fonts';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ColorScheme } from 'vs/platform/theme/common/theme';
|
||||
import { IWorkbenchThemeService, IWorkbenchColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
|
||||
import { IWorkbenchColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { WebviewStyles } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
|
||||
interface WebviewThemeData {
|
||||
|
||||
Reference in New Issue
Block a user